struct delayed_work work;
        unsigned long delay;
        unsigned short keycode[ADP5588_KEYMAPSIZE];
+       const struct adp5588_gpi_map *gpimap;
+       unsigned short gpimapsize;
 };
 
 static int adp5588_read(struct i2c_client *client, u8 reg)
        return i2c_smbus_write_byte_data(client, reg, val);
 }
 
+static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
+{
+       int i, j;
+
+       for (i = 0; i < ev_cnt; i++) {
+               int key = adp5588_read(kpad->client, Key_EVENTA + i);
+               int key_val = key & KEY_EV_MASK;
+
+               if (key_val >= GPI_PIN_BASE && key_val <= GPI_PIN_END) {
+                       for (j = 0; j < kpad->gpimapsize; j++) {
+                               if (key_val == kpad->gpimap[j].pin) {
+                                       input_report_switch(kpad->input,
+                                                       kpad->gpimap[j].sw_evt,
+                                                       key & KEY_EV_PRESSED);
+                                       break;
+                               }
+                       }
+               } else {
+                       input_report_key(kpad->input,
+                                        kpad->keycode[key_val - 1],
+                                        key & KEY_EV_PRESSED);
+               }
+       }
+}
+
 static void adp5588_work(struct work_struct *work)
 {
        struct adp5588_kpad *kpad = container_of(work,
                                                struct adp5588_kpad, work.work);
        struct i2c_client *client = kpad->client;
-       int i, key, status, ev_cnt;
+       int status, ev_cnt;
 
        status = adp5588_read(client, INT_STAT);
 
        if (status & KE_INT) {
                ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
                if (ev_cnt) {
-                       for (i = 0; i < ev_cnt; i++) {
-                               key = adp5588_read(client, Key_EVENTA + i);
-                               input_report_key(kpad->input,
-                                       kpad->keycode[(key & KEY_EV_MASK) - 1],
-                                       key & KEY_EV_PRESSED);
-                       }
+                       adp5588_report_events(kpad, ev_cnt);
                        input_sync(kpad->input);
                }
        }
 {
        struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
        int i, ret;
+       unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
 
        ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
        ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
        for (i = 0; i < KEYP_MAX_EVENT; i++)
                ret |= adp5588_read(client, Key_EVENTA);
 
+       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);
+               }
+       }
+
+       if (pdata->gpimapsize) {
+               ret |= adp5588_write(client, GPI_EM1, evt_mode1);
+               ret |= adp5588_write(client, GPI_EM2, evt_mode2);
+               ret |= adp5588_write(client, GPI_EM3, evt_mode3);
+       }
+
        ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
                                        OVR_FLOW_INT | K_LCK_INT |
                                        GPI_INT | KE_INT); /* Status is W1C */
        return 0;
 }
 
+static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad)
+{
+       int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1);
+       int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2);
+       int gpi_stat3 = adp5588_read(kpad->client, GPIO_DAT_STAT3);
+       int gpi_stat_tmp, pin_loc;
+       int i;
+
+       for (i = 0; i < kpad->gpimapsize; i++) {
+               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(&kpad->client->dev,
+                               "Can't read GPIO_DAT_STAT switch %d default to OFF\n",
+                               pin);
+                       gpi_stat_tmp = 0;
+               }
+
+               input_report_switch(kpad->input,
+                                   kpad->gpimap[i].sw_evt,
+                                   !(gpi_stat_tmp & (1 << pin_loc)));
+       }
+
+       input_sync(kpad->input);
+}
+
+
 static int __devinit adp5588_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
                return -EINVAL;
        }
 
+       if (!pdata->gpimap && pdata->gpimapsize) {
+               dev_err(&client->dev, "invalid 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;
+                       }
+               }
+       }
+
        if (!client->irq) {
                dev_err(&client->dev, "no IRQ?\n");
                return -EINVAL;
        memcpy(kpad->keycode, pdata->keymap,
                pdata->keymapsize * input->keycodesize);
 
+       kpad->gpimap = pdata->gpimap;
+       kpad->gpimapsize = pdata->gpimapsize;
+
        /* setup input device */
        __set_bit(EV_KEY, input->evbit);
 
                __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
        __clear_bit(KEY_RESERVED, input->keybit);
 
+       if (kpad->gpimapsize)
+               __set_bit(EV_SW, input->evbit);
+       for (i = 0; i < kpad->gpimapsize; i++)
+               __set_bit(kpad->gpimap[i].sw_evt, input->swbit);
+
        error = input_register_device(input);
        if (error) {
                dev_err(&client->dev, "unable to register input device\n");
        if (error)
                goto err_free_irq;
 
+       if (kpad->gpimapsize)
+               adp5588_report_switch_state(kpad);
+
        device_init_wakeup(&client->dev, 1);
        i2c_set_clientdata(client, kpad);
 
 
 
 #define ADP5588_KEYMAPSIZE     80
 
+#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;
+};
+
 struct adp5588_kpad_platform_data {
        int rows;                       /* Number of rows */
        int cols;                       /* Number of columns */
        unsigned en_keylock:1;          /* Enable Key Lock feature */
        unsigned short unlock_key1;     /* Unlock Key 1 */
        unsigned short unlock_key2;     /* Unlock Key 2 */
+       const struct adp5588_gpi_map *gpimap;
+       unsigned short gpimapsize;
 };
 
 struct adp5588_gpio_platform_data {