Merge master.kernel.org:/pub/scm/linux/kernel/git/lethal/genesis-2.6 into devel-stable
[sfrench/cifs-2.6.git] / drivers / input / keyboard / samsung-keypad.c
1 /*
2  * Samsung keypad driver
3  *
4  * Copyright (C) 2010 Samsung Electronics Co.Ltd
5  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
6  * Author: Donghwa Lee <dh09.lee@samsung.com>
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under  the terms of  the GNU General  Public License as published by the
10  * Free Software Foundation;  either version 2 of the  License, or (at your
11  * option) any later version.
12  */
13
14 #include <linux/clk.h>
15 #include <linux/delay.h>
16 #include <linux/err.h>
17 #include <linux/init.h>
18 #include <linux/input.h>
19 #include <linux/interrupt.h>
20 #include <linux/io.h>
21 #include <linux/module.h>
22 #include <linux/platform_device.h>
23 #include <linux/slab.h>
24 #include <linux/sched.h>
25 #include <plat/keypad.h>
26
27 #define SAMSUNG_KEYIFCON                        0x00
28 #define SAMSUNG_KEYIFSTSCLR                     0x04
29 #define SAMSUNG_KEYIFCOL                        0x08
30 #define SAMSUNG_KEYIFROW                        0x0c
31 #define SAMSUNG_KEYIFFC                         0x10
32
33 /* SAMSUNG_KEYIFCON */
34 #define SAMSUNG_KEYIFCON_INT_F_EN               (1 << 0)
35 #define SAMSUNG_KEYIFCON_INT_R_EN               (1 << 1)
36 #define SAMSUNG_KEYIFCON_DF_EN                  (1 << 2)
37 #define SAMSUNG_KEYIFCON_FC_EN                  (1 << 3)
38 #define SAMSUNG_KEYIFCON_WAKEUPEN               (1 << 4)
39
40 /* SAMSUNG_KEYIFSTSCLR */
41 #define SAMSUNG_KEYIFSTSCLR_P_INT_MASK          (0xff << 0)
42 #define SAMSUNG_KEYIFSTSCLR_R_INT_MASK          (0xff << 8)
43 #define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET        8
44 #define S5PV210_KEYIFSTSCLR_P_INT_MASK          (0x3fff << 0)
45 #define S5PV210_KEYIFSTSCLR_R_INT_MASK          (0x3fff << 16)
46 #define S5PV210_KEYIFSTSCLR_R_INT_OFFSET        16
47
48 /* SAMSUNG_KEYIFCOL */
49 #define SAMSUNG_KEYIFCOL_MASK                   (0xff << 0)
50 #define S5PV210_KEYIFCOLEN_MASK                 (0xff << 8)
51
52 /* SAMSUNG_KEYIFROW */
53 #define SAMSUNG_KEYIFROW_MASK                   (0xff << 0)
54 #define S5PV210_KEYIFROW_MASK                   (0x3fff << 0)
55
56 /* SAMSUNG_KEYIFFC */
57 #define SAMSUNG_KEYIFFC_MASK                    (0x3ff << 0)
58
59 enum samsung_keypad_type {
60         KEYPAD_TYPE_SAMSUNG,
61         KEYPAD_TYPE_S5PV210,
62 };
63
64 struct samsung_keypad {
65         struct input_dev *input_dev;
66         struct clk *clk;
67         void __iomem *base;
68         wait_queue_head_t wait;
69         bool stopped;
70         int irq;
71         unsigned int row_shift;
72         unsigned int rows;
73         unsigned int cols;
74         unsigned int row_state[SAMSUNG_MAX_COLS];
75         unsigned short keycodes[];
76 };
77
78 static int samsung_keypad_is_s5pv210(struct device *dev)
79 {
80         struct platform_device *pdev = to_platform_device(dev);
81         enum samsung_keypad_type type =
82                 platform_get_device_id(pdev)->driver_data;
83
84         return type == KEYPAD_TYPE_S5PV210;
85 }
86
87 static void samsung_keypad_scan(struct samsung_keypad *keypad,
88                                 unsigned int *row_state)
89 {
90         struct device *dev = keypad->input_dev->dev.parent;
91         unsigned int col;
92         unsigned int val;
93
94         for (col = 0; col < keypad->cols; col++) {
95                 if (samsung_keypad_is_s5pv210(dev)) {
96                         val = S5PV210_KEYIFCOLEN_MASK;
97                         val &= ~(1 << col) << 8;
98                 } else {
99                         val = SAMSUNG_KEYIFCOL_MASK;
100                         val &= ~(1 << col);
101                 }
102
103                 writel(val, keypad->base + SAMSUNG_KEYIFCOL);
104                 mdelay(1);
105
106                 val = readl(keypad->base + SAMSUNG_KEYIFROW);
107                 row_state[col] = ~val & ((1 << keypad->rows) - 1);
108         }
109
110         /* KEYIFCOL reg clear */
111         writel(0, keypad->base + SAMSUNG_KEYIFCOL);
112 }
113
114 static bool samsung_keypad_report(struct samsung_keypad *keypad,
115                                   unsigned int *row_state)
116 {
117         struct input_dev *input_dev = keypad->input_dev;
118         unsigned int changed;
119         unsigned int pressed;
120         unsigned int key_down = 0;
121         unsigned int val;
122         unsigned int col, row;
123
124         for (col = 0; col < keypad->cols; col++) {
125                 changed = row_state[col] ^ keypad->row_state[col];
126                 key_down |= row_state[col];
127                 if (!changed)
128                         continue;
129
130                 for (row = 0; row < keypad->rows; row++) {
131                         if (!(changed & (1 << row)))
132                                 continue;
133
134                         pressed = row_state[col] & (1 << row);
135
136                         dev_dbg(&keypad->input_dev->dev,
137                                 "key %s, row: %d, col: %d\n",
138                                 pressed ? "pressed" : "released", row, col);
139
140                         val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
141
142                         input_event(input_dev, EV_MSC, MSC_SCAN, val);
143                         input_report_key(input_dev,
144                                         keypad->keycodes[val], pressed);
145                 }
146                 input_sync(keypad->input_dev);
147         }
148
149         memcpy(keypad->row_state, row_state, sizeof(keypad->row_state));
150
151         return key_down;
152 }
153
154 static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
155 {
156         struct samsung_keypad *keypad = dev_id;
157         unsigned int row_state[SAMSUNG_MAX_COLS];
158         unsigned int val;
159         bool key_down;
160
161         do {
162                 val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
163                 /* Clear interrupt. */
164                 writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
165
166                 samsung_keypad_scan(keypad, row_state);
167
168                 key_down = samsung_keypad_report(keypad, row_state);
169                 if (key_down)
170                         wait_event_timeout(keypad->wait, keypad->stopped,
171                                            msecs_to_jiffies(50));
172
173         } while (key_down && !keypad->stopped);
174
175         return IRQ_HANDLED;
176 }
177
178 static void samsung_keypad_start(struct samsung_keypad *keypad)
179 {
180         unsigned int val;
181
182         /* Tell IRQ thread that it may poll the device. */
183         keypad->stopped = false;
184
185         clk_enable(keypad->clk);
186
187         /* Enable interrupt bits. */
188         val = readl(keypad->base + SAMSUNG_KEYIFCON);
189         val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN;
190         writel(val, keypad->base + SAMSUNG_KEYIFCON);
191
192         /* KEYIFCOL reg clear. */
193         writel(0, keypad->base + SAMSUNG_KEYIFCOL);
194 }
195
196 static void samsung_keypad_stop(struct samsung_keypad *keypad)
197 {
198         unsigned int val;
199
200         /* Signal IRQ thread to stop polling and disable the handler. */
201         keypad->stopped = true;
202         wake_up(&keypad->wait);
203         disable_irq(keypad->irq);
204
205         /* Clear interrupt. */
206         writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
207
208         /* Disable interrupt bits. */
209         val = readl(keypad->base + SAMSUNG_KEYIFCON);
210         val &= ~(SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN);
211         writel(val, keypad->base + SAMSUNG_KEYIFCON);
212
213         clk_disable(keypad->clk);
214
215         /*
216          * Now that chip should not generate interrupts we can safely
217          * re-enable the handler.
218          */
219         enable_irq(keypad->irq);
220 }
221
222 static int samsung_keypad_open(struct input_dev *input_dev)
223 {
224         struct samsung_keypad *keypad = input_get_drvdata(input_dev);
225
226         samsung_keypad_start(keypad);
227
228         return 0;
229 }
230
231 static void samsung_keypad_close(struct input_dev *input_dev)
232 {
233         struct samsung_keypad *keypad = input_get_drvdata(input_dev);
234
235         samsung_keypad_stop(keypad);
236 }
237
238 static int __devinit samsung_keypad_probe(struct platform_device *pdev)
239 {
240         const struct samsung_keypad_platdata *pdata;
241         const struct matrix_keymap_data *keymap_data;
242         struct samsung_keypad *keypad;
243         struct resource *res;
244         struct input_dev *input_dev;
245         unsigned int row_shift;
246         unsigned int keymap_size;
247         int error;
248
249         pdata = pdev->dev.platform_data;
250         if (!pdata) {
251                 dev_err(&pdev->dev, "no platform data defined\n");
252                 return -EINVAL;
253         }
254
255         keymap_data = pdata->keymap_data;
256         if (!keymap_data) {
257                 dev_err(&pdev->dev, "no keymap data defined\n");
258                 return -EINVAL;
259         }
260
261         if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS)
262                 return -EINVAL;
263
264         if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS)
265                 return -EINVAL;
266
267         /* initialize the gpio */
268         if (pdata->cfg_gpio)
269                 pdata->cfg_gpio(pdata->rows, pdata->cols);
270
271         row_shift = get_count_order(pdata->cols);
272         keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);
273
274         keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);
275         input_dev = input_allocate_device();
276         if (!keypad || !input_dev) {
277                 error = -ENOMEM;
278                 goto err_free_mem;
279         }
280
281         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
282         if (!res) {
283                 error = -ENODEV;
284                 goto err_free_mem;
285         }
286
287         keypad->base = ioremap(res->start, resource_size(res));
288         if (!keypad->base) {
289                 error = -EBUSY;
290                 goto err_free_mem;
291         }
292
293         keypad->clk = clk_get(&pdev->dev, "keypad");
294         if (IS_ERR(keypad->clk)) {
295                 dev_err(&pdev->dev, "failed to get keypad clk\n");
296                 error = PTR_ERR(keypad->clk);
297                 goto err_unmap_base;
298         }
299
300         keypad->input_dev = input_dev;
301         keypad->row_shift = row_shift;
302         keypad->rows = pdata->rows;
303         keypad->cols = pdata->cols;
304         init_waitqueue_head(&keypad->wait);
305
306         input_dev->name = pdev->name;
307         input_dev->id.bustype = BUS_HOST;
308         input_dev->dev.parent = &pdev->dev;
309         input_set_drvdata(input_dev, keypad);
310
311         input_dev->open = samsung_keypad_open;
312         input_dev->close = samsung_keypad_close;
313
314         input_dev->evbit[0] = BIT_MASK(EV_KEY);
315         if (!pdata->no_autorepeat)
316                 input_dev->evbit[0] |= BIT_MASK(EV_REP);
317
318         input_set_capability(input_dev, EV_MSC, MSC_SCAN);
319
320         input_dev->keycode = keypad->keycodes;
321         input_dev->keycodesize = sizeof(keypad->keycodes[0]);
322         input_dev->keycodemax = pdata->rows << row_shift;
323
324         matrix_keypad_build_keymap(keymap_data, row_shift,
325                         input_dev->keycode, input_dev->keybit);
326
327         keypad->irq = platform_get_irq(pdev, 0);
328         if (keypad->irq < 0) {
329                 error = keypad->irq;
330                 goto err_put_clk;
331         }
332
333         error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,
334                         IRQF_ONESHOT, dev_name(&pdev->dev), keypad);
335         if (error) {
336                 dev_err(&pdev->dev, "failed to register keypad interrupt\n");
337                 goto err_put_clk;
338         }
339
340         error = input_register_device(keypad->input_dev);
341         if (error)
342                 goto err_free_irq;
343
344         device_init_wakeup(&pdev->dev, pdata->wakeup);
345         platform_set_drvdata(pdev, keypad);
346         return 0;
347
348 err_free_irq:
349         free_irq(keypad->irq, keypad);
350 err_put_clk:
351         clk_put(keypad->clk);
352 err_unmap_base:
353         iounmap(keypad->base);
354 err_free_mem:
355         input_free_device(input_dev);
356         kfree(keypad);
357
358         return error;
359 }
360
361 static int __devexit samsung_keypad_remove(struct platform_device *pdev)
362 {
363         struct samsung_keypad *keypad = platform_get_drvdata(pdev);
364
365         device_init_wakeup(&pdev->dev, 0);
366         platform_set_drvdata(pdev, NULL);
367
368         input_unregister_device(keypad->input_dev);
369
370         /*
371          * It is safe to free IRQ after unregistering device because
372          * samsung_keypad_close will shut off interrupts.
373          */
374         free_irq(keypad->irq, keypad);
375
376         clk_put(keypad->clk);
377
378         iounmap(keypad->base);
379         kfree(keypad);
380
381         return 0;
382 }
383
384 #ifdef CONFIG_PM
385 static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
386                                          bool enable)
387 {
388         struct device *dev = keypad->input_dev->dev.parent;
389         unsigned int val;
390
391         clk_enable(keypad->clk);
392
393         val = readl(keypad->base + SAMSUNG_KEYIFCON);
394         if (enable) {
395                 val |= SAMSUNG_KEYIFCON_WAKEUPEN;
396                 if (device_may_wakeup(dev))
397                         enable_irq_wake(keypad->irq);
398         } else {
399                 val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
400                 if (device_may_wakeup(dev))
401                         disable_irq_wake(keypad->irq);
402         }
403         writel(val, keypad->base + SAMSUNG_KEYIFCON);
404
405         clk_disable(keypad->clk);
406 }
407
408 static int samsung_keypad_suspend(struct device *dev)
409 {
410         struct platform_device *pdev = to_platform_device(dev);
411         struct samsung_keypad *keypad = platform_get_drvdata(pdev);
412         struct input_dev *input_dev = keypad->input_dev;
413
414         mutex_lock(&input_dev->mutex);
415
416         if (input_dev->users)
417                 samsung_keypad_stop(keypad);
418
419         samsung_keypad_toggle_wakeup(keypad, true);
420
421         mutex_unlock(&input_dev->mutex);
422
423         return 0;
424 }
425
426 static int samsung_keypad_resume(struct device *dev)
427 {
428         struct platform_device *pdev = to_platform_device(dev);
429         struct samsung_keypad *keypad = platform_get_drvdata(pdev);
430         struct input_dev *input_dev = keypad->input_dev;
431
432         mutex_lock(&input_dev->mutex);
433
434         samsung_keypad_toggle_wakeup(keypad, false);
435
436         if (input_dev->users)
437                 samsung_keypad_start(keypad);
438
439         mutex_unlock(&input_dev->mutex);
440
441         return 0;
442 }
443
444 static const struct dev_pm_ops samsung_keypad_pm_ops = {
445         .suspend        = samsung_keypad_suspend,
446         .resume         = samsung_keypad_resume,
447 };
448 #endif
449
450 static struct platform_device_id samsung_keypad_driver_ids[] = {
451         {
452                 .name           = "samsung-keypad",
453                 .driver_data    = KEYPAD_TYPE_SAMSUNG,
454         }, {
455                 .name           = "s5pv210-keypad",
456                 .driver_data    = KEYPAD_TYPE_S5PV210,
457         },
458         { },
459 };
460 MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids);
461
462 static struct platform_driver samsung_keypad_driver = {
463         .probe          = samsung_keypad_probe,
464         .remove         = __devexit_p(samsung_keypad_remove),
465         .driver         = {
466                 .name   = "samsung-keypad",
467                 .owner  = THIS_MODULE,
468 #ifdef CONFIG_PM
469                 .pm     = &samsung_keypad_pm_ops,
470 #endif
471         },
472         .id_table       = samsung_keypad_driver_ids,
473 };
474
475 static int __init samsung_keypad_init(void)
476 {
477         return platform_driver_register(&samsung_keypad_driver);
478 }
479 module_init(samsung_keypad_init);
480
481 static void __exit samsung_keypad_exit(void)
482 {
483         platform_driver_unregister(&samsung_keypad_driver);
484 }
485 module_exit(samsung_keypad_exit);
486
487 MODULE_DESCRIPTION("Samsung keypad driver");
488 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
489 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
490 MODULE_LICENSE("GPL");
491 MODULE_ALIAS("platform:samsung-keypad");