From patchwork Tue Jun 22 11:12:40 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiaolong CHEN X-Patchwork-Id: 107369 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o5MBCmW2028858 for ; Tue, 22 Jun 2010 11:12:48 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752714Ab0FVLMs (ORCPT ); Tue, 22 Jun 2010 07:12:48 -0400 Received: from exprod5og114.obsmtp.com ([64.18.0.28]:47463 "EHLO exprod5og114.obsmtp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752695Ab0FVLMr convert rfc822-to-8bit (ORCPT ); Tue, 22 Jun 2010 07:12:47 -0400 Received: from source ([129.188.136.12]) (using TLSv1) by exprod5ob114.postini.com ([64.18.4.12]) with SMTP ID DSNKTCCareJ3mYKqYBg189uwxUiOS2dS/Syb@postini.com; Tue, 22 Jun 2010 04:12:46 PDT Received: from il06vts04.mot.com (il06vts04.mot.com [129.188.137.144]) by mdgate1.mot.com (8.14.3/8.14.3) with SMTP id o5MBCvqD029565 for ; Tue, 22 Jun 2010 05:12:57 -0600 (MDT) Received: from mail-iw0-f182.google.com (mail-iw0-f182.google.com [209.85.214.182]) by mdgate1.mot.com (8.14.3/8.14.3) with ESMTP id o5MBCvS1029554 (version=TLSv1/SSLv3 cipher=RC4-MD5 bits=128 verify=OK) for ; Tue, 22 Jun 2010 05:12:57 -0600 (MDT) Received: by iwn7 with SMTP id 7so6040116iwn.27 for ; Tue, 22 Jun 2010 04:12:44 -0700 (PDT) MIME-Version: 1.0 Received: by 10.42.2.147 with SMTP id 19mr2305372ick.25.1277205160785; Tue, 22 Jun 2010 04:12:40 -0700 (PDT) Received: by 10.231.174.138 with HTTP; Tue, 22 Jun 2010 04:12:40 -0700 (PDT) In-Reply-To: References: <201006101228.03993.dmitry.torokhov@gmail.com> Date: Tue, 22 Jun 2010 19:12:40 +0800 Message-ID: Subject: [PATCH] Input: ADP5588 - Support GPI event for ADP5588 devices From: Xiaolong CHEN To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Michael Hennerich , TAO HU , "Yuan.Bo YE" X-CFilter-Loop: Reflected Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 22 Jun 2010 11:12:49 +0000 (UTC) diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index b5142d2..ca5085e 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -66,6 +66,8 @@ struct adp5588_kpad { 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) @@ -99,10 +101,28 @@ 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++) { + int j, key_val, pin; + key = adp5588_read(client, Key_EVENTA + i); - input_report_key(kpad->input, - kpad->keycode[(key & KEY_EV_MASK) - 1], - key & KEY_EV_PRESSED); + key_val = key & KEY_EV_MASK; + + 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 { + input_report_key(kpad->input, + kpad->keycode[key_val - 1], + key & KEY_EV_PRESSED); + } } input_sync(kpad->input); } @@ -129,6 +149,7 @@ static int __devinit adp5588_setup(struct i2c_client *client) { 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); @@ -143,6 +164,23 @@ static int __devinit adp5588_setup(struct i2c_client *client) 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 */ @@ -166,6 +204,7 @@ static int __devinit adp5588_probe(struct i2c_client *client, unsigned int revid; int ret, i; int error; + int gpi_stat1 = 0, gpi_stat2 = 0, gpi_stat3 = 0; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -188,6 +227,37 @@ static int __devinit adp5588_probe(struct i2c_client *client, 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; @@ -232,6 +302,9 @@ static int __devinit adp5588_probe(struct i2c_client *client, 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); @@ -242,6 +315,11 @@ static int __devinit adp5588_probe(struct i2c_client *client, __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"); @@ -263,6 +341,38 @@ static int __devinit adp5588_probe(struct i2c_client *client, device_init_wakeup(&client->dev, 1); i2c_set_clientdata(client, kpad); + if (kpad->gpimapsize) { + 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); + } + 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..b5f57c4 100644 --- a/include/linux/i2c/adp5588.h +++ b/include/linux/i2c/adp5588.h @@ -78,6 +78,40 @@ #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 */ @@ -87,6 +121,8 @@ 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 */ + const struct adp5588_gpi_map *gpimap; + unsigned short gpimapsize; }; struct adp5588_gpio_platform_data {