--- /dev/null
+/*\r
+ * linux/drivers/input/keyboard/rk28_jogball.c\r
+ *\r
+ * Driver for the rk28 matrix keyboard controller.\r
+ *\r
+ * Created: 2009-11-28\r
+ * Author: TY <ty@rockchip.com>\r
+ *\r
+ * This driver program support to AD key which use for rk28 chip\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License version 2 as\r
+ * published by the Free Software Foundation.\r
+ */\r
+\r
+#include <linux/kernel.h>\r
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/input.h>\r
+#include <linux/device.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/clk.h>\r
+#include <linux/err.h>\r
+#include <linux/delay.h>\r
+#include <linux/time.h>\r
+\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include <linux/irq.h>\r
+\r
+\r
+#ifdef CONFIG_ANDROID_POWER\r
+#include <linux/android_power.h>\r
+\r
+static android_early_suspend_t jogball_early_suspend;\r
+#endif\r
+\r
+/* Debug */\r
+#define JB_DEBUG 1\r
+\r
+#ifdef JB_DEBUG\r
+#define DBG printk\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+#define JB_KEY_UP 103\r
+#define JB_KEY_DOWN 108\r
+#define JB_KEY_LEFT 105\r
+#define JB_KEY_RIGHT 106\r
+\r
+#define JOGBALL_PHYS_NAME "rk28_jogball/input0"\r
+\r
+#define JOGBALL_KEY_UP_IO TCA6424_P06\r
+#define JOGBALL_KEY_DOWN_IO TCA6424_P07\r
+#define JOGBALL_KEY_LEFT_IO TCA6424_P10\r
+#define JOGBALL_KEY_RIGHT_IO TCA6424_P11\r
+\r
+#define JOGBALL_MAX_CNT 2\r
+\r
+static volatile int jogball_cnt_up = 0;\r
+static volatile int jogball_cnt_down = 0;\r
+static volatile int jogball_cnt_left = 0;\r
+static volatile int jogball_cnt_right = 0;\r
+\r
+//key code tab\r
+static unsigned char initkey_code[ ] = \r
+{\r
+ JB_KEY_UP, JB_KEY_DOWN, JB_KEY_LEFT, JB_KEY_RIGHT\r
+};\r
+\r
+struct rk28_jogball \r
+{\r
+ struct input_dev *input_dev;\r
+ unsigned char keycodes[5];\r
+};\r
+\r
+struct rk28_jogball *prockjogball;\r
+\r
+//static void rk28_jogball_up_ISR(void)\r
+\r
+static int rk28_jogball_disable_irq(void )\r
+{\r
+ //DBG("IN jogball suspend !!\n");\r
+ disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_UP_IO));\r
+ disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_DOWN_IO));\r
+ disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_LEFT_IO));\r
+ disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_RIGHT_IO));\r
+ \r
+ return 0;\r
+}\r
+\r
+static int rk28_jogball_enable_irq(void)\r
+{\r
+ //DBG("IN jogball resume !!\n");\r
+ enable_irq (gpio_to_irq(JOGBALL_KEY_UP_IO));\r
+ enable_irq (gpio_to_irq(JOGBALL_KEY_DOWN_IO));\r
+ enable_irq (gpio_to_irq(JOGBALL_KEY_LEFT_IO));\r
+ enable_irq (gpio_to_irq(JOGBALL_KEY_RIGHT_IO));\r
+\r
+ return 0;\r
+}\r
+static irqreturn_t rk28_jogball_up_ISR(int irq, void *dev_id)\r
+{ \r
+ \r
+ rk28_jogball_disable_irq( );\r
+ jogball_cnt_up++;\r
+\r
+ if (jogball_cnt_up > JOGBALL_MAX_CNT){\r
+ //printk("jogball: up\n");\r
+ \r
+ input_report_key(prockjogball->input_dev, JB_KEY_UP, 1);\r
+ input_sync(prockjogball->input_dev);\r
+ input_report_key(prockjogball->input_dev, JB_KEY_UP, 0);\r
+ input_sync(prockjogball->input_dev);\r
+\r
+ jogball_cnt_up = 0;\r
+ jogball_cnt_down = 0;\r
+ jogball_cnt_left = 0;\r
+ jogball_cnt_right = 0;\r
+ }\r
+ \r
+ //gpio_irq_enable(JOGBALL_KEY_UP_IO);\r
+ //enable_irq (gpio_to_irq(JOGBALL_KEY_UP_IO));\r
+ rk28_jogball_enable_irq( );\r
+ return IRQ_HANDLED;\r
+}\r
+\r
+//static void rk28_jogball_down_ISR(void)\r
+static irqreturn_t rk28_jogball_down_ISR(int irq, void *dev_id)\r
+{\r
+ rk28_jogball_disable_irq( );\r
+ //disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_DOWN_IO));\r
+ jogball_cnt_down++;\r
+ \r
+ if (jogball_cnt_down > JOGBALL_MAX_CNT){\r
+ //printk("jogball: down\n");\r
+ \r
+ input_report_key(prockjogball->input_dev, JB_KEY_DOWN, 1);\r
+ input_sync(prockjogball->input_dev);\r
+ input_report_key(prockjogball->input_dev, JB_KEY_DOWN, 0);\r
+ input_sync(prockjogball->input_dev);\r
+ \r
+ jogball_cnt_up = 0;\r
+ jogball_cnt_down = 0;\r
+ jogball_cnt_left = 0;\r
+ jogball_cnt_right = 0;\r
+ }\r
+ \r
+ //gpio_irq_enable(JOGBALL_KEY_DOWN_IO);\r
+ //enable_irq (gpio_to_irq(JOGBALL_KEY_DOWN_IO));\r
+ rk28_jogball_enable_irq( );\r
+ return IRQ_HANDLED;\r
+}\r
+\r
+//static void rk28_jogball_left_ISR(void)\r
+static irqreturn_t rk28_jogball_left_ISR(int irq, void *dev_id)\r
+{\r
+ rk28_jogball_disable_irq( );\r
+ //disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_LEFT_IO));\r
+ jogball_cnt_left++;\r
+\r
+ if (jogball_cnt_left > JOGBALL_MAX_CNT){\r
+ //printk("jogball: left\n");\r
+ \r
+ input_report_key(prockjogball->input_dev, JB_KEY_LEFT, 1);\r
+ input_sync(prockjogball->input_dev);\r
+ input_report_key(prockjogball->input_dev, JB_KEY_LEFT, 0);\r
+ input_sync(prockjogball->input_dev);\r
+\r
+ jogball_cnt_up = 0;\r
+ jogball_cnt_down = 0;\r
+ jogball_cnt_left = 0;\r
+ jogball_cnt_right = 0;\r
+ }\r
+ \r
+ //gpio_irq_enable(JOGBALL_KEY_LEFT_IO);\r
+ //enable_irq (gpio_to_irq(JOGBALL_KEY_LEFT_IO));\r
+ rk28_jogball_enable_irq( );\r
+ return IRQ_HANDLED;\r
+}\r
+\r
+//static void rk28_jogball_right_ISR(void)\r
+static irqreturn_t rk28_jogball_right_ISR(int irq, void *dev_id)\r
+{\r
+ rk28_jogball_disable_irq( );\r
+ //disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_RIGHT_IO));\r
+ jogball_cnt_right++;\r
+\r
+ if (jogball_cnt_right > JOGBALL_MAX_CNT){\r
+ //printk("jogball: right\n");\r
+ \r
+ input_report_key(prockjogball->input_dev, JB_KEY_RIGHT, 1);\r
+ input_sync(prockjogball->input_dev);\r
+ input_report_key(prockjogball->input_dev, JB_KEY_RIGHT, 0);\r
+ input_sync(prockjogball->input_dev);\r
+\r
+ jogball_cnt_up = 0;\r
+ jogball_cnt_down = 0;\r
+ jogball_cnt_left = 0;\r
+ jogball_cnt_right = 0;\r
+ }\r
+ \r
+ //gpio_irq_enable(JOGBALL_KEY_RIGHT_IO);\r
+ //enable_irq (gpio_to_irq(JOGBALL_KEY_RIGHT_IO));\r
+ rk28_jogball_enable_irq( );\r
+ return IRQ_HANDLED;\r
+}\r
+\r
+\r
+\r
+#ifdef CONFIG_ANDROID_POWER\r
+\r
+void rk28_jogball_early_suspend(android_early_suspend_t *h)\r
+{\r
+ DBG("IN jogball early suspend !!\n\n\n");\r
+}\r
+\r
+void rk28_jogball_early_resume(android_early_suspend_t *h)\r
+{\r
+ DBG("IN jogball early resume !!\n\n\n");\r
+}\r
+\r
+#endif\r
+\r
+void rk28_jogball_shutdown(struct platform_device *dev)\r
+{\r
+ DBG("IN jogball early shutdown !!\n\n\n");\r
+}\r
+\r
+static int rk28_jogball_probe(struct platform_device *pdev)\r
+{\r
+ #if 1\r
+ int error, i;\r
+ struct rk28_jogball *jogball = NULL;\r
+ struct input_dev *input_dev = NULL;\r
+\r
+ printk("***************rk28_jogball_probe...\n");\r
+ \r
+ jogball = kzalloc(sizeof(struct rk28_jogball), GFP_KERNEL);\r
+ if (jogball == NULL)\r
+ {\r
+ printk("Alloc memory for rk28_jogball failed.\n");\r
+ return -ENOMEM;\r
+ }\r
+ \r
+ /* Create and register the input driver. */\r
+ input_dev = input_allocate_device();\r
+ if (!input_dev || !jogball) \r
+ {\r
+ printk("failed to allocate input device.\n");\r
+ error = -ENOMEM;\r
+ goto failed1;\r
+ }\r
+ \r
+ memcpy(jogball->keycodes, initkey_code, sizeof(jogball->keycodes));\r
+ input_dev->name = "jogball";\r
+ input_dev->dev.parent = &pdev->dev;\r
+ input_dev->phys = JOGBALL_PHYS_NAME;\r
+ input_dev->keycode = jogball->keycodes;\r
+ input_dev->keycodesize = sizeof(unsigned char);\r
+ input_dev->keycodemax = ARRAY_SIZE(initkey_code);\r
+ for (i = 0; i < ARRAY_SIZE(initkey_code); i++)\r
+ set_bit(initkey_code[i], input_dev->keybit);\r
+ clear_bit(0, input_dev->keybit);\r
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);\r
+ \r
+ jogball->input_dev = input_dev;\r
+ input_set_drvdata(input_dev, jogball);\r
+\r
+ platform_set_drvdata(pdev, jogball);\r
+\r
+ prockjogball = jogball;\r
+\r
+ /* Register the input device */\r
+ error = input_register_device(input_dev);\r
+ if (error) \r
+ {\r
+ printk("failed to register input device.\n");\r
+ goto failed2;\r
+ }\r
+ printk(" irq register for input device.\n");\r
+ #if 1 //ÉêÇëEXTERN GPIO INTERRUPT\r
+ //JOG_UP_PORT\r
+ \r
+\r
+ error = gpio_request(JOGBALL_KEY_UP_IO,"Jog up");\r
+ if(error)\r
+ {\r
+ printk("unable to request JOG_UP_PORT IRQ err=%d\n", error);\r
+ goto failed3;\r
+ }\r
+ gpio_direction_input(JOGBALL_KEY_UP_IO); \r
+ error = request_irq(gpio_to_irq(JOGBALL_KEY_UP_IO),rk28_jogball_up_ISR,IRQ_TYPE_EDGE_RISING,NULL,jogball);\r
+ if(error)\r
+ {\r
+ printk("unable to request JOG_UP_PORT irq\n");\r
+ goto failed4;\r
+ } \r
+ //JOG_DOWN_PORT\r
+ error = gpio_request(JOGBALL_KEY_DOWN_IO,"jog down");\r
+ if(error)\r
+ {\r
+ printk("unable to request JOG_DOWN_PORT IRQ err=%d\n", error);\r
+ goto failed5;\r
+ }\r
+ gpio_direction_input(JOGBALL_KEY_DOWN_IO);\r
+ //gpio_pull_updown(JOG_DOWN_PORT,GPIOPullUp);\r
+ error = request_irq(gpio_to_irq(JOGBALL_KEY_DOWN_IO),rk28_jogball_down_ISR,IRQ_TYPE_EDGE_RISING,NULL,jogball);\r
+ if(error)\r
+ {\r
+ printk("unable to request JOG_DOWN_PORT irq\n");\r
+ goto failed6;\r
+ } \r
+ //JOG_LEFT_PORT\r
+ error = gpio_request(JOGBALL_KEY_LEFT_IO,"jog left");\r
+ if(error)\r
+ {\r
+ printk("unable to request JOG_LEFT_PORT IRQ err=%d\n", error);\r
+ goto failed7;\r
+ }\r
+ gpio_direction_input(JOGBALL_KEY_LEFT_IO);\r
+ //gpio_pull_updown(JOG_LEFT_PORT,GPIOPullUp);\r
+ error = request_irq(gpio_to_irq(JOGBALL_KEY_LEFT_IO),rk28_jogball_left_ISR,IRQ_TYPE_EDGE_RISING,NULL,jogball);\r
+ if(error)\r
+ {\r
+ printk("unable to request JOG_LEFT_PORT irq\n");\r
+ goto failed8;\r
+ } \r
+ //JOG_RIGHT_PORT\r
+ error = gpio_request(JOGBALL_KEY_RIGHT_IO,NULL);\r
+ if(error)\r
+ {\r
+ printk("unable to request JOG_RIGHT_PORT IRQ err=%d\n", error);\r
+ goto failed9;\r
+ }\r
+ gpio_direction_input(JOGBALL_KEY_RIGHT_IO);\r
+ //gpio_pull_updown(JOG_RIGHT_PORT,GPIOPullUp);\r
+ error = request_irq(gpio_to_irq(JOGBALL_KEY_RIGHT_IO),rk28_jogball_right_ISR,IRQ_TYPE_EDGE_RISING,NULL,jogball);\r
+ if(error)\r
+ {\r
+ printk("unable to request JOG_RIGHT_PORT irq\n");\r
+ goto failed10;\r
+ } \r
+#endif\r
+\r
+#ifdef CONFIG_ANDROID_POWER\r
+ jogball_early_suspend.suspend = rk28_jogball_early_suspend;\r
+ jogball_early_suspend.resume = rk28_jogball_early_resume;\r
+ jogball_early_suspend.level = 0x2;\r
+ android_register_early_suspend(&jogball_early_suspend);\r
+#endif\r
+#endif\r
+ printk("******************rk28_jogball_probe end\n");\r
+ return 0;\r
+#if 1\r
+failed10:\r
+ free_irq(gpio_to_irq(JOGBALL_KEY_RIGHT_IO),NULL);\r
+failed9:\r
+ gpio_free(JOGBALL_KEY_RIGHT_IO);\r
+failed8:\r
+ free_irq(gpio_to_irq(JOGBALL_KEY_LEFT_IO),NULL);\r
+failed7:\r
+ gpio_free(JOGBALL_KEY_LEFT_IO);\r
+failed6: \r
+ free_irq(gpio_to_irq(JOGBALL_KEY_DOWN_IO),NULL);\r
+failed5:\r
+ gpio_free(JOGBALL_KEY_DOWN_IO);\r
+failed4:\r
+ free_irq(gpio_to_irq(JOGBALL_KEY_UP_IO),NULL);\r
+failed3:\r
+ gpio_free(JOGBALL_KEY_UP_IO);\r
+ \r
+ input_unregister_device(jogball->input_dev);\r
+\r
+failed2:\r
+ platform_set_drvdata(pdev, NULL);\r
+ input_free_device(input_dev);\r
+\r
+failed1:\r
+ kfree(jogball);\r
+ \r
+ return error;\r
+#endif\r
+}\r
+\r
+static int __devexit rk28_jogball_remove(struct platform_device *pdev)\r
+{\r
+ struct rk28_jogball *jogball = platform_get_drvdata(pdev);\r
+\r
+ platform_set_drvdata(pdev, NULL);\r
+ \r
+ input_unregister_device(jogball->input_dev);\r
+ input_free_device(jogball->input_dev);\r
+ kfree(jogball);\r
+ \r
+ return 0;\r
+}\r
+\r
+#ifdef CONFIG_PM\r
+\r
+static int rk28_jogball_suspend(struct platform_device *pdev, pm_message_t state)\r
+{\r
+ DBG("IN jogball suspend !!\n");\r
+ disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_UP_IO));\r
+ disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_DOWN_IO));\r
+ disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_LEFT_IO));\r
+ disable_irq_nosync (gpio_to_irq(JOGBALL_KEY_RIGHT_IO));\r
+ \r
+ return 0;\r
+}\r
+\r
+static int rk28_jogball_resume(struct platform_device *pdev)\r
+{\r
+ DBG("IN jogball resume !!\n");\r
+ enable_irq (gpio_to_irq(JOGBALL_KEY_UP_IO));\r
+ enable_irq (gpio_to_irq(JOGBALL_KEY_DOWN_IO));\r
+ enable_irq (gpio_to_irq(JOGBALL_KEY_LEFT_IO));\r
+ enable_irq (gpio_to_irq(JOGBALL_KEY_RIGHT_IO));\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+#endif\r
+\r
+static struct platform_driver rk28_jogball_driver = \r
+{\r
+ .probe = rk28_jogball_probe,\r
+ .remove = __devexit_p(rk28_jogball_remove),\r
+ .driver = {\r
+ .name = "rk28_jogball",\r
+ .owner = THIS_MODULE,\r
+ },\r
+ .shutdown = rk28_jogball_shutdown,\r
+#ifdef CONFIG_PM\r
+ .suspend = rk28_jogball_suspend,\r
+ .resume = rk28_jogball_resume,\r
+#endif\r
+};\r
+\r
+ int __init rk28_jogball_init(void)\r
+{\r
+ int ret;\r
+\r
+ printk("****************JOGBALL inital\n");\r
+ ret = platform_driver_register(&rk28_jogball_driver);\r
+ if (ret < 0){\r
+ printk("register rk28_jogball_driver failed!!\n");\r
+ }\r
+ printk("********************JOGBALL inital end\n");\r
+ return ret;\r
+}\r
+\r
+static void __exit rk28_jogball_exit(void)\r
+{\r
+ platform_driver_unregister(&rk28_jogball_driver);\r
+}\r
+\r
+late_initcall(rk28_jogball_init);\r
+module_exit(rk28_jogball_exit);\r
+\r
+MODULE_DESCRIPTION("rk28 jogball Controller Driver");\r
+MODULE_AUTHOR("Yi Tang && Yongle Lai");\r
+MODULE_LICENSE("GPL");\r
+\r
+\r