From d809b68ff7493ced086dc6cddd69e564b713f864 Mon Sep 17 00:00:00 2001 From: huang zhibao Date: Tue, 22 Jul 2014 15:40:52 +0800 Subject: [PATCH] input:ir:add remotectl support --- arch/arm/boot/dts/rk3036.dtsi | 12 + arch/arm/configs/rk3036_defconfig | 2 + drivers/input/Kconfig | 2 + drivers/input/Makefile | 1 + drivers/input/remotectl/Kconfig | 11 +- drivers/input/remotectl/Makefile | 2 +- drivers/input/remotectl/rkxx_remotectl.c | 686 ------------------ .../input/remotectl/rockchip_pwm_remotectl.c | 453 ++++++++++++ .../input/remotectl/rockchip_pwm_remotectl.h | 128 ++++ 9 files changed, 602 insertions(+), 695 deletions(-) mode change 100644 => 100755 drivers/input/Kconfig mode change 100644 => 100755 drivers/input/Makefile delete mode 100755 drivers/input/remotectl/rkxx_remotectl.c create mode 100755 drivers/input/remotectl/rockchip_pwm_remotectl.c create mode 100755 drivers/input/remotectl/rockchip_pwm_remotectl.h diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index 535ee42a2929..dc6f245f8611 100755 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -435,6 +435,18 @@ clock-names = "pclk_pwm"; status = "disabled"; }; + + remotectl: pwm@20050030 { + compatible = "rockchip,remotectl-pwm"; + reg = <0x20050030 0x10>; + #pwm-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pwm3_pin>; + clocks = <&clk_gates7 10>; + clock-names = "pclk_pwm"; + interrupts = ; + status = "okay"; + }; emmc: rksdmmc@1021c000 { compatible = "rockchip,rk_mmc", "rockchip,rk3036-sdmmc"; diff --git a/arch/arm/configs/rk3036_defconfig b/arch/arm/configs/rk3036_defconfig index 9f038ac3357d..d074574ba689 100644 --- a/arch/arm/configs/rk3036_defconfig +++ b/arch/arm/configs/rk3036_defconfig @@ -299,6 +299,8 @@ CONFIG_INPUT_GPIO=y # CONFIG_COMPASS_DEVICE is not set # CONFIG_GYROSCOPE_DEVICE is not set # CONFIG_HALL_DEVICE is not set +CONFIG_ROCKCHIP_REMOTECTL=y +CONFIG_ROCKCHIP_REMOTECTL_PWM=y # CONFIG_SERIO is not set # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig old mode 100644 new mode 100755 index 12eaec2e9a7e..dfcb7942964a --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -198,6 +198,8 @@ source "drivers/input/touchscreen/Kconfig" source "drivers/input/misc/Kconfig" source "drivers/input/sensors/Kconfig" + +source "drivers/input/remotectl/Kconfig" endif menu "Hardware I/O ports" diff --git a/drivers/input/Makefile b/drivers/input/Makefile old mode 100644 new mode 100755 index 1b7621cae016..20ff7f8c228a --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_SENSOR_DEVICE) += sensors/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o +obj-$(CONFIG_ROCKCHIP_REMOTECTL) += remotectl/ diff --git a/drivers/input/remotectl/Kconfig b/drivers/input/remotectl/Kconfig index 8f353cfc9453..eb8f7bd33c99 100755 --- a/drivers/input/remotectl/Kconfig +++ b/drivers/input/remotectl/Kconfig @@ -2,7 +2,7 @@ # Touchscreen driver configuration # menuconfig ROCKCHIP_REMOTECTL - bool "rkxx remotectl" + bool "rockchip remotectl" default n help Say Y here, will suport rk remotectl. @@ -11,12 +11,7 @@ menuconfig ROCKCHIP_REMOTECTL if ROCKCHIP_REMOTECTL -config RK_REMOTECTL - bool "rkxx remoctrl" +config ROCKCHIP_REMOTECTL_PWM + bool "rockchip remoctrl pwm capture" default n - -config RK_IR_WAKEUP - bool "rkxx remoctrl wakeup" - depends on PLAT_RK - default n endif diff --git a/drivers/input/remotectl/Makefile b/drivers/input/remotectl/Makefile index 0edc158f05c2..3b6f4e299ad6 100755 --- a/drivers/input/remotectl/Makefile +++ b/drivers/input/remotectl/Makefile @@ -4,4 +4,4 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_RK_REMOTECTL) += rkxx_remotectl.o +obj-$(CONFIG_ROCKCHIP_REMOTECTL_PWM) += rockchip_pwm_remotectl.o diff --git a/drivers/input/remotectl/rkxx_remotectl.c b/drivers/input/remotectl/rkxx_remotectl.c deleted file mode 100755 index 94f631952d17..000000000000 --- a/drivers/input/remotectl/rkxx_remotectl.c +++ /dev/null @@ -1,686 +0,0 @@ - -/* - * Driver for keys on GPIO lines capable of generating interrupts. - * - * Copyright 2005 Phil Blundell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if 1 -#define remotectl_dbg(bdata, format, arg...) \ - dev_printk(KERN_INFO , &bdata->input->dev , format , ## arg) -#else -#define remotectl_dbg(bdata, format, arg...) -#endif - -extern suspend_state_t get_suspend_state(void); - -struct rkxx_remotectl_suspend_data{ - int suspend_flag; - int cnt; - long scanTime[50]; -}; - -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 { - int state; - int nbuttons; - int result; - unsigned long pre_time; - unsigned long cur_time; - long int pre_sec; - long int cur_sec; - long period; - int scanData; - int count; - int keybdNum; - int keycode; - int press; - int pre_press; - - struct input_dev *input; - struct timer_list timer; - struct tasklet_struct remote_tasklet; - struct wake_lock remotectl_wake_lock; - struct rkxx_remotectl_suspend_data remotectl_suspend_data; -}; - - - -//ÌØÊ⹦ÄܼüÖµ¶¨Òå - //193 //photo - //194 //video - //195 //music - //196 //IE - //197 // - //198 - //199 - //200 - - //183 //rorate_left - //184 //rorate_right - //185 //zoom out - //186 //zoom in - -static struct rkxx_remote_key_table remote_key_table_meiyu_202[] = { - {0xB0, KEY_ENTER},//ok = DPAD CENTER - {0xA2, KEY_BACK}, - {0xD0, KEY_UP}, - {0x70, KEY_DOWN}, - {0x08, KEY_LEFT}, - {0x88, KEY_RIGHT}, //////// - {0x42, KEY_HOME}, //home - {0xA8, KEY_VOLUMEUP}, - {0x38, KEY_VOLUMEDOWN}, - {0xE2, KEY_SEARCH}, //search - {0xB2, KEY_POWER}, //power off - {0xC2, KEY_MUTE}, //mute - {0xC8, KEY_MENU}, - -//media ctrl - {0x78, 0x190}, //play pause - {0xF8, 0x191}, //pre - {0x02, 0x192}, //next - -//pic - {0xB8, 183}, //rorate left - {0x58, 248}, //rorate right - {0x68, 185}, //zoom out - {0x98, 186}, //zoom in -//mouse switch - {0xf0,388}, -//display switch - {0x82, 0x175}, -}; - -static struct rkxx_remote_key_table remote_key_table_df[] = { - {0xf8, KEY_REPLY}, - {0xc0, KEY_BACK}, - {0xf0, KEY_UP}, - {0xd8, KEY_DOWN}, - {0xd0, KEY_LEFT}, - {0xe8,KEY_RIGHT}, //////// - {0x90, KEY_VOLUMEDOWN}, - {0x60, KEY_VOLUMEUP}, - {0x80, KEY_HOME}, //home - {0xe0, 183}, //rorate left - {0x10, 184}, //rorate right - {0x20, 185}, //zoom out - {0xa0, 186}, //zoom in - {0x70, KEY_MUTE}, //mute - {0x50, KEY_POWER}, //power off - {0x40, KEY_SEARCH}, //search -}; - -extern suspend_state_t get_suspend_state(void); - - -static struct rkxx_remotectl_button remotectl_button[] = -{ - { - .usercode = 0x206, - .nbuttons = 22, - .key_table = &remote_key_table_meiyu_202[0], - }, - { - .usercode = 0x12ee, - .nbuttons = 22, - .key_table = &remote_key_table_meiyu_202[0], - }, - { - .usercode = 0x202, - .nbuttons = 22, - .key_table = &remote_key_table_meiyu_202[0], - }, - { - .usercode = 0xdf, - .nbuttons = 16, - .key_table = &remote_key_table_df[0], - }, - -}; - - -static int remotectl_keybdNum_lookup(struct rkxx_remotectl_drvdata *ddata) -{ - int i; - - for (i = 0; i < sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button); i++){ - if (remotectl_button[i].usercode == (ddata->scanData&0xFFFF)){ - ddata->keybdNum = i; - return 1; - } - } - return 0; -} - - -static int remotectl_keycode_lookup(struct rkxx_remotectl_drvdata *ddata) -{ - int i; - unsigned char keyData = ((ddata->scanData >> 8) & 0xff); - - for (i = 0; i < remotectl_button[ddata->keybdNum].nbuttons; i++){ - if (remotectl_button[ddata->keybdNum].key_table[i].scanCode == keyData){ - ddata->keycode = remotectl_button[ddata->keybdNum].key_table[i].keyCode; - return 1; - } - } - return 0; -} - - -static void remotectl_get_pwr_scanData(struct rkxx_remotectl_drvdata *ddata,int *pwr_data,int loop) -{ - int i; - int temp_scanCode; - int temp_pwr_data; - - for (i = 0; i < remotectl_button[loop].nbuttons; i++){ - if (remotectl_button[loop].key_table[i].keyCode == KEY_POWER){ - temp_scanCode = remotectl_button[loop].key_table[i].scanCode; - temp_pwr_data = (temp_scanCode<<8)|((~temp_scanCode)&0xFF); - //printk("pwr data =0x%x\n",temp_pwr_data); - } - } - *pwr_data = temp_pwr_data; -} - -static void remotectl_do_something(unsigned long data) -{ - struct rkxx_remotectl_drvdata *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)); - //printk("RMC_PRELOAD,period=%d\n",ddata->period); - if ((TIME_PRE_MIN < ddata->period) && (ddata->period < TIME_PRE_MAX)){ - - ddata->scanData = 0; - ddata->count = 0; - ddata->state = RMC_USERCODE; - }else{ - ddata->state = RMC_PRELOAD; - } - ddata->pre_time = ddata->cur_time; - //mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130)); - } - break; - - case RMC_USERCODE: - { - ddata->scanData <<= 1; - ddata->count ++; - printk("RMC_USERCODE,period=%d£¬count=%d\n",ddata->period,ddata->count ); - if ((TIME_BIT1_MIN < ddata->period) && (ddata->period < TIME_BIT1_MAX)){ - ddata->scanData |= 0x01; - } - - if (ddata->count == 0x10){//16 bit user code - printk("u=0x%x\n",((ddata->scanData)&0xFFFF)); - if (remotectl_keybdNum_lookup(ddata)){ - ddata->state = RMC_GETDATA; - ddata->scanData = 0; - ddata->count = 0; - }else{ //user code error - ddata->state = RMC_PRELOAD; - } - } - } - break; - - case RMC_GETDATA: - { - ddata->count ++; - ddata->scanData <<= 1; - - - if ((TIME_BIT1_MIN < ddata->period) && (ddata->period < TIME_BIT1_MAX)){ - ddata->scanData |= 0x01; - } - if (ddata->count == 0x10){ - //printk("RMC_GETDATA=%x\n",(ddata->scanData&0xFFFF)); - - if ((ddata->scanData&0x0ff) == ((~ddata->scanData >> 8)&0x0ff)){ - if (remotectl_keycode_lookup(ddata)){ - ddata->press = 1; - /* - if (get_suspend_state()==0){ - input_event(ddata->input, EV_KEY, ddata->keycode, 1); - input_sync(ddata->input); - }else if ((get_suspend_state())&&(ddata->keycode==KEY_POWER)){ - input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1); - input_sync(ddata->input); - }*/ - //printk("0\n"); - input_event(ddata->input, EV_KEY, ddata->keycode, 1); - input_sync(ddata->input); - //input_event(ddata->input, EV_KEY, ddata->keycode, ddata->press); - //input_sync(ddata->input); - ddata->state = RMC_SEQUENCE; - }else{ - ddata->state = RMC_PRELOAD; - } - }else{ - ddata->state = RMC_PRELOAD; - } - } - } - break; - - case RMC_SEQUENCE:{ - - //printk( "S=%d\n",ddata->period); - - if ((TIME_RPT_MIN < ddata->period) && (ddata->period < TIME_RPT_MAX)){ - mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(110)); - //printk("1\n");; - }else if ((TIME_SEQ1_MIN < ddata->period) && (ddata->period < TIME_SEQ1_MAX)){ - mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(110)); - //printk("2\n"); - }else if ((TIME_SEQ2_MIN < ddata->period) && (ddata->period < TIME_SEQ2_MAX)){ - mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(110)); - //printk("3\n");; - }else{ - input_event(ddata->input, EV_KEY, ddata->keycode, 0); - input_sync(ddata->input); - ddata->state = RMC_PRELOAD; - ddata->press = 0; - //printk("4\n"); - } - } - break; - - default: - break; - } - return; -} - - -#ifdef CONFIG_PM -void remotectl_wakeup(unsigned long _data) -{ - struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)_data; - long *time; - int i; - int power_scanData; - - time = ddata->remotectl_suspend_data.scanTime; - - if (get_suspend_state()){ - ddata->remotectl_suspend_data.suspend_flag = 0; - ddata->count = 0; - ddata->state = RMC_USERCODE; - ddata->scanData = 0; - - for (i=0;iremotectl_suspend_data.cnt;i++){ - if (ddata->count>=32) - break; - - if ((TIME_BIT1_MIN < time[i]) && (time[i] < TIME_BIT1_MAX)){ - ddata->scanData |= 0x01; - ddata->scanData <<= 1; - ddata->count ++;; - }else if ((TIME_BIT0_MIN < time[i]) && (time[i] < TIME_BIT0_MAX)){ - ddata->scanData <<= 1; - ddata->count ++;; - }/*else{ - if (ddata->count>16){ - break; - }else{ - - printk(KERN_ERR "ddata->count=0x%x**********************\n",ddata->count); - ddata->count = 0; - ddata->scanData = 0; - } - }*/ - } - //printk(KERN_ERR"data=0x%x\n",ddata->scanData); - if (ddata->scanData) //(ddata->scanData>16) - { - ddata->scanData=(ddata->scanData>>1)&0xFFFF; - printk(KERN_ERR"data=0x%x\n",ddata->scanData); - - for (i=0;iscanData == power_scanData)||((ddata->scanData&0x0fff) == (power_scanData&0x0fff))||((ddata->scanData&0x00ff) == (power_scanData&0x00ff))) //modified by zwm 2013.06.19 - { - input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1); - input_sync(ddata->input); - input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0); - input_sync(ddata->input); - break; - } - } - } - } - memset(ddata->remotectl_suspend_data.scanTime,0,50*sizeof(long)); - ddata->remotectl_suspend_data.cnt= 0; - ddata->state = RMC_PRELOAD; - -} - -#endif - - -static void remotectl_timer(unsigned long _data) -{ - struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)_data; - - //printk("to\n"); - - if(ddata->press != ddata->pre_press) { - ddata->pre_press = ddata->press = 0; - - input_event(ddata->input, EV_KEY, ddata->keycode, 0); - input_sync(ddata->input); - //printk("5\n"); - //if (get_suspend_state()==0){ - //input_event(ddata->input, EV_KEY, ddata->keycode, 1); - //input_sync(ddata->input); - //input_event(ddata->input, EV_KEY, ddata->keycode, 0); - //input_sync(ddata->input); - //}else if ((get_suspend_state())&&(ddata->keycode==KEY_POWER)){ - //input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1); - //input_sync(ddata->input); - //input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0); - //input_sync(ddata->input); - //} - } -#ifdef CONFIG_PM - remotectl_wakeup(_data); -#endif - ddata->state = RMC_PRELOAD; -} - - - -static irqreturn_t remotectl_isr(int irq, void *dev_id) -{ - struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)dev_id; - struct timeval ts; - - - ddata->pre_time = ddata->cur_time; - ddata->pre_sec = ddata->cur_sec; - do_gettimeofday(&ts); - ddata->cur_time = ts.tv_usec; - ddata->cur_sec = ts.tv_sec; - - if (likely(ddata->cur_sec == ddata->pre_sec)){ - ddata->period = ddata->cur_time - ddata->pre_time; - }else{ - ddata->period = 1000000 - ddata->pre_time + ddata->cur_time; - } - - tasklet_hi_schedule(&ddata->remote_tasklet); - //if ((ddata->state==RMC_PRELOAD)||(ddata->state==RMC_SEQUENCE)) - //mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130)); -#ifdef CONFIG_PM - if (ddata->state==RMC_PRELOAD) - wake_lock_timeout(&ddata->remotectl_wake_lock, HZ); - if ((get_suspend_state())&&(ddata->remotectl_suspend_data.cnt<50)) //zwm - ddata->remotectl_suspend_data.scanTime[ddata->remotectl_suspend_data.cnt++] = ddata->period; -#endif - - return IRQ_HANDLED; -} - - -static int __devinit remotectl_probe(struct platform_device *pdev) -{ - struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data; - struct rkxx_remotectl_drvdata *ddata; - struct input_dev *input; - int i, j; - int irq; - int error = 0; - - printk("++++++++remotectl_probe\n"); - - if(!pdata) - return -EINVAL; - - ddata = kzalloc(sizeof(struct rkxx_remotectl_drvdata),GFP_KERNEL); - memset(ddata,0,sizeof(struct rkxx_remotectl_drvdata)); - - ddata->state = RMC_PRELOAD; - input = input_allocate_device(); - - if (!ddata || !input) { - error = -ENOMEM; - goto fail0; - } - - platform_set_drvdata(pdev, ddata); - - input->name = pdev->name; - input->phys = "gpio-keys/input0"; - input->dev.parent = &pdev->dev; - - input->id.bustype = BUS_HOST; - input->id.vendor = 0x0001; - input->id.product = 0x0001; - input->id.version = 0x0100; - - /* Enable auto repeat feature of Linux input subsystem */ - if (pdata->rep) - __set_bit(EV_REP, input->evbit); - - ddata->nbuttons = pdata->nbuttons; - ddata->input = input; - wake_lock_init(&ddata->remotectl_wake_lock, WAKE_LOCK_SUSPEND, "rk29_remote"); - if (pdata->set_iomux){ - pdata->set_iomux(); - } - error = gpio_request(pdata->gpio, "remotectl"); - if (error < 0) { - printk("gpio-keys: failed to request GPIO %d," - " error %d\n", pdata->gpio, error); - //goto fail1; - } - error = gpio_direction_input(pdata->gpio); - if (error < 0) { - pr_err("gpio-keys: failed to configure input" - " direction for GPIO %d, error %d\n", - pdata->gpio, error); - gpio_free(pdata->gpio); - //goto fail1; - } - irq = gpio_to_irq(pdata->gpio); - if (irq < 0) { - error = irq; - pr_err("gpio-keys: Unable to get irq number for GPIO %d, error %d\n", - pdata->gpio, error); - gpio_free(pdata->gpio); - goto fail1; - } - - error = request_irq(irq, remotectl_isr, IRQF_TRIGGER_FALLING , "remotectl", ddata); - - if (error) { - pr_err("gpio-remotectl: Unable to claim irq %d; error %d\n", irq, error); - gpio_free(pdata->gpio); - goto fail1; - } - setup_timer(&ddata->timer,remotectl_timer, (unsigned long)ddata); - - tasklet_init(&ddata->remote_tasklet, remotectl_do_something, (unsigned long)ddata); - - for (j=0;jdev, 1); - - return 0; - -fail2: - pr_err("gpio-remotectl input_allocate_device fail\n"); - input_free_device(input); - kfree(ddata); -fail1: - pr_err("gpio-remotectl gpio irq request fail\n"); - free_irq(gpio_to_irq(pdata->gpio), ddata); - del_timer_sync(&ddata->timer); - tasklet_kill(&ddata->remote_tasklet); - gpio_free(pdata->gpio); -fail0: - pr_err("gpio-remotectl input_register_device fail\n"); - platform_set_drvdata(pdev, NULL); - - return error; -} - -static int __devexit remotectl_remove(struct platform_device *pdev) -{ - struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data; - struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev); - struct input_dev *input = ddata->input; - int irq; - - device_init_wakeup(&pdev->dev, 0); - irq = gpio_to_irq(pdata->gpio); - free_irq(irq, ddata); - tasklet_kill(&ddata->remote_tasklet); - gpio_free(pdata->gpio); - - input_unregister_device(input); - - return 0; -} - - -#ifdef CONFIG_PM -static int remotectl_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data; - struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev); - - //ddata->remotectl_suspend_data.suspend_flag = 1; - ddata->remotectl_suspend_data.cnt = 0; - - if (device_may_wakeup(&pdev->dev)) { - if (pdata->wakeup) { - int irq = gpio_to_irq(pdata->gpio); - enable_irq_wake(irq); - } - } - - return 0; -} - -static int remotectl_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data; - - if (device_may_wakeup(&pdev->dev)) { - if (pdata->wakeup) { - int irq = gpio_to_irq(pdata->gpio); - disable_irq_wake(irq); - } - } - - return 0; -} - -static const struct dev_pm_ops remotectl_pm_ops = { - .suspend = remotectl_suspend, - .resume = remotectl_resume, -}; -#endif - - - -static struct platform_driver remotectl_device_driver = { - .probe = remotectl_probe, - .remove = __devexit_p(remotectl_remove), - .driver = { - .name = "rkxx-remotectl", - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &remotectl_pm_ops, -#endif - }, - -}; - -static int remotectl_init(void) -{ - printk(KERN_INFO "++++++++remotectl_init\n"); - return platform_driver_register(&remotectl_device_driver); -} - - -static void remotectl_exit(void) -{ - platform_driver_unregister(&remotectl_device_driver); - printk(KERN_INFO "++++++++remotectl_init\n"); -} - -module_init(remotectl_init); -module_exit(remotectl_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("rockchip"); -MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); -MODULE_ALIAS("platform:gpio-keys1"); - - diff --git a/drivers/input/remotectl/rockchip_pwm_remotectl.c b/drivers/input/remotectl/rockchip_pwm_remotectl.c new file mode 100755 index 000000000000..b1db3dc990d8 --- /dev/null +++ b/drivers/input/remotectl/rockchip_pwm_remotectl.c @@ -0,0 +1,453 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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<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"); diff --git a/drivers/input/remotectl/rockchip_pwm_remotectl.h b/drivers/input/remotectl/rockchip_pwm_remotectl.h new file mode 100755 index 000000000000..6cb64bac0d40 --- /dev/null +++ b/drivers/input/remotectl/rockchip_pwm_remotectl.h @@ -0,0 +1,128 @@ + +#ifndef __RKXX_PWM_REMOTECTL_H__ +#define __RKXX_PWM_REMOTECTL_H__ +#include + +/* PWM0 registers */ +#define PWM_REG_CNTR 0x00 /* Counter Register */ +#define PWM_REG_HPR 0x04 /* Period Register */ +#define PWM_REG_LPR 0x08 /* Duty Cycle Register */ +#define PWM_REG_CTRL 0x0c /* Control Register */ +#define PWM_REG_INTSTS 0x10 /* Interrupt Status Refister */ +#define PWM_REG_INT_EN 0x14 /* Interrupt Enable Refister */ + + +/*REG_CTRL bits definitions*/ +#define PWM_ENABLE (1 << 0) +#define PWM_DISABLE (0 << 0) + +/*operation mode*/ +#define PWM_MODE_ONESHOT (0x00 << 1) +#define PWM_MODE_CONTINUMOUS (0x01 << 1) +#define PWM_MODE_CAPTURE (0x02 << 1) + +/*duty cycle output polarity*/ +#define PWM_DUTY_POSTIVE (0x01 << 3) +#define PWM_DUTY_NEGATIVE (0x00 << 3) + +/*incative state output polarity*/ +#define PWM_INACTIVE_POSTIVE (0x01 << 4) +#define PWM_INACTIVE_NEGATIVE (0x00 << 4) + +/*clock source select*/ +#define PWM_CLK_SCALE (1 << 9) +#define PWM_CLK_NON_SCALE (0 << 9) + +#define PWM_CH0_INT (1 << 0) +#define PWM_CH1_INT (1 << 1) +#define PWM_CH2_INT (1 << 2) +#define PWM_CH3_INT (1 << 3) + +#define PWM_CH0_POL (1 << 8) +#define PWM_CH1_POL (1 << 9) +#define PWM_CH2_POL (1 << 10) +#define PWM_CH3_POL (1 << 11) + +#define PWM_CH0_INT_ENABLE (1 << 0) +#define PWM_CH0_INT_DISABLE (0 << 0) + +#define PWM_CH1_INT_ENABLE (1 << 0) +#define PWM_CH1_INT_DISABLE (0 << 1) + +#define PWM_CH2_INT_ENABLE (1 << 2) +#define PWM_CH2_INT_DISABLE (0 << 2) + +#define PWM_CH3_INT_ENABLE (1 << 3) +#define PWM_CH3_INT_DISABLE (0 << 3) + +/*prescale factor*/ +#define PWMCR_MIN_PRESCALE 0x00 +#define PWMCR_MAX_PRESCALE 0x07 + +#define PWMDCR_MIN_DUTY 0x0001 +#define PWMDCR_MAX_DUTY 0xFFFF + +#define PWMPCR_MIN_PERIOD 0x0001 +#define PWMPCR_MAX_PERIOD 0xFFFF + +#define PWMPCR_MIN_PERIOD 0x0001 +#define PWMPCR_MAX_PERIOD 0xFFFF + +enum pwm_div { + PWM_DIV1 = (0x0 << 12), + PWM_DIV2 = (0x1 << 12), + PWM_DIV4 = (0x2 << 12), + PWM_DIV8 = (0x3 << 12), + PWM_DIV16 = (0x4 << 12), + PWM_DIV32 = (0x5 << 12), + PWM_DIV64 = (0x6 << 12), + PWM_DIV128 = (0x7 << 12), +}; + + + + +/******************************************************************** +** ºê¶¨Òå * +********************************************************************/ +#define RK_PWM_TIME_PRE_MIN 19 /*4500*/ +#define RK_PWM_TIME_PRE_MAX 30 /*5500*/ /*PreLoad 4.5+0.56 = 5.06ms*/ + +#define RK_PWM_TIME_BIT0_MIN 1 /*Bit0 1.125ms*/ +#define RK_PWM_TIME_BIT0_MAX 5 + +#define RK_PWM_TIME_BIT1_MIN 7 /*Bit1 2.25ms*/ +#define RK_PWM_TIME_BIT1_MAX 11 + +#define RK_PWM_TIME_RPT_MIN 200 /*101000*/ +#define RK_PWM_TIME_RPT_MAX 250 /*103000*/ /*Repeat 105-2.81=102.19ms*/ //110-9-2.25-0.56=98.19ms + +#define RK_PWM_TIME_SEQ1_MIN 8 /*2650*/ +#define RK_PWM_TIME_SEQ1_MAX 12 /*3000*/ /*sequence 2.25+0.56=2.81ms*/ //11.25ms + +#define RK_PWM_TIME_SEQ2_MIN 450 /*101000*/ +#define RK_PWM_TIME_SEQ2_MAX 500 /*103000*/ /*Repeat 105-2.81=102.19ms*/ //110-9-2.25-0.56=98.19ms + +/******************************************************************** +** ½á¹¹¶¨Òå * +********************************************************************/ +typedef enum _RMC_STATE +{ + RMC_IDLE, + RMC_PRELOAD, + RMC_USERCODE, + RMC_GETDATA, + RMC_SEQUENCE +}eRMC_STATE; + + +struct RKxx_remotectl_platform_data { + //struct rkxx_remotectl_button *buttons; + int nbuttons; + int rep; + int timer; + int wakeup; +}; + +#endif + -- 2.34.1