From: Ben Dooks <ben-linux@fluff.org>
To: Joonyoung Shim <jy0922.shim@samsung.com>
Cc: ben-linux@fluff.org, kyungmin.park@samsung.com,
linux-samsung-soc@vger.kernel.org, dmitry.torokhov@gmail.com,
linux-arm-kernel@lists.infradead.org,
linux-input@vger.kernel.org
Subject: Re: [PATCH v2 5/5] input: samsung-keypad - Add samsung keypad driver
Date: Sun, 30 May 2010 04:42:50 +0100 [thread overview]
Message-ID: <20100530034250.GK7248@trinity.fluff.org> (raw)
In-Reply-To: <1275188784-23395-5-git-send-email-jy0922.shim@samsung.com>
On Sun, May 30, 2010 at 12:06:24PM +0900, Joonyoung Shim wrote:
> This patch adds support for keypad driver running on Samsung cpus. This
> driver is tested on GONI and Aquila board using S5PC110 cpu.
>
> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> drivers/input/keyboard/Kconfig | 9 +
> drivers/input/keyboard/Makefile | 1 +
> drivers/input/keyboard/samsung-keypad.c | 364 +++++++++++++++++++++++++++++++
> 3 files changed, 374 insertions(+), 0 deletions(-)
> create mode 100644 drivers/input/keyboard/samsung-keypad.c
>
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index d8fa5d7..bf6a50f 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -342,6 +342,15 @@ config KEYBOARD_PXA930_ROTARY
> To compile this driver as a module, choose M here: the
> module will be called pxa930_rotary.
>
> +config KEYBOARD_SAMSUNG
> + tristate "Samsung keypad support"
> + depends on SAMSUNG_DEV_KEYPAD
> + help
> + Say Y here if you want to use the Samsung keypad.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called samsung-keypad.
> +
> config KEYBOARD_STOWAWAY
> tristate "Stowaway keyboard"
> select SERIO
> diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
> index 4596d0c..8f973ed 100644
> --- a/drivers/input/keyboard/Makefile
> +++ b/drivers/input/keyboard/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
> obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
> obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
> obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
> +obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
> obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
> obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
> obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
> diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
> new file mode 100644
> index 0000000..f4bcf97
> --- /dev/null
> +++ b/drivers/input/keyboard/samsung-keypad.c
> @@ -0,0 +1,364 @@
> +/*
> + * samsung-keypad.c -- Samsung keypad driver
> + *
> + * Copyright (C) 2010 Samsung Electronics Co.Ltd
> + * Author: Joonyoung Shim <jy0922.shim@samsung.com>
> + * Author: Donghwa Lee <dh09.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <plat/cpu.h>
you should _not_ be including <plat/cpu.h> here. and it looks form
the rest of the file that there's nothing from it being used.
> +#include <plat/keypad.h>
> +#include <plat/regs-keypad.h>
> +
> +struct samsung_kp {
> + struct input_dev *input_dev;
> + struct timer_list timer;
> + struct clk *clk;
> + struct work_struct work;
> + void __iomem *base;
> + unsigned short *keycodes;
> + unsigned int row_shift;
> + unsigned int rows;
> + unsigned int cols;
> + unsigned int row_state[SAMSUNG_MAX_COLS];
> + int irq;
> +};
> +
> +static void samsung_kp_scan(struct samsung_kp *keypad, unsigned int *row_state)
> +{
> + unsigned int col;
> + unsigned int val;
> +
> + for (col = 0; col < keypad->cols; col++) {
> +#if CONFIG_ARCH_S5PV210
> + val = S5PV210_KEYIFCOLEN_MASK;
> + val &= ~(1 << col) << 8;
> +#else
> + val = SAMSUNG_KEYIFCOL_MASK;
> + val &= ~(1 << col);
> +#endif
no platform specific #ifdefs
> + writel(val, keypad->base + SAMSUNG_KEYIFCOL);
> + mdelay(1);
> +
> + val = readl(keypad->base + SAMSUNG_KEYIFROW);
> + row_state[col] = ~val & ((1 << keypad->rows) - 1);
> + }
> +
> + /* KEYIFCOL reg clear */
> + writel(0, keypad->base + SAMSUNG_KEYIFCOL);
> +}
> +
> +static void samsung_kp_worker(struct work_struct *work)
> +{
> + struct samsung_kp *keypad = container_of(work, struct samsung_kp, work);
> + unsigned int row_state[SAMSUNG_MAX_COLS];
> + unsigned int val;
> + unsigned int changed;
> + unsigned int pressed;
> + unsigned int key_down = 0;
> + int col, row;
> +
> + clk_enable(keypad->clk);
> +
> + val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
> +
> + /* interrupt clear */
> + writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
> +
> + val = readl(keypad->base + SAMSUNG_KEYIFCON);
> + val &= ~(SAMSUNG_INT_F_EN | SAMSUNG_INT_R_EN);
> + writel(val, keypad->base + SAMSUNG_KEYIFCON);
> +
> + samsung_kp_scan(keypad, row_state);
> +
> + for (col = 0; col < keypad->cols; col++) {
> + changed = row_state[col] ^ keypad->row_state[col];
> + key_down |= row_state[col];
> + if (!changed)
> + continue;
> +
> + for (row = 0; row < keypad->rows; row++) {
> + if (!(changed & (1 << row)))
> + continue;
> +
> + pressed = row_state[col] & (1 << row);
> +
> + dev_dbg(&keypad->input_dev->dev,
> + "key %s, row: %d, col: %d\n",
> + pressed ? "pressed" : "released", row, col);
> +
> + val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
> +
> + input_report_key(keypad->input_dev,
> + keypad->keycodes[val], pressed);
> + input_sync(keypad->input_dev);
> + }
> + }
> + memcpy(keypad->row_state, row_state, sizeof(row_state));
> +
> + if (key_down)
> + mod_timer(&keypad->timer, jiffies + HZ / 20);
> + else {
> + /* enable interrupt bit */
> + val = readl(keypad->base + SAMSUNG_KEYIFCON);
> + val |= (SAMSUNG_INT_F_EN | SAMSUNG_INT_R_EN);
> + writel(val, keypad->base + SAMSUNG_KEYIFCON);
> + enable_irq(keypad->irq);
> + }
> + clk_disable(keypad->clk);
> +}
> +
> +static irqreturn_t samsung_kp_interrupt(int irq, void *dev_id)
> +{
> + struct samsung_kp *keypad = dev_id;
> +
> + if (!work_pending(&keypad->work)) {
> + disable_irq_nosync(keypad->irq);
> + schedule_work(&keypad->work);
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void samsung_kp_timer(unsigned long data)
> +{
> + struct samsung_kp *keypad = (struct samsung_kp *)data;
> +
> + schedule_work(&keypad->work);
> +}
> +
> +static int __devinit samsung_kp_probe(struct platform_device *pdev)
> +{
> + const struct samsung_kp_platdata *pdata;
> + const struct matrix_keymap_data *keymap_data;
> + struct samsung_kp *keypad;
> + struct resource *res;
> + struct input_dev *input_dev;
> + unsigned short *keycodes;
> + unsigned int row_shift;
> + unsigned int val;
> + int ret;
> +
> + pdata = pdev->dev.platform_data;
> + if (!pdata) {
> + dev_err(&pdev->dev, "no platform data defined\n");
> + return -EINVAL;
> + }
> +
> + keymap_data = pdata->keymap_data;
> + if (!keymap_data) {
> + dev_err(&pdev->dev, "no keymap data defined\n");
> + return -EINVAL;
> + }
> +
> + if ((pdata->rows <= 0) || (pdata->rows > SAMSUNG_MAX_ROWS))
> + return -EINVAL;
how about making pdata->rows unsigned then if -ve values are illegal
> + if ((pdata->cols <= 0) || (pdata->cols > SAMSUNG_MAX_COLS))
> + return -EINVAL;
> +
> + /* initialize the gpio */
> + if (pdata->cfg_gpio)
> + pdata->cfg_gpio(pdata->rows, pdata->cols);
> +
> + row_shift = get_count_order(pdata->cols);
> + keypad = kzalloc(sizeof(*keypad), GFP_KERNEL);
> + keycodes = kzalloc((pdata->rows << row_shift) * sizeof(*keycodes),
> + GFP_KERNEL);
you could allocate this in one go.
> + input_dev = input_allocate_device();
> + if (!keypad || !keycodes || !input_dev) {
> + ret = -ENOMEM;
> + goto err_free_mem;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + ret = -ENODEV;
> + goto err_free_mem;
> + }
> +
> + keypad->base = ioremap(res->start, resource_size(res));
> + if (!keypad->base) {
> + ret = -EBUSY;
> + goto err_free_mem;
> + }
> +
> + keypad->clk = clk_get(&pdev->dev, "keypad");
> + if (IS_ERR(keypad->clk)) {
> + dev_err(&pdev->dev, "failed to get keypad clk\n");
> + ret = PTR_ERR(keypad->clk);
> + goto err_unmap_base;
> + }
> + clk_enable(keypad->clk);
> +
> + keypad->input_dev = input_dev;
> + keypad->keycodes = keycodes;
> + keypad->row_shift = row_shift;
> + keypad->rows = pdata->rows;
> + keypad->cols = pdata->cols;
> +
> + INIT_WORK(&keypad->work, samsung_kp_worker);
> +
> + setup_timer(&keypad->timer, samsung_kp_timer, (unsigned long)keypad);
> +
> + /* enable interrupt and wakeup bit */
> + val = SAMSUNG_INT_F_EN | SAMSUNG_INT_R_EN | SAMSUNG_WAKEUPEN;
> + writel(val, keypad->base + SAMSUNG_KEYIFCON);
> +
> + /* KEYIFCOL reg clear */
> + writel(0, keypad->base + SAMSUNG_KEYIFCOL);
> +
> + keypad->irq = platform_get_irq(pdev, 0);
> + if (keypad->irq < 0) {
> + ret = keypad->irq;
> + goto err_disable_clk;
> + }
> +
> + ret = request_irq(keypad->irq, samsung_kp_interrupt, 0,
> + dev_name(&pdev->dev), keypad);
> +
> + if (ret)
> + goto err_disable_clk;
> +
> + input_dev->name = pdev->name;
> + input_dev->id.bustype = BUS_HOST;
> + input_dev->dev.parent = &pdev->dev;
> +
> + input_dev->evbit[0] = BIT_MASK(EV_KEY);
> + if (pdata->rep)
> + input_dev->evbit[0] |= BIT_MASK(EV_REP);
> +
> + input_dev->keycode = keycodes;
> + input_dev->keycodesize = sizeof(*keycodes);
> + input_dev->keycodemax = pdata->rows << row_shift;
> +
> + matrix_keypad_build_keymap(keymap_data, row_shift,
> + input_dev->keycode, input_dev->keybit);
> +
> + ret = input_register_device(keypad->input_dev);
> + if (ret)
> + goto err_free_irq;
> +
> + platform_set_drvdata(pdev, keypad);
> + clk_disable(keypad->clk);
> +
> + return 0;
> +
> +err_free_irq:
> + free_irq(keypad->irq, keypad);
> +err_disable_clk:
> + clk_disable(keypad->clk);
> + clk_put(keypad->clk);
> +err_unmap_base:
> + iounmap(keypad->base);
> +err_free_mem:
> + input_free_device(input_dev);
> + kfree(keycodes);
> + kfree(keypad);
> +
> + return ret;
> +}
> +
> +static int __devexit samsung_kp_remove(struct platform_device *pdev)
> +{
> + struct samsung_kp *keypad = platform_get_drvdata(pdev);
> +
> + free_irq(keypad->irq, keypad);
> + cancel_work_sync(&keypad->work);
> + del_timer_sync(&keypad->timer);
> +
> + platform_set_drvdata(pdev, NULL);
> + input_unregister_device(keypad->input_dev);
> +
> + clk_disable(keypad->clk);
> + clk_put(keypad->clk);
> +
> + iounmap(keypad->base);
> + kfree(keypad->keycodes);
> + kfree(keypad);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int samsung_kp_suspend(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct samsung_kp *keypad = platform_get_drvdata(pdev);
> +
> + disable_irq(keypad->irq);
> +
> + return 0;
> +}
> +
> +static int samsung_kp_resume(struct device pdev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct samsung_kp *keypad = platform_get_drvdata(pdev);
> + unsigned int val;
> +
> + clk_enable(keypad->clk);
> +
> + /* enable interrupt and wakeup bit */
> + val = SAMSUNG_INT_F_EN | SAMSUNG_INT_R_EN | SAMSUNG_WAKEUPEN;
> + writel(val, keypad->base + SAMSUNG_KEYIFCON);
> +
> + /* KEYIFCOL reg clear */
> + writel(0, keypad->base + SAMSUNG_KEYIFCOL);
> +
> + enable_irq(keypad->irq);
> + clk_disable(keypad->clk);
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops samsung_kp_pm_ops = {
> + .suspend = samsung_kp_suspend,
> + .resume = samsung_kp_resume,
> +};
> +#endif
> +
> +static struct platform_driver samsung_kp_driver = {
> + .probe = samsung_kp_probe,
> + .remove = __devexit_p(samsung_kp_remove),
> + .driver = {
> + .name = "samsung-keypad",
> + .owner = THIS_MODULE,
> +#ifdef CONFIG_PM
> + .pm = &samsung_kp_pm_ops,
> +#endif
> + },
> +};
> +
> +static int __init samsung_kp_init(void)
> +{
> + return platform_driver_register(&samsung_kp_driver);
> +}
> +
> +static void __exit samsung_kp_exit(void)
> +{
> + platform_driver_unregister(&samsung_kp_driver);
> +}
> +
> +module_init(samsung_kp_init);
> +module_exit(samsung_kp_exit);
> +
> +MODULE_DESCRIPTION("Samsung keypad driver");
> +MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
> +MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
> +MODULE_LICENSE("GPL");
> --
> 1.7.0.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
--
Ben
Q: What's a light-year?
A: One-third less calories than a regular year.
WARNING: multiple messages have this Message-ID (diff)
From: ben-linux@fluff.org (Ben Dooks)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 5/5] input: samsung-keypad - Add samsung keypad driver
Date: Sun, 30 May 2010 04:42:50 +0100 [thread overview]
Message-ID: <20100530034250.GK7248@trinity.fluff.org> (raw)
In-Reply-To: <1275188784-23395-5-git-send-email-jy0922.shim@samsung.com>
On Sun, May 30, 2010 at 12:06:24PM +0900, Joonyoung Shim wrote:
> This patch adds support for keypad driver running on Samsung cpus. This
> driver is tested on GONI and Aquila board using S5PC110 cpu.
>
> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> drivers/input/keyboard/Kconfig | 9 +
> drivers/input/keyboard/Makefile | 1 +
> drivers/input/keyboard/samsung-keypad.c | 364 +++++++++++++++++++++++++++++++
> 3 files changed, 374 insertions(+), 0 deletions(-)
> create mode 100644 drivers/input/keyboard/samsung-keypad.c
>
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index d8fa5d7..bf6a50f 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -342,6 +342,15 @@ config KEYBOARD_PXA930_ROTARY
> To compile this driver as a module, choose M here: the
> module will be called pxa930_rotary.
>
> +config KEYBOARD_SAMSUNG
> + tristate "Samsung keypad support"
> + depends on SAMSUNG_DEV_KEYPAD
> + help
> + Say Y here if you want to use the Samsung keypad.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called samsung-keypad.
> +
> config KEYBOARD_STOWAWAY
> tristate "Stowaway keyboard"
> select SERIO
> diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
> index 4596d0c..8f973ed 100644
> --- a/drivers/input/keyboard/Makefile
> +++ b/drivers/input/keyboard/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
> obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
> obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
> obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
> +obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
> obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
> obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
> obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
> diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
> new file mode 100644
> index 0000000..f4bcf97
> --- /dev/null
> +++ b/drivers/input/keyboard/samsung-keypad.c
> @@ -0,0 +1,364 @@
> +/*
> + * samsung-keypad.c -- Samsung keypad driver
> + *
> + * Copyright (C) 2010 Samsung Electronics Co.Ltd
> + * Author: Joonyoung Shim <jy0922.shim@samsung.com>
> + * Author: Donghwa Lee <dh09.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <plat/cpu.h>
you should _not_ be including <plat/cpu.h> here. and it looks form
the rest of the file that there's nothing from it being used.
> +#include <plat/keypad.h>
> +#include <plat/regs-keypad.h>
> +
> +struct samsung_kp {
> + struct input_dev *input_dev;
> + struct timer_list timer;
> + struct clk *clk;
> + struct work_struct work;
> + void __iomem *base;
> + unsigned short *keycodes;
> + unsigned int row_shift;
> + unsigned int rows;
> + unsigned int cols;
> + unsigned int row_state[SAMSUNG_MAX_COLS];
> + int irq;
> +};
> +
> +static void samsung_kp_scan(struct samsung_kp *keypad, unsigned int *row_state)
> +{
> + unsigned int col;
> + unsigned int val;
> +
> + for (col = 0; col < keypad->cols; col++) {
> +#if CONFIG_ARCH_S5PV210
> + val = S5PV210_KEYIFCOLEN_MASK;
> + val &= ~(1 << col) << 8;
> +#else
> + val = SAMSUNG_KEYIFCOL_MASK;
> + val &= ~(1 << col);
> +#endif
no platform specific #ifdefs
> + writel(val, keypad->base + SAMSUNG_KEYIFCOL);
> + mdelay(1);
> +
> + val = readl(keypad->base + SAMSUNG_KEYIFROW);
> + row_state[col] = ~val & ((1 << keypad->rows) - 1);
> + }
> +
> + /* KEYIFCOL reg clear */
> + writel(0, keypad->base + SAMSUNG_KEYIFCOL);
> +}
> +
> +static void samsung_kp_worker(struct work_struct *work)
> +{
> + struct samsung_kp *keypad = container_of(work, struct samsung_kp, work);
> + unsigned int row_state[SAMSUNG_MAX_COLS];
> + unsigned int val;
> + unsigned int changed;
> + unsigned int pressed;
> + unsigned int key_down = 0;
> + int col, row;
> +
> + clk_enable(keypad->clk);
> +
> + val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
> +
> + /* interrupt clear */
> + writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
> +
> + val = readl(keypad->base + SAMSUNG_KEYIFCON);
> + val &= ~(SAMSUNG_INT_F_EN | SAMSUNG_INT_R_EN);
> + writel(val, keypad->base + SAMSUNG_KEYIFCON);
> +
> + samsung_kp_scan(keypad, row_state);
> +
> + for (col = 0; col < keypad->cols; col++) {
> + changed = row_state[col] ^ keypad->row_state[col];
> + key_down |= row_state[col];
> + if (!changed)
> + continue;
> +
> + for (row = 0; row < keypad->rows; row++) {
> + if (!(changed & (1 << row)))
> + continue;
> +
> + pressed = row_state[col] & (1 << row);
> +
> + dev_dbg(&keypad->input_dev->dev,
> + "key %s, row: %d, col: %d\n",
> + pressed ? "pressed" : "released", row, col);
> +
> + val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
> +
> + input_report_key(keypad->input_dev,
> + keypad->keycodes[val], pressed);
> + input_sync(keypad->input_dev);
> + }
> + }
> + memcpy(keypad->row_state, row_state, sizeof(row_state));
> +
> + if (key_down)
> + mod_timer(&keypad->timer, jiffies + HZ / 20);
> + else {
> + /* enable interrupt bit */
> + val = readl(keypad->base + SAMSUNG_KEYIFCON);
> + val |= (SAMSUNG_INT_F_EN | SAMSUNG_INT_R_EN);
> + writel(val, keypad->base + SAMSUNG_KEYIFCON);
> + enable_irq(keypad->irq);
> + }
> + clk_disable(keypad->clk);
> +}
> +
> +static irqreturn_t samsung_kp_interrupt(int irq, void *dev_id)
> +{
> + struct samsung_kp *keypad = dev_id;
> +
> + if (!work_pending(&keypad->work)) {
> + disable_irq_nosync(keypad->irq);
> + schedule_work(&keypad->work);
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void samsung_kp_timer(unsigned long data)
> +{
> + struct samsung_kp *keypad = (struct samsung_kp *)data;
> +
> + schedule_work(&keypad->work);
> +}
> +
> +static int __devinit samsung_kp_probe(struct platform_device *pdev)
> +{
> + const struct samsung_kp_platdata *pdata;
> + const struct matrix_keymap_data *keymap_data;
> + struct samsung_kp *keypad;
> + struct resource *res;
> + struct input_dev *input_dev;
> + unsigned short *keycodes;
> + unsigned int row_shift;
> + unsigned int val;
> + int ret;
> +
> + pdata = pdev->dev.platform_data;
> + if (!pdata) {
> + dev_err(&pdev->dev, "no platform data defined\n");
> + return -EINVAL;
> + }
> +
> + keymap_data = pdata->keymap_data;
> + if (!keymap_data) {
> + dev_err(&pdev->dev, "no keymap data defined\n");
> + return -EINVAL;
> + }
> +
> + if ((pdata->rows <= 0) || (pdata->rows > SAMSUNG_MAX_ROWS))
> + return -EINVAL;
how about making pdata->rows unsigned then if -ve values are illegal
> + if ((pdata->cols <= 0) || (pdata->cols > SAMSUNG_MAX_COLS))
> + return -EINVAL;
> +
> + /* initialize the gpio */
> + if (pdata->cfg_gpio)
> + pdata->cfg_gpio(pdata->rows, pdata->cols);
> +
> + row_shift = get_count_order(pdata->cols);
> + keypad = kzalloc(sizeof(*keypad), GFP_KERNEL);
> + keycodes = kzalloc((pdata->rows << row_shift) * sizeof(*keycodes),
> + GFP_KERNEL);
you could allocate this in one go.
> + input_dev = input_allocate_device();
> + if (!keypad || !keycodes || !input_dev) {
> + ret = -ENOMEM;
> + goto err_free_mem;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + ret = -ENODEV;
> + goto err_free_mem;
> + }
> +
> + keypad->base = ioremap(res->start, resource_size(res));
> + if (!keypad->base) {
> + ret = -EBUSY;
> + goto err_free_mem;
> + }
> +
> + keypad->clk = clk_get(&pdev->dev, "keypad");
> + if (IS_ERR(keypad->clk)) {
> + dev_err(&pdev->dev, "failed to get keypad clk\n");
> + ret = PTR_ERR(keypad->clk);
> + goto err_unmap_base;
> + }
> + clk_enable(keypad->clk);
> +
> + keypad->input_dev = input_dev;
> + keypad->keycodes = keycodes;
> + keypad->row_shift = row_shift;
> + keypad->rows = pdata->rows;
> + keypad->cols = pdata->cols;
> +
> + INIT_WORK(&keypad->work, samsung_kp_worker);
> +
> + setup_timer(&keypad->timer, samsung_kp_timer, (unsigned long)keypad);
> +
> + /* enable interrupt and wakeup bit */
> + val = SAMSUNG_INT_F_EN | SAMSUNG_INT_R_EN | SAMSUNG_WAKEUPEN;
> + writel(val, keypad->base + SAMSUNG_KEYIFCON);
> +
> + /* KEYIFCOL reg clear */
> + writel(0, keypad->base + SAMSUNG_KEYIFCOL);
> +
> + keypad->irq = platform_get_irq(pdev, 0);
> + if (keypad->irq < 0) {
> + ret = keypad->irq;
> + goto err_disable_clk;
> + }
> +
> + ret = request_irq(keypad->irq, samsung_kp_interrupt, 0,
> + dev_name(&pdev->dev), keypad);
> +
> + if (ret)
> + goto err_disable_clk;
> +
> + input_dev->name = pdev->name;
> + input_dev->id.bustype = BUS_HOST;
> + input_dev->dev.parent = &pdev->dev;
> +
> + input_dev->evbit[0] = BIT_MASK(EV_KEY);
> + if (pdata->rep)
> + input_dev->evbit[0] |= BIT_MASK(EV_REP);
> +
> + input_dev->keycode = keycodes;
> + input_dev->keycodesize = sizeof(*keycodes);
> + input_dev->keycodemax = pdata->rows << row_shift;
> +
> + matrix_keypad_build_keymap(keymap_data, row_shift,
> + input_dev->keycode, input_dev->keybit);
> +
> + ret = input_register_device(keypad->input_dev);
> + if (ret)
> + goto err_free_irq;
> +
> + platform_set_drvdata(pdev, keypad);
> + clk_disable(keypad->clk);
> +
> + return 0;
> +
> +err_free_irq:
> + free_irq(keypad->irq, keypad);
> +err_disable_clk:
> + clk_disable(keypad->clk);
> + clk_put(keypad->clk);
> +err_unmap_base:
> + iounmap(keypad->base);
> +err_free_mem:
> + input_free_device(input_dev);
> + kfree(keycodes);
> + kfree(keypad);
> +
> + return ret;
> +}
> +
> +static int __devexit samsung_kp_remove(struct platform_device *pdev)
> +{
> + struct samsung_kp *keypad = platform_get_drvdata(pdev);
> +
> + free_irq(keypad->irq, keypad);
> + cancel_work_sync(&keypad->work);
> + del_timer_sync(&keypad->timer);
> +
> + platform_set_drvdata(pdev, NULL);
> + input_unregister_device(keypad->input_dev);
> +
> + clk_disable(keypad->clk);
> + clk_put(keypad->clk);
> +
> + iounmap(keypad->base);
> + kfree(keypad->keycodes);
> + kfree(keypad);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int samsung_kp_suspend(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct samsung_kp *keypad = platform_get_drvdata(pdev);
> +
> + disable_irq(keypad->irq);
> +
> + return 0;
> +}
> +
> +static int samsung_kp_resume(struct device pdev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct samsung_kp *keypad = platform_get_drvdata(pdev);
> + unsigned int val;
> +
> + clk_enable(keypad->clk);
> +
> + /* enable interrupt and wakeup bit */
> + val = SAMSUNG_INT_F_EN | SAMSUNG_INT_R_EN | SAMSUNG_WAKEUPEN;
> + writel(val, keypad->base + SAMSUNG_KEYIFCON);
> +
> + /* KEYIFCOL reg clear */
> + writel(0, keypad->base + SAMSUNG_KEYIFCOL);
> +
> + enable_irq(keypad->irq);
> + clk_disable(keypad->clk);
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops samsung_kp_pm_ops = {
> + .suspend = samsung_kp_suspend,
> + .resume = samsung_kp_resume,
> +};
> +#endif
> +
> +static struct platform_driver samsung_kp_driver = {
> + .probe = samsung_kp_probe,
> + .remove = __devexit_p(samsung_kp_remove),
> + .driver = {
> + .name = "samsung-keypad",
> + .owner = THIS_MODULE,
> +#ifdef CONFIG_PM
> + .pm = &samsung_kp_pm_ops,
> +#endif
> + },
> +};
> +
> +static int __init samsung_kp_init(void)
> +{
> + return platform_driver_register(&samsung_kp_driver);
> +}
> +
> +static void __exit samsung_kp_exit(void)
> +{
> + platform_driver_unregister(&samsung_kp_driver);
> +}
> +
> +module_init(samsung_kp_init);
> +module_exit(samsung_kp_exit);
> +
> +MODULE_DESCRIPTION("Samsung keypad driver");
> +MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
> +MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
> +MODULE_LICENSE("GPL");
> --
> 1.7.0.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
--
Ben
Q: What's a light-year?
A: One-third less calories than a regular year.
next prev parent reply other threads:[~2010-05-30 3:42 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-30 3:06 [PATCH v2 1/5] ARM: SAMSUNG: Add keypad device support Joonyoung Shim
2010-05-30 3:06 ` Joonyoung Shim
2010-05-30 3:06 ` [PATCH v2 2/5] ARM: S5PV210: Add keypad device helpers Joonyoung Shim
2010-05-30 3:06 ` Joonyoung Shim
2010-05-30 3:06 ` [PATCH v2 3/5] ARM: S5PV210: Add keypad device to the GONI board Joonyoung Shim
2010-05-30 3:06 ` Joonyoung Shim
2010-05-30 3:06 ` [PATCH v2 4/5] ARM: S5PV210: Add keypad device to the Aquila board Joonyoung Shim
2010-05-30 3:06 ` Joonyoung Shim
2010-05-30 3:06 ` [PATCH v2 5/5] input: samsung-keypad - Add samsung keypad driver Joonyoung Shim
2010-05-30 3:06 ` Joonyoung Shim
2010-05-30 3:39 ` Marek Vasut
2010-05-30 3:39 ` Marek Vasut
2010-05-30 3:44 ` Ben Dooks
2010-05-30 3:44 ` Ben Dooks
2010-05-30 3:42 ` Joonyoung Shim
2010-05-30 3:42 ` Joonyoung Shim
2010-05-30 3:42 ` Ben Dooks [this message]
2010-05-30 3:42 ` Ben Dooks
2010-05-30 4:35 ` Joonyoung Shim
2010-05-30 4:35 ` Joonyoung Shim
2010-06-03 1:00 ` Ben Dooks
2010-06-03 1:00 ` Ben Dooks
2010-06-03 4:47 ` Joonyoung Shim
2010-06-03 4:47 ` Joonyoung Shim
2010-06-07 7:30 ` Marek Szyprowski
2010-06-07 7:30 ` Marek Szyprowski
2010-05-30 3:42 ` [PATCH v2 1/5] ARM: SAMSUNG: Add keypad device support Marek Vasut
2010-05-30 3:42 ` Marek Vasut
2010-05-30 4:46 ` Jassi Brar
2010-05-30 4:46 ` Jassi Brar
2010-05-30 4:51 ` Ben Dooks
2010-05-30 4:51 ` Ben Dooks
2010-05-30 5:04 ` Jassi Brar
2010-05-30 5:04 ` Jassi Brar
2010-05-30 5:21 ` Ben Dooks
2010-05-30 5:21 ` Ben Dooks
2010-05-31 9:44 ` Mark Brown
2010-05-31 9:44 ` Mark Brown
2010-05-30 8:52 ` Dmitry Torokhov
2010-05-30 8:52 ` Dmitry Torokhov
2010-05-31 1:14 ` Joonyoung Shim
2010-05-31 1:14 ` Joonyoung Shim
2010-05-31 0:06 ` Kukjin Kim
2010-05-31 0:06 ` Kukjin Kim
2010-05-31 0:15 ` Marek Vasut
2010-05-31 0:15 ` Marek Vasut
2010-05-31 1:09 ` Joonyoung Shim
2010-05-31 1:09 ` Joonyoung Shim
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100530034250.GK7248@trinity.fluff.org \
--to=ben-linux@fluff.org \
--cc=dmitry.torokhov@gmail.com \
--cc=jy0922.shim@samsung.com \
--cc=kyungmin.park@samsung.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-samsung-soc@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.