rk fb: extend output mutex lock in win config
[firefly-linux-kernel-4.4.55.git] / drivers / input / jogball / rk2818_jogball.c
1 /*\r
2  * linux/drivers/input/keyboard/rk28_jogball.c\r
3  *\r
4  * Driver for the rk28 matrix keyboard controller.\r
5  *\r
6  * Created: 2009-11-28\r
7  * Author:      TY <ty@rockchip.com>\r
8  *\r
9  * This driver program support to AD key which use for rk28 chip\r
10  *\r
11  * This program is free software; you can redistribute it and/or modify\r
12  * it under the terms of the GNU General Public License version 2 as\r
13  * published by the Free Software Foundation.\r
14  */\r
15 \r
16 #include <linux/kernel.h>\r
17 #include <linux/module.h>\r
18 #include <linux/init.h>\r
19 #include <linux/interrupt.h>\r
20 #include <linux/input.h>\r
21 #include <linux/device.h>\r
22 #include <linux/platform_device.h>\r
23 #include <linux/clk.h>\r
24 #include <linux/err.h>\r
25 #include <linux/delay.h>\r
26 #include <linux/time.h>\r
27 \r
28 #include <mach/gpio.h>\r
29 #include <mach/iomux.h>\r
30 #include <linux/irq.h>\r
31 #include <mach/board.h>\r
32 \r
33 #ifdef CONFIG_ANDROID_POWER\r
34 #include <linux/android_power.h>\r
35 \r
36 static android_early_suspend_t jogball_early_suspend;\r
37 #endif\r
38 \r
39 /* Debug */\r
40 //#define JB_DEBUG 0\r
41 \r
42 #ifdef JB_DEBUG\r
43 #define DBG     printk\r
44 #else\r
45 #define DBG(x...)\r
46 #endif\r
47 \r
48 #define JB_KEY_UP           103\r
49 #define JB_KEY_DOWN         108\r
50 #define JB_KEY_LEFT         105\r
51 #define JB_KEY_RIGHT        106\r
52 \r
53 #define JOGBALL_PHYS_NAME       "rk28_jogball/input0"\r
54 \r
55 #define JOGBALL_MAX_CNT 1\r
56 \r
57 static volatile int jogball_cnt_up = 0;\r
58 static volatile int jogball_cnt_down = 0;\r
59 static volatile int jogball_cnt_left = 0;\r
60 static volatile int jogball_cnt_right = 0;\r
61 \r
62 //key code tab\r
63 static unsigned char initkey_code[ ] = \r
64 {\r
65         JB_KEY_UP, JB_KEY_DOWN, JB_KEY_LEFT, JB_KEY_RIGHT\r
66 };\r
67 \r
68 struct rk28_jogball \r
69 {\r
70         struct input_dev *input_dev;\r
71         struct rk2818_jogball_paltform_data *pdata;\r
72         unsigned char keycodes[5];\r
73 };\r
74 \r
75 struct rk28_jogball *prockjogball;\r
76 \r
77 \r
78 static int rk28_jogball_disable_irq(struct rk2818_jogball_paltform_data *pdata )\r
79 {\r
80 \r
81         disable_irq_nosync (gpio_to_irq(pdata->jogball_key->pin_up));\r
82         disable_irq_nosync (gpio_to_irq(pdata->jogball_key->pin_down));\r
83         disable_irq_nosync (gpio_to_irq(pdata->jogball_key->pin_left));\r
84         disable_irq_nosync (gpio_to_irq(pdata->jogball_key->pin_right));\r
85         \r
86         return 0;\r
87 }\r
88 \r
89 static int rk28_jogball_enable_irq(struct rk2818_jogball_paltform_data *pdata)\r
90 {\r
91 \r
92         enable_irq (gpio_to_irq(pdata->jogball_key->pin_up));\r
93         enable_irq (gpio_to_irq(pdata->jogball_key->pin_down));\r
94         enable_irq (gpio_to_irq(pdata->jogball_key->pin_left));\r
95         enable_irq (gpio_to_irq(pdata->jogball_key->pin_right));\r
96 \r
97     return 0;\r
98 }\r
99 static irqreturn_t rk28_jogball_up_ISR(int irq, void *dev_id)\r
100 {       \r
101                 \r
102         struct rk28_jogball *ball = dev_id;     \r
103          rk28_jogball_disable_irq(ball->pdata);\r
104          DBG("jogball: up begain\n");\r
105         jogball_cnt_up++;\r
106 \r
107         if (jogball_cnt_up >= JOGBALL_MAX_CNT){\r
108                 DBG("jogball: up\n");\r
109                 \r
110                 input_report_key(prockjogball->input_dev, JB_KEY_UP, 1);\r
111                 input_sync(prockjogball->input_dev);\r
112                 input_report_key(prockjogball->input_dev, JB_KEY_UP, 0);\r
113                 input_sync(prockjogball->input_dev);\r
114 \r
115                 jogball_cnt_up = 0;\r
116                 jogball_cnt_down = 0;\r
117                 jogball_cnt_left = 0;\r
118                 jogball_cnt_right = 0;\r
119         }       \r
120 \r
121          rk28_jogball_enable_irq( ball->pdata);\r
122          DBG("jogball: up end\n");\r
123         return IRQ_HANDLED;\r
124 }\r
125 \r
126 \r
127 static irqreturn_t rk28_jogball_down_ISR(int irq, void *dev_id)\r
128 {\r
129         struct rk28_jogball *ball = dev_id;     \r
130          rk28_jogball_disable_irq(ball->pdata);\r
131         jogball_cnt_down++;\r
132         DBG("jogball: down start \n");\r
133         if (jogball_cnt_down >= JOGBALL_MAX_CNT){\r
134                 DBG("jogball: down\n");\r
135                 \r
136                 input_report_key(prockjogball->input_dev, JB_KEY_DOWN, 1);\r
137                 input_sync(prockjogball->input_dev);\r
138                 input_report_key(prockjogball->input_dev, JB_KEY_DOWN, 0);\r
139                 input_sync(prockjogball->input_dev);\r
140                 \r
141                 jogball_cnt_up = 0;\r
142                 jogball_cnt_down = 0;\r
143                 jogball_cnt_left = 0;\r
144                 jogball_cnt_right = 0;\r
145         }       \r
146         DBG("jogball: down end\n");\r
147          rk28_jogball_enable_irq(ball->pdata);\r
148         return IRQ_HANDLED;\r
149 }\r
150 \r
151 \r
152 static irqreturn_t rk28_jogball_left_ISR(int irq, void *dev_id)\r
153 {\r
154 \r
155          struct rk28_jogball *ball = dev_id;    \r
156          rk28_jogball_disable_irq(ball->pdata);\r
157         DBG("jogball: left begain\n");\r
158         jogball_cnt_left++;\r
159         \r
160         if (jogball_cnt_left >= JOGBALL_MAX_CNT){\r
161                 DBG("jogball: left\n");\r
162                 \r
163                 input_report_key(prockjogball->input_dev, JB_KEY_LEFT, 1);\r
164                 input_sync(prockjogball->input_dev);\r
165                 input_report_key(prockjogball->input_dev, JB_KEY_LEFT, 0);\r
166                 input_sync(prockjogball->input_dev);\r
167 \r
168                 jogball_cnt_up = 0;\r
169                 jogball_cnt_down = 0;\r
170                 jogball_cnt_left = 0;\r
171                 jogball_cnt_right = 0;\r
172         }       \r
173         DBG("jogball: left end \n");\r
174          rk28_jogball_enable_irq(ball->pdata);\r
175         return IRQ_HANDLED;\r
176 }\r
177 \r
178 static irqreturn_t rk28_jogball_right_ISR(int irq, void *dev_id)\r
179 {\r
180         struct rk28_jogball *ball = dev_id;     \r
181         rk28_jogball_disable_irq(ball->pdata);\r
182         DBG("jogball: right start\n");\r
183         jogball_cnt_right++;\r
184 \r
185         if (jogball_cnt_right >= JOGBALL_MAX_CNT){\r
186                 DBG("jogball: right\n");\r
187                 \r
188                 input_report_key(prockjogball->input_dev, JB_KEY_RIGHT, 1);\r
189                 input_sync(prockjogball->input_dev);\r
190                 input_report_key(prockjogball->input_dev, JB_KEY_RIGHT, 0);\r
191                 input_sync(prockjogball->input_dev);\r
192 \r
193                 jogball_cnt_up = 0;\r
194                 jogball_cnt_down = 0;\r
195                 jogball_cnt_left = 0;\r
196                 jogball_cnt_right = 0;\r
197         }       \r
198         DBG("jogball: right end\n");\r
199          rk28_jogball_enable_irq(ball->pdata);\r
200         return IRQ_HANDLED;\r
201 }\r
202 \r
203 \r
204 \r
205 #ifdef CONFIG_ANDROID_POWER\r
206 \r
207 void rk28_jogball_early_suspend(android_early_suspend_t *h)\r
208 {\r
209     DBG("IN jogball early suspend !!\n\n\n");\r
210 }\r
211 \r
212 void rk28_jogball_early_resume(android_early_suspend_t *h)\r
213 {\r
214     DBG("IN jogball early resume !!\n\n\n");\r
215 }\r
216 \r
217 #endif\r
218 \r
219 void rk28_jogball_shutdown(struct platform_device *dev)\r
220 {\r
221     DBG("IN jogball early shutdown !!\n\n\n");\r
222 }\r
223 \r
224 static int rk28_jogball_probe(struct platform_device *pdev)\r
225 {\r
226 \r
227       int    error, i;\r
228         struct rk28_jogball *jogball = NULL;\r
229         struct input_dev *input_dev = NULL;\r
230         struct rk2818_jogball_paltform_data *pdata = pdev->dev.platform_data;\r
231         if(!(pdata->jogball_key))\r
232                 return -1;\r
233         \r
234         jogball = kzalloc(sizeof(struct rk28_jogball), GFP_KERNEL);\r
235         if (jogball == NULL)\r
236         {\r
237             printk("Alloc memory for rk28_jogball failed.\n");\r
238             return -ENOMEM;\r
239         }\r
240         \r
241         /* Create and register the input driver. */\r
242         input_dev = input_allocate_device();\r
243         if (!input_dev || !jogball) \r
244         {\r
245                 printk("failed to allocate input device.\n");\r
246                 error = -ENOMEM;\r
247                 goto failed1;\r
248         }\r
249         \r
250         memcpy(jogball->keycodes, initkey_code, sizeof(jogball->keycodes));\r
251         input_dev->name = "jogball";\r
252         input_dev->dev.parent = &pdev->dev;\r
253         input_dev->phys = JOGBALL_PHYS_NAME;\r
254         input_dev->keycode = jogball->keycodes;\r
255         input_dev->keycodesize = sizeof(unsigned char);\r
256         input_dev->keycodemax = ARRAY_SIZE(initkey_code);\r
257         for (i = 0; i < ARRAY_SIZE(initkey_code); i++)\r
258                 set_bit(initkey_code[i], input_dev->keybit);\r
259         clear_bit(0, input_dev->keybit);\r
260         input_dev->evbit[0] = BIT_MASK(EV_KEY);\r
261         jogball->pdata = pdata;\r
262         jogball->input_dev = input_dev;\r
263         input_set_drvdata(input_dev, jogball);\r
264 \r
265         platform_set_drvdata(pdev, jogball);\r
266 \r
267         prockjogball = jogball;\r
268 \r
269         /* Register the input device */\r
270         error = input_register_device(input_dev);\r
271         if (error) \r
272         {\r
273                 printk("failed to register input device.\n");\r
274                 goto failed2;\r
275         }\r
276         printk(" irq register for input device.\n");\r
277         #if 1   //ÉêÇëEXTERN GPIO INTERRUPT\r
278         //JOG_UP_PORT\r
279         \r
280 \r
281         error = gpio_request(pdata->jogball_key->pin_up,"Jog up");\r
282         if(error)\r
283         {\r
284                 printk("unable to request JOG_UP_PORT IRQ err=%d\n", error);\r
285                 goto failed3;\r
286         }\r
287         gpio_direction_input(pdata->jogball_key->pin_up);       \r
288         error = request_irq(gpio_to_irq(pdata->jogball_key->pin_up),rk28_jogball_up_ISR,IRQ_TYPE_EDGE_RISING,NULL,jogball);\r
289         if(error)\r
290         {\r
291                 printk("unable to request JOG_UP_PORT irq\n");\r
292                 goto failed4;\r
293         }       \r
294         //JOG_DOWN_PORT\r
295         error = gpio_request(pdata->jogball_key->pin_down,"jog down");\r
296         if(error)\r
297         {\r
298                 printk("unable to request JOG_DOWN_PORT IRQ err=%d\n", error);\r
299                 goto failed5;\r
300         }\r
301         gpio_direction_input(pdata->jogball_key->pin_down);\r
302         //gpio_pull_updown(JOG_DOWN_PORT,GPIOPullUp);\r
303         error = request_irq(gpio_to_irq(pdata->jogball_key->pin_down),rk28_jogball_down_ISR,IRQ_TYPE_EDGE_RISING,NULL,jogball);\r
304         if(error)\r
305         {\r
306                 printk("unable to request JOG_DOWN_PORT irq\n");\r
307                 goto failed6;\r
308         }       \r
309         //JOG_LEFT_PORT\r
310         error = gpio_request(pdata->jogball_key->pin_left,"jog left");\r
311         if(error)\r
312         {\r
313                 printk("unable to request JOG_LEFT_PORT IRQ err=%d\n", error);\r
314                 goto failed7;\r
315         }\r
316         gpio_direction_input(pdata->jogball_key->pin_left);\r
317         //gpio_pull_updown(JOG_LEFT_PORT,GPIOPullUp);\r
318         error = request_irq(gpio_to_irq(pdata->jogball_key->pin_left),rk28_jogball_left_ISR,IRQ_TYPE_EDGE_RISING,NULL,jogball);\r
319         if(error)\r
320         {\r
321                 printk("unable to request JOG_LEFT_PORT irq\n");\r
322                 goto failed8;\r
323         }       \r
324         //JOG_RIGHT_PORT\r
325         error = gpio_request(pdata->jogball_key->pin_right,NULL);\r
326         if(error)\r
327         {\r
328                 printk("unable to request JOG_RIGHT_PORT IRQ err=%d\n", error);\r
329                 goto failed9;\r
330         }\r
331         gpio_direction_input(pdata->jogball_key->pin_right);\r
332         //gpio_pull_updown(JOG_RIGHT_PORT,GPIOPullUp);\r
333         error = request_irq(gpio_to_irq(pdata->jogball_key->pin_right),rk28_jogball_right_ISR,IRQ_TYPE_EDGE_RISING,NULL,jogball);\r
334         if(error)\r
335         {\r
336                 printk("unable to request JOG_RIGHT_PORT irq\n");\r
337                 goto failed10;\r
338         }                       \r
339 #endif\r
340 \r
341 #ifdef CONFIG_ANDROID_POWER\r
342     jogball_early_suspend.suspend = rk28_jogball_early_suspend;\r
343     jogball_early_suspend.resume = rk28_jogball_early_resume;\r
344     jogball_early_suspend.level = 0x2;\r
345     android_register_early_suspend(&jogball_early_suspend);\r
346 #endif\r
347 \r
348         printk("JOGBALL:rk28_jogball_probe sucess\n");\r
349         return 0;\r
350 #if 1\r
351 failed10:\r
352         free_irq(gpio_to_irq(pdata->jogball_key->pin_down),NULL);\r
353 failed9:\r
354         gpio_free(pdata->jogball_key->pin_down);\r
355 failed8:\r
356         free_irq(gpio_to_irq(pdata->jogball_key->pin_left),NULL);\r
357 failed7:\r
358         gpio_free(pdata->jogball_key->pin_left);\r
359 failed6:                \r
360         free_irq(gpio_to_irq(pdata->jogball_key->pin_down),NULL);\r
361 failed5:\r
362         gpio_free(pdata->jogball_key->pin_down);\r
363 failed4:\r
364         free_irq(gpio_to_irq(pdata->jogball_key->pin_up),NULL);\r
365 failed3:\r
366         gpio_free(pdata->jogball_key->pin_up);\r
367         \r
368         input_unregister_device(jogball->input_dev);\r
369 \r
370 failed2:\r
371     platform_set_drvdata(pdev, NULL);\r
372     input_free_device(input_dev);\r
373 \r
374 failed1:\r
375         kfree(jogball);\r
376         \r
377         return error;\r
378 #endif\r
379 }\r
380 \r
381 static int __devexit rk28_jogball_remove(struct platform_device *pdev)\r
382 {\r
383         struct rk28_jogball *jogball = platform_get_drvdata(pdev);\r
384 \r
385     platform_set_drvdata(pdev, NULL);\r
386     \r
387         input_unregister_device(jogball->input_dev);\r
388         input_free_device(jogball->input_dev);\r
389         kfree(jogball);\r
390         \r
391         return 0;\r
392 }\r
393 \r
394 #ifdef CONFIG_PM\r
395 \r
396 static int rk28_jogball_suspend(struct platform_device *pdev, pm_message_t state)\r
397 {\r
398         \r
399         struct rk2818_jogball_paltform_data *pdata = pdev->dev.platform_data;\r
400         disable_irq_nosync (gpio_to_irq(pdata->jogball_key->pin_up));\r
401         disable_irq_nosync (gpio_to_irq(pdata->jogball_key->pin_down));\r
402         disable_irq_nosync (gpio_to_irq(pdata->jogball_key->pin_left));\r
403         disable_irq_nosync (gpio_to_irq(pdata->jogball_key->pin_right));\r
404         DBG("rk28_jogball_suspend\n")\r
405         return 0;\r
406 }\r
407 \r
408 static int rk28_jogball_resume(struct platform_device *pdev)\r
409 {\r
410         \r
411         struct rk2818_jogball_paltform_data *pdata = pdev->dev.platform_data;\r
412         enable_irq (gpio_to_irq(pdata->jogball_key->pin_up));\r
413         enable_irq (gpio_to_irq(pdata->jogball_key->pin_down));\r
414         enable_irq (gpio_to_irq(pdata->jogball_key->pin_left));\r
415         enable_irq (gpio_to_irq(pdata->jogball_key->pin_right));\r
416         DBG("rk28_jogball_resume\n")\r
417     return 0;\r
418 }\r
419 \r
420 \r
421 #endif\r
422 \r
423 static struct platform_driver rk28_jogball_driver = \r
424 {\r
425         .probe          = rk28_jogball_probe,\r
426         .remove         = __devexit_p(rk28_jogball_remove),\r
427         .driver         = {\r
428                 .name   = "rk2818_jogball",\r
429                 .owner  = THIS_MODULE,\r
430         },\r
431         .shutdown   = rk28_jogball_shutdown,\r
432 #ifdef CONFIG_PM\r
433    .suspend    = rk28_jogball_suspend,\r
434    .resume     = rk28_jogball_resume,\r
435 #endif\r
436 };\r
437 \r
438  int __init rk28_jogball_init(void)\r
439 {\r
440         int ret;\r
441 \r
442         DBG("rk28_jogball_initl\n");\r
443         ret = platform_driver_register(&rk28_jogball_driver);\r
444         if (ret < 0){\r
445                 printk("register rk28_jogball_driver failed!!\n");\r
446         }       \r
447         return ret;\r
448 }\r
449 \r
450 static void __exit rk28_jogball_exit(void)\r
451 {\r
452         platform_driver_unregister(&rk28_jogball_driver);\r
453 }\r
454 \r
455 late_initcall(rk28_jogball_init);\r
456 module_exit(rk28_jogball_exit);\r
457 \r
458 MODULE_DESCRIPTION("rk28 jogball Controller Driver");\r
459 MODULE_AUTHOR("Yi Tang && Yongle Lai");\r
460 MODULE_LICENSE("GPL");\r
461 \r
462 \r