2 * linux/drivers/input/keyboard/rk28_jogball.c
\r
4 * Driver for the rk28 matrix keyboard controller.
\r
6 * Created: 2009-11-28
\r
7 * Author: TY <ty@rockchip.com>
\r
9 * This driver program support to AD key which use for rk28 chip
\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
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
28 #include <mach/gpio.h>
\r
29 #include <mach/iomux.h>
\r
30 #include <linux/irq.h>
\r
31 #include <mach/board.h>
\r
33 #ifdef CONFIG_ANDROID_POWER
\r
34 #include <linux/android_power.h>
\r
36 static android_early_suspend_t jogball_early_suspend;
\r
40 //#define JB_DEBUG 0
\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
53 #define JOGBALL_PHYS_NAME "rk28_jogball/input0"
\r
55 #define JOGBALL_MAX_CNT 1
\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
63 static unsigned char initkey_code[ ] =
\r
65 JB_KEY_UP, JB_KEY_DOWN, JB_KEY_LEFT, JB_KEY_RIGHT
\r
68 struct rk28_jogball
\r
70 struct input_dev *input_dev;
\r
71 struct rk2818_jogball_paltform_data *pdata;
\r
72 unsigned char keycodes[5];
\r
75 struct rk28_jogball *prockjogball;
\r
78 static int rk28_jogball_disable_irq(struct rk2818_jogball_paltform_data *pdata )
\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
89 static int rk28_jogball_enable_irq(struct rk2818_jogball_paltform_data *pdata)
\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
99 static irqreturn_t rk28_jogball_up_ISR(int irq, void *dev_id)
\r
102 struct rk28_jogball *ball = dev_id;
\r
103 rk28_jogball_disable_irq(ball->pdata);
\r
104 DBG("jogball: up begain\n");
\r
107 if (jogball_cnt_up >= JOGBALL_MAX_CNT){
\r
108 DBG("jogball: up\n");
\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
115 jogball_cnt_up = 0;
\r
116 jogball_cnt_down = 0;
\r
117 jogball_cnt_left = 0;
\r
118 jogball_cnt_right = 0;
\r
121 rk28_jogball_enable_irq( ball->pdata);
\r
122 DBG("jogball: up end\n");
\r
123 return IRQ_HANDLED;
\r
127 static irqreturn_t rk28_jogball_down_ISR(int irq, void *dev_id)
\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
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
141 jogball_cnt_up = 0;
\r
142 jogball_cnt_down = 0;
\r
143 jogball_cnt_left = 0;
\r
144 jogball_cnt_right = 0;
\r
146 DBG("jogball: down end\n");
\r
147 rk28_jogball_enable_irq(ball->pdata);
\r
148 return IRQ_HANDLED;
\r
152 static irqreturn_t rk28_jogball_left_ISR(int irq, void *dev_id)
\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
160 if (jogball_cnt_left >= JOGBALL_MAX_CNT){
\r
161 DBG("jogball: left\n");
\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
168 jogball_cnt_up = 0;
\r
169 jogball_cnt_down = 0;
\r
170 jogball_cnt_left = 0;
\r
171 jogball_cnt_right = 0;
\r
173 DBG("jogball: left end \n");
\r
174 rk28_jogball_enable_irq(ball->pdata);
\r
175 return IRQ_HANDLED;
\r
178 static irqreturn_t rk28_jogball_right_ISR(int irq, void *dev_id)
\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
185 if (jogball_cnt_right >= JOGBALL_MAX_CNT){
\r
186 DBG("jogball: right\n");
\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
193 jogball_cnt_up = 0;
\r
194 jogball_cnt_down = 0;
\r
195 jogball_cnt_left = 0;
\r
196 jogball_cnt_right = 0;
\r
198 DBG("jogball: right end\n");
\r
199 rk28_jogball_enable_irq(ball->pdata);
\r
200 return IRQ_HANDLED;
\r
205 #ifdef CONFIG_ANDROID_POWER
\r
207 void rk28_jogball_early_suspend(android_early_suspend_t *h)
\r
209 DBG("IN jogball early suspend !!\n\n\n");
\r
212 void rk28_jogball_early_resume(android_early_suspend_t *h)
\r
214 DBG("IN jogball early resume !!\n\n\n");
\r
219 void rk28_jogball_shutdown(struct platform_device *dev)
\r
221 DBG("IN jogball early shutdown !!\n\n\n");
\r
224 static int rk28_jogball_probe(struct platform_device *pdev)
\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
234 jogball = kzalloc(sizeof(struct rk28_jogball), GFP_KERNEL);
\r
235 if (jogball == NULL)
\r
237 printk("Alloc memory for rk28_jogball failed.\n");
\r
241 /* Create and register the input driver. */
\r
242 input_dev = input_allocate_device();
\r
243 if (!input_dev || !jogball)
\r
245 printk("failed to allocate input device.\n");
\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
265 platform_set_drvdata(pdev, jogball);
\r
267 prockjogball = jogball;
\r
269 /* Register the input device */
\r
270 error = input_register_device(input_dev);
\r
273 printk("failed to register input device.\n");
\r
276 printk(" irq register for input device.\n");
\r
277 #if 1 //ÉêÇëEXTERN GPIO INTERRUPT
\r
281 error = gpio_request(pdata->jogball_key->pin_up,"Jog up");
\r
284 printk("unable to request JOG_UP_PORT IRQ err=%d\n", error);
\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
291 printk("unable to request JOG_UP_PORT irq\n");
\r
295 error = gpio_request(pdata->jogball_key->pin_down,"jog down");
\r
298 printk("unable to request JOG_DOWN_PORT IRQ err=%d\n", error);
\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
306 printk("unable to request JOG_DOWN_PORT irq\n");
\r
310 error = gpio_request(pdata->jogball_key->pin_left,"jog left");
\r
313 printk("unable to request JOG_LEFT_PORT IRQ err=%d\n", error);
\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
321 printk("unable to request JOG_LEFT_PORT irq\n");
\r
325 error = gpio_request(pdata->jogball_key->pin_right,NULL);
\r
328 printk("unable to request JOG_RIGHT_PORT IRQ err=%d\n", error);
\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
336 printk("unable to request JOG_RIGHT_PORT irq\n");
\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
348 printk("JOGBALL:rk28_jogball_probe sucess\n");
\r
352 free_irq(gpio_to_irq(pdata->jogball_key->pin_down),NULL);
\r
354 gpio_free(pdata->jogball_key->pin_down);
\r
356 free_irq(gpio_to_irq(pdata->jogball_key->pin_left),NULL);
\r
358 gpio_free(pdata->jogball_key->pin_left);
\r
360 free_irq(gpio_to_irq(pdata->jogball_key->pin_down),NULL);
\r
362 gpio_free(pdata->jogball_key->pin_down);
\r
364 free_irq(gpio_to_irq(pdata->jogball_key->pin_up),NULL);
\r
366 gpio_free(pdata->jogball_key->pin_up);
\r
368 input_unregister_device(jogball->input_dev);
\r
371 platform_set_drvdata(pdev, NULL);
\r
372 input_free_device(input_dev);
\r
381 static int __devexit rk28_jogball_remove(struct platform_device *pdev)
\r
383 struct rk28_jogball *jogball = platform_get_drvdata(pdev);
\r
385 platform_set_drvdata(pdev, NULL);
\r
387 input_unregister_device(jogball->input_dev);
\r
388 input_free_device(jogball->input_dev);
\r
396 static int rk28_jogball_suspend(struct platform_device *pdev, pm_message_t state)
\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
408 static int rk28_jogball_resume(struct platform_device *pdev)
\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
423 static struct platform_driver rk28_jogball_driver =
\r
425 .probe = rk28_jogball_probe,
\r
426 .remove = __devexit_p(rk28_jogball_remove),
\r
428 .name = "rk2818_jogball",
\r
429 .owner = THIS_MODULE,
\r
431 .shutdown = rk28_jogball_shutdown,
\r
433 .suspend = rk28_jogball_suspend,
\r
434 .resume = rk28_jogball_resume,
\r
438 int __init rk28_jogball_init(void)
\r
442 DBG("rk28_jogball_initl\n");
\r
443 ret = platform_driver_register(&rk28_jogball_driver);
\r
445 printk("register rk28_jogball_driver failed!!\n");
\r
450 static void __exit rk28_jogball_exit(void)
\r
452 platform_driver_unregister(&rk28_jogball_driver);
\r
455 late_initcall(rk28_jogball_init);
\r
456 module_exit(rk28_jogball_exit);
\r
458 MODULE_DESCRIPTION("rk28 jogball Controller Driver");
\r
459 MODULE_AUTHOR("Yi Tang && Yongle Lai");
\r
460 MODULE_LICENSE("GPL");
\r