diff options
-rw-r--r-- | drivers/input/keyboard/pxa27x_keypad.c | 224 | ||||
-rw-r--r-- | include/asm-arm/arch-pxa/pxa27x_keypad.h | 21 |
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 | ||
45 | static struct clk *pxa27x_keypad_clk; | 44 | #define KPASMKP_MKC_MASK (0xff) |
45 | |||
46 | #define MAX_MATRIX_KEY_NUM (8 * 8) | ||
47 | |||
48 | struct 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 | |||
61 | static 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 | |||
79 | static 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 | |||
85 | static 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 | } | ||
127 | scan: | ||
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 | ||
47 | static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) | 148 | static 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 | ||
96 | static int pxa27x_keypad_open(struct input_dev *dev) | 184 | static 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 | ||
116 | static void pxa27x_keypad_close(struct input_dev *dev) | 206 | static 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 |
123 | static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state) | 215 | static 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 | ||
134 | static int pxa27x_keypad_resume(struct platform_device *pdev) | 227 | static 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 | ||
160 | static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) | 253 | static 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: | 333 | failed_put_clk: |
229 | clk_put(pxa27x_keypad_clk); | 334 | clk_put(keypad->clk); |
230 | err_clk: | 335 | failed_free: |
336 | kfree(keypad); | ||
231 | return error; | 337 | return error; |
232 | } | 338 | } |
233 | 339 | ||
234 | static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) | 340 | static 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 | ||
4 | struct pxa27x_keypad_platform_data { | 9 | struct 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 */ | ||