[PATCH 1/2] input: keyboard: Add keys driver for the LPC32xx SoC
Axel Lin
axel.lin at gmail.com
Tue Apr 24 06:01:10 EDT 2012
> +#ifdef CONFIG_OF
> +static struct lpc32XX_kscan_cfg *lpc32XX_parse_dt(struct device *dev)
> +{
> + struct lpc32XX_kscan_cfg *pdata;
> + struct device_node *np = dev->of_node;
> + struct device_node *key_np;
> + int key_count;
> + int i;
> +
> + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> + if (!pdata) {
> + dev_err(dev, "could not allocate memory for platform data\n");
> + return NULL;
> + }
> +
> + of_property_read_u32(np, "nxp,matrix-size", &pdata->matrix_sz);
> + of_property_read_u32(np, "nxp,debounce-delay-ms", &pdata->deb_clks);
> + of_property_read_u32(np, "nxp,scan-delay-ms", &pdata->scan_delay);
> +
> + if (!pdata->matrix_sz || !pdata->deb_clks || !pdata->scan_delay) {
> + dev_err(dev,
> + "matrix size, debounce or scan delay not specified\n");
> + goto out1;
> + }
> +
> + key_count = pdata->matrix_sz * pdata->matrix_sz;
> + pdata->keymap = devm_kzalloc(dev, sizeof(int) * key_count, GFP_KERNEL);
> + if (!pdata->keymap) {
> + dev_err(dev, "could not allocate memory for keymap\n");
> + goto out1;
> + }
> +
> + i = 0;
> + for_each_child_of_node(np, key_np) {
> + u32 key_code;
> + of_property_read_u32(key_np, "linux,code", &key_code);
> + pdata->keymap[i++] = key_code;
> + }
> +
> + return pdata;
> +out1:
> + devm_kfree(dev, pdata);
Since you are using devm_kzalloc, you don't need to call devm_kfree here.
> + return NULL;
> +}
> +
> +static
> +void lpc32XX_free_dt(struct device *dev, struct lpc32XX_kscan_cfg *pdata)
> +{
> + devm_kfree(dev, pdata->keymap);
> + devm_kfree(dev, pdata);
> +}
The same, you don't need the devm_kfree calls, so you can just kill
lpc32XX_free_dt function.
> +
> +#else
> +static struct lpc32XX_kscan_cfg *lpc32XX_parse_dt(struct device *dev)
> +{
> + return NULL;
> +}
> +
> +static
> +void lpc32XX_free_dt(struct device *dev, struct lpc32XX_kscan_cfg *pdata)
> +{
> +}
> +#endif
> +
> +static int __devinit lpc32xx_kscan_probe(struct platform_device *pdev)
> +{
> + struct lpc32xx_kscan_drv *kscandat;
> + struct resource *res;
> + int retval, i, keynum;
> +
> + kscandat = kzalloc(sizeof(struct lpc32xx_kscan_drv), GFP_KERNEL);
> + if (unlikely(!kscandat)) {
> + dev_err(&pdev->dev, "failed to allocate memory\n");
> + return -ENOMEM;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (res == NULL) {
> + dev_err(&pdev->dev, "failed to get platform I/O memory\n");
> + retval = -EBUSY;
> + goto err_nores;
> + }
> +
> + kscandat->kscan_base = devm_request_and_ioremap(&pdev->dev, res);
> + if (kscandat->kscan_base == NULL) {
> + dev_err(&pdev->dev, "failed to request and remap I/O memory\n");
> + retval = -EBUSY;
> + goto err_noremap;
> + }
> +
> + /* Get the key scanner clock */
> + kscandat->clk = clk_get(&pdev->dev, NULL);
> + if (IS_ERR(kscandat->clk)) {
> + dev_err(&pdev->dev, "failed to get clock\n");
> + retval = -ENODEV;
> + goto err_noclk;
> + }
> + clk_enable(kscandat->clk);
> +
> + kscandat->irq = platform_get_irq(pdev, 0);
> + if ((kscandat->irq < 0) || (kscandat->irq >= NR_IRQS)) {
> + dev_err(&pdev->dev, "failed to get platform irq\n");
> + retval = -EINVAL;
> + goto err_noirq;
> + }
> + retval = request_irq(kscandat->irq, lpc32xx_kscan_irq,
> + 0, pdev->name, kscandat);
> + if (retval) {
> + dev_err(&pdev->dev, "failed to request irq\n");
> + goto err_noirq;
> + }
> +
> + kscandat->input = input_allocate_device();
> + if (kscandat->input == NULL) {
> + dev_err(&pdev->dev, "failed to allocate device\n");
> + retval = -ENOMEM;
> + goto err_noalloc;
> + }
> +
> + if (pdev->dev.of_node)
> + kscandat->kscancfg = lpc32XX_parse_dt(&pdev->dev);
> + else
> + kscandat->kscancfg =
> + (struct lpc32XX_kscan_cfg *)pdev->dev.platform_data;
> + if (!kscandat->kscancfg) {
> + dev_err(&pdev->dev, "failed to get platform data\n");
> + retval = -EINVAL;
> + goto err_nopdata;
> + }
> +
> + platform_set_drvdata(pdev, kscandat);
> +
> + /* Setup key input */
> + kscandat->input->evbit[0] = BIT_MASK(EV_KEY);
> + kscandat->input->name = pdev->name;
> + kscandat->input->phys = "matrix-keys/input0";
> + kscandat->input->dev.parent = &pdev->dev;
> + kscandat->input->id.vendor = 0x0001;
> + kscandat->input->id.product = 0x0001;
> + kscandat->input->id.version = 0x0100;
> + keynum = kscandat->kscancfg->matrix_sz * kscandat->kscancfg->matrix_sz;
> + for (i = 0; i < keynum; i++)
> + __set_bit(kscandat->kscancfg->keymap[i],
> + kscandat->input->keybit);
> +
> + input_set_capability(kscandat->input, EV_MSC, MSC_SCAN);
> +
> + retval = input_register_device(kscandat->input);
> + if (retval) {
> + dev_err(&pdev->dev, "failed to register input device\n");
> + goto err_notregistered;
> + }
> +
> + /* Configure the key scanner */
> + __raw_writel(kscandat->kscancfg->deb_clks,
> + LPC32XX_KS_DEB(kscandat->kscan_base));
> + __raw_writel(kscandat->kscancfg->scan_delay,
> + LPC32XX_KS_SCAN_CTL(kscandat->kscan_base));
> + __raw_writel(LPC32XX_KSCAN_FTST_USE32K_CLK,
> + LPC32XX_KS_FAST_TST(kscandat->kscan_base));
> + __raw_writel(kscandat->kscancfg->matrix_sz,
> + LPC32XX_KS_MATRIX_DIM(kscandat->kscan_base));
> + __raw_writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base));
> +
> + return 0;
> +
> +err_notregistered:
> + lpc32XX_free_dt(&pdev->dev, kscandat->kscancfg);
> +err_nopdata:
> + input_free_device(kscandat->input);
> +err_noalloc:
> + free_irq(kscandat->irq, pdev);
> +err_noirq:
> + clk_put(kscandat->clk);
> +err_noclk:
> + iounmap(kscandat->kscan_base);
> +err_noremap:
> + release_mem_region(res->start, resource_size(res));
You are using devm_request_and_ioremap, so the iounmap and
release_mem_region calls
are not necessary.
> +err_nores:
> + kfree(kscandat);
> +
> + return retval;
> +}
> +
> +static int __devexit lpc32xx_kscan_remove(struct platform_device *pdev)
> +{
> + struct resource *res;
> + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev);
> +
> + free_irq(kscandat->irq, pdev);
> + input_unregister_device(kscandat->input);
> + clk_put(kscandat->clk);
> + iounmap(kscandat->kscan_base);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + release_mem_region(res->start, resource_size(res));
The same, iounmap and release_mem_region can be removed.
> +
> + kfree(kscandat);
> +
> + return 0;
> +}
> +
More information about the linux-arm-kernel
mailing list