aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Miao <eric.y.miao@gmail.com>2008-01-31 00:58:37 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2008-01-31 00:58:37 -0500
commit1814db69698479eec2c000a43c83b5f263f6fbb6 (patch)
tree311c8980e0224d4842125ff1cf49c117f6d2a4e7
parent1a1cd739a4b985f87c47e2809db7e240dba2c385 (diff)
Input: pxa27x_keypad - introduce driver structure and use KEY() to define matrix keys
1. Introduce the "struct pxa27x_keypad" structure for driver specific information, such as "struct clk", generated matrix key codes and so on 2. Use KEY() macro to define matrix keys, instead of original 8x8 map this makes definition easier with keypad where keys are sparse 3. Keep a generated array in "struct pxa27x_keypad" for fast lookup 4. Separate the matrix scan into a dedicated function for readability and report only those keys whose state has been changed, instead of report all states 5. Make use of KPAS to decide the faster path if only one key has been detected Signed-off-by: Eric Miao <eric.miao@marvell.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c224
-rw-r--r--include/asm-arm/arch-pxa/pxa27x_keypad.h21
2 files changed, 184 insertions, 61 deletions
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index 43fb63d68122..8de35b0500f3 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -37,20 +37,120 @@
37 37
38#define DRIVER_NAME "pxa27x-keypad" 38#define DRIVER_NAME "pxa27x-keypad"
39 39
40#define KPASMKP(col) (col/2 == 0 ? KPASMKP0 : \ 40#define KPAS_MUKP(n) (((n) >> 26) & 0x1f)
41 col/2 == 1 ? KPASMKP1 : \ 41#define KPAS_RP(n) (((n) >> 4) & 0xf)
42 col/2 == 2 ? KPASMKP2 : KPASMKP3) 42#define KPAS_CP(n) ((n) & 0xf)
43#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
44 43
45static struct clk *pxa27x_keypad_clk; 44#define KPASMKP_MKC_MASK (0xff)
45
46#define MAX_MATRIX_KEY_NUM (8 * 8)
47
48struct pxa27x_keypad {
49 struct pxa27x_keypad_platform_data *pdata;
50
51 struct clk *clk;
52 struct input_dev *input_dev;
53
54 /* matrix key code map */
55 unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM];
56
57 /* state row bits of each column scan */
58 uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
59};
60
61static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
62{
63 struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
64 struct input_dev *input_dev = keypad->input_dev;
65 unsigned int *key;
66 int i;
67
68 key = &pdata->matrix_key_map[0];
69 for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
70 int row = ((*key) >> 28) & 0xf;
71 int col = ((*key) >> 24) & 0xf;
72 int code = (*key) & 0xffffff;
73
74 keypad->matrix_keycodes[(row << 3) + col] = code;
75 set_bit(code, input_dev->keybit);
76 }
77}
78
79static inline unsigned int lookup_matrix_keycode(
80 struct pxa27x_keypad *keypad, int row, int col)
81{
82 return keypad->matrix_keycodes[(row << 3) + col];
83}
84
85static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
86{
87 struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
88 int row, col, num_keys_pressed = 0;
89 uint32_t new_state[MAX_MATRIX_KEY_COLS];
90 uint32_t kpas = KPAS;
91
92 num_keys_pressed = KPAS_MUKP(kpas);
93
94 memset(new_state, 0, sizeof(new_state));
95
96 if (num_keys_pressed == 0)
97 goto scan;
98
99 if (num_keys_pressed == 1) {
100 col = KPAS_CP(kpas);
101 row = KPAS_RP(kpas);
102
103 /* if invalid row/col, treat as no key pressed */
104 if (col >= pdata->matrix_key_cols ||
105 row >= pdata->matrix_key_rows)
106 goto scan;
107
108 new_state[col] = (1 << row);
109 goto scan;
110 }
111
112 if (num_keys_pressed > 1) {
113 uint32_t kpasmkp0 = KPASMKP0;
114 uint32_t kpasmkp1 = KPASMKP1;
115 uint32_t kpasmkp2 = KPASMKP2;
116 uint32_t kpasmkp3 = KPASMKP3;
117
118 new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK;
119 new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK;
120 new_state[2] = kpasmkp1 & KPASMKP_MKC_MASK;
121 new_state[3] = (kpasmkp1 >> 16) & KPASMKP_MKC_MASK;
122 new_state[4] = kpasmkp2 & KPASMKP_MKC_MASK;
123 new_state[5] = (kpasmkp2 >> 16) & KPASMKP_MKC_MASK;
124 new_state[6] = kpasmkp3 & KPASMKP_MKC_MASK;
125 new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK;
126 }
127scan:
128 for (col = 0; col < pdata->matrix_key_cols; col++) {
129 uint32_t bits_changed;
130
131 bits_changed = keypad->matrix_key_state[col] ^ new_state[col];
132 if (bits_changed == 0)
133 continue;
134
135 for (row = 0; row < pdata->matrix_key_rows; row++) {
136 if ((bits_changed & (1 << row)) == 0)
137 continue;
138
139 input_report_key(keypad->input_dev,
140 lookup_matrix_keycode(keypad, row, col),
141 new_state[col] & (1 << row));
142 }
143 }
144 input_sync(keypad->input_dev);
145 memcpy(keypad->matrix_key_state, new_state, sizeof(new_state));
146}
46 147
47static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) 148static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
48{ 149{
49 struct platform_device *pdev = dev_id; 150 struct pxa27x_keypad *keypad = dev_id;
50 struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; 151 struct input_dev *input_dev = keypad->input_dev;
51 struct input_dev *input_dev = platform_get_drvdata(pdev);
52 unsigned long kpc = KPC; 152 unsigned long kpc = KPC;
53 int p, row, col, rel; 153 int rel;
54 154
55 if (kpc & KPC_DI) { 155 if (kpc & KPC_DI) {
56 unsigned long kpdk = KPDK; 156 unsigned long kpdk = KPDK;
@@ -75,26 +175,16 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
75 } 175 }
76 } 176 }
77 177
78 if (kpc & KPC_MI) { 178 if (kpc & KPC_MI)
79 /* report the status of every button */ 179 pxa27x_keypad_scan_matrix(keypad);
80 for (row = 0; row < pdata->nr_rows; row++) {
81 for (col = 0; col < pdata->nr_cols; col++) {
82 p = KPASMKP(col) & KPASMKPx_MKC(row, col) ?
83 1 : 0;
84 pr_debug("keycode %x - pressed %x\n",
85 pdata->keycodes[row][col], p);
86 input_report_key(input_dev,
87 pdata->keycodes[row][col], p);
88 }
89 }
90 input_sync(input_dev);
91 }
92 180
93 return IRQ_HANDLED; 181 return IRQ_HANDLED;
94} 182}
95 183
96static int pxa27x_keypad_open(struct input_dev *dev) 184static int pxa27x_keypad_open(struct input_dev *dev)
97{ 185{
186 struct pxa27x_keypad *keypad = input_get_drvdata(dev);
187
98 /* Set keypad control register */ 188 /* Set keypad control register */
99 KPC |= (KPC_ASACT | 189 KPC |= (KPC_ASACT |
100 KPC_MS_ALL | 190 KPC_MS_ALL |
@@ -108,21 +198,24 @@ static int pxa27x_keypad_open(struct input_dev *dev)
108 KPREC = 0x7F; 198 KPREC = 0x7F;
109 199
110 /* Enable unit clock */ 200 /* Enable unit clock */
111 clk_enable(pxa27x_keypad_clk); 201 clk_enable(keypad->clk);
112 202
113 return 0; 203 return 0;
114} 204}
115 205
116static void pxa27x_keypad_close(struct input_dev *dev) 206static void pxa27x_keypad_close(struct input_dev *dev)
117{ 207{
208 struct pxa27x_keypad *keypad = input_get_drvdata(dev);
209
118 /* Disable clock unit */ 210 /* Disable clock unit */
119 clk_disable(pxa27x_keypad_clk); 211 clk_disable(keypad->clk);
120} 212}
121 213
122#ifdef CONFIG_PM 214#ifdef CONFIG_PM
123static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state) 215static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state)
124{ 216{
125 struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; 217 struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
218 struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
126 219
127 /* Save controller status */ 220 /* Save controller status */
128 pdata->reg_kpc = KPC; 221 pdata->reg_kpc = KPC;
@@ -133,8 +226,9 @@ static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t stat
133 226
134static int pxa27x_keypad_resume(struct platform_device *pdev) 227static int pxa27x_keypad_resume(struct platform_device *pdev)
135{ 228{
136 struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; 229 struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
137 struct input_dev *input_dev = platform_get_drvdata(pdev); 230 struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
231 struct input_dev *input_dev = keypad->input_dev;
138 232
139 mutex_lock(&input_dev->mutex); 233 mutex_lock(&input_dev->mutex);
140 234
@@ -144,8 +238,7 @@ static int pxa27x_keypad_resume(struct platform_device *pdev)
144 KPREC = pdata->reg_kprec; 238 KPREC = pdata->reg_kprec;
145 239
146 /* Enable unit clock */ 240 /* Enable unit clock */
147 clk_disable(pxa27x_keypad_clk); 241 clk_enable(keypad->clk);
148 clk_enable(pxa27x_keypad_clk);
149 } 242 }
150 243
151 mutex_unlock(&input_dev->mutex); 244 mutex_unlock(&input_dev->mutex);
@@ -159,22 +252,36 @@ static int pxa27x_keypad_resume(struct platform_device *pdev)
159 252
160static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) 253static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
161{ 254{
162 struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; 255 struct pxa27x_keypad *keypad;
163 struct input_dev *input_dev; 256 struct input_dev *input_dev;
164 int i, row, col, error; 257 int col, error;
165 258
166 pxa27x_keypad_clk = clk_get(&pdev->dev, "KBDCLK"); 259 keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL);
167 if (IS_ERR(pxa27x_keypad_clk)) { 260 if (keypad == NULL) {
168 error = PTR_ERR(pxa27x_keypad_clk); 261 dev_err(&pdev->dev, "failed to allocate driver data\n");
169 goto err_clk; 262 return -ENOMEM;
263 }
264
265 keypad->pdata = pdev->dev.platform_data;
266 if (keypad->pdata == NULL) {
267 dev_err(&pdev->dev, "no platform data defined\n");
268 error = -EINVAL;
269 goto failed_free;
270 }
271
272 keypad->clk = clk_get(&pdev->dev, "KBDCLK");
273 if (IS_ERR(keypad->clk)) {
274 dev_err(&pdev->dev, "failed to get keypad clock\n");
275 error = PTR_ERR(keypad->clk);
276 goto failed_free;
170 } 277 }
171 278
172 /* Create and register the input driver. */ 279 /* Create and register the input driver. */
173 input_dev = input_allocate_device(); 280 input_dev = input_allocate_device();
174 if (!input_dev) { 281 if (!input_dev) {
175 printk(KERN_ERR "Cannot request keypad device\n"); 282 dev_err(&pdev->dev, "failed to allocate input device\n");
176 error = -ENOMEM; 283 error = -ENOMEM;
177 goto err_alloc; 284 goto failed_put_clk;
178 } 285 }
179 286
180 input_dev->name = DRIVER_NAME; 287 input_dev->name = DRIVER_NAME;
@@ -183,25 +290,23 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
183 input_dev->close = pxa27x_keypad_close; 290 input_dev->close = pxa27x_keypad_close;
184 input_dev->dev.parent = &pdev->dev; 291 input_dev->dev.parent = &pdev->dev;
185 292
293 keypad->input_dev = input_dev;
294 input_set_drvdata(input_dev, keypad);
295
186 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | 296 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
187 BIT_MASK(EV_REL); 297 BIT_MASK(EV_REL);
188 input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL); 298 input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL);
189 for (row = 0; row < pdata->nr_rows; row++) { 299
190 for (col = 0; col < pdata->nr_cols; col++) { 300 pxa27x_keypad_build_keycode(keypad);
191 int code = pdata->keycodes[row][col];
192 if (code > 0)
193 set_bit(code, input_dev->keybit);
194 }
195 }
196 301
197 error = request_irq(IRQ_KEYPAD, pxa27x_keypad_irq_handler, IRQF_DISABLED, 302 error = request_irq(IRQ_KEYPAD, pxa27x_keypad_irq_handler, IRQF_DISABLED,
198 DRIVER_NAME, pdev); 303 DRIVER_NAME, keypad);
199 if (error) { 304 if (error) {
200 printk(KERN_ERR "Cannot request keypad IRQ\n"); 305 printk(KERN_ERR "Cannot request keypad IRQ\n");
201 goto err_free_dev; 306 goto err_free_dev;
202 } 307 }
203 308
204 platform_set_drvdata(pdev, input_dev); 309 platform_set_drvdata(pdev, keypad);
205 310
206 /* Register the input device */ 311 /* Register the input device */
207 error = input_register_device(input_dev); 312 error = input_register_device(input_dev);
@@ -212,10 +317,10 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
212 * Store rows/cols info into keyboard registers. 317 * Store rows/cols info into keyboard registers.
213 */ 318 */
214 319
215 KPC |= (pdata->nr_rows - 1) << 26; 320 KPC |= (keypad->pdata->matrix_key_rows - 1) << 26;
216 KPC |= (pdata->nr_cols - 1) << 23; 321 KPC |= (keypad->pdata->matrix_key_cols - 1) << 23;
217 322
218 for (col = 0; col < pdata->nr_cols; col++) 323 for (col = 0; col < keypad->pdata->matrix_key_cols; col++)
219 KPC |= KPC_MS0 << col; 324 KPC |= KPC_MS0 << col;
220 325
221 return 0; 326 return 0;
@@ -225,21 +330,26 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
225 free_irq(IRQ_KEYPAD, pdev); 330 free_irq(IRQ_KEYPAD, pdev);
226 err_free_dev: 331 err_free_dev:
227 input_free_device(input_dev); 332 input_free_device(input_dev);
228 err_alloc: 333failed_put_clk:
229 clk_put(pxa27x_keypad_clk); 334 clk_put(keypad->clk);
230 err_clk: 335failed_free:
336 kfree(keypad);
231 return error; 337 return error;
232} 338}
233 339
234static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) 340static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
235{ 341{
236 struct input_dev *input_dev = platform_get_drvdata(pdev); 342 struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
237 343
238 input_unregister_device(input_dev);
239 free_irq(IRQ_KEYPAD, pdev); 344 free_irq(IRQ_KEYPAD, pdev);
240 clk_put(pxa27x_keypad_clk);
241 platform_set_drvdata(pdev, NULL);
242 345
346 clk_disable(keypad->clk);
347 clk_put(keypad->clk);
348
349 input_unregister_device(keypad->input_dev);
350
351 platform_set_drvdata(pdev, NULL);
352 kfree(keypad);
243 return 0; 353 return 0;
244} 354}
245 355
diff --git a/include/asm-arm/arch-pxa/pxa27x_keypad.h b/include/asm-arm/arch-pxa/pxa27x_keypad.h
index ef17db6d791e..1b1bf9fe6d81 100644
--- a/include/asm-arm/arch-pxa/pxa27x_keypad.h
+++ b/include/asm-arm/arch-pxa/pxa27x_keypad.h
@@ -1,12 +1,25 @@
1#define PXAKBD_MAXROW 8 1#ifndef __ASM_ARCH_PXA27x_KEYPAD_H
2#define PXAKBD_MAXCOL 8 2#define __ASM_ARCH_PXA27x_KEYPAD_H
3
4#include <linux/input.h>
5
6#define MAX_MATRIX_KEY_ROWS (8)
7#define MAX_MATRIX_KEY_COLS (8)
3 8
4struct pxa27x_keypad_platform_data { 9struct pxa27x_keypad_platform_data {
5 int nr_rows, nr_cols; 10
6 int keycodes[PXAKBD_MAXROW][PXAKBD_MAXCOL]; 11 /* code map for the matrix keys */
12 unsigned int matrix_key_rows;
13 unsigned int matrix_key_cols;
14 unsigned int *matrix_key_map;
15 int matrix_key_map_size;
7 16
8#ifdef CONFIG_PM 17#ifdef CONFIG_PM
9 u32 reg_kpc; 18 u32 reg_kpc;
10 u32 reg_kprec; 19 u32 reg_kprec;
11#endif 20#endif
12}; 21};
22
23#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val))
24
25#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */