diff options
author | Trilok Soni <tsoni@codeaurora.org> | 2011-05-19 01:24:04 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2011-05-26 13:45:53 -0400 |
commit | 39325b59d88b42ba2ccf2e62c234059e9941a47c (patch) | |
tree | c30b276c1a7dcd1546ef5051721647c43e9abc92 | |
parent | 7e6502d577106fb5b202bbaac64c5f1b065e6daa (diff) |
input: Add Qualcomm pm8xxx keypad controller driver
Add Qualcomm PMIC8XXX based keypad controller driver
supporting upto 18x8 matrix configuration.
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Trilok Soni <tsoni@codeaurora.org>
Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r-- | drivers/input/keyboard/Kconfig | 11 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/pmic8xxx-keypad.c | 799 | ||||
-rw-r--r-- | include/linux/input/pmic8xxx-keypad.h | 52 |
4 files changed, 863 insertions, 0 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 69badb4e06aa..b4dee9d5a055 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -412,6 +412,17 @@ config KEYBOARD_PXA930_ROTARY | |||
412 | To compile this driver as a module, choose M here: the | 412 | To compile this driver as a module, choose M here: the |
413 | module will be called pxa930_rotary. | 413 | module will be called pxa930_rotary. |
414 | 414 | ||
415 | config KEYBOARD_PMIC8XXX | ||
416 | tristate "Qualcomm PMIC8XXX keypad support" | ||
417 | depends on MFD_PM8XXX | ||
418 | help | ||
419 | Say Y here if you want to enable the driver for the PMIC8XXX | ||
420 | keypad provided as a reference design from Qualcomm. This is intended | ||
421 | to support upto 18x8 matrix based keypad design. | ||
422 | |||
423 | To compile this driver as a module, choose M here: the module will | ||
424 | be called pmic8xxx-keypad. | ||
425 | |||
415 | config KEYBOARD_SAMSUNG | 426 | config KEYBOARD_SAMSUNG |
416 | tristate "Samsung keypad support" | 427 | tristate "Samsung keypad support" |
417 | depends on SAMSUNG_DEV_KEYPAD | 428 | depends on SAMSUNG_DEV_KEYPAD |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index c49cf8e04cd7..ddde0fd476f7 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
@@ -34,6 +34,7 @@ obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o | |||
34 | obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o | 34 | obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o |
35 | obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o | 35 | obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o |
36 | obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o | 36 | obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o |
37 | obj-$(CONFIG_KEYBOARD_PMIC8XXX) += pmic8xxx-keypad.o | ||
37 | obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o | 38 | obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o |
38 | obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o | 39 | obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o |
39 | obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o | 40 | obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o |
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c new file mode 100644 index 000000000000..40b02ae96f86 --- /dev/null +++ b/drivers/input/keyboard/pmic8xxx-keypad.c | |||
@@ -0,0 +1,799 @@ | |||
1 | /* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <linux/bitops.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/mutex.h> | ||
22 | |||
23 | #include <linux/mfd/pm8xxx/core.h> | ||
24 | #include <linux/mfd/pm8xxx/gpio.h> | ||
25 | #include <linux/input/pmic8xxx-keypad.h> | ||
26 | |||
27 | #define PM8XXX_MAX_ROWS 18 | ||
28 | #define PM8XXX_MAX_COLS 8 | ||
29 | #define PM8XXX_ROW_SHIFT 3 | ||
30 | #define PM8XXX_MATRIX_MAX_SIZE (PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS) | ||
31 | |||
32 | #define PM8XXX_MIN_ROWS 5 | ||
33 | #define PM8XXX_MIN_COLS 5 | ||
34 | |||
35 | #define MAX_SCAN_DELAY 128 | ||
36 | #define MIN_SCAN_DELAY 1 | ||
37 | |||
38 | /* in nanoseconds */ | ||
39 | #define MAX_ROW_HOLD_DELAY 122000 | ||
40 | #define MIN_ROW_HOLD_DELAY 30500 | ||
41 | |||
42 | #define MAX_DEBOUNCE_TIME 20 | ||
43 | #define MIN_DEBOUNCE_TIME 5 | ||
44 | |||
45 | #define KEYP_CTRL 0x148 | ||
46 | |||
47 | #define KEYP_CTRL_EVNTS BIT(0) | ||
48 | #define KEYP_CTRL_EVNTS_MASK 0x3 | ||
49 | |||
50 | #define KEYP_CTRL_SCAN_COLS_SHIFT 5 | ||
51 | #define KEYP_CTRL_SCAN_COLS_MIN 5 | ||
52 | #define KEYP_CTRL_SCAN_COLS_BITS 0x3 | ||
53 | |||
54 | #define KEYP_CTRL_SCAN_ROWS_SHIFT 2 | ||
55 | #define KEYP_CTRL_SCAN_ROWS_MIN 5 | ||
56 | #define KEYP_CTRL_SCAN_ROWS_BITS 0x7 | ||
57 | |||
58 | #define KEYP_CTRL_KEYP_EN BIT(7) | ||
59 | |||
60 | #define KEYP_SCAN 0x149 | ||
61 | |||
62 | #define KEYP_SCAN_READ_STATE BIT(0) | ||
63 | #define KEYP_SCAN_DBOUNCE_SHIFT 1 | ||
64 | #define KEYP_SCAN_PAUSE_SHIFT 3 | ||
65 | #define KEYP_SCAN_ROW_HOLD_SHIFT 6 | ||
66 | |||
67 | #define KEYP_TEST 0x14A | ||
68 | |||
69 | #define KEYP_TEST_CLEAR_RECENT_SCAN BIT(6) | ||
70 | #define KEYP_TEST_CLEAR_OLD_SCAN BIT(5) | ||
71 | #define KEYP_TEST_READ_RESET BIT(4) | ||
72 | #define KEYP_TEST_DTEST_EN BIT(3) | ||
73 | #define KEYP_TEST_ABORT_READ BIT(0) | ||
74 | |||
75 | #define KEYP_TEST_DBG_SELECT_SHIFT 1 | ||
76 | |||
77 | /* bits of these registers represent | ||
78 | * '0' for key press | ||
79 | * '1' for key release | ||
80 | */ | ||
81 | #define KEYP_RECENT_DATA 0x14B | ||
82 | #define KEYP_OLD_DATA 0x14C | ||
83 | |||
84 | #define KEYP_CLOCK_FREQ 32768 | ||
85 | |||
86 | /** | ||
87 | * struct pmic8xxx_kp - internal keypad data structure | ||
88 | * @pdata - keypad platform data pointer | ||
89 | * @input - input device pointer for keypad | ||
90 | * @key_sense_irq - key press/release irq number | ||
91 | * @key_stuck_irq - key stuck notification irq number | ||
92 | * @keycodes - array to hold the key codes | ||
93 | * @dev - parent device pointer | ||
94 | * @keystate - present key press/release state | ||
95 | * @stuckstate - present state when key stuck irq | ||
96 | * @ctrl_reg - control register value | ||
97 | */ | ||
98 | struct pmic8xxx_kp { | ||
99 | const struct pm8xxx_keypad_platform_data *pdata; | ||
100 | struct input_dev *input; | ||
101 | int key_sense_irq; | ||
102 | int key_stuck_irq; | ||
103 | |||
104 | unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE]; | ||
105 | |||
106 | struct device *dev; | ||
107 | u16 keystate[PM8XXX_MAX_ROWS]; | ||
108 | u16 stuckstate[PM8XXX_MAX_ROWS]; | ||
109 | |||
110 | u8 ctrl_reg; | ||
111 | }; | ||
112 | |||
113 | static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp, | ||
114 | u8 data, u16 reg) | ||
115 | { | ||
116 | int rc; | ||
117 | |||
118 | rc = pm8xxx_writeb(kp->dev->parent, reg, data); | ||
119 | return rc; | ||
120 | } | ||
121 | |||
122 | static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp, | ||
123 | u8 *data, u16 reg, unsigned num_bytes) | ||
124 | { | ||
125 | int rc; | ||
126 | |||
127 | rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes); | ||
128 | return rc; | ||
129 | } | ||
130 | |||
131 | static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp, | ||
132 | u8 *data, u16 reg) | ||
133 | { | ||
134 | int rc; | ||
135 | |||
136 | rc = pmic8xxx_kp_read(kp, data, reg, 1); | ||
137 | return rc; | ||
138 | } | ||
139 | |||
140 | static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col) | ||
141 | { | ||
142 | /* all keys pressed on that particular row? */ | ||
143 | if (col == 0x00) | ||
144 | return 1 << kp->pdata->num_cols; | ||
145 | else | ||
146 | return col & ((1 << kp->pdata->num_cols) - 1); | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * Synchronous read protocol for RevB0 onwards: | ||
151 | * | ||
152 | * 1. Write '1' to ReadState bit in KEYP_SCAN register | ||
153 | * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode | ||
154 | * synchronously | ||
155 | * 3. Read rows in old array first if events are more than one | ||
156 | * 4. Read rows in recent array | ||
157 | * 5. Wait 4*32KHz clocks | ||
158 | * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can | ||
159 | * synchronously exit read mode. | ||
160 | */ | ||
161 | static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp) | ||
162 | { | ||
163 | int rc; | ||
164 | u8 scan_val; | ||
165 | |||
166 | rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN); | ||
167 | if (rc < 0) { | ||
168 | dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); | ||
169 | return rc; | ||
170 | } | ||
171 | |||
172 | scan_val |= 0x1; | ||
173 | |||
174 | rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); | ||
175 | if (rc < 0) { | ||
176 | dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); | ||
177 | return rc; | ||
178 | } | ||
179 | |||
180 | /* 2 * 32KHz clocks */ | ||
181 | udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); | ||
182 | |||
183 | return rc; | ||
184 | } | ||
185 | |||
186 | static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state, | ||
187 | u16 data_reg, int read_rows) | ||
188 | { | ||
189 | int rc, row; | ||
190 | u8 new_data[PM8XXX_MAX_ROWS]; | ||
191 | |||
192 | rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows); | ||
193 | if (rc) | ||
194 | return rc; | ||
195 | |||
196 | for (row = 0; row < kp->pdata->num_rows; row++) { | ||
197 | dev_dbg(kp->dev, "new_data[%d] = %d\n", row, | ||
198 | new_data[row]); | ||
199 | state[row] = pmic8xxx_col_state(kp, new_data[row]); | ||
200 | } | ||
201 | |||
202 | return rc; | ||
203 | } | ||
204 | |||
205 | static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state, | ||
206 | u16 *old_state) | ||
207 | { | ||
208 | int rc, read_rows; | ||
209 | u8 scan_val; | ||
210 | |||
211 | if (kp->pdata->num_rows < PM8XXX_MIN_ROWS) | ||
212 | read_rows = PM8XXX_MIN_ROWS; | ||
213 | else | ||
214 | read_rows = kp->pdata->num_rows; | ||
215 | |||
216 | pmic8xxx_chk_sync_read(kp); | ||
217 | |||
218 | if (old_state) { | ||
219 | rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA, | ||
220 | read_rows); | ||
221 | if (rc < 0) { | ||
222 | dev_err(kp->dev, | ||
223 | "Error reading KEYP_OLD_DATA, rc=%d\n", rc); | ||
224 | return rc; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA, | ||
229 | read_rows); | ||
230 | if (rc < 0) { | ||
231 | dev_err(kp->dev, | ||
232 | "Error reading KEYP_RECENT_DATA, rc=%d\n", rc); | ||
233 | return rc; | ||
234 | } | ||
235 | |||
236 | /* 4 * 32KHz clocks */ | ||
237 | udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); | ||
238 | |||
239 | rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN); | ||
240 | if (rc < 0) { | ||
241 | dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); | ||
242 | return rc; | ||
243 | } | ||
244 | |||
245 | scan_val &= 0xFE; | ||
246 | rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); | ||
247 | if (rc < 0) | ||
248 | dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); | ||
249 | |||
250 | return rc; | ||
251 | } | ||
252 | |||
253 | static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state, | ||
254 | u16 *old_state) | ||
255 | { | ||
256 | int row, col, code; | ||
257 | |||
258 | for (row = 0; row < kp->pdata->num_rows; row++) { | ||
259 | int bits_changed = new_state[row] ^ old_state[row]; | ||
260 | |||
261 | if (!bits_changed) | ||
262 | continue; | ||
263 | |||
264 | for (col = 0; col < kp->pdata->num_cols; col++) { | ||
265 | if (!(bits_changed & (1 << col))) | ||
266 | continue; | ||
267 | |||
268 | dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col, | ||
269 | !(new_state[row] & (1 << col)) ? | ||
270 | "pressed" : "released"); | ||
271 | |||
272 | code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT); | ||
273 | |||
274 | input_event(kp->input, EV_MSC, MSC_SCAN, code); | ||
275 | input_report_key(kp->input, | ||
276 | kp->keycodes[code], | ||
277 | !(new_state[row] & (1 << col))); | ||
278 | |||
279 | input_sync(kp->input); | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state) | ||
285 | { | ||
286 | int row, found_first = -1; | ||
287 | u16 check, row_state; | ||
288 | |||
289 | check = 0; | ||
290 | for (row = 0; row < kp->pdata->num_rows; row++) { | ||
291 | row_state = (~new_state[row]) & | ||
292 | ((1 << kp->pdata->num_cols) - 1); | ||
293 | |||
294 | if (hweight16(row_state) > 1) { | ||
295 | if (found_first == -1) | ||
296 | found_first = row; | ||
297 | if (check & row_state) { | ||
298 | dev_dbg(kp->dev, "detected ghost key on row[%d]" | ||
299 | " and row[%d]\n", found_first, row); | ||
300 | return true; | ||
301 | } | ||
302 | } | ||
303 | check |= row_state; | ||
304 | } | ||
305 | return false; | ||
306 | } | ||
307 | |||
308 | static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events) | ||
309 | { | ||
310 | u16 new_state[PM8XXX_MAX_ROWS]; | ||
311 | u16 old_state[PM8XXX_MAX_ROWS]; | ||
312 | int rc; | ||
313 | |||
314 | switch (events) { | ||
315 | case 0x1: | ||
316 | rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL); | ||
317 | if (rc < 0) | ||
318 | return rc; | ||
319 | |||
320 | /* detecting ghost key is not an error */ | ||
321 | if (pmic8xxx_detect_ghost_keys(kp, new_state)) | ||
322 | return 0; | ||
323 | __pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate); | ||
324 | memcpy(kp->keystate, new_state, sizeof(new_state)); | ||
325 | break; | ||
326 | case 0x3: /* two events - eventcounter is gray-coded */ | ||
327 | rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); | ||
328 | if (rc < 0) | ||
329 | return rc; | ||
330 | |||
331 | __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); | ||
332 | __pmic8xxx_kp_scan_matrix(kp, new_state, old_state); | ||
333 | memcpy(kp->keystate, new_state, sizeof(new_state)); | ||
334 | break; | ||
335 | case 0x2: | ||
336 | dev_dbg(kp->dev, "Some key events were lost\n"); | ||
337 | rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); | ||
338 | if (rc < 0) | ||
339 | return rc; | ||
340 | __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); | ||
341 | __pmic8xxx_kp_scan_matrix(kp, new_state, old_state); | ||
342 | memcpy(kp->keystate, new_state, sizeof(new_state)); | ||
343 | break; | ||
344 | default: | ||
345 | rc = -EINVAL; | ||
346 | } | ||
347 | return rc; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * NOTE: We are reading recent and old data registers blindly | ||
352 | * whenever key-stuck interrupt happens, because events counter doesn't | ||
353 | * get updated when this interrupt happens due to key stuck doesn't get | ||
354 | * considered as key state change. | ||
355 | * | ||
356 | * We are not using old data register contents after they are being read | ||
357 | * because it might report the key which was pressed before the key being stuck | ||
358 | * as stuck key because it's pressed status is stored in the old data | ||
359 | * register. | ||
360 | */ | ||
361 | static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data) | ||
362 | { | ||
363 | u16 new_state[PM8XXX_MAX_ROWS]; | ||
364 | u16 old_state[PM8XXX_MAX_ROWS]; | ||
365 | int rc; | ||
366 | struct pmic8xxx_kp *kp = data; | ||
367 | |||
368 | rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); | ||
369 | if (rc < 0) { | ||
370 | dev_err(kp->dev, "failed to read keypad matrix\n"); | ||
371 | return IRQ_HANDLED; | ||
372 | } | ||
373 | |||
374 | __pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate); | ||
375 | |||
376 | return IRQ_HANDLED; | ||
377 | } | ||
378 | |||
379 | static irqreturn_t pmic8xxx_kp_irq(int irq, void *data) | ||
380 | { | ||
381 | struct pmic8xxx_kp *kp = data; | ||
382 | u8 ctrl_val, events; | ||
383 | int rc; | ||
384 | |||
385 | rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1); | ||
386 | if (rc < 0) { | ||
387 | dev_err(kp->dev, "failed to read keyp_ctrl register\n"); | ||
388 | return IRQ_HANDLED; | ||
389 | } | ||
390 | |||
391 | events = ctrl_val & KEYP_CTRL_EVNTS_MASK; | ||
392 | |||
393 | rc = pmic8xxx_kp_scan_matrix(kp, events); | ||
394 | if (rc < 0) | ||
395 | dev_err(kp->dev, "failed to scan matrix\n"); | ||
396 | |||
397 | return IRQ_HANDLED; | ||
398 | } | ||
399 | |||
400 | static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) | ||
401 | { | ||
402 | int bits, rc, cycles; | ||
403 | u8 scan_val = 0, ctrl_val = 0; | ||
404 | static const u8 row_bits[] = { | ||
405 | 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, | ||
406 | }; | ||
407 | |||
408 | /* Find column bits */ | ||
409 | if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN) | ||
410 | bits = 0; | ||
411 | else | ||
412 | bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN; | ||
413 | ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) << | ||
414 | KEYP_CTRL_SCAN_COLS_SHIFT; | ||
415 | |||
416 | /* Find row bits */ | ||
417 | if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) | ||
418 | bits = 0; | ||
419 | else | ||
420 | bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; | ||
421 | |||
422 | ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); | ||
423 | |||
424 | rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL); | ||
425 | if (rc < 0) { | ||
426 | dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); | ||
427 | return rc; | ||
428 | } | ||
429 | |||
430 | bits = (kp->pdata->debounce_ms / 5) - 1; | ||
431 | |||
432 | scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); | ||
433 | |||
434 | bits = fls(kp->pdata->scan_delay_ms) - 1; | ||
435 | scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT); | ||
436 | |||
437 | /* Row hold time is a multiple of 32KHz cycles. */ | ||
438 | cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; | ||
439 | |||
440 | scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); | ||
441 | |||
442 | rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); | ||
443 | if (rc) | ||
444 | dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); | ||
445 | |||
446 | return rc; | ||
447 | |||
448 | } | ||
449 | |||
450 | static int __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios, | ||
451 | struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config) | ||
452 | { | ||
453 | int rc, i; | ||
454 | |||
455 | if (gpio_start < 0 || num_gpios < 0) | ||
456 | return -EINVAL; | ||
457 | |||
458 | for (i = 0; i < num_gpios; i++) { | ||
459 | rc = pm8xxx_gpio_config(gpio_start + i, gpio_config); | ||
460 | if (rc) { | ||
461 | dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():" | ||
462 | "for PM GPIO [%d] rc=%d.\n", | ||
463 | __func__, gpio_start + i, rc); | ||
464 | return rc; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp) | ||
472 | { | ||
473 | int rc; | ||
474 | |||
475 | kp->ctrl_reg |= KEYP_CTRL_KEYP_EN; | ||
476 | |||
477 | rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); | ||
478 | if (rc < 0) | ||
479 | dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); | ||
480 | |||
481 | return rc; | ||
482 | } | ||
483 | |||
484 | static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp) | ||
485 | { | ||
486 | int rc; | ||
487 | |||
488 | kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN; | ||
489 | |||
490 | rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); | ||
491 | if (rc < 0) | ||
492 | return rc; | ||
493 | |||
494 | return rc; | ||
495 | } | ||
496 | |||
497 | static int pmic8xxx_kp_open(struct input_dev *dev) | ||
498 | { | ||
499 | struct pmic8xxx_kp *kp = input_get_drvdata(dev); | ||
500 | |||
501 | return pmic8xxx_kp_enable(kp); | ||
502 | } | ||
503 | |||
504 | static void pmic8xxx_kp_close(struct input_dev *dev) | ||
505 | { | ||
506 | struct pmic8xxx_kp *kp = input_get_drvdata(dev); | ||
507 | |||
508 | pmic8xxx_kp_disable(kp); | ||
509 | } | ||
510 | |||
511 | /* | ||
512 | * keypad controller should be initialized in the following sequence | ||
513 | * only, otherwise it might get into FSM stuck state. | ||
514 | * | ||
515 | * - Initialize keypad control parameters, like no. of rows, columns, | ||
516 | * timing values etc., | ||
517 | * - configure rows and column gpios pull up/down. | ||
518 | * - set irq edge type. | ||
519 | * - enable the keypad controller. | ||
520 | */ | ||
521 | static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev) | ||
522 | { | ||
523 | const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev); | ||
524 | const struct matrix_keymap_data *keymap_data; | ||
525 | struct pmic8xxx_kp *kp; | ||
526 | int rc; | ||
527 | u8 ctrl_val; | ||
528 | |||
529 | struct pm_gpio kypd_drv = { | ||
530 | .direction = PM_GPIO_DIR_OUT, | ||
531 | .output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN, | ||
532 | .output_value = 0, | ||
533 | .pull = PM_GPIO_PULL_NO, | ||
534 | .vin_sel = PM_GPIO_VIN_S3, | ||
535 | .out_strength = PM_GPIO_STRENGTH_LOW, | ||
536 | .function = PM_GPIO_FUNC_1, | ||
537 | .inv_int_pol = 1, | ||
538 | }; | ||
539 | |||
540 | struct pm_gpio kypd_sns = { | ||
541 | .direction = PM_GPIO_DIR_IN, | ||
542 | .pull = PM_GPIO_PULL_UP_31P5, | ||
543 | .vin_sel = PM_GPIO_VIN_S3, | ||
544 | .out_strength = PM_GPIO_STRENGTH_NO, | ||
545 | .function = PM_GPIO_FUNC_NORMAL, | ||
546 | .inv_int_pol = 1, | ||
547 | }; | ||
548 | |||
549 | |||
550 | if (!pdata || !pdata->num_cols || !pdata->num_rows || | ||
551 | pdata->num_cols > PM8XXX_MAX_COLS || | ||
552 | pdata->num_rows > PM8XXX_MAX_ROWS || | ||
553 | pdata->num_cols < PM8XXX_MIN_COLS) { | ||
554 | dev_err(&pdev->dev, "invalid platform data\n"); | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | |||
558 | if (!pdata->scan_delay_ms || | ||
559 | pdata->scan_delay_ms > MAX_SCAN_DELAY || | ||
560 | pdata->scan_delay_ms < MIN_SCAN_DELAY || | ||
561 | !is_power_of_2(pdata->scan_delay_ms)) { | ||
562 | dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); | ||
563 | return -EINVAL; | ||
564 | } | ||
565 | |||
566 | if (!pdata->row_hold_ns || | ||
567 | pdata->row_hold_ns > MAX_ROW_HOLD_DELAY || | ||
568 | pdata->row_hold_ns < MIN_ROW_HOLD_DELAY || | ||
569 | ((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { | ||
570 | dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); | ||
571 | return -EINVAL; | ||
572 | } | ||
573 | |||
574 | if (!pdata->debounce_ms || | ||
575 | ((pdata->debounce_ms % 5) != 0) || | ||
576 | pdata->debounce_ms > MAX_DEBOUNCE_TIME || | ||
577 | pdata->debounce_ms < MIN_DEBOUNCE_TIME) { | ||
578 | dev_err(&pdev->dev, "invalid debounce time supplied\n"); | ||
579 | return -EINVAL; | ||
580 | } | ||
581 | |||
582 | keymap_data = pdata->keymap_data; | ||
583 | if (!keymap_data) { | ||
584 | dev_err(&pdev->dev, "no keymap data supplied\n"); | ||
585 | return -EINVAL; | ||
586 | } | ||
587 | |||
588 | kp = kzalloc(sizeof(*kp), GFP_KERNEL); | ||
589 | if (!kp) | ||
590 | return -ENOMEM; | ||
591 | |||
592 | platform_set_drvdata(pdev, kp); | ||
593 | |||
594 | kp->pdata = pdata; | ||
595 | kp->dev = &pdev->dev; | ||
596 | |||
597 | kp->input = input_allocate_device(); | ||
598 | if (!kp->input) { | ||
599 | dev_err(&pdev->dev, "unable to allocate input device\n"); | ||
600 | rc = -ENOMEM; | ||
601 | goto err_alloc_device; | ||
602 | } | ||
603 | |||
604 | kp->key_sense_irq = platform_get_irq(pdev, 0); | ||
605 | if (kp->key_sense_irq < 0) { | ||
606 | dev_err(&pdev->dev, "unable to get keypad sense irq\n"); | ||
607 | rc = -ENXIO; | ||
608 | goto err_get_irq; | ||
609 | } | ||
610 | |||
611 | kp->key_stuck_irq = platform_get_irq(pdev, 1); | ||
612 | if (kp->key_stuck_irq < 0) { | ||
613 | dev_err(&pdev->dev, "unable to get keypad stuck irq\n"); | ||
614 | rc = -ENXIO; | ||
615 | goto err_get_irq; | ||
616 | } | ||
617 | |||
618 | kp->input->name = pdata->input_name ? : "PMIC8XXX keypad"; | ||
619 | kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0"; | ||
620 | |||
621 | kp->input->dev.parent = &pdev->dev; | ||
622 | |||
623 | kp->input->id.bustype = BUS_I2C; | ||
624 | kp->input->id.version = 0x0001; | ||
625 | kp->input->id.product = 0x0001; | ||
626 | kp->input->id.vendor = 0x0001; | ||
627 | |||
628 | kp->input->evbit[0] = BIT_MASK(EV_KEY); | ||
629 | |||
630 | if (pdata->rep) | ||
631 | __set_bit(EV_REP, kp->input->evbit); | ||
632 | |||
633 | kp->input->keycode = kp->keycodes; | ||
634 | kp->input->keycodemax = PM8XXX_MATRIX_MAX_SIZE; | ||
635 | kp->input->keycodesize = sizeof(kp->keycodes); | ||
636 | kp->input->open = pmic8xxx_kp_open; | ||
637 | kp->input->close = pmic8xxx_kp_close; | ||
638 | |||
639 | matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT, | ||
640 | kp->input->keycode, kp->input->keybit); | ||
641 | |||
642 | input_set_capability(kp->input, EV_MSC, MSC_SCAN); | ||
643 | input_set_drvdata(kp->input, kp); | ||
644 | |||
645 | /* initialize keypad state */ | ||
646 | memset(kp->keystate, 0xff, sizeof(kp->keystate)); | ||
647 | memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate)); | ||
648 | |||
649 | rc = pmic8xxx_kpd_init(kp); | ||
650 | if (rc < 0) { | ||
651 | dev_err(&pdev->dev, "unable to initialize keypad controller\n"); | ||
652 | goto err_get_irq; | ||
653 | } | ||
654 | |||
655 | rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start, | ||
656 | pdata->num_cols, kp, &kypd_sns); | ||
657 | if (rc < 0) { | ||
658 | dev_err(&pdev->dev, "unable to configure keypad sense lines\n"); | ||
659 | goto err_gpio_config; | ||
660 | } | ||
661 | |||
662 | rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start, | ||
663 | pdata->num_rows, kp, &kypd_drv); | ||
664 | if (rc < 0) { | ||
665 | dev_err(&pdev->dev, "unable to configure keypad drive lines\n"); | ||
666 | goto err_gpio_config; | ||
667 | } | ||
668 | |||
669 | rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq, | ||
670 | IRQF_TRIGGER_RISING, "pmic-keypad", kp); | ||
671 | if (rc < 0) { | ||
672 | dev_err(&pdev->dev, "failed to request keypad sense irq\n"); | ||
673 | goto err_get_irq; | ||
674 | } | ||
675 | |||
676 | rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq, | ||
677 | IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp); | ||
678 | if (rc < 0) { | ||
679 | dev_err(&pdev->dev, "failed to request keypad stuck irq\n"); | ||
680 | goto err_req_stuck_irq; | ||
681 | } | ||
682 | |||
683 | rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL); | ||
684 | if (rc < 0) { | ||
685 | dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n"); | ||
686 | goto err_pmic_reg_read; | ||
687 | } | ||
688 | |||
689 | kp->ctrl_reg = ctrl_val; | ||
690 | |||
691 | rc = input_register_device(kp->input); | ||
692 | if (rc < 0) { | ||
693 | dev_err(&pdev->dev, "unable to register keypad input device\n"); | ||
694 | goto err_pmic_reg_read; | ||
695 | } | ||
696 | |||
697 | device_init_wakeup(&pdev->dev, pdata->wakeup); | ||
698 | |||
699 | return 0; | ||
700 | |||
701 | err_pmic_reg_read: | ||
702 | free_irq(kp->key_stuck_irq, NULL); | ||
703 | err_req_stuck_irq: | ||
704 | free_irq(kp->key_sense_irq, NULL); | ||
705 | err_gpio_config: | ||
706 | err_get_irq: | ||
707 | input_free_device(kp->input); | ||
708 | err_alloc_device: | ||
709 | platform_set_drvdata(pdev, NULL); | ||
710 | kfree(kp); | ||
711 | return rc; | ||
712 | } | ||
713 | |||
714 | static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev) | ||
715 | { | ||
716 | struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); | ||
717 | |||
718 | device_init_wakeup(&pdev->dev, 0); | ||
719 | free_irq(kp->key_stuck_irq, NULL); | ||
720 | free_irq(kp->key_sense_irq, NULL); | ||
721 | input_unregister_device(kp->input); | ||
722 | kfree(kp); | ||
723 | |||
724 | platform_set_drvdata(pdev, NULL); | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | #ifdef CONFIG_PM_SLEEP | ||
729 | static int pmic8xxx_kp_suspend(struct device *dev) | ||
730 | { | ||
731 | struct platform_device *pdev = to_platform_device(dev); | ||
732 | struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); | ||
733 | struct input_dev *input_dev = kp->input; | ||
734 | |||
735 | if (device_may_wakeup(dev)) { | ||
736 | enable_irq_wake(kp->key_sense_irq); | ||
737 | } else { | ||
738 | mutex_lock(&input_dev->mutex); | ||
739 | |||
740 | if (input_dev->users) | ||
741 | pmic8xxx_kp_disable(kp); | ||
742 | |||
743 | mutex_unlock(&input_dev->mutex); | ||
744 | } | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | static int pmic8xxx_kp_resume(struct device *dev) | ||
750 | { | ||
751 | struct platform_device *pdev = to_platform_device(dev); | ||
752 | struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); | ||
753 | struct input_dev *input_dev = kp->input; | ||
754 | |||
755 | if (device_may_wakeup(dev)) { | ||
756 | disable_irq_wake(kp->key_sense_irq); | ||
757 | } else { | ||
758 | mutex_lock(&input_dev->mutex); | ||
759 | |||
760 | if (input_dev->users) | ||
761 | pmic8xxx_kp_enable(kp); | ||
762 | |||
763 | mutex_unlock(&input_dev->mutex); | ||
764 | } | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | #endif | ||
769 | |||
770 | static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops, | ||
771 | pmic8xxx_kp_suspend, pmic8xxx_kp_resume); | ||
772 | |||
773 | static struct platform_driver pmic8xxx_kp_driver = { | ||
774 | .probe = pmic8xxx_kp_probe, | ||
775 | .remove = __devexit_p(pmic8xxx_kp_remove), | ||
776 | .driver = { | ||
777 | .name = PM8XXX_KEYPAD_DEV_NAME, | ||
778 | .owner = THIS_MODULE, | ||
779 | .pm = &pm8xxx_kp_pm_ops, | ||
780 | }, | ||
781 | }; | ||
782 | |||
783 | static int __init pmic8xxx_kp_init(void) | ||
784 | { | ||
785 | return platform_driver_register(&pmic8xxx_kp_driver); | ||
786 | } | ||
787 | module_init(pmic8xxx_kp_init); | ||
788 | |||
789 | static void __exit pmic8xxx_kp_exit(void) | ||
790 | { | ||
791 | platform_driver_unregister(&pmic8xxx_kp_driver); | ||
792 | } | ||
793 | module_exit(pmic8xxx_kp_exit); | ||
794 | |||
795 | MODULE_LICENSE("GPL v2"); | ||
796 | MODULE_DESCRIPTION("PMIC8XXX keypad driver"); | ||
797 | MODULE_VERSION("1.0"); | ||
798 | MODULE_ALIAS("platform:pmic8xxx_keypad"); | ||
799 | MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>"); | ||
diff --git a/include/linux/input/pmic8xxx-keypad.h b/include/linux/input/pmic8xxx-keypad.h new file mode 100644 index 000000000000..5f1e2f9ad959 --- /dev/null +++ b/include/linux/input/pmic8xxx-keypad.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* Copyright (c) 2011, Code Aurora Forum. All rights reserved. | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | ||
12 | |||
13 | #ifndef __PMIC8XXX_KEYPAD_H__ | ||
14 | #define __PMIC8XXX_KEYPAD_H__ | ||
15 | |||
16 | #include <linux/input/matrix_keypad.h> | ||
17 | |||
18 | #define PM8XXX_KEYPAD_DEV_NAME "pm8xxx-keypad" | ||
19 | |||
20 | /** | ||
21 | * struct pm8xxx_keypad_platform_data - platform data for keypad | ||
22 | * @keymap_data - matrix keymap data | ||
23 | * @input_name - input device name | ||
24 | * @input_phys_device - input device name | ||
25 | * @num_cols - number of columns of keypad | ||
26 | * @num_rows - number of row of keypad | ||
27 | * @debounce_ms - debounce period in milliseconds | ||
28 | * @scan_delay_ms - scan delay in milliseconds | ||
29 | * @row_hold_ns - row hold period in nanoseconds | ||
30 | * @wakeup - configure keypad as wakeup | ||
31 | * @rep - enable or disable key repeat bit | ||
32 | */ | ||
33 | struct pm8xxx_keypad_platform_data { | ||
34 | const struct matrix_keymap_data *keymap_data; | ||
35 | |||
36 | const char *input_name; | ||
37 | const char *input_phys_device; | ||
38 | |||
39 | unsigned int num_cols; | ||
40 | unsigned int num_rows; | ||
41 | unsigned int rows_gpio_start; | ||
42 | unsigned int cols_gpio_start; | ||
43 | |||
44 | unsigned int debounce_ms; | ||
45 | unsigned int scan_delay_ms; | ||
46 | unsigned int row_hold_ns; | ||
47 | |||
48 | bool wakeup; | ||
49 | bool rep; | ||
50 | }; | ||
51 | |||
52 | #endif /*__PMIC8XXX_KEYPAD_H__ */ | ||