From 6d413fbb815b9fae3a846e5b7e428f6770847244 Mon Sep 17 00:00:00 2001 From: swj Date: Wed, 8 Sep 2010 19:14:24 -0700 Subject: [PATCH] swj add it50 adckey --- arch/arm/mach-rk2818/board-infoit50.c | 8 +- drivers/input/keyboard/Kconfig | 10 + drivers/input/keyboard/Makefile | 2 + drivers/input/keyboard/rk2818_adckey_t50.c | 416 +++++++++++++++++++++ 4 files changed, 432 insertions(+), 4 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk2818/board-infoit50.c mode change 100644 => 100755 drivers/input/keyboard/Kconfig mode change 100644 => 100755 drivers/input/keyboard/Makefile create mode 100755 drivers/input/keyboard/rk2818_adckey_t50.c diff --git a/arch/arm/mach-rk2818/board-infoit50.c b/arch/arm/mach-rk2818/board-infoit50.c old mode 100644 new mode 100755 index 6d02d50baccf..d04ab2868c81 --- a/arch/arm/mach-rk2818/board-infoit50.c +++ b/arch/arm/mach-rk2818/board-infoit50.c @@ -1365,11 +1365,11 @@ static void rk2818_power_off(void) #define PLAY_ON_LEVEL 0 static ADC_keyst gAdcValueTab[] = { - {95, AD2KEY1},///VOLUME_DOWN - {249, AD2KEY2},///VOLUME_UP + {0, AD2KEY1},///VOLUME_DOWN + {118, AD2KEY2},///VOLUME_UP {408, AD2KEY3},///MENU - {560, AD2KEY4},///HOME - {725, AD2KEY5},///BACK + {510, AD2KEY4},///HOME + {612, AD2KEY5},///BACK {816, AD2KEY6},///CALL {0,0} }; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig old mode 100644 new mode 100755 index 7f51714d1772..b99eefca4a35 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -425,6 +425,16 @@ config KEYBOARD_W90P910 config KEYBOARD_RK28ADC tristate "RK2818 ADC Keypad support" depends on RK28_ADC + help + Say Y here to enable the adc keypad on SDK board + based on RK2818. + + To compile this driver as a module, choose M here: the + module will be called rk2818_adckey. + +config KEYBOARD_RK28ADC_IT50 + tristate "RK2818 ADC Keypad it50 support" + depends on RK28_ADC default y help Say Y here to enable the adc keypad on SDK board diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile old mode 100644 new mode 100755 index 82a01e27eda4..bae114f8c5c7 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -38,3 +38,5 @@ obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o obj-$(CONFIG_KEYBOARD_RK28ADC) += rk2818_adckey.o +obj-$(CONFIG_KEYBOARD_RK28ADC_IT50) += rk2818_adckey_t50.o + diff --git a/drivers/input/keyboard/rk2818_adckey_t50.c b/drivers/input/keyboard/rk2818_adckey_t50.c new file mode 100755 index 000000000000..e83a38a41171 --- /dev/null +++ b/drivers/input/keyboard/rk2818_adckey_t50.c @@ -0,0 +1,416 @@ +/* + * linux/drivers/input/keyboard/rk28_adckey.c + * + * This driver program support to AD key which use for rk28 chip + * + * 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 + +#if 0 +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#define KEY_PHYS_NAME "rk2818_adckey/input0" + +volatile int gADSampleTimes = 0; +volatile int gStatePlaykey = 0; +volatile unsigned int gCodeCount = 0; +volatile unsigned int gThisCode = 0; +volatile unsigned int gLastCode = 0; +volatile unsigned int gFlagShortPlay = 0; +volatile unsigned int gFlagLongPlay = 0; +volatile unsigned int gPlayCount = 0; + +//key code tab +struct rk28_adckey +{ + struct semaphore lock; + struct rk28_adc_client *client; + struct input_dev *input_dev; + struct timer_list timer; + unsigned char * keycodes; + void __iomem *mmio_base; +}; + +struct rk28_adckey *pRk28AdcKey; + +unsigned int rk28_get_keycode(unsigned int advalue,pADC_keyst ptab,struct adc_key_data *rk2818_adckey_data) +{ + if(advalue >= 0 && advalue <= 5) + return ptab->adc_keycode; + + while(ptab->adc_keycode != 0) + { + + if((advalue > ptab->adc_value - rk2818_adckey_data->adc_drift) && (advalue < ptab->adc_value + rk2818_adckey_data->adc_drift)) + { + DBG("ptab->adc_keycode is :%d\n",ptab->adc_keycode); + return ptab->adc_keycode; + } + ptab++; + } + + return 0; +} + +static irqreturn_t rk28_playkey_irq(int irq, void *handle) +{ + + //gFlagPlay = 1; + //DBG("Enter::%s,LINE=%d,KEY_PLAY_SHORT_PRESS=%d\n",__FUNCTION__,__LINE__,KEY_PLAY_SHORT_PRESS); + + return IRQ_HANDLED; +} + +void rk28_send_wakeup_key( void ) +{ + input_report_key(pRk28AdcKey->input_dev,KEY_WAKEUP,1); + input_sync(pRk28AdcKey->input_dev); + input_report_key(pRk28AdcKey->input_dev,KEY_WAKEUP,0); + input_sync(pRk28AdcKey->input_dev); + DBG("Wake up system\n"); +} + +static int rk28_adckey_open(struct input_dev *dev) +{ + //struct rk28_adckey *adckey = input_get_drvdata(dev); + + return 0; +} + +static void rk28_adckey_close(struct input_dev *dev) +{ + //struct rk28_adckey *adckey = input_get_drvdata(dev); +// +} + +#ifdef CONFIG_PM +static int rk28_adckey_suspend(struct platform_device *pdev, pm_message_t state) +{ + //struct rk28_adckey *adckey = platform_get_drvdata(pdev); + + return 0; +} + +static int rk28_adckey_resume(struct platform_device *pdev) +{ + //struct rk28_adckey *adckey = platform_get_drvdata(pdev); + //struct input_dev *input_dev = adckey->input_dev; +#if 0 + mutex_lock(&input_dev->mutex); + + mutex_unlock(&input_dev->mutex); +#endif + return 0; +} +#else +#define rk28_adckey_suspend NULL +#define rk28_adckey_resume NULL +#endif +static void rk28_adkeyscan_timer(unsigned long data) +{ + unsigned int adcvalue = -1, code; + struct adc_key_data *rk2818_adckey_data = (struct adc_key_data *)data; + + pRk28AdcKey->timer.expires = jiffies + msecs_to_jiffies(10); + add_timer(&pRk28AdcKey->timer); + + /*handle long press of play key*/ + if(gpio_get_value(rk2818_adckey_data->pin_playon) == rk2818_adckey_data->playon_level) + { + if(++gPlayCount > 20000) + gPlayCount = 101; + if((2 == gPlayCount) && (0 == gFlagShortPlay)) + { + gFlagShortPlay = 1; + } + else if((100 == gPlayCount) && (0 == gFlagLongPlay)) + { + gFlagLongPlay = 1; + gFlagShortPlay = 0; + input_report_key(pRk28AdcKey->input_dev,KEY_PLAY_LONG_PRESS,1); + input_sync(pRk28AdcKey->input_dev); + DBG("Enter::%s,LINE=%d,KEY_PLAY_LONG_PRESS=%d,1\n",__FUNCTION__,__LINE__,KEY_PLAY_LONG_PRESS); + } + } + else + { + if (1 == gFlagShortPlay) + { + input_report_key(pRk28AdcKey->input_dev,ENDCALL,1); + input_sync(pRk28AdcKey->input_dev); + input_report_key(pRk28AdcKey->input_dev,ENDCALL,0); + input_sync(pRk28AdcKey->input_dev); + DBG("Wake up system,ENDCALL=%d\n",ENDCALL); + + input_report_key(pRk28AdcKey->input_dev,KEY_PLAY_SHORT_PRESS,1); + input_sync(pRk28AdcKey->input_dev); + DBG("Enter::%s,LINE=%d,KEY_PLAY_SHORT_PRESS=%d,1\n",__FUNCTION__,__LINE__,KEY_PLAY_SHORT_PRESS); + input_report_key(pRk28AdcKey->input_dev,KEY_PLAY_SHORT_PRESS,0); + input_sync(pRk28AdcKey->input_dev); + DBG("Enter::%s,LINE=%d,KEY_PLAY_SHORT_PRESS=%d,0\n",__FUNCTION__,__LINE__,KEY_PLAY_SHORT_PRESS); + } + else if(1 == gFlagLongPlay) + { + input_report_key(pRk28AdcKey->input_dev,KEY_PLAY_LONG_PRESS,0); + input_sync(pRk28AdcKey->input_dev); + DBG("Enter::%s,LINE=%d,KEY_PLAY_LONG_PRESS=%d,0\n",__FUNCTION__,__LINE__,KEY_PLAY_LONG_PRESS); + } + + gFlagShortPlay = 0; + gFlagLongPlay = 0; + gPlayCount = 0; + } + + /*handle long press of adc key*/ + if (gADSampleTimes < 4) + { + gADSampleTimes ++; + return; + } + + gADSampleTimes = 0; + + //rk28_read_adc(pRk28AdcKey); + adcvalue = gAdcValue[rk2818_adckey_data->adc_chn]; + //printk("=========== adcvalue=0x%x ===========\n",adcvalue); + + if(adcvalue > rk2818_adckey_data->adc_empty) + { + //DBG("adcvalue invalid !!!\n"); + if(gLastCode == 0) { + //DBG("(gLastCode == 0\n"); + return; + } + else + { + if(gLastCode == KEYMENU) + { + if(gCodeCount > 31) + { + input_report_key(pRk28AdcKey->input_dev,ENDCALL,0); + input_sync(pRk28AdcKey->input_dev); + DBG("Enter::%s,LINE=%d,code=%d,ENDCALL,0\n",__FUNCTION__,__LINE__,gLastCode); + } + input_report_key(pRk28AdcKey->input_dev,gLastCode,1); + input_sync(pRk28AdcKey->input_dev); + DBG("Enter::%s,LINE=%d,code=%d,1\n",__FUNCTION__,__LINE__,gLastCode); + } + + input_report_key(pRk28AdcKey->input_dev,gLastCode,0); + input_sync(pRk28AdcKey->input_dev); + DBG("Enter::%s,LINE=%d,code=%d,0\n",__FUNCTION__,__LINE__,gLastCode); + gLastCode = 0; + gCodeCount = 0; + return; + } + } + + DBG("adcvalue=0x%x\n",adcvalue); + + code=rk28_get_keycode(adcvalue,rk2818_adckey_data->adc_key_table,rk2818_adckey_data); + if(code) + { + if(code == KEYMENU) + { + gLastCode = code; + if(++gCodeCount == 31)//40ms * 30 =1.2s + { + input_report_key(pRk28AdcKey->input_dev,ENDCALL,1); + input_sync(pRk28AdcKey->input_dev); + DBG("Enter menu::%s,LINE=%d,code=%d,ENDCALL,1\n",__FUNCTION__,__LINE__,code); + } + } + else + { + DBG("Enter key ::%s,LINE=%d,gCodeCount=%d,1\n",__FUNCTION__,__LINE__,gCodeCount); + gLastCode = code; + if(++gCodeCount == 2)//only one event once one touch + { + input_report_key(pRk28AdcKey->input_dev,code,1); + input_sync(pRk28AdcKey->input_dev); + DBG("Enter key ::%s,LINE=%d,code=%d,1\n",__FUNCTION__,__LINE__,code); + } + } + + } + +} + + +static int __devinit rk28_adckey_probe(struct platform_device *pdev) +{ + struct rk28_adckey *adckey; + struct input_dev *input_dev; + int error,i,irq_num; + struct rk2818_adckey_platform_data *pdata = pdev->dev.platform_data; + + if (!(pdata->adc_key)) + return -1; + + adckey = kzalloc(sizeof(struct rk28_adckey), GFP_KERNEL); + if (adckey == NULL) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + return -ENOMEM; + } + + //memcpy(adckey->keycodes, gInitKeyCode, sizeof(adckey->keycodes)); + adckey->keycodes = pdata->adc_key->initKeyCode; + + /* Create and register the input driver. */ + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + error = -ENOMEM; + goto failed_free; + } + + input_dev->name = pdev->name; + //input_dev->id.bustype = BUS_HOST; + input_dev->open = rk28_adckey_open; + input_dev->close = rk28_adckey_close; + input_dev->dev.parent = &pdev->dev; + input_dev->phys = KEY_PHYS_NAME; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + + input_dev->keycode = adckey->keycodes; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = pdata->adc_key->adc_key_cnt; + for (i = 0; i < pdata->adc_key->adc_key_cnt; i++) + set_bit(pdata->adc_key->initKeyCode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); + + adckey->input_dev = input_dev; + input_set_drvdata(input_dev, adckey); + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + +// rk28_adckey_build_keycode(adckey); + platform_set_drvdata(pdev, adckey); + + pRk28AdcKey = adckey; + + /* Register the input device */ + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto failed_free_dev; + } + + error = gpio_request(pdata->adc_key->pin_playon, "play key gpio"); + if (error) { + dev_err(&pdev->dev, "failed to request play key gpio\n"); + goto free_gpio; + } + + irq_num = gpio_to_irq(pdata->adc_key->pin_playon); + + if(pdata->adc_key->playon_level) + { + gpio_pull_updown(pdata->adc_key->pin_playon,GPIOPullDown); + error = request_irq(irq_num,rk28_playkey_irq,IRQF_TRIGGER_RISING,NULL,NULL); + if(error) + { + printk("unable to request play key irq\n"); + goto free_gpio_irq; + } + } + else + { + gpio_pull_updown(pdata->adc_key->pin_playon,GPIOPullUp); + error = request_irq(irq_num,rk28_playkey_irq,IRQF_TRIGGER_FALLING,NULL,NULL); + if(error) + { + printk("unable to request play key irq\n"); + goto free_gpio_irq; + } + } + + enable_irq_wake(irq_num); // so play/wakeup key can wake up system + + setup_timer(&adckey->timer, rk28_adkeyscan_timer, (unsigned long)(pdata->adc_key)); + adckey->timer.expires = jiffies+50; + add_timer(&adckey->timer); + printk(KERN_INFO "rk2818_adckey: driver initialized\n"); + return 0; + +free_gpio_irq: + free_irq(irq_num,NULL); +free_gpio: + gpio_free(pdata->adc_key->pin_playon); +failed_free_dev: + platform_set_drvdata(pdev, NULL); + input_free_device(input_dev); +failed_free: + kfree(adckey); + return error; +} + +static int __devexit rk28_adckey_remove(struct platform_device *pdev) +{ + struct rk28_adckey *adckey = platform_get_drvdata(pdev); + struct rk2818_adckey_platform_data *pdata = pdev->dev.platform_data; + + input_unregister_device(adckey->input_dev); + input_free_device(adckey->input_dev); + platform_set_drvdata(pdev, NULL); + kfree(adckey); + free_irq(gpio_to_irq(pdata->adc_key->pin_playon), NULL); + gpio_free(pdata->adc_key->pin_playon); + return 0; +} + +static struct platform_driver rk28_adckey_driver = +{ + .probe = rk28_adckey_probe, + .remove = __devexit_p(rk28_adckey_remove), + .suspend = rk28_adckey_suspend, + .resume = rk28_adckey_resume, + .driver = { + .name = "rk2818-adckey", + .owner = THIS_MODULE, + }, +}; + + int __init rk28_adckey_init(void) +{ + return platform_driver_register(&rk28_adckey_driver); +} + +static void __exit rk28_adckey_exit(void) +{ + platform_driver_unregister(&rk28_adckey_driver); +} + +module_init(rk28_adckey_init); +module_exit(rk28_adckey_exit); + +MODULE_DESCRIPTION("rk2818 adc Key Controller Driver"); +MODULE_AUTHOR("luowei lw@rock-chips.com"); +MODULE_LICENSE("GPL"); + -- 2.34.1