+++ /dev/null
-\r
-/*\r
- * Driver for keys on GPIO lines capable of generating interrupts.\r
- *\r
- * Copyright 2005 Phil Blundell\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/module.h>\r
-#include <linux/init.h>\r
-#include <linux/fs.h>\r
-#include <linux/interrupt.h>\r
-#include <linux/irq.h>\r
-#include <linux/sched.h>\r
-#include <linux/pm.h>\r
-#include <linux/sysctl.h>\r
-#include <linux/proc_fs.h>\r
-#include <linux/delay.h>\r
-#include <linux/platform_device.h>\r
-#include <linux/input.h>\r
-#include <linux/workqueue.h>\r
-#include <linux/adc.h>\r
-#include <asm/gpio.h>\r
-#include <mach/remotectl.h>\r
-#include <mach/iomux.h>\r
-#include <linux/wakelock.h>\r
-#include <linux/suspend.h>\r
-\r
-\r
-#if 1\r
-#define remotectl_dbg(bdata, format, arg...) \\r
- dev_printk(KERN_INFO , &bdata->input->dev , format , ## arg)\r
-#else\r
-#define remotectl_dbg(bdata, format, arg...) \r
-#endif\r
-\r
-extern suspend_state_t get_suspend_state(void);\r
-\r
-struct rkxx_remotectl_suspend_data{\r
- int suspend_flag;\r
- int cnt;\r
- long scanTime[50];\r
-};\r
-\r
-struct rkxx_remote_key_table{\r
- int scanCode;\r
- int keyCode; \r
-};\r
-\r
-struct rkxx_remotectl_button { \r
- int usercode;\r
- int nbuttons;\r
- struct rkxx_remote_key_table *key_table;\r
-};\r
-\r
-struct rkxx_remotectl_drvdata {\r
- int state;\r
- int nbuttons;\r
- int result;\r
- unsigned long pre_time;\r
- unsigned long cur_time;\r
- long int pre_sec;\r
- long int cur_sec;\r
- long period;\r
- int scanData;\r
- int count;\r
- int keybdNum;\r
- int keycode;\r
- int press;\r
- int pre_press;\r
- \r
- struct input_dev *input;\r
- struct timer_list timer;\r
- struct tasklet_struct remote_tasklet;\r
- struct wake_lock remotectl_wake_lock;\r
- struct rkxx_remotectl_suspend_data remotectl_suspend_data;\r
-};\r
-\r
-\r
-\r
-//ÌØÊ⹦ÄܼüÖµ¶¨Òå\r
- //193 //photo\r
- //194 //video\r
- //195 //music\r
- //196 //IE\r
- //197 //\r
- //198\r
- //199\r
- //200\r
- \r
- //183 //rorate_left\r
- //184 //rorate_right\r
- //185 //zoom out\r
- //186 //zoom in\r
- \r
-static struct rkxx_remote_key_table remote_key_table_meiyu_202[] = {\r
- {0xB0, KEY_ENTER},//ok = DPAD CENTER\r
- {0xA2, KEY_BACK}, \r
- {0xD0, KEY_UP},\r
- {0x70, KEY_DOWN},\r
- {0x08, KEY_LEFT},\r
- {0x88, KEY_RIGHT}, ////////\r
- {0x42, KEY_HOME}, //home\r
- {0xA8, KEY_VOLUMEUP},\r
- {0x38, KEY_VOLUMEDOWN},\r
- {0xE2, KEY_SEARCH}, //search\r
- {0xB2, KEY_POWER}, //power off\r
- {0xC2, KEY_MUTE}, //mute\r
- {0xC8, KEY_MENU},\r
-\r
-//media ctrl\r
- {0x78, 0x190}, //play pause\r
- {0xF8, 0x191}, //pre\r
- {0x02, 0x192}, //next\r
-\r
-//pic\r
- {0xB8, 183}, //rorate left\r
- {0x58, 248}, //rorate right\r
- {0x68, 185}, //zoom out\r
- {0x98, 186}, //zoom in\r
-//mouse switch\r
- {0xf0,388},\r
-//display switch\r
- {0x82, 0x175},\r
-};\r
-\r
-static struct rkxx_remote_key_table remote_key_table_df[] = {\r
- {0xf8, KEY_REPLY},\r
- {0xc0, KEY_BACK}, \r
- {0xf0, KEY_UP},\r
- {0xd8, KEY_DOWN},\r
- {0xd0, KEY_LEFT},\r
- {0xe8,KEY_RIGHT}, ////////\r
- {0x90, KEY_VOLUMEDOWN},\r
- {0x60, KEY_VOLUMEUP},\r
- {0x80, KEY_HOME}, //home\r
- {0xe0, 183}, //rorate left\r
- {0x10, 184}, //rorate right\r
- {0x20, 185}, //zoom out\r
- {0xa0, 186}, //zoom in\r
- {0x70, KEY_MUTE}, //mute\r
- {0x50, KEY_POWER}, //power off\r
- {0x40, KEY_SEARCH}, //search\r
-};\r
-\r
-extern suspend_state_t get_suspend_state(void);\r
-\r
-\r
-static struct rkxx_remotectl_button remotectl_button[] = \r
-{\r
- { \r
- .usercode = 0x206, \r
- .nbuttons = 22, \r
- .key_table = &remote_key_table_meiyu_202[0],\r
- },\r
- {\r
- .usercode = 0x12ee,\r
- .nbuttons = 22,\r
- .key_table = &remote_key_table_meiyu_202[0],\r
- },\r
- { \r
- .usercode = 0x202, \r
- .nbuttons = 22, \r
- .key_table = &remote_key_table_meiyu_202[0],\r
- },\r
- { \r
- .usercode = 0xdf, \r
- .nbuttons = 16, \r
- .key_table = &remote_key_table_df[0],\r
- }, \r
- \r
-};\r
-\r
-\r
-static int remotectl_keybdNum_lookup(struct rkxx_remotectl_drvdata *ddata)\r
-{ \r
- int i; \r
-\r
- for (i = 0; i < sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button); i++){ \r
- if (remotectl_button[i].usercode == (ddata->scanData&0xFFFF)){ \r
- ddata->keybdNum = i;\r
- return 1;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-\r
-static int remotectl_keycode_lookup(struct rkxx_remotectl_drvdata *ddata)\r
-{ \r
- int i; \r
- unsigned char keyData = ((ddata->scanData >> 8) & 0xff);\r
-\r
- for (i = 0; i < remotectl_button[ddata->keybdNum].nbuttons; i++){\r
- if (remotectl_button[ddata->keybdNum].key_table[i].scanCode == keyData){ \r
- ddata->keycode = remotectl_button[ddata->keybdNum].key_table[i].keyCode;\r
- return 1;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-\r
-static void remotectl_get_pwr_scanData(struct rkxx_remotectl_drvdata *ddata,int *pwr_data,int loop)\r
-{ \r
- int i;\r
- int temp_scanCode;\r
- int temp_pwr_data;\r
- \r
- for (i = 0; i < remotectl_button[loop].nbuttons; i++){\r
- if (remotectl_button[loop].key_table[i].keyCode == KEY_POWER){ \r
- temp_scanCode = remotectl_button[loop].key_table[i].scanCode;\r
- temp_pwr_data = (temp_scanCode<<8)|((~temp_scanCode)&0xFF);\r
- //printk("pwr data =0x%x\n",temp_pwr_data);\r
- }\r
- }\r
- *pwr_data = temp_pwr_data;\r
-}\r
-\r
-static void remotectl_do_something(unsigned long data)\r
-{\r
- struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata *)data;\r
-\r
- switch (ddata->state)\r
- {\r
- case RMC_IDLE:\r
- {\r
- ;\r
- }\r
- break;\r
- \r
- case RMC_PRELOAD:\r
- {\r
- mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130));\r
- //printk("RMC_PRELOAD,period=%d\n",ddata->period);\r
- if ((TIME_PRE_MIN < ddata->period) && (ddata->period < TIME_PRE_MAX)){\r
- \r
- ddata->scanData = 0;\r
- ddata->count = 0;\r
- ddata->state = RMC_USERCODE;\r
- }else{\r
- ddata->state = RMC_PRELOAD;\r
- }\r
- ddata->pre_time = ddata->cur_time;\r
- //mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130));\r
- }\r
- break;\r
- \r
- case RMC_USERCODE:\r
- {\r
- ddata->scanData <<= 1;\r
- ddata->count ++;\r
- printk("RMC_USERCODE,period=%d£¬count=%d\n",ddata->period,ddata->count );\r
- if ((TIME_BIT1_MIN < ddata->period) && (ddata->period < TIME_BIT1_MAX)){\r
- ddata->scanData |= 0x01;\r
- }\r
- \r
- if (ddata->count == 0x10){//16 bit user code\r
- printk("u=0x%x\n",((ddata->scanData)&0xFFFF));\r
- if (remotectl_keybdNum_lookup(ddata)){\r
- ddata->state = RMC_GETDATA;\r
- ddata->scanData = 0;\r
- ddata->count = 0;\r
- }else{ //user code error\r
- ddata->state = RMC_PRELOAD;\r
- }\r
- }\r
- }\r
- break;\r
- \r
- case RMC_GETDATA:\r
- {\r
- ddata->count ++;\r
- ddata->scanData <<= 1;\r
-\r
- \r
- if ((TIME_BIT1_MIN < ddata->period) && (ddata->period < TIME_BIT1_MAX)){\r
- ddata->scanData |= 0x01;\r
- } \r
- if (ddata->count == 0x10){\r
- //printk("RMC_GETDATA=%x\n",(ddata->scanData&0xFFFF));\r
-\r
- if ((ddata->scanData&0x0ff) == ((~ddata->scanData >> 8)&0x0ff)){\r
- if (remotectl_keycode_lookup(ddata)){\r
- ddata->press = 1;\r
- /*\r
- if (get_suspend_state()==0){\r
- input_event(ddata->input, EV_KEY, ddata->keycode, 1);\r
- input_sync(ddata->input);\r
- }else if ((get_suspend_state())&&(ddata->keycode==KEY_POWER)){\r
- input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);\r
- input_sync(ddata->input);\r
- }*/\r
- //printk("0\n");\r
- input_event(ddata->input, EV_KEY, ddata->keycode, 1);\r
- input_sync(ddata->input);\r
- //input_event(ddata->input, EV_KEY, ddata->keycode, ddata->press);\r
- //input_sync(ddata->input);\r
- ddata->state = RMC_SEQUENCE;\r
- }else{\r
- ddata->state = RMC_PRELOAD;\r
- }\r
- }else{\r
- ddata->state = RMC_PRELOAD;\r
- }\r
- }\r
- }\r
- break;\r
- \r
- case RMC_SEQUENCE:{\r
-\r
- //printk( "S=%d\n",ddata->period);\r
- \r
- if ((TIME_RPT_MIN < ddata->period) && (ddata->period < TIME_RPT_MAX)){\r
- mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(110));\r
- //printk("1\n");;\r
- }else if ((TIME_SEQ1_MIN < ddata->period) && (ddata->period < TIME_SEQ1_MAX)){\r
- mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(110));\r
- //printk("2\n");\r
- }else if ((TIME_SEQ2_MIN < ddata->period) && (ddata->period < TIME_SEQ2_MAX)){\r
- mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(110));\r
- //printk("3\n");; \r
- }else{\r
- input_event(ddata->input, EV_KEY, ddata->keycode, 0);\r
- input_sync(ddata->input);\r
- ddata->state = RMC_PRELOAD;\r
- ddata->press = 0;\r
- //printk("4\n");\r
- }\r
- }\r
- break;\r
- \r
- default:\r
- break;\r
- } \r
- return;\r
-}\r
-\r
-\r
-#ifdef CONFIG_PM\r
-void remotectl_wakeup(unsigned long _data)\r
-{\r
- struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)_data;\r
- long *time;\r
- int i;\r
- int power_scanData;\r
- \r
- time = ddata->remotectl_suspend_data.scanTime;\r
-\r
- if (get_suspend_state()){\r
- ddata->remotectl_suspend_data.suspend_flag = 0;\r
- ddata->count = 0;\r
- ddata->state = RMC_USERCODE;\r
- ddata->scanData = 0;\r
- \r
- for (i=0;i<ddata->remotectl_suspend_data.cnt;i++){\r
- if (ddata->count>=32)\r
- break;\r
-\r
- if ((TIME_BIT1_MIN < time[i]) && (time[i] < TIME_BIT1_MAX)){\r
- ddata->scanData |= 0x01;\r
- ddata->scanData <<= 1;\r
- ddata->count ++;;\r
- }else if ((TIME_BIT0_MIN < time[i]) && (time[i] < TIME_BIT0_MAX)){\r
- ddata->scanData <<= 1;\r
- ddata->count ++;;\r
- }/*else{\r
- if (ddata->count>16){\r
- break;\r
- }else{\r
- \r
- printk(KERN_ERR "ddata->count=0x%x**********************\n",ddata->count);\r
- ddata->count = 0;\r
- ddata->scanData = 0;\r
- } \r
- }*/\r
- }\r
- //printk(KERN_ERR"data=0x%x\n",ddata->scanData);\r
- if (ddata->scanData) //(ddata->scanData>16) \r
- {\r
- ddata->scanData=(ddata->scanData>>1)&0xFFFF; \r
- printk(KERN_ERR"data=0x%x\n",ddata->scanData);\r
- \r
- for (i=0;i<sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);i++){\r
- remotectl_get_pwr_scanData(ddata,&power_scanData,i);\r
- if ((ddata->scanData == power_scanData)||((ddata->scanData&0x0fff) == (power_scanData&0x0fff))||((ddata->scanData&0x00ff) == (power_scanData&0x00ff))) //modified by zwm 2013.06.19\r
- {\r
- input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);\r
- input_sync(ddata->input);\r
- input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0);\r
- input_sync(ddata->input);\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- memset(ddata->remotectl_suspend_data.scanTime,0,50*sizeof(long));\r
- ddata->remotectl_suspend_data.cnt= 0; \r
- ddata->state = RMC_PRELOAD;\r
- \r
-}\r
-\r
-#endif\r
-\r
-\r
-static void remotectl_timer(unsigned long _data)\r
-{\r
- struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)_data;\r
- \r
- //printk("to\n");\r
- \r
- if(ddata->press != ddata->pre_press) {\r
- ddata->pre_press = ddata->press = 0;\r
- \r
- input_event(ddata->input, EV_KEY, ddata->keycode, 0);\r
- input_sync(ddata->input);\r
- //printk("5\n");\r
- //if (get_suspend_state()==0){\r
- //input_event(ddata->input, EV_KEY, ddata->keycode, 1);\r
- //input_sync(ddata->input);\r
- //input_event(ddata->input, EV_KEY, ddata->keycode, 0);\r
- //input_sync(ddata->input);\r
- //}else if ((get_suspend_state())&&(ddata->keycode==KEY_POWER)){\r
- //input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);\r
- //input_sync(ddata->input);\r
- //input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0);\r
- //input_sync(ddata->input);\r
- //}\r
- }\r
-#ifdef CONFIG_PM\r
- remotectl_wakeup(_data);\r
-#endif\r
- ddata->state = RMC_PRELOAD;\r
-}\r
-\r
-\r
-\r
-static irqreturn_t remotectl_isr(int irq, void *dev_id)\r
-{\r
- struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)dev_id;\r
- struct timeval ts;\r
-\r
-\r
- ddata->pre_time = ddata->cur_time;\r
- ddata->pre_sec = ddata->cur_sec;\r
- do_gettimeofday(&ts);\r
- ddata->cur_time = ts.tv_usec;\r
- ddata->cur_sec = ts.tv_sec;\r
- \r
- if (likely(ddata->cur_sec == ddata->pre_sec)){\r
- ddata->period = ddata->cur_time - ddata->pre_time;\r
- }else{\r
- ddata->period = 1000000 - ddata->pre_time + ddata->cur_time;\r
- }\r
-\r
- tasklet_hi_schedule(&ddata->remote_tasklet); \r
- //if ((ddata->state==RMC_PRELOAD)||(ddata->state==RMC_SEQUENCE))\r
- //mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130));\r
-#ifdef CONFIG_PM\r
- if (ddata->state==RMC_PRELOAD)\r
- wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);\r
- if ((get_suspend_state())&&(ddata->remotectl_suspend_data.cnt<50)) //zwm\r
- ddata->remotectl_suspend_data.scanTime[ddata->remotectl_suspend_data.cnt++] = ddata->period;\r
-#endif\r
-\r
- return IRQ_HANDLED;\r
-}\r
-\r
-\r
-static int __devinit remotectl_probe(struct platform_device *pdev)\r
-{\r
- struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;\r
- struct rkxx_remotectl_drvdata *ddata;\r
- struct input_dev *input;\r
- int i, j;\r
- int irq;\r
- int error = 0;\r
-\r
- printk("++++++++remotectl_probe\n");\r
-\r
- if(!pdata) \r
- return -EINVAL;\r
-\r
- ddata = kzalloc(sizeof(struct rkxx_remotectl_drvdata),GFP_KERNEL);\r
- memset(ddata,0,sizeof(struct rkxx_remotectl_drvdata));\r
-\r
- ddata->state = RMC_PRELOAD;\r
- input = input_allocate_device();\r
- \r
- if (!ddata || !input) {\r
- error = -ENOMEM;\r
- goto fail0;\r
- }\r
-\r
- platform_set_drvdata(pdev, ddata);\r
-\r
- input->name = pdev->name;\r
- input->phys = "gpio-keys/input0";\r
- input->dev.parent = &pdev->dev;\r
-\r
- input->id.bustype = BUS_HOST;\r
- input->id.vendor = 0x0001;\r
- input->id.product = 0x0001;\r
- input->id.version = 0x0100;\r
-\r
- /* Enable auto repeat feature of Linux input subsystem */\r
- if (pdata->rep)\r
- __set_bit(EV_REP, input->evbit);\r
- \r
- ddata->nbuttons = pdata->nbuttons;\r
- ddata->input = input;\r
- wake_lock_init(&ddata->remotectl_wake_lock, WAKE_LOCK_SUSPEND, "rk29_remote");\r
- if (pdata->set_iomux){\r
- pdata->set_iomux();\r
- }\r
- error = gpio_request(pdata->gpio, "remotectl");\r
- if (error < 0) {\r
- printk("gpio-keys: failed to request GPIO %d,"\r
- " error %d\n", pdata->gpio, error);\r
- //goto fail1;\r
- }\r
- error = gpio_direction_input(pdata->gpio);\r
- if (error < 0) {\r
- pr_err("gpio-keys: failed to configure input"\r
- " direction for GPIO %d, error %d\n",\r
- pdata->gpio, error);\r
- gpio_free(pdata->gpio);\r
- //goto fail1;\r
- }\r
- irq = gpio_to_irq(pdata->gpio);\r
- if (irq < 0) {\r
- error = irq;\r
- pr_err("gpio-keys: Unable to get irq number for GPIO %d, error %d\n",\r
- pdata->gpio, error);\r
- gpio_free(pdata->gpio);\r
- goto fail1;\r
- }\r
- \r
- error = request_irq(irq, remotectl_isr, IRQF_TRIGGER_FALLING , "remotectl", ddata);\r
- \r
- if (error) {\r
- pr_err("gpio-remotectl: Unable to claim irq %d; error %d\n", irq, error);\r
- gpio_free(pdata->gpio);\r
- goto fail1;\r
- }\r
- setup_timer(&ddata->timer,remotectl_timer, (unsigned long)ddata);\r
- \r
- tasklet_init(&ddata->remote_tasklet, remotectl_do_something, (unsigned long)ddata);\r
- \r
- for (j=0;j<sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);j++){ \r
- printk("remotectl probe j=0x%x\n",j);\r
- for (i = 0; i < remotectl_button[j].nbuttons; i++) {\r
- unsigned int type = EV_KEY;\r
- \r
- input_set_capability(input, type, remotectl_button[j].key_table[i].keyCode);\r
- }\r
- }\r
- error = input_register_device(input);\r
- if (error) {\r
- pr_err("gpio-keys: Unable to register input device, error: %d\n", error);\r
- goto fail2;\r
- }\r
- \r
- input_set_capability(input, EV_KEY, KEY_WAKEUP);\r
-\r
- device_init_wakeup(&pdev->dev, 1);\r
-\r
- return 0;\r
-\r
-fail2:\r
- pr_err("gpio-remotectl input_allocate_device fail\n");\r
- input_free_device(input);\r
- kfree(ddata);\r
-fail1:\r
- pr_err("gpio-remotectl gpio irq request fail\n");\r
- free_irq(gpio_to_irq(pdata->gpio), ddata);\r
- del_timer_sync(&ddata->timer);\r
- tasklet_kill(&ddata->remote_tasklet); \r
- gpio_free(pdata->gpio);\r
-fail0: \r
- pr_err("gpio-remotectl input_register_device fail\n");\r
- platform_set_drvdata(pdev, NULL);\r
-\r
- return error;\r
-}\r
-\r
-static int __devexit remotectl_remove(struct platform_device *pdev)\r
-{\r
- struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;\r
- struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev);\r
- struct input_dev *input = ddata->input;\r
- int irq;\r
-\r
- device_init_wakeup(&pdev->dev, 0);\r
- irq = gpio_to_irq(pdata->gpio);\r
- free_irq(irq, ddata);\r
- tasklet_kill(&ddata->remote_tasklet); \r
- gpio_free(pdata->gpio);\r
-\r
- input_unregister_device(input);\r
-\r
- return 0;\r
-}\r
-\r
-\r
-#ifdef CONFIG_PM\r
-static int remotectl_suspend(struct device *dev)\r
-{\r
- struct platform_device *pdev = to_platform_device(dev);\r
- struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;\r
- struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev);\r
- \r
- //ddata->remotectl_suspend_data.suspend_flag = 1;\r
- ddata->remotectl_suspend_data.cnt = 0;\r
-\r
- if (device_may_wakeup(&pdev->dev)) {\r
- if (pdata->wakeup) {\r
- int irq = gpio_to_irq(pdata->gpio);\r
- enable_irq_wake(irq);\r
- }\r
- }\r
- \r
- return 0;\r
-}\r
-\r
-static int remotectl_resume(struct device *dev)\r
-{\r
- struct platform_device *pdev = to_platform_device(dev);\r
- struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;\r
-\r
- if (device_may_wakeup(&pdev->dev)) {\r
- if (pdata->wakeup) {\r
- int irq = gpio_to_irq(pdata->gpio);\r
- disable_irq_wake(irq);\r
- }\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static const struct dev_pm_ops remotectl_pm_ops = {\r
- .suspend = remotectl_suspend,\r
- .resume = remotectl_resume,\r
-};\r
-#endif\r
-\r
-\r
-\r
-static struct platform_driver remotectl_device_driver = {\r
- .probe = remotectl_probe,\r
- .remove = __devexit_p(remotectl_remove),\r
- .driver = {\r
- .name = "rkxx-remotectl",\r
- .owner = THIS_MODULE,\r
-#ifdef CONFIG_PM\r
- .pm = &remotectl_pm_ops,\r
-#endif\r
- },\r
-\r
-};\r
-\r
-static int remotectl_init(void)\r
-{\r
- printk(KERN_INFO "++++++++remotectl_init\n");\r
- return platform_driver_register(&remotectl_device_driver);\r
-}\r
-\r
-\r
-static void remotectl_exit(void)\r
-{\r
- platform_driver_unregister(&remotectl_device_driver);\r
- printk(KERN_INFO "++++++++remotectl_init\n");\r
-}\r
-\r
-module_init(remotectl_init);\r
-module_exit(remotectl_exit);\r
-\r
-MODULE_LICENSE("GPL");\r
-MODULE_AUTHOR("rockchip");\r
-MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");\r
-MODULE_ALIAS("platform:gpio-keys1");\r
-\r
-\r
--- /dev/null
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/wakelock.h>
+#include "rockchip_pwm_remotectl.h"
+
+
+
+/*sys/module/rk_pwm_remotectl/parameters,
+modify code_print to change the value*/
+
+static int rk_remote_print_code;
+module_param_named(code_print, rk_remote_print_code, int, 0644);
+#define DBG_CODE(args...) \
+ do { \
+ if (rk_remote_print_code) { \
+ pr_info(args); \
+ } \
+ } while (0)
+
+static int rk_remote_pwm_dbg_level;
+module_param_named(dbg_level, rk_remote_pwm_dbg_level, int, 0644);
+#define DBG(args...) \
+ do { \
+ if (rk_remote_pwm_dbg_level) { \
+ pr_info(args); \
+ } \
+ } while (0)
+
+
+struct rkxx_remote_key_table {
+ int scancode;
+ int keycode;
+};
+
+struct rkxx_remotectl_button {
+ int usercode;
+ int nbuttons;
+ struct rkxx_remote_key_table *key_table;
+};
+
+struct rkxx_remotectl_drvdata {
+ void __iomem *base;
+ int state;
+ int nbuttons;
+ int result;
+ int scandata;
+ int count;
+ int keynum;
+ int keycode;
+ int press;
+ int pre_press;
+ int period;
+ int irq;
+ int wakeup;
+ struct input_dev *input;
+ struct timer_list timer;
+ struct tasklet_struct remote_tasklet;
+ struct wake_lock remotectl_wake_lock;
+};
+
+
+static struct rkxx_remote_key_table remote_key_table_meiyu_4040[] = {
+ {0xf2, KEY_REPLY},
+ {0xba, KEY_BACK},
+ {0xf4, KEY_UP},
+ {0xf1, KEY_DOWN},
+ {0xef, KEY_LEFT},
+ {0xee, KEY_RIGHT},
+ {0xbd, KEY_HOME},
+ {0xea, KEY_VOLUMEUP},
+ {0xe3, KEY_VOLUMEDOWN},
+ {0xe2, KEY_SEARCH},
+ {0xb2, KEY_POWER},
+ {0xbc, KEY_MUTE},
+ {0xec, KEY_MENU},
+/*lay pause*/
+ {0xbf, 0x190},
+/*pre*/
+ {0xe0, 0x191},
+/*next*/
+ {0xe1, 0x192},
+/*pic,rorate left*/
+ {0xe9, 183},
+/*rorate right*/
+ {0xe6, 248},
+/*zoom out*/
+ {0xe8, 185},
+/*zoom in*/
+ {0xe7, 186},
+/*mouse switch*/
+ {0xb8, 388},
+/*zoom outdisplay switch*/
+ {0xbe, 0x175},
+};
+
+
+static struct rkxx_remote_key_table remote_key_table_sunchip_ff00[] = {
+ {0xf9, KEY_HOME},
+ {0xbf, KEY_BACK},
+ {0xfb, KEY_MENU},
+ {0xaa, KEY_REPLY},
+ {0xb9, KEY_UP},
+ {0xe9, KEY_DOWN},
+ {0xb8, KEY_LEFT},
+ {0xea, KEY_RIGHT},
+ {0xeb, KEY_VOLUMEDOWN},
+ {0xef, KEY_VOLUMEUP},
+ {0xf7, KEY_MUTE},
+ {0xe7, KEY_POWER},
+ {0xfc, KEY_POWER},
+ {0xa9, KEY_VOLUMEDOWN},
+ {0xa8, KEY_VOLUMEDOWN},
+ {0xe0, KEY_VOLUMEDOWN},
+ {0xa5, KEY_VOLUMEDOWN},
+ {0xab, 183},
+ {0xb7, 388},
+ {0xf8, 184},
+ {0xaf, 185},
+ {0xed, KEY_VOLUMEDOWN},
+ {0xee, 186},
+ {0xb3, KEY_VOLUMEDOWN},
+ {0xf1, KEY_VOLUMEDOWN},
+ {0xf2, KEY_VOLUMEDOWN},
+ {0xf3, KEY_SEARCH},
+ {0xb4, KEY_VOLUMEDOWN},
+ {0xbe, KEY_SEARCH},
+};
+
+
+static struct rkxx_remotectl_button remotectl_button[] = {
+ {
+ .usercode = 0xff00,
+ .nbuttons = 29,
+ .key_table = &remote_key_table_sunchip_ff00[0],
+ },
+ {
+ .usercode = 0x4040,
+ .nbuttons = 22,
+ .key_table = &remote_key_table_meiyu_4040[0],
+ },
+};
+
+
+static int remotectl_keybd_num_lookup(struct rkxx_remotectl_drvdata *ddata)
+{
+ int i;
+ int num;
+
+ num = sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);
+ for (i = 0; i < num; i++) {
+ if (remotectl_button[i].usercode == (ddata->scandata&0xFFFF)) {
+ ddata->keynum = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static int remotectl_keycode_lookup(struct rkxx_remotectl_drvdata *ddata)
+{
+ int i;
+ unsigned char keydata = (unsigned char)((ddata->scandata >> 8) & 0xff);
+
+ for (i = 0; i < remotectl_button[ddata->keynum].nbuttons; i++) {
+ if (remotectl_button[ddata->keynum].key_table[i].scancode ==
+ keydata) {
+ ddata->keycode =
+ remotectl_button[ddata->keynum].key_table[i].keycode;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static void rk_pwm_remotectl_do_something(unsigned long data)
+{
+ struct rkxx_remotectl_drvdata *ddata;
+
+ ddata = (struct rkxx_remotectl_drvdata *)data;
+ switch (ddata->state) {
+ case RMC_IDLE: {
+ ;
+ break;
+ }
+ case RMC_PRELOAD: {
+ mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(130));
+ if ((RK_PWM_TIME_PRE_MIN < ddata->period) &&
+ (ddata->period < RK_PWM_TIME_PRE_MAX)) {
+ ddata->scandata = 0;
+ ddata->count = 0;
+ ddata->state = RMC_USERCODE;
+ } else {
+ ddata->state = RMC_PRELOAD;
+ }
+ break;
+ }
+ case RMC_USERCODE: {
+ if ((RK_PWM_TIME_BIT1_MIN < ddata->period) &&
+ (ddata->period < RK_PWM_TIME_BIT1_MAX))
+ ddata->scandata |= (0x01 << ddata->count);
+ ddata->count++;
+ if (ddata->count == 0x10) {
+ DBG_CODE("USERCODE=0x%x\n", ddata->scandata);
+ if (remotectl_keybd_num_lookup(ddata)) {
+ ddata->state = RMC_GETDATA;
+ ddata->scandata = 0;
+ ddata->count = 0;
+ } else {
+ ddata->state = RMC_PRELOAD;
+ }
+ }
+ }
+ break;
+ case RMC_GETDATA: {
+ if ((RK_PWM_TIME_BIT1_MIN < ddata->period) &&
+ (ddata->period < RK_PWM_TIME_BIT1_MAX))
+ ddata->scandata |= (0x01<<ddata->count);
+ ddata->count++;
+ if (ddata->count < 0x10)
+ return;
+ DBG_CODE("RMC_GETDATA=%x\n", (ddata->scandata>>8));
+ if ((ddata->scandata&0x0ff) ==
+ ((~ddata->scandata >> 8) & 0x0ff)) {
+ if (remotectl_keycode_lookup(ddata)) {
+ ddata->press = 1;
+ input_event(ddata->input, EV_KEY,
+ ddata->keycode, 1);
+ input_sync(ddata->input);
+ ddata->state = RMC_SEQUENCE;
+ } else {
+ ddata->state = RMC_PRELOAD;
+ }
+ } else {
+ ddata->state = RMC_PRELOAD;
+ }
+ }
+ break;
+ case RMC_SEQUENCE:{
+ DBG("S=%d\n", ddata->period);
+ if ((RK_PWM_TIME_RPT_MIN < ddata->period) &&
+ (ddata->period < RK_PWM_TIME_RPT_MAX)) {
+ DBG("S1\n");
+ mod_timer(&ddata->timer, jiffies
+ + msecs_to_jiffies(110));
+ } else if ((RK_PWM_TIME_SEQ1_MIN < ddata->period) &&
+ (ddata->period < RK_PWM_TIME_SEQ1_MAX)) {
+ DBG("S2\n");
+ mod_timer(&ddata->timer, jiffies
+ + msecs_to_jiffies(110));
+ } else if ((RK_PWM_TIME_SEQ2_MIN < ddata->period) &&
+ (ddata->period < RK_PWM_TIME_SEQ2_MAX)) {
+ DBG("S3\n");
+ mod_timer(&ddata->timer, jiffies
+ + msecs_to_jiffies(110));
+ } else {
+ DBG("S4\n");
+ input_event(ddata->input, EV_KEY,
+ ddata->keycode, 0);
+ input_sync(ddata->input);
+ ddata->state = RMC_PRELOAD;
+ ddata->press = 0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void rk_pwm_remotectl_timer(unsigned long _data)
+{
+ struct rkxx_remotectl_drvdata *ddata;
+
+ ddata = (struct rkxx_remotectl_drvdata *)_data;
+ if (ddata->press != ddata->pre_press) {
+ ddata->pre_press = 0;
+ ddata->press = 0;
+ input_event(ddata->input, EV_KEY, ddata->keycode, 0);
+ input_sync(ddata->input);
+ }
+ ddata->state = RMC_PRELOAD;
+}
+
+
+static irqreturn_t rockchip_pwm_irq(int irq, void *dev_id)
+{
+ struct rkxx_remotectl_drvdata *ddata;
+ int val;
+
+ ddata = (struct rkxx_remotectl_drvdata *)dev_id;
+ val = readl_relaxed(ddata->base + PWM_REG_INTSTS);
+ if (val&PWM_CH3_INT) {
+ if (val & PWM_CH3_POL) {
+ val = readl_relaxed(ddata->base + PWM_REG_HPR);
+ ddata->period = val;
+ tasklet_hi_schedule(&ddata->remote_tasklet);
+ DBG("hpr=0x%x\n", val);
+ } else {
+ val = readl_relaxed(ddata->base + PWM_REG_LPR);
+ DBG("lpr=0x%x\n", val);
+ }
+ writel_relaxed(PWM_CH3_INT, ddata->base + PWM_REG_INTSTS);
+ if (ddata->state == RMC_PRELOAD)
+ wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int rk_pwm_remotectl_hw_init(struct rkxx_remotectl_drvdata *ddata)
+{
+ int val;
+
+ val = readl_relaxed(ddata->base + PWM_REG_CTRL);
+ val = (val & 0xFFFFFFFE) | PWM_DISABLE;
+ writel_relaxed(val, ddata->base + PWM_REG_CTRL);
+ val = readl_relaxed(ddata->base + PWM_REG_CTRL);
+ val = (val & 0xFFFFFFF9) | PWM_MODE_CAPTURE;
+ writel_relaxed(val, ddata->base + PWM_REG_CTRL);
+ val = readl_relaxed(ddata->base + PWM_REG_CTRL);
+ val = (val & 0xFF008DFF) | 0x00646200;
+ writel_relaxed(val, ddata->base + PWM_REG_CTRL);
+ val = readl_relaxed(ddata->base + PWM_REG_INT_EN);
+ val = (val & 0xFFFFFFF7) | PWM_CH3_INT_ENABLE;
+ writel_relaxed(val, ddata->base + PWM_REG_INT_EN);
+ val = readl_relaxed(ddata->base + PWM_REG_CTRL);
+ val = (val & 0xFFFFFFFE) | PWM_ENABLE;
+ writel_relaxed(val, ddata->base + PWM_REG_CTRL);
+ return 0;
+}
+
+
+
+static int rk_pwm_probe(struct platform_device *pdev)
+{
+ struct rkxx_remotectl_drvdata *ddata;
+ struct resource *r;
+ struct input_dev *input;
+ struct clk *clk;
+ int num;
+ int irq;
+ int ret;
+ int i, j;
+
+ DBG(".. rk pwm remotectl v1.1 init\n");
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "no memory resources defined\n");
+ return -ENODEV;
+ }
+ ddata = devm_kzalloc(&pdev->dev, sizeof(struct rkxx_remotectl_drvdata),
+ GFP_KERNEL);
+ if (!ddata) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+ ddata->state = RMC_PRELOAD;
+ ddata->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(ddata->base))
+ return PTR_ERR(ddata->base);
+ clk = devm_clk_get(&pdev->dev, "pclk_pwm");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ platform_set_drvdata(pdev, ddata);
+ input = input_allocate_device();
+ input->name = pdev->name;
+ input->phys = "gpio-keys/remotectl";
+ input->dev.parent = &pdev->dev;
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+ ddata->input = input;
+ ddata->input = input;
+ wake_lock_init(&ddata->remotectl_wake_lock,
+ WAKE_LOCK_SUSPEND, "rk29_pwm_remote");
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
+ irq = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ return ret;
+ }
+ ddata->irq = irq;
+ ddata->wakeup = 1;
+ tasklet_init(&ddata->remote_tasklet, rk_pwm_remotectl_do_something,
+ (unsigned long)ddata);
+ num = sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);
+ for (j = 0; j < num; j++) {
+ DBG("remotectl probe j = 0x%x\n", j);
+ for (i = 0; i < remotectl_button[j].nbuttons; i++) {
+ unsigned int type = EV_KEY;
+
+ input_set_capability(input, type, remotectl_button[j].
+ key_table[i].keycode);
+ }
+ }
+ ret = input_register_device(input);
+ if (ret)
+ pr_err("remotectl: register input device err, ret: %d\n", ret);
+ input_set_capability(input, EV_KEY, KEY_WAKEUP);
+ device_init_wakeup(&pdev->dev, 1);
+ ret = devm_request_irq(&pdev->dev, irq, rockchip_pwm_irq,
+ 0, "rk_pwm_irq", ddata);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", irq);
+ return ret;
+ }
+ enable_irq_wake(irq);
+ setup_timer(&ddata->timer, rk_pwm_remotectl_timer,
+ (unsigned long)ddata);
+ mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(1000));
+ rk_pwm_remotectl_hw_init(ddata);
+ return ret;
+}
+
+static int rk_pwm_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+
+static const struct of_device_id rk_pwm_of_match[] = {
+ { .compatible = "rockchip,remotectl-pwm"},
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, rk_pwm_of_match);
+
+static struct platform_driver rk_pwm_driver = {
+ .driver = {
+ .name = "remotectl-pwm",
+ .of_match_table = rk_pwm_of_match,
+ },
+ .probe = rk_pwm_probe,
+ .remove = rk_pwm_remove,
+};
+
+module_platform_driver(rk_pwm_driver);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+\r
+#ifndef __RKXX_PWM_REMOTECTL_H__\r
+#define __RKXX_PWM_REMOTECTL_H__\r
+#include <linux/input.h>\r
+\r
+/* PWM0 registers */\r
+#define PWM_REG_CNTR 0x00 /* Counter Register */\r
+#define PWM_REG_HPR 0x04 /* Period Register */\r
+#define PWM_REG_LPR 0x08 /* Duty Cycle Register */\r
+#define PWM_REG_CTRL 0x0c /* Control Register */\r
+#define PWM_REG_INTSTS 0x10 /* Interrupt Status Refister */\r
+#define PWM_REG_INT_EN 0x14 /* Interrupt Enable Refister */\r
+\r
+\r
+/*REG_CTRL bits definitions*/\r
+#define PWM_ENABLE (1 << 0)\r
+#define PWM_DISABLE (0 << 0)\r
+\r
+/*operation mode*/\r
+#define PWM_MODE_ONESHOT (0x00 << 1)\r
+#define PWM_MODE_CONTINUMOUS (0x01 << 1)\r
+#define PWM_MODE_CAPTURE (0x02 << 1)\r
+\r
+/*duty cycle output polarity*/\r
+#define PWM_DUTY_POSTIVE (0x01 << 3)\r
+#define PWM_DUTY_NEGATIVE (0x00 << 3)\r
+\r
+/*incative state output polarity*/\r
+#define PWM_INACTIVE_POSTIVE (0x01 << 4)\r
+#define PWM_INACTIVE_NEGATIVE (0x00 << 4)\r
+\r
+/*clock source select*/\r
+#define PWM_CLK_SCALE (1 << 9)\r
+#define PWM_CLK_NON_SCALE (0 << 9)\r
+\r
+#define PWM_CH0_INT (1 << 0)\r
+#define PWM_CH1_INT (1 << 1)\r
+#define PWM_CH2_INT (1 << 2)\r
+#define PWM_CH3_INT (1 << 3)\r
+\r
+#define PWM_CH0_POL (1 << 8)\r
+#define PWM_CH1_POL (1 << 9)\r
+#define PWM_CH2_POL (1 << 10)\r
+#define PWM_CH3_POL (1 << 11)\r
+\r
+#define PWM_CH0_INT_ENABLE (1 << 0)\r
+#define PWM_CH0_INT_DISABLE (0 << 0)\r
+\r
+#define PWM_CH1_INT_ENABLE (1 << 0)\r
+#define PWM_CH1_INT_DISABLE (0 << 1)\r
+\r
+#define PWM_CH2_INT_ENABLE (1 << 2)\r
+#define PWM_CH2_INT_DISABLE (0 << 2)\r
+\r
+#define PWM_CH3_INT_ENABLE (1 << 3)\r
+#define PWM_CH3_INT_DISABLE (0 << 3)\r
+\r
+/*prescale factor*/\r
+#define PWMCR_MIN_PRESCALE 0x00\r
+#define PWMCR_MAX_PRESCALE 0x07\r
+\r
+#define PWMDCR_MIN_DUTY 0x0001\r
+#define PWMDCR_MAX_DUTY 0xFFFF\r
+\r
+#define PWMPCR_MIN_PERIOD 0x0001\r
+#define PWMPCR_MAX_PERIOD 0xFFFF\r
+\r
+#define PWMPCR_MIN_PERIOD 0x0001\r
+#define PWMPCR_MAX_PERIOD 0xFFFF\r
+\r
+enum pwm_div {\r
+ PWM_DIV1 = (0x0 << 12),\r
+ PWM_DIV2 = (0x1 << 12),\r
+ PWM_DIV4 = (0x2 << 12),\r
+ PWM_DIV8 = (0x3 << 12),\r
+ PWM_DIV16 = (0x4 << 12),\r
+ PWM_DIV32 = (0x5 << 12),\r
+ PWM_DIV64 = (0x6 << 12),\r
+ PWM_DIV128 = (0x7 << 12),\r
+}; \r
+\r
+\r
+\r
+\r
+/********************************************************************\r
+** ºê¶¨Òå *\r
+********************************************************************/\r
+#define RK_PWM_TIME_PRE_MIN 19 /*4500*/\r
+#define RK_PWM_TIME_PRE_MAX 30 /*5500*/ /*PreLoad 4.5+0.56 = 5.06ms*/\r
+\r
+#define RK_PWM_TIME_BIT0_MIN 1 /*Bit0 1.125ms*/\r
+#define RK_PWM_TIME_BIT0_MAX 5\r
+\r
+#define RK_PWM_TIME_BIT1_MIN 7 /*Bit1 2.25ms*/\r
+#define RK_PWM_TIME_BIT1_MAX 11\r
+\r
+#define RK_PWM_TIME_RPT_MIN 200 /*101000*/\r
+#define RK_PWM_TIME_RPT_MAX 250 /*103000*/ /*Repeat 105-2.81=102.19ms*/ //110-9-2.25-0.56=98.19ms\r
+\r
+#define RK_PWM_TIME_SEQ1_MIN 8 /*2650*/\r
+#define RK_PWM_TIME_SEQ1_MAX 12 /*3000*/ /*sequence 2.25+0.56=2.81ms*/ //11.25ms\r
+\r
+#define RK_PWM_TIME_SEQ2_MIN 450 /*101000*/\r
+#define RK_PWM_TIME_SEQ2_MAX 500 /*103000*/ /*Repeat 105-2.81=102.19ms*/ //110-9-2.25-0.56=98.19ms\r
+\r
+/********************************************************************\r
+** ½á¹¹¶¨Òå *\r
+********************************************************************/\r
+typedef enum _RMC_STATE\r
+{\r
+ RMC_IDLE,\r
+ RMC_PRELOAD,\r
+ RMC_USERCODE,\r
+ RMC_GETDATA,\r
+ RMC_SEQUENCE\r
+}eRMC_STATE;\r
+\r
+\r
+struct RKxx_remotectl_platform_data {\r
+ //struct rkxx_remotectl_button *buttons;\r
+ int nbuttons;\r
+ int rep;\r
+ int timer;\r
+ int wakeup;\r
+};\r
+\r
+#endif\r
+\r