mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-30 08:02:30 +00:00
Input: adp5588-keys - support GPI events 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 be monitored. 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 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@motorola.com> Signed-off-by: Yuanbo Ye <yuan-bo.ye@motorola.com> Signed-off-by: Tao Hu <taohu@motorola.com> Acked-by: Michael Hennerich <michael.hennerich@analog.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
parent
e725a4945d
commit
69a4af606e
2 changed files with 163 additions and 7 deletions
|
@ -67,6 +67,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)
|
||||
|
@ -84,12 +86,37 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
|
|||
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);
|
||||
|
||||
|
@ -99,12 +126,7 @@ static void adp5588_work(struct work_struct *work)
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +152,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);
|
||||
|
@ -144,6 +167,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 */
|
||||
|
@ -158,6 +198,44 @@ static int __devinit adp5588_setup(struct i2c_client *client)
|
|||
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)
|
||||
{
|
||||
|
@ -189,6 +267,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;
|
||||
|
@ -233,6 +342,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);
|
||||
|
||||
|
@ -243,6 +355,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");
|
||||
|
@ -261,6 +378,9 @@ static int __devinit adp5588_probe(struct i2c_client *client,
|
|||
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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue