blob: 4ef789ef104242712d14107f3834b59a39965040 [file] [log] [blame]
Michael Hennerich88751dd2009-09-17 22:39:38 -07001/*
2 * File: drivers/input/keyboard/adp5588_keys.c
Michael Hennerich5a9003d2010-01-19 00:28:44 -08003 * Description: keypad driver for ADP5588 and ADP5587
4 * I2C QWERTY Keypad and IO Expander
Michael Hennerich88751dd2009-09-17 22:39:38 -07005 * Bugs: Enter bugs at http://blackfin.uclinux.org/
6 *
7 * Copyright (C) 2008-2009 Analog Devices Inc.
8 * Licensed under the GPL-2 or later.
9 */
10
11#include <linux/module.h>
12#include <linux/version.h>
13#include <linux/init.h>
14#include <linux/interrupt.h>
15#include <linux/irq.h>
16#include <linux/workqueue.h>
17#include <linux/errno.h>
18#include <linux/pm.h>
19#include <linux/platform_device.h>
20#include <linux/input.h>
21#include <linux/i2c.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Michael Hennerich88751dd2009-09-17 22:39:38 -070023
24#include <linux/i2c/adp5588.h>
25
26 /* Configuration Register1 */
27#define AUTO_INC (1 << 7)
28#define GPIEM_CFG (1 << 6)
29#define OVR_FLOW_M (1 << 5)
30#define INT_CFG (1 << 4)
31#define OVR_FLOW_IEN (1 << 3)
32#define K_LCK_IM (1 << 2)
33#define GPI_IEN (1 << 1)
34#define KE_IEN (1 << 0)
35
36/* Interrupt Status Register */
37#define CMP2_INT (1 << 5)
38#define CMP1_INT (1 << 4)
39#define OVR_FLOW_INT (1 << 3)
40#define K_LCK_INT (1 << 2)
41#define GPI_INT (1 << 1)
42#define KE_INT (1 << 0)
43
44/* Key Lock and Event Counter Register */
45#define K_LCK_EN (1 << 6)
46#define LCK21 0x30
47#define KEC 0xF
48
49/* Key Event Register xy */
50#define KEY_EV_PRESSED (1 << 7)
51#define KEY_EV_MASK (0x7F)
52
53#define KP_SEL(x) (0xFFFF >> (16 - x)) /* 2^x-1 */
54
55#define KEYP_MAX_EVENT 10
56
57/*
58 * Early pre 4.0 Silicon required to delay readout by at least 25ms,
59 * since the Event Counter Register updated 25ms after the interrupt
60 * asserted.
61 */
62#define WA_DELAYED_READOUT_REVID(rev) ((rev) < 4)
63
64struct adp5588_kpad {
65 struct i2c_client *client;
66 struct input_dev *input;
67 struct delayed_work work;
68 unsigned long delay;
69 unsigned short keycode[ADP5588_KEYMAPSIZE];
Xiaolong CHEN69a4af62010-06-24 19:10:40 -070070 const struct adp5588_gpi_map *gpimap;
71 unsigned short gpimapsize;
Michael Hennerich88751dd2009-09-17 22:39:38 -070072};
73
74static int adp5588_read(struct i2c_client *client, u8 reg)
75{
76 int ret = i2c_smbus_read_byte_data(client, reg);
77
78 if (ret < 0)
79 dev_err(&client->dev, "Read Error\n");
80
81 return ret;
82}
83
84static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
85{
86 return i2c_smbus_write_byte_data(client, reg, val);
87}
88
Xiaolong CHEN69a4af62010-06-24 19:10:40 -070089static 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
Michael Hennerich88751dd2009-09-17 22:39:38 -0700114static void adp5588_work(struct work_struct *work)
115{
116 struct adp5588_kpad *kpad = container_of(work,
117 struct adp5588_kpad, work.work);
118 struct i2c_client *client = kpad->client;
Xiaolong CHEN69a4af62010-06-24 19:10:40 -0700119 int status, ev_cnt;
Michael Hennerich88751dd2009-09-17 22:39:38 -0700120
121 status = adp5588_read(client, INT_STAT);
122
123 if (status & OVR_FLOW_INT) /* Unlikely and should never happen */
124 dev_err(&client->dev, "Event Overflow Error\n");
125
126 if (status & KE_INT) {
127 ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
128 if (ev_cnt) {
Xiaolong CHEN69a4af62010-06-24 19:10:40 -0700129 adp5588_report_events(kpad, ev_cnt);
Michael Hennerich88751dd2009-09-17 22:39:38 -0700130 input_sync(kpad->input);
131 }
132 }
133 adp5588_write(client, INT_STAT, status); /* Status is W1C */
134}
135
136static irqreturn_t adp5588_irq(int irq, void *handle)
137{
138 struct adp5588_kpad *kpad = handle;
139
140 /*
141 * use keventd context to read the event fifo registers
142 * Schedule readout at least 25ms after notification for
143 * REVID < 4
144 */
145
146 schedule_delayed_work(&kpad->work, kpad->delay);
147
148 return IRQ_HANDLED;
149}
150
151static int __devinit adp5588_setup(struct i2c_client *client)
152{
153 struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
154 int i, ret;
Xiaolong CHEN69a4af62010-06-24 19:10:40 -0700155 unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
Michael Hennerich88751dd2009-09-17 22:39:38 -0700156
157 ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
158 ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
159 ret |= adp5588_write(client, KP_GPIO3, KP_SEL(pdata->cols) >> 8);
160
161 if (pdata->en_keylock) {
162 ret |= adp5588_write(client, UNLOCK1, pdata->unlock_key1);
163 ret |= adp5588_write(client, UNLOCK2, pdata->unlock_key2);
164 ret |= adp5588_write(client, KEY_LCK_EC_STAT, K_LCK_EN);
165 }
166
167 for (i = 0; i < KEYP_MAX_EVENT; i++)
168 ret |= adp5588_read(client, Key_EVENTA);
169
Xiaolong CHEN69a4af62010-06-24 19:10:40 -0700170 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
Michael Hennerich88751dd2009-09-17 22:39:38 -0700187 ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
188 OVR_FLOW_INT | K_LCK_INT |
189 GPI_INT | KE_INT); /* Status is W1C */
190
191 ret |= adp5588_write(client, CFG, INT_CFG | OVR_FLOW_IEN | KE_IEN);
192
193 if (ret < 0) {
194 dev_err(&client->dev, "Write Error\n");
195 return ret;
196 }
197
198 return 0;
199}
200
Xiaolong CHEN69a4af62010-06-24 19:10:40 -0700201static 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
Michael Hennerich88751dd2009-09-17 22:39:38 -0700239static int __devinit adp5588_probe(struct i2c_client *client,
240 const struct i2c_device_id *id)
241{
242 struct adp5588_kpad *kpad;
243 struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
244 struct input_dev *input;
245 unsigned int revid;
246 int ret, i;
247 int error;
248
249 if (!i2c_check_functionality(client->adapter,
250 I2C_FUNC_SMBUS_BYTE_DATA)) {
251 dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
252 return -EIO;
253 }
254
255 if (!pdata) {
256 dev_err(&client->dev, "no platform data?\n");
257 return -EINVAL;
258 }
259
260 if (!pdata->rows || !pdata->cols || !pdata->keymap) {
261 dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
262 return -EINVAL;
263 }
264
265 if (pdata->keymapsize != ADP5588_KEYMAPSIZE) {
266 dev_err(&client->dev, "invalid keymapsize\n");
267 return -EINVAL;
268 }
269
Xiaolong CHEN69a4af62010-06-24 19:10:40 -0700270 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
Michael Hennerich88751dd2009-09-17 22:39:38 -0700301 if (!client->irq) {
302 dev_err(&client->dev, "no IRQ?\n");
303 return -EINVAL;
304 }
305
306 kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
307 input = input_allocate_device();
308 if (!kpad || !input) {
309 error = -ENOMEM;
310 goto err_free_mem;
311 }
312
313 kpad->client = client;
314 kpad->input = input;
315 INIT_DELAYED_WORK(&kpad->work, adp5588_work);
316
317 ret = adp5588_read(client, DEV_ID);
318 if (ret < 0) {
319 error = ret;
320 goto err_free_mem;
321 }
322
323 revid = (u8) ret & ADP5588_DEVICE_ID_MASK;
324 if (WA_DELAYED_READOUT_REVID(revid))
325 kpad->delay = msecs_to_jiffies(30);
326
327 input->name = client->name;
328 input->phys = "adp5588-keys/input0";
329 input->dev.parent = &client->dev;
330
331 input_set_drvdata(input, kpad);
332
333 input->id.bustype = BUS_I2C;
334 input->id.vendor = 0x0001;
335 input->id.product = 0x0001;
336 input->id.version = revid;
337
338 input->keycodesize = sizeof(kpad->keycode[0]);
339 input->keycodemax = pdata->keymapsize;
340 input->keycode = kpad->keycode;
341
342 memcpy(kpad->keycode, pdata->keymap,
343 pdata->keymapsize * input->keycodesize);
344
Xiaolong CHEN69a4af62010-06-24 19:10:40 -0700345 kpad->gpimap = pdata->gpimap;
346 kpad->gpimapsize = pdata->gpimapsize;
347
Michael Hennerich88751dd2009-09-17 22:39:38 -0700348 /* setup input device */
349 __set_bit(EV_KEY, input->evbit);
350
351 if (pdata->repeat)
352 __set_bit(EV_REP, input->evbit);
353
354 for (i = 0; i < input->keycodemax; i++)
355 __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
356 __clear_bit(KEY_RESERVED, input->keybit);
357
Xiaolong CHEN69a4af62010-06-24 19:10:40 -0700358 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
Michael Hennerich88751dd2009-09-17 22:39:38 -0700363 error = input_register_device(input);
364 if (error) {
365 dev_err(&client->dev, "unable to register input device\n");
366 goto err_free_mem;
367 }
368
369 error = request_irq(client->irq, adp5588_irq,
370 IRQF_TRIGGER_FALLING | IRQF_DISABLED,
371 client->dev.driver->name, kpad);
372 if (error) {
373 dev_err(&client->dev, "irq %d busy?\n", client->irq);
374 goto err_unreg_dev;
375 }
376
377 error = adp5588_setup(client);
378 if (error)
379 goto err_free_irq;
380
Xiaolong CHEN69a4af62010-06-24 19:10:40 -0700381 if (kpad->gpimapsize)
382 adp5588_report_switch_state(kpad);
383
Michael Hennerich88751dd2009-09-17 22:39:38 -0700384 device_init_wakeup(&client->dev, 1);
385 i2c_set_clientdata(client, kpad);
386
387 dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
388 return 0;
389
390 err_free_irq:
391 free_irq(client->irq, kpad);
392 err_unreg_dev:
393 input_unregister_device(input);
394 input = NULL;
395 err_free_mem:
396 input_free_device(input);
397 kfree(kpad);
398
399 return error;
400}
401
402static int __devexit adp5588_remove(struct i2c_client *client)
403{
404 struct adp5588_kpad *kpad = i2c_get_clientdata(client);
405
406 adp5588_write(client, CFG, 0);
407 free_irq(client->irq, kpad);
408 cancel_delayed_work_sync(&kpad->work);
409 input_unregister_device(kpad->input);
410 i2c_set_clientdata(client, NULL);
411 kfree(kpad);
412
413 return 0;
414}
415
416#ifdef CONFIG_PM
417static int adp5588_suspend(struct device *dev)
418{
419 struct adp5588_kpad *kpad = dev_get_drvdata(dev);
420 struct i2c_client *client = kpad->client;
421
422 disable_irq(client->irq);
423 cancel_delayed_work_sync(&kpad->work);
424
425 if (device_may_wakeup(&client->dev))
426 enable_irq_wake(client->irq);
427
428 return 0;
429}
430
431static int adp5588_resume(struct device *dev)
432{
433 struct adp5588_kpad *kpad = dev_get_drvdata(dev);
434 struct i2c_client *client = kpad->client;
435
436 if (device_may_wakeup(&client->dev))
437 disable_irq_wake(client->irq);
438
439 enable_irq(client->irq);
440
441 return 0;
442}
443
Alexey Dobriyan47145212009-12-14 18:00:08 -0800444static const struct dev_pm_ops adp5588_dev_pm_ops = {
Michael Hennerich88751dd2009-09-17 22:39:38 -0700445 .suspend = adp5588_suspend,
446 .resume = adp5588_resume,
447};
448#endif
449
450static const struct i2c_device_id adp5588_id[] = {
451 { KBUILD_MODNAME, 0 },
Michael Hennerich5a9003d2010-01-19 00:28:44 -0800452 { "adp5587-keys", 0 },
Michael Hennerich88751dd2009-09-17 22:39:38 -0700453 { }
454};
455MODULE_DEVICE_TABLE(i2c, adp5588_id);
456
457static struct i2c_driver adp5588_driver = {
458 .driver = {
459 .name = KBUILD_MODNAME,
460#ifdef CONFIG_PM
461 .pm = &adp5588_dev_pm_ops,
462#endif
463 },
464 .probe = adp5588_probe,
465 .remove = __devexit_p(adp5588_remove),
466 .id_table = adp5588_id,
467};
468
469static int __init adp5588_init(void)
470{
471 return i2c_add_driver(&adp5588_driver);
472}
473module_init(adp5588_init);
474
475static void __exit adp5588_exit(void)
476{
477 i2c_del_driver(&adp5588_driver);
478}
479module_exit(adp5588_exit);
480
481MODULE_LICENSE("GPL");
482MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
Michael Hennerich5a9003d2010-01-19 00:28:44 -0800483MODULE_DESCRIPTION("ADP5588/87 Keypad driver");
Michael Hennerich88751dd2009-09-17 22:39:38 -0700484MODULE_ALIAS("platform:adp5588-keys");