diff options
-rw-r--r-- | drivers/input/keyboard/adp5588-keys.c | 134 | ||||
-rw-r--r-- | include/linux/i2c/adp5588.h | 36 |
2 files changed, 163 insertions, 7 deletions
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 4771ab172b59..4ef789ef1042 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c | |||
@@ -67,6 +67,8 @@ struct adp5588_kpad { | |||
67 | struct delayed_work work; | 67 | struct delayed_work work; |
68 | unsigned long delay; | 68 | unsigned long delay; |
69 | unsigned short keycode[ADP5588_KEYMAPSIZE]; | 69 | unsigned short keycode[ADP5588_KEYMAPSIZE]; |
70 | const struct adp5588_gpi_map *gpimap; | ||
71 | unsigned short gpimapsize; | ||
70 | }; | 72 | }; |
71 | 73 | ||
72 | static int adp5588_read(struct i2c_client *client, u8 reg) | 74 | 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) | |||
84 | return i2c_smbus_write_byte_data(client, reg, val); | 86 | return i2c_smbus_write_byte_data(client, reg, val); |
85 | } | 87 | } |
86 | 88 | ||
89 | static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt) | ||
90 | { | ||
91 | int i, j; | ||
92 | |||
93 | for (i = 0; i < ev_cnt; i++) { | ||
94 | int key = adp5588_read(kpad->client, Key_EVENTA + i); | ||
95 | int key_val = key & KEY_EV_MASK; | ||
96 | |||
97 | if (key_val >= GPI_PIN_BASE && key_val <= GPI_PIN_END) { | ||
98 | for (j = 0; j < kpad->gpimapsize; j++) { | ||
99 | if (key_val == kpad->gpimap[j].pin) { | ||
100 | input_report_switch(kpad->input, | ||
101 | kpad->gpimap[j].sw_evt, | ||
102 | key & KEY_EV_PRESSED); | ||
103 | break; | ||
104 | } | ||
105 | } | ||
106 | } else { | ||
107 | input_report_key(kpad->input, | ||
108 | kpad->keycode[key_val - 1], | ||
109 | key & KEY_EV_PRESSED); | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
87 | static void adp5588_work(struct work_struct *work) | 114 | static void adp5588_work(struct work_struct *work) |
88 | { | 115 | { |
89 | struct adp5588_kpad *kpad = container_of(work, | 116 | struct adp5588_kpad *kpad = container_of(work, |
90 | struct adp5588_kpad, work.work); | 117 | struct adp5588_kpad, work.work); |
91 | struct i2c_client *client = kpad->client; | 118 | struct i2c_client *client = kpad->client; |
92 | int i, key, status, ev_cnt; | 119 | int status, ev_cnt; |
93 | 120 | ||
94 | status = adp5588_read(client, INT_STAT); | 121 | status = adp5588_read(client, INT_STAT); |
95 | 122 | ||
@@ -99,12 +126,7 @@ static void adp5588_work(struct work_struct *work) | |||
99 | if (status & KE_INT) { | 126 | if (status & KE_INT) { |
100 | ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC; | 127 | ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC; |
101 | if (ev_cnt) { | 128 | if (ev_cnt) { |
102 | for (i = 0; i < ev_cnt; i++) { | 129 | adp5588_report_events(kpad, ev_cnt); |
103 | key = adp5588_read(client, Key_EVENTA + i); | ||
104 | input_report_key(kpad->input, | ||
105 | kpad->keycode[(key & KEY_EV_MASK) - 1], | ||
106 | key & KEY_EV_PRESSED); | ||
107 | } | ||
108 | input_sync(kpad->input); | 130 | input_sync(kpad->input); |
109 | } | 131 | } |
110 | } | 132 | } |
@@ -130,6 +152,7 @@ static int __devinit adp5588_setup(struct i2c_client *client) | |||
130 | { | 152 | { |
131 | struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; | 153 | struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; |
132 | int i, ret; | 154 | int i, ret; |
155 | unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; | ||
133 | 156 | ||
134 | ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows)); | 157 | ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows)); |
135 | ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF); | 158 | ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF); |
@@ -144,6 +167,23 @@ static int __devinit adp5588_setup(struct i2c_client *client) | |||
144 | for (i = 0; i < KEYP_MAX_EVENT; i++) | 167 | for (i = 0; i < KEYP_MAX_EVENT; i++) |
145 | ret |= adp5588_read(client, Key_EVENTA); | 168 | ret |= adp5588_read(client, Key_EVENTA); |
146 | 169 | ||
170 | for (i = 0; i < pdata->gpimapsize; i++) { | ||
171 | unsigned short pin = pdata->gpimap[i].pin; | ||
172 | |||
173 | if (pin <= GPI_PIN_ROW_END) { | ||
174 | evt_mode1 |= (1 << (pin - GPI_PIN_ROW_BASE)); | ||
175 | } else { | ||
176 | evt_mode2 |= ((1 << (pin - GPI_PIN_COL_BASE)) & 0xFF); | ||
177 | evt_mode3 |= ((1 << (pin - GPI_PIN_COL_BASE)) >> 8); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | if (pdata->gpimapsize) { | ||
182 | ret |= adp5588_write(client, GPI_EM1, evt_mode1); | ||
183 | ret |= adp5588_write(client, GPI_EM2, evt_mode2); | ||
184 | ret |= adp5588_write(client, GPI_EM3, evt_mode3); | ||
185 | } | ||
186 | |||
147 | ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT | | 187 | ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT | |
148 | OVR_FLOW_INT | K_LCK_INT | | 188 | OVR_FLOW_INT | K_LCK_INT | |
149 | GPI_INT | KE_INT); /* Status is W1C */ | 189 | GPI_INT | KE_INT); /* Status is W1C */ |
@@ -158,6 +198,44 @@ static int __devinit adp5588_setup(struct i2c_client *client) | |||
158 | return 0; | 198 | return 0; |
159 | } | 199 | } |
160 | 200 | ||
201 | static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad) | ||
202 | { | ||
203 | int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1); | ||
204 | int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2); | ||
205 | int gpi_stat3 = adp5588_read(kpad->client, GPIO_DAT_STAT3); | ||
206 | int gpi_stat_tmp, pin_loc; | ||
207 | int i; | ||
208 | |||
209 | for (i = 0; i < kpad->gpimapsize; i++) { | ||
210 | unsigned short pin = kpad->gpimap[i].pin; | ||
211 | |||
212 | if (pin <= GPI_PIN_ROW_END) { | ||
213 | gpi_stat_tmp = gpi_stat1; | ||
214 | pin_loc = pin - GPI_PIN_ROW_BASE; | ||
215 | } else if ((pin - GPI_PIN_COL_BASE) < 8) { | ||
216 | gpi_stat_tmp = gpi_stat2; | ||
217 | pin_loc = pin - GPI_PIN_COL_BASE; | ||
218 | } else { | ||
219 | gpi_stat_tmp = gpi_stat3; | ||
220 | pin_loc = pin - GPI_PIN_COL_BASE - 8; | ||
221 | } | ||
222 | |||
223 | if (gpi_stat_tmp < 0) { | ||
224 | dev_err(&kpad->client->dev, | ||
225 | "Can't read GPIO_DAT_STAT switch %d default to OFF\n", | ||
226 | pin); | ||
227 | gpi_stat_tmp = 0; | ||
228 | } | ||
229 | |||
230 | input_report_switch(kpad->input, | ||
231 | kpad->gpimap[i].sw_evt, | ||
232 | !(gpi_stat_tmp & (1 << pin_loc))); | ||
233 | } | ||
234 | |||
235 | input_sync(kpad->input); | ||
236 | } | ||
237 | |||
238 | |||
161 | static int __devinit adp5588_probe(struct i2c_client *client, | 239 | static int __devinit adp5588_probe(struct i2c_client *client, |
162 | const struct i2c_device_id *id) | 240 | const struct i2c_device_id *id) |
163 | { | 241 | { |
@@ -189,6 +267,37 @@ static int __devinit adp5588_probe(struct i2c_client *client, | |||
189 | return -EINVAL; | 267 | return -EINVAL; |
190 | } | 268 | } |
191 | 269 | ||
270 | if (!pdata->gpimap && pdata->gpimapsize) { | ||
271 | dev_err(&client->dev, "invalid gpimap from pdata\n"); | ||
272 | return -EINVAL; | ||
273 | } | ||
274 | |||
275 | if (pdata->gpimapsize > ADP5588_GPIMAPSIZE_MAX) { | ||
276 | dev_err(&client->dev, "invalid gpimapsize\n"); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | for (i = 0; i < pdata->gpimapsize; i++) { | ||
281 | unsigned short pin = pdata->gpimap[i].pin; | ||
282 | |||
283 | if (pin < GPI_PIN_BASE || pin > GPI_PIN_END) { | ||
284 | dev_err(&client->dev, "invalid gpi pin data\n"); | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | |||
288 | if (pin <= GPI_PIN_ROW_END) { | ||
289 | if (pin - GPI_PIN_ROW_BASE + 1 <= pdata->rows) { | ||
290 | dev_err(&client->dev, "invalid gpi row data\n"); | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | } else { | ||
294 | if (pin - GPI_PIN_COL_BASE + 1 <= pdata->cols) { | ||
295 | dev_err(&client->dev, "invalid gpi col data\n"); | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | |||
192 | if (!client->irq) { | 301 | if (!client->irq) { |
193 | dev_err(&client->dev, "no IRQ?\n"); | 302 | dev_err(&client->dev, "no IRQ?\n"); |
194 | return -EINVAL; | 303 | return -EINVAL; |
@@ -233,6 +342,9 @@ static int __devinit adp5588_probe(struct i2c_client *client, | |||
233 | memcpy(kpad->keycode, pdata->keymap, | 342 | memcpy(kpad->keycode, pdata->keymap, |
234 | pdata->keymapsize * input->keycodesize); | 343 | pdata->keymapsize * input->keycodesize); |
235 | 344 | ||
345 | kpad->gpimap = pdata->gpimap; | ||
346 | kpad->gpimapsize = pdata->gpimapsize; | ||
347 | |||
236 | /* setup input device */ | 348 | /* setup input device */ |
237 | __set_bit(EV_KEY, input->evbit); | 349 | __set_bit(EV_KEY, input->evbit); |
238 | 350 | ||
@@ -243,6 +355,11 @@ static int __devinit adp5588_probe(struct i2c_client *client, | |||
243 | __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); | 355 | __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); |
244 | __clear_bit(KEY_RESERVED, input->keybit); | 356 | __clear_bit(KEY_RESERVED, input->keybit); |
245 | 357 | ||
358 | if (kpad->gpimapsize) | ||
359 | __set_bit(EV_SW, input->evbit); | ||
360 | for (i = 0; i < kpad->gpimapsize; i++) | ||
361 | __set_bit(kpad->gpimap[i].sw_evt, input->swbit); | ||
362 | |||
246 | error = input_register_device(input); | 363 | error = input_register_device(input); |
247 | if (error) { | 364 | if (error) { |
248 | dev_err(&client->dev, "unable to register input device\n"); | 365 | dev_err(&client->dev, "unable to register input device\n"); |
@@ -261,6 +378,9 @@ static int __devinit adp5588_probe(struct i2c_client *client, | |||
261 | if (error) | 378 | if (error) |
262 | goto err_free_irq; | 379 | goto err_free_irq; |
263 | 380 | ||
381 | if (kpad->gpimapsize) | ||
382 | adp5588_report_switch_state(kpad); | ||
383 | |||
264 | device_init_wakeup(&client->dev, 1); | 384 | device_init_wakeup(&client->dev, 1); |
265 | i2c_set_clientdata(client, kpad); | 385 | i2c_set_clientdata(client, kpad); |
266 | 386 | ||
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h index 02c9af374741..b5f57c498e24 100644 --- a/include/linux/i2c/adp5588.h +++ b/include/linux/i2c/adp5588.h | |||
@@ -78,6 +78,40 @@ | |||
78 | 78 | ||
79 | #define ADP5588_KEYMAPSIZE 80 | 79 | #define ADP5588_KEYMAPSIZE 80 |
80 | 80 | ||
81 | #define GPI_PIN_ROW0 97 | ||
82 | #define GPI_PIN_ROW1 98 | ||
83 | #define GPI_PIN_ROW2 99 | ||
84 | #define GPI_PIN_ROW3 100 | ||
85 | #define GPI_PIN_ROW4 101 | ||
86 | #define GPI_PIN_ROW5 102 | ||
87 | #define GPI_PIN_ROW6 103 | ||
88 | #define GPI_PIN_ROW7 104 | ||
89 | #define GPI_PIN_COL0 105 | ||
90 | #define GPI_PIN_COL1 106 | ||
91 | #define GPI_PIN_COL2 107 | ||
92 | #define GPI_PIN_COL3 108 | ||
93 | #define GPI_PIN_COL4 109 | ||
94 | #define GPI_PIN_COL5 110 | ||
95 | #define GPI_PIN_COL6 111 | ||
96 | #define GPI_PIN_COL7 112 | ||
97 | #define GPI_PIN_COL8 113 | ||
98 | #define GPI_PIN_COL9 114 | ||
99 | |||
100 | #define GPI_PIN_ROW_BASE GPI_PIN_ROW0 | ||
101 | #define GPI_PIN_ROW_END GPI_PIN_ROW7 | ||
102 | #define GPI_PIN_COL_BASE GPI_PIN_COL0 | ||
103 | #define GPI_PIN_COL_END GPI_PIN_COL9 | ||
104 | |||
105 | #define GPI_PIN_BASE GPI_PIN_ROW_BASE | ||
106 | #define GPI_PIN_END GPI_PIN_COL_END | ||
107 | |||
108 | #define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1) | ||
109 | |||
110 | struct adp5588_gpi_map { | ||
111 | unsigned short pin; | ||
112 | unsigned short sw_evt; | ||
113 | }; | ||
114 | |||
81 | struct adp5588_kpad_platform_data { | 115 | struct adp5588_kpad_platform_data { |
82 | int rows; /* Number of rows */ | 116 | int rows; /* Number of rows */ |
83 | int cols; /* Number of columns */ | 117 | int cols; /* Number of columns */ |
@@ -87,6 +121,8 @@ struct adp5588_kpad_platform_data { | |||
87 | unsigned en_keylock:1; /* Enable Key Lock feature */ | 121 | unsigned en_keylock:1; /* Enable Key Lock feature */ |
88 | unsigned short unlock_key1; /* Unlock Key 1 */ | 122 | unsigned short unlock_key1; /* Unlock Key 1 */ |
89 | unsigned short unlock_key2; /* Unlock Key 2 */ | 123 | unsigned short unlock_key2; /* Unlock Key 2 */ |
124 | const struct adp5588_gpi_map *gpimap; | ||
125 | unsigned short gpimapsize; | ||
90 | }; | 126 | }; |
91 | 127 | ||
92 | struct adp5588_gpio_platform_data { | 128 | struct adp5588_gpio_platform_data { |