Re: [RFC] Input: ADP5588 - Support GPI event for ADP5588 devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi, Michael  and Dmitry

Any comments?

-- 
Best Regards
Hu Tao

On Thu, Jun 10, 2010 at 10:36 AM, Xiaolong CHEN
<xiao-long.chen@xxxxxxxxxxxx> wrote:
> Hi,
>
> This patch supports GPI event for ADP5588 devices.
>
> Kernel Version: 2.6.34
>
> A column or row configured as a GPI can be programmed to be part of
> the key event table and therefore also capable of generating a key
> event interrupt. A key event interrupt caused by a GPI follows the
> same process flow as a key event interrupt caused by a key press. GPIs
> configured as part of the key event table allow single key switches
> and other GPI interrupts to bemonitored. As part of the event table,
> GPIs are represented by the decimal value 97 (0x61or 1100001) through
> the decimal value 114 (0x72 or 1110010). See Table as below for GPI
> event number assignments for rows and columns.
>
> GPI Event Number Assignments for Rows
> Row0 Row1 Row2 Row3 Row4 Row5 Row6 Row7
> 97       98       99       100     101     102     103    104
>
> GPI Event Number Assignments for Cols
> Col0 Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8 Col9
> 105  106   107   108   109   110   111   112  113  114
>
> Usage:
> 1. Enable CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> 2. Add gpimap and gpimapsize setting in adp5588_kpad_platform_data
> (The settings should not conflict with rows/cols for keymap)
>
> Patch:
> From 75412f66cc16c19c8b6046ed499ccf6e34db01c3 Mon Sep 17 00:00:00 2001
> From: xiaolong <a21785@xxxxxxxxxxxx>
> Date: Thu, 10 Jun 2010 05:13:13 -0400
> Subject: [PATCH] Input: ADP5588 - Support GPI event for ADP5588 devices
>
> A column or row configured as a GPI can be programmed to be part
> of the key event table and therefore also capable of generating a
> key event interrupt. A key event interrupt caused by a GPI follows
> the same process flow as a key event interrupt caused by a key
> press. GPIs configured as part of the key event table allow single
> key switches and other GPI interrupts to bemonitored. As part of
> the event table, GPIs are represented by the decimal value 97 (0x61
> or 1100001) through the decimal value 114 (0x72 or 1110010). See
> Table as below for GPI event number assignments for rows and columns.
>
> GPI Event Number Assignments for Rows
> Row0 Row1 Row2 Row3 Row4 Row5 Row6 Row7
> 97   98   99   100  101  102  103  104
>
> GPI Event Number Assignments for Cols
> Col0 Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8 Col9
> 105  106  107  108  109  110  111  112  113  114
>
> Signed-off-by: Xiaolong Chen <xiao-long.chen@xxxxxxxxxxxx>
> Signed-off-by: Yuanbo Ye <yuan-bo.ye@xxxxxxxxxxxx>
> Signed-off-by: Tao Hu <taohu@xxxxxxxxxxxx>
> ---
>  drivers/input/keyboard/Kconfig        |    8 ++
>  drivers/input/keyboard/adp5588-keys.c |  126 +++++++++++++++++++++++++++++++++
>  include/linux/i2c/adp5588.h           |   40 ++++++++++
>  3 files changed, 174 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index 64c1023..aebf8de 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -44,6 +44,14 @@ config KEYBOARD_ADP5588
>          To compile this driver as a module, choose M here: the
>          module will be called adp5588-keys.
>
> +config KEYBOARD_ADP5588_GPI_EVENT
> +       tristate "ADP5588 GPI event on key event interrupt"
> +       depends on KEYBOARD_ADP5588
> +       help
> +         Enable GPI events on key event interrupt, GPIs configured
> +         as part of the key event table allow single key switches
> +         and other GPI interrupts to be monitored.
> +
>  config KEYBOARD_AMIGA
>        tristate "Amiga keyboard"
>        depends on AMIGA
> diff --git a/drivers/input/keyboard/adp5588-keys.c
> b/drivers/input/keyboard/adp5588-keys.c
> index b5142d2..4cd5cee 100644
> --- a/drivers/input/keyboard/adp5588-keys.c
> +++ b/drivers/input/keyboard/adp5588-keys.c
> @@ -66,6 +66,10 @@ struct adp5588_kpad {
>        struct delayed_work work;
>        unsigned long delay;
>        unsigned short keycode[ADP5588_KEYMAPSIZE];
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +       const struct adp5588_gpi_map *gpimap;
> +       unsigned short gpimapsize;
> +#endif
>  };
>
>  static int adp5588_read(struct i2c_client *client, u8 reg)
> @@ -99,10 +103,33 @@ static void adp5588_work(struct work_struct *work)
>                ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
>                if (ev_cnt) {
>                        for (i = 0; i < ev_cnt; i++) {
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +                               int j, key_val, pin;
> +#endif
>                                key = adp5588_read(client, Key_EVENTA + i);
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +                               key_val = key & (~KEY_EV_PRESSED);
> +
> +                               if ((key_val >= GPI_PIN_BASE) &&
> +                                       (key_val <= GPI_PIN_END)) {
> +                                       for (j = 0; j < kpad->gpimapsize; j++) {
> +                                               pin = kpad->gpimap[j].pin;
> +                                               if (key_val != pin)
> +                                                       continue;
> +
> +                                               input_report_switch(kpad->input,
> +                                                       kpad->gpimap[j].sw_evt,
> +                                                       key & KEY_EV_PRESSED);
> +                                               break;
> +                                       }
> +                               } else {
> +#endif
>                                input_report_key(kpad->input,
>                                        kpad->keycode[(key & KEY_EV_MASK) - 1],
>                                        key & KEY_EV_PRESSED);
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +                               }
> +#endif
>                        }
>                        input_sync(kpad->input);
>                }
> @@ -129,6 +156,9 @@ static int __devinit adp5588_setup(struct
> i2c_client *client)
>  {
>        struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
>        int i, ret;
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +       unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
> +#endif
>
>        ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
>        ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
> @@ -143,6 +173,23 @@ static int __devinit adp5588_setup(struct
> i2c_client *client)
>        for (i = 0; i < KEYP_MAX_EVENT; i++)
>                ret |= adp5588_read(client, Key_EVENTA);
>
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +       for (i = 0; i < pdata->gpimapsize; i++) {
> +               unsigned short pin = pdata->gpimap[i].pin;
> +
> +               if (pin <= GPI_PIN_ROW_END) {
> +                       evt_mode1 |= (1 << (pin - GPI_PIN_ROW_BASE));
> +               } else {
> +                       evt_mode2 |= ((1 << (pin - GPI_PIN_COL_BASE)) & 0xFF);
> +                       evt_mode3 |= ((1 << (pin - GPI_PIN_COL_BASE)) >> 8);
> +               }
> +       }
> +
> +       ret |= adp5588_write(client, GPI_EM1, evt_mode1);
> +       ret |= adp5588_write(client, GPI_EM2, evt_mode2);
> +       ret |= adp5588_write(client, GPI_EM3, evt_mode3);
> +#endif
> +
>        ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
>                                        OVR_FLOW_INT | K_LCK_INT |
>                                        GPI_INT | KE_INT); /* Status is W1C */
> @@ -166,6 +213,9 @@ static int __devinit adp5588_probe(struct
> i2c_client *client,
>        unsigned int revid;
>        int ret, i;
>        int error;
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +       int gpi_stat1 = 0, gpi_stat2 = 0, gpi_stat3 = 0;
> +#endif
>
>        if (!i2c_check_functionality(client->adapter,
>                                        I2C_FUNC_SMBUS_BYTE_DATA)) {
> @@ -188,6 +238,39 @@ static int __devinit adp5588_probe(struct
> i2c_client *client,
>                return -EINVAL;
>        }
>
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +       if (!pdata->gpimap) {
> +               dev_err(&client->dev, "no gpimap from pdata\n");
> +               return -EINVAL;
> +       }
> +
> +       if (pdata->gpimapsize > ADP5588_GPIMAPSIZE_MAX) {
> +               dev_err(&client->dev, "invalid gpimapsize\n");
> +               return -EINVAL;
> +       }
> +
> +       for (i = 0; i < pdata->gpimapsize; i++) {
> +               unsigned short pin = pdata->gpimap[i].pin;
> +
> +               if ((pin < GPI_PIN_BASE) || (pin > GPI_PIN_END)) {
> +                       dev_err(&client->dev, "invalid gpi pin data\n");
> +                       return -EINVAL;
> +               }
> +
> +               if (pin <= GPI_PIN_ROW_END) {
> +                       if ((pin - GPI_PIN_ROW_BASE + 1) <= pdata->rows) {
> +                               dev_err(&client->dev, "invalid gpi row data\n");
> +                               return -EINVAL;
> +                       }
> +               } else {
> +                       if ((pin - GPI_PIN_COL_BASE + 1) <= pdata->cols) {
> +                               dev_err(&client->dev, "invalid gpi col data\n");
> +                               return -EINVAL;
> +                       }
> +               }
> +       }
> +#endif
> +
>        if (!client->irq) {
>                dev_err(&client->dev, "no IRQ?\n");
>                return -EINVAL;
> @@ -232,6 +315,11 @@ static int __devinit adp5588_probe(struct
> i2c_client *client,
>        memcpy(kpad->keycode, pdata->keymap,
>                pdata->keymapsize * input->keycodesize);
>
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +       kpad->gpimap = pdata->gpimap;
> +       kpad->gpimapsize = pdata->gpimapsize;
> +#endif
> +
>        /* setup input device */
>        __set_bit(EV_KEY, input->evbit);
>
> @@ -242,6 +330,12 @@ static int __devinit adp5588_probe(struct
> i2c_client *client,
>                __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
>        __clear_bit(KEY_RESERVED, input->keybit);
>
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +       __set_bit(EV_SW, input->evbit);
> +       for (i = 0; i < kpad->gpimapsize; i++)
> +               __set_bit(kpad->gpimap[i].sw_evt, input->swbit);
> +#endif
> +
>        error = input_register_device(input);
>        if (error) {
>                dev_err(&client->dev, "unable to register input device\n");
> @@ -263,6 +357,38 @@ static int __devinit adp5588_probe(struct
> i2c_client *client,
>        device_init_wakeup(&client->dev, 1);
>        i2c_set_clientdata(client, kpad);
>
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +       gpi_stat1 = adp5588_read(client, GPIO_DAT_STAT1);
> +       gpi_stat2 = adp5588_read(client, GPIO_DAT_STAT2);
> +       gpi_stat3 = adp5588_read(client, GPIO_DAT_STAT3);
> +
> +       for (i = 0; i < kpad->gpimapsize; i++) {
> +               int gpi_stat_tmp, pin_loc;
> +               unsigned short pin = kpad->gpimap[i].pin;
> +
> +               if (pin <= GPI_PIN_ROW_END) {
> +                       gpi_stat_tmp = gpi_stat1;
> +                       pin_loc = pin - GPI_PIN_ROW_BASE;
> +               } else if ((pin - GPI_PIN_COL_BASE) < 8) {
> +                       gpi_stat_tmp = gpi_stat2;
> +                       pin_loc = pin - GPI_PIN_COL_BASE;
> +               } else {
> +                       gpi_stat_tmp = gpi_stat3;
> +                       pin_loc = pin - GPI_PIN_COL_BASE - 8;
> +               }
> +
> +               if (gpi_stat_tmp < 0) {
> +                       dev_err(&client->dev, "Can't read GPIO_DAT_STAT "
> +                               "switch %d default to OFF\n", pin);
> +                       gpi_stat_tmp = 0;
> +               }
> +
> +               input_report_switch(input, kpad->gpimap[i].sw_evt,
> +                       !(gpi_stat_tmp & (1 << pin_loc)));
> +               input_sync(input);
> +       }
> +#endif
> +
>        dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
>        return 0;
>
> diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
> index 02c9af3..bb6365d 100644
> --- a/include/linux/i2c/adp5588.h
> +++ b/include/linux/i2c/adp5588.h
> @@ -78,6 +78,42 @@
>
>  #define ADP5588_KEYMAPSIZE     80
>
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +#define GPI_PIN_ROW0 97
> +#define GPI_PIN_ROW1 98
> +#define GPI_PIN_ROW2 99
> +#define GPI_PIN_ROW3 100
> +#define GPI_PIN_ROW4 101
> +#define GPI_PIN_ROW5 102
> +#define GPI_PIN_ROW6 103
> +#define GPI_PIN_ROW7 104
> +#define GPI_PIN_COL0 105
> +#define GPI_PIN_COL1 106
> +#define GPI_PIN_COL2 107
> +#define GPI_PIN_COL3 108
> +#define GPI_PIN_COL4 109
> +#define GPI_PIN_COL5 110
> +#define GPI_PIN_COL6 111
> +#define GPI_PIN_COL7 112
> +#define GPI_PIN_COL8 113
> +#define GPI_PIN_COL9 114
> +
> +#define GPI_PIN_ROW_BASE GPI_PIN_ROW0
> +#define GPI_PIN_ROW_END GPI_PIN_ROW7
> +#define GPI_PIN_COL_BASE GPI_PIN_COL0
> +#define GPI_PIN_COL_END GPI_PIN_COL9
> +
> +#define GPI_PIN_BASE GPI_PIN_ROW_BASE
> +#define GPI_PIN_END GPI_PIN_COL_END
> +
> +#define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1)
> +
> +struct adp5588_gpi_map {
> +       unsigned short pin;
> +       unsigned short sw_evt;
> +};
> +#endif
> +
>  struct adp5588_kpad_platform_data {
>        int rows;                       /* Number of rows */
>        int cols;                       /* Number of columns */
> @@ -87,6 +123,10 @@ struct adp5588_kpad_platform_data {
>        unsigned en_keylock:1;          /* Enable Key Lock feature */
>        unsigned short unlock_key1;     /* Unlock Key 1 */
>        unsigned short unlock_key2;     /* Unlock Key 2 */
> +#ifdef CONFIG_KEYBOARD_ADP5588_GPI_EVENT
> +       const struct adp5588_gpi_map *gpimap;
> +       unsigned short gpimapsize;
> +#endif
>  };
>
>  struct adp5588_gpio_platform_data {
> --
> 1.5.4.3
>
> If there is any comments and suggestion, please let me know.
>
> Thanks,
> Xiaolong
>



-- 
Best Regards
Hu Tao
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux