* [PATCH] Add support for touch screen on W90P910 ARM platform @ 2009-04-27 15:03 Wan ZongShun 2009-05-08 3:41 ` Dmitry Torokhov 0 siblings, 1 reply; 10+ messages in thread From: Wan ZongShun @ 2009-04-27 15:03 UTC (permalink / raw) To: linux-input Dear sirs, The patch adds this touch screen driver to w90p910 ARM platform. It is based on version of 2.6.30-rc3. would you please give me some advice about this patch? arch/arm/mach-w90x900/include/mach/regs-adc.h | 57 +++ drivers/input/touchscreen/Kconfig | 6 drivers/input/touchscreen/Makefile | 1 drivers/input/touchscreen/w90p910_ts.c | 229 ++++++++++++++++ 4 files changed, 293 insertions(+) --- Add this touch screen driver c file for W90P910 platform. It is only one part of patch,the other such as maping, device register will be submitted soon after. Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> diff -Npur linux-2.6.29/arch/arm/mach-w90x900/include/mach/regs-adc.h linux-2.6.30-rc3/arch/arm/mach-w90x900/include/mach/regs-adc.h --- linux-2.6.29/arch/arm/mach-w90x900/include/mach/regs-adc.h 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.30-rc3/arch/arm/mach-w90x900/include/mach/regs-adc.h 2009-04-27 20:53:57.000000000 +0800 @@ -0,0 +1,57 @@ +/* + * arch/arm/mach-w90x900/include/mach/regs-adc.h + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * Wan ZongShun <mcuos.com@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARM_REGS_ADC_H +#define __ASM_ARM_REGS_ADC_H + +/* ADC Control Registers */ +#define ADC_BA W90X900_VA_ADC +#define REG_ADC_CON (ADC_BA+0x00) +#define REG_ADC_TSC (ADC_BA+0x04) +#define REG_ADC_DLY (ADC_BA+0x08) +#define REG_ADC_XDATA (ADC_BA+0x0C) +#define REG_ADC_YDATA (ADC_BA+0x10) +#define REG_ADC_LV_CON (ADC_BA+0x14) +#define REG_ADC_LV_STS (ADC_BA+0x18) +#define ADC_INT 0x040000 +#define WT_INT 0x100000 +#define ADC_RESOULTION 1024 + +#define ADC_WRITE(addr, val) __raw_writel(val, addr) +#define ADC_READ(addr) __raw_readl(addr) +#define DEV_NAME "ADC" + +#define TSDEV_SCREEN_X 320 +#define TSDEV_SCREEN_Y 240 + +unsigned int INTERVAL_TIME = 4; +unsigned int pre_x, pre_y, STATE; +unsigned int nRadioWidth1, nRadioWidth2, nRadioHeight1, nRadioHeight2; +int adc_get = 0, adc_block = 1; + +static struct input_dev *w90p910_dev; +static DECLARE_MUTEX(sem); +static DEFINE_SPINLOCK(w90x900_touch_lock); +static struct timer_list ts_timer1; + +struct _pointmap{ + int x; + int y; + int status; +}; + +struct _pointmap point; + +#endif/*__ASM_ARM_REGS_ADC_H*/ diff -Npur linux-2.6.29/drivers/input/touchscreen/Kconfig linux-2.6.30-rc3/drivers/input/touchscreen/Kconfig --- linux-2.6.29/drivers/input/touchscreen/Kconfig 2009-04-27 14:10:36.000000000 +0800 +++ linux-2.6.30-rc3/drivers/input/touchscreen/Kconfig 2009-04-27 19:50:36.000000000 +0800 @@ -466,4 +466,10 @@ config TOUCHSCREEN_TSC2007 To compile this driver as a module, choose M here: the module will be called tsc2007. +config TOUCHSCREEN_W90X900 + tristate "W90P910 touchscreens" + depends on CPU_W90P910 + help + Compile this driver to support W90P910 touchscreen. + endif diff -Npur linux-2.6.29/drivers/input/touchscreen/Makefile linux-2.6.30-rc3/drivers/input/touchscreen/Makefile --- linux-2.6.29/drivers/input/touchscreen/Makefile 2009-04-27 14:10:36.000000000 +0800 +++ linux-2.6.30-rc3/drivers/input/touchscreen/Makefile 2009-04-27 19:50:49.000000000 +0800 @@ -37,3 +37,4 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) + wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o +obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o diff -Npur linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c linux-2.6.30-rc3/drivers/input/touchscreen/w90p910_ts.c --- linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.30-rc3/drivers/input/touchscreen/w90p910_ts.c 2009-04-27 20:55:21.000000000 +0800 @@ -0,0 +1,229 @@ +/* + * linux/driver/input/w90x900_ts.c + * + * Copyright (c) 2008 Nuvoton technology corporation + * All rights reserved. + * + * Wan ZongShun <mcuos.com@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/input.h> +#include <linux/interrupt.h> + +#include <mach/hardware.h> +#include <mach/regs-clock.h> +#include <mach/regs-adc.h> + +short ADCDataIn(void) +{ + pre_x = ((ADC_READ(REG_ADC_XDATA)*TSDEV_SCREEN_X)/ADC_RESOULTION); + pre_y = ((ADC_READ(REG_ADC_YDATA)*TSDEV_SCREEN_Y)/ADC_RESOULTION); + + input_report_key(w90p910_dev, BTN_TOUCH, 1); + input_report_abs(w90p910_dev, ABS_X, pre_x); + input_report_abs(w90p910_dev, ABS_Y, pre_y); + input_report_abs(w90p910_dev, ABS_PRESSURE, 1000); + input_sync(w90p910_dev); + return 0; +} + +static void wb_sensitivity(unsigned long sensi) +{ + unsigned long flags; + down_interruptible(&sem); + spin_lock_irqsave(&w90x900_touch_lock, flags); + + if ((ADC_READ(REG_ADC_TSC)&0x1) == 0x1) { + + ADC_WRITE(REG_ADC_TSC, 0x0); + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| + 0x00206000)&0xFF7F7FFF); + STATE = 1; + } else{ + input_sync(w90p910_dev); + input_report_key(w90p910_dev, BTN_TOUCH, 0); + input_report_abs(w90p910_dev, ABS_PRESSURE, 0); + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| + 0x0080C000)&0xFFCBFFFF); + STATE = 0; + point.status = 0; + } + up(&sem); + spin_unlock_irqrestore(&w90x900_touch_lock, flags); +} + +static irqreturn_t wb_adc_irq(int irq, void *dev_id) +{ + unsigned long flags; + + down_interruptible(&sem); + spin_lock_irqsave(&w90x900_touch_lock, flags); + adc_get = 1; + + if (((ADC_READ(REG_ADC_CON)&WT_INT)>>20) == 1 && STATE == 0) { + STATE = 1; + ADC_WRITE(REG_ADC_TSC, 0x0); + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| + 0x00206000)&0xFF6F7FFF); + } + + if (((ADC_READ(REG_ADC_CON)&ADC_INT)>>18) == 1 && STATE == 1) { + STATE = 2; + ADC_WRITE(REG_ADC_TSC, 0x100); + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| + 0x00206000)&0xFF7B7FFF); + } + + if (((ADC_READ(REG_ADC_CON)&ADC_INT)>>18) == 1 && STATE == 2) { + ADCDataIn(); + point.status = 1; + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| + 0x0000C000)&0xFF5BFFFF); + + del_timer(&ts_timer1); + ts_timer1.expires = jiffies+INTERVAL_TIME; + ts_timer1.data = 0UL; + add_timer(&ts_timer1); + + } + up(&sem); + spin_unlock_irqrestore(&w90x900_touch_lock, flags); + return IRQ_HANDLED; +} + +static int wb_adc_open(struct input_dev *dev) +{ + + adc_block = 1; + adc_get = 1; + init_timer(&ts_timer1); + ts_timer1.function = wb_sensitivity; + /* reset */ + ADC_WRITE(REG_ADC_CON, 0x00010000); + udelay(1000); + ADC_WRITE(REG_ADC_CON, 0x00000000); + udelay(1000); + /* ADC setting */ + /* set delay and screen type */ + ADC_WRITE(REG_ADC_TSC, ADC_READ(REG_CLKSEL) & 0xFFFFFFF9); + ADC_WRITE(REG_ADC_DLY, 0xF00); + /* waitting for trigger mode */ + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| + 0x0082C008) & 0xFFEBFF09); + STATE = 0; + pre_x = pre_y = 0; + return 0; +} + +static void wb_adc_close(struct input_dev *dev) +{ + free_irq(IRQ_ADC, NULL); +} + +static int __init w90x900ts_probe(struct platform_device *pdev) +{ + int irq, result, err; + unsigned int tmp32; + struct resource *res; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq for device\n"); + return -ENOENT; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + if (!request_mem_region(res->start, res->end - res->start + 1, + pdev->name)) { + dev_err(&pdev->dev, "Memory region busy\n"); + err = -EBUSY; + goto fail; + } + + /* enable the ADC clock */ + tmp32 = ADC_READ(REG_CLKEN); + tmp32 = tmp32 | 0x10000000; + ADC_WRITE(REG_CLKEN, tmp32); + + w90p910_dev = input_allocate_device(); + + if (!w90p910_dev) { + printk(KERN_ERR "w90p910_dev: not enough memory\n"); + err = -ENOMEM; + goto fail; + } + + w90p910_dev->name = "W90P910 TouchScreen"; + w90p910_dev->phys = "input/event0"; + w90p910_dev->id.bustype = BUS_HOST; + w90p910_dev->id.vendor = 0x0005; + w90p910_dev->id.product = 0x0001; + w90p910_dev->id.version = 0x0100; + + w90p910_dev->open = wb_adc_open; + w90p910_dev->close = wb_adc_close; + + w90p910_dev->evbit[0] = BIT_MASK(EV_KEY)| + BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN); + w90p910_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(w90p910_dev, ABS_X, 0, 0x400, 0, 0); + input_set_abs_params(w90p910_dev, ABS_Y, 0, 0x400, 0, 0); + input_set_abs_params(w90p910_dev, ABS_PRESSURE, 0, 1000, 0, 0); + + result = request_irq(irq, wb_adc_irq, IRQF_DISABLED, DEV_NAME, NULL); + if (result != 0) + printk(KERN_ERR"register the wb_adc_irq failed!\n"); + + input_register_device(w90p910_dev); + return 0; + +fail: + input_free_device(w90p910_dev); + return err; +} + +static int w90x900ts_remove(struct platform_device *pdev) +{ + + input_unregister_device(w90p910_dev); + return 0; +} + +static struct platform_driver w90x900ts_driver = { + .probe = w90x900ts_probe, + .remove = w90x900ts_remove, + .driver = { + .name = "w90x900-ts", + .owner = THIS_MODULE, + }, +}; + +int __init w90x900ts_init(void) +{ + return platform_driver_register(&w90x900ts_driver); +} + +static void __exit w90x900ts_exit(void) +{ + platform_driver_unregister(&w90x900ts_driver); +} + +module_init(w90x900ts_init); +module_exit(w90x900ts_exit); + +MODULE_AUTHOR("PT50 zswan <mcuos.com@gmail.com>"); +MODULE_DESCRIPTION("w90p910 touch screen driver!"); +MODULE_LICENSE("GPL"); -- embedded forum http://mcuos.com ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Add support for touch screen on W90P910 ARM platform 2009-04-27 15:03 [PATCH] Add support for touch screen on W90P910 ARM platform Wan ZongShun @ 2009-05-08 3:41 ` Dmitry Torokhov 2009-05-09 1:30 ` Wan ZongShun 0 siblings, 1 reply; 10+ messages in thread From: Dmitry Torokhov @ 2009-05-08 3:41 UTC (permalink / raw) To: Wan ZongShun; +Cc: linux-input Hi, On Mon, Apr 27, 2009 at 11:03:20PM +0800, Wan ZongShun wrote: > Dear sirs, > > The patch adds this touch screen driver to w90p910 ARM platform. > It is based on version of 2.6.30-rc3. > would you please give me some advice about this patch? > Thank you very much for your patch. Some comments below. > arch/arm/mach-w90x900/include/mach/regs-adc.h | 57 +++ > drivers/input/touchscreen/Kconfig | 6 > drivers/input/touchscreen/Makefile | 1 > drivers/input/touchscreen/w90p910_ts.c | 229 ++++++++++++++++ > 4 files changed, 293 insertions(+) > --- > Add this touch screen driver c file for W90P910 platform. > It is only one part of patch,the other such as maping, > device register will be submitted soon after. > > Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> > > diff -Npur linux-2.6.29/arch/arm/mach-w90x900/include/mach/regs-adc.h > linux-2.6.30-rc3/arch/arm/mach-w90x900/include/mach/regs-adc.h > --- linux-2.6.29/arch/arm/mach-w90x900/include/mach/regs-adc.h 1970-01-01 > 08:00:00.000000000 +0800 > +++ linux-2.6.30-rc3/arch/arm/mach-w90x900/include/mach/regs-adc.h > 2009-04-27 > 20:53:57.000000000 +0800 > @@ -0,0 +1,57 @@ > +/* > + * arch/arm/mach-w90x900/include/mach/regs-adc.h > + * > + * Copyright (c) 2008 Nuvoton technology corporation > + * All rights reserved. > + * > + * Wan ZongShun <mcuos.com@gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + */ > + > +#ifndef __ASM_ARM_REGS_ADC_H > +#define __ASM_ARM_REGS_ADC_H > + > +/* ADC Control Registers */ > +#define ADC_BA W90X900_VA_ADC > +#define REG_ADC_CON (ADC_BA+0x00) > +#define REG_ADC_TSC (ADC_BA+0x04) > +#define REG_ADC_DLY (ADC_BA+0x08) > +#define REG_ADC_XDATA (ADC_BA+0x0C) > +#define REG_ADC_YDATA (ADC_BA+0x10) > +#define REG_ADC_LV_CON (ADC_BA+0x14) > +#define REG_ADC_LV_STS (ADC_BA+0x18) > +#define ADC_INT 0x040000 > +#define WT_INT 0x100000 > +#define ADC_RESOULTION 1024 > + > +#define ADC_WRITE(addr, val) __raw_writel(val, addr) > +#define ADC_READ(addr) __raw_readl(addr) > +#define DEV_NAME "ADC" > + > +#define TSDEV_SCREEN_X 320 > +#define TSDEV_SCREEN_Y 240 > + > +unsigned int INTERVAL_TIME = 4; > +unsigned int pre_x, pre_y, STATE; > +unsigned int nRadioWidth1, nRadioWidth2, nRadioHeight1, nRadioHeight2; > +int adc_get = 0, adc_block = 1; > + > +static struct input_dev *w90p910_dev; > +static DECLARE_MUTEX(sem); > +static DEFINE_SPINLOCK(w90x900_touch_lock); > +static struct timer_list ts_timer1; > + All of this does not belong in a header file. > +struct _pointmap{ > + int x; > + int y; > + int status; > +}; > + > +struct _pointmap point; > + > +#endif/*__ASM_ARM_REGS_ADC_H*/ > diff -Npur linux-2.6.29/drivers/input/touchscreen/Kconfig > linux-2.6.30-rc3/drivers/input/touchscreen/Kconfig > --- linux-2.6.29/drivers/input/touchscreen/Kconfig 2009-04-27 > 14:10:36.000000000 +0800 > +++ linux-2.6.30-rc3/drivers/input/touchscreen/Kconfig 2009-04-27 > 19:50:36.000000000 +0800 > @@ -466,4 +466,10 @@ config TOUCHSCREEN_TSC2007 > To compile this driver as a module, choose M here: the > module will be called tsc2007. > > +config TOUCHSCREEN_W90X900 > + tristate "W90P910 touchscreens" > + depends on CPU_W90P910 > + help > + Compile this driver to support W90P910 touchscreen. > + > endif > diff -Npur linux-2.6.29/drivers/input/touchscreen/Makefile > linux-2.6.30-rc3/drivers/input/touchscreen/Makefile > --- linux-2.6.29/drivers/input/touchscreen/Makefile 2009-04-27 > 14:10:36.000000000 +0800 > +++ linux-2.6.30-rc3/drivers/input/touchscreen/Makefile 2009-04-27 > 19:50:49.000000000 +0800 > @@ -37,3 +37,4 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) + > wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o > obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o > obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o > +obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o > diff -Npur linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c > linux-2.6.30-rc3/drivers/input/touchscreen/w90p910_ts.c > --- linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c 1970-01-01 > 08:00:00.000000000 +0800 > +++ linux-2.6.30-rc3/drivers/input/touchscreen/w90p910_ts.c 2009-04-27 > 20:55:21.000000000 +0800 > @@ -0,0 +1,229 @@ > +/* > + * linux/driver/input/w90x900_ts.c > + * > + * Copyright (c) 2008 Nuvoton technology corporation > + * All rights reserved. > + * > + * Wan ZongShun <mcuos.com@gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + */ > + > +#include <linux/delay.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/io.h> > +#include <linux/input.h> > +#include <linux/interrupt.h> > + > +#include <mach/hardware.h> > +#include <mach/regs-clock.h> > +#include <mach/regs-adc.h> > + > +short ADCDataIn(void) No camel-case in the kernel, please. > +{ > + pre_x = ((ADC_READ(REG_ADC_XDATA)*TSDEV_SCREEN_X)/ADC_RESOULTION); > + pre_y = ((ADC_READ(REG_ADC_YDATA)*TSDEV_SCREEN_Y)/ADC_RESOULTION); Why do we need to scale? > + > + input_report_key(w90p910_dev, BTN_TOUCH, 1); > + input_report_abs(w90p910_dev, ABS_X, pre_x); > + input_report_abs(w90p910_dev, ABS_Y, pre_y); > + input_report_abs(w90p910_dev, ABS_PRESSURE, 1000); If your device does not provide true pressure readings to not fake them. > + input_sync(w90p910_dev); > + return 0; > +} > + > +static void wb_sensitivity(unsigned long sensi) > +{ > + unsigned long flags; > + down_interruptible(&sem); > + spin_lock_irqsave(&w90x900_touch_lock, flags); > + > + if ((ADC_READ(REG_ADC_TSC)&0x1) == 0x1) { > + > + ADC_WRITE(REG_ADC_TSC, 0x0); > + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| > + 0x00206000)&0xFF7F7FFF); > + STATE = 1; > + } else{ > + input_sync(w90p910_dev); You should report events, then issue EV_SYN, not the other way around. > + input_report_key(w90p910_dev, BTN_TOUCH, 0); > + input_report_abs(w90p910_dev, ABS_PRESSURE, 0); > + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| > + 0x0080C000)&0xFFCBFFFF); > + STATE = 0; > + point.status = 0; > + } > + up(&sem); > + spin_unlock_irqrestore(&w90x900_touch_lock, flags); > +} > + > +static irqreturn_t wb_adc_irq(int irq, void *dev_id) > +{ > + unsigned long flags; > + > + down_interruptible(&sem); Down_interruptible in an IRQ context? That is... interesting... > + spin_lock_irqsave(&w90x900_touch_lock, flags); > + adc_get = 1; > + > + if (((ADC_READ(REG_ADC_CON)&WT_INT)>>20) == 1 && STATE == 0) { > + STATE = 1; > + ADC_WRITE(REG_ADC_TSC, 0x0); > + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| > + 0x00206000)&0xFF6F7FFF); Magic values... Can we have proper #defines here? > + } > + > + if (((ADC_READ(REG_ADC_CON)&ADC_INT)>>18) == 1 && STATE == 1) { > + STATE = 2; > + ADC_WRITE(REG_ADC_TSC, 0x100); > + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| > + 0x00206000)&0xFF7B7FFF); > + } > + > + if (((ADC_READ(REG_ADC_CON)&ADC_INT)>>18) == 1 && STATE == 2) { > + ADCDataIn(); > + point.status = 1; > + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| > + 0x0000C000)&0xFF5BFFFF); > + > + del_timer(&ts_timer1); > + ts_timer1.expires = jiffies+INTERVAL_TIME; > + ts_timer1.data = 0UL; > + add_timer(&ts_timer1); This can be exprerssed as mod_timer(). > + > + } > + up(&sem); > + spin_unlock_irqrestore(&w90x900_touch_lock, flags); > + return IRQ_HANDLED; > +} > + > +static int wb_adc_open(struct input_dev *dev) > +{ > + > + adc_block = 1; > + adc_get = 1; > + init_timer(&ts_timer1); > + ts_timer1.function = wb_sensitivity; > + /* reset */ > + ADC_WRITE(REG_ADC_CON, 0x00010000); > + udelay(1000); > + ADC_WRITE(REG_ADC_CON, 0x00000000); > + udelay(1000); > + /* ADC setting */ > + /* set delay and screen type */ > + ADC_WRITE(REG_ADC_TSC, ADC_READ(REG_CLKSEL) & 0xFFFFFFF9); > + ADC_WRITE(REG_ADC_DLY, 0xF00); > + /* waitting for trigger mode */ > + ADC_WRITE(REG_ADC_CON, (ADC_READ(REG_ADC_CON)| > + 0x0082C008) & 0xFFEBFF09); > + STATE = 0; > + pre_x = pre_y = 0; > + return 0; > +} > + > +static void wb_adc_close(struct input_dev *dev) > +{ > + free_irq(IRQ_ADC, NULL); Uh-oh... What will happen if we try to open the device again? Don't free IRQ here, do that in w90x900ts_remove(). > +} > + > +static int __init w90x900ts_probe(struct platform_device *pdev) __devinit. > +{ > + int irq, result, err; > + unsigned int tmp32; > + struct resource *res; Blank line after declarations. > + irq = platform_get_irq(pdev, 0); > + if (irq < 0) { > + dev_err(&pdev->dev, "no irq for device\n"); > + return -ENOENT; > + } > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) > + return -ENXIO; > + > + if (!request_mem_region(res->start, res->end - res->start + 1, > + pdev->name)) { > + dev_err(&pdev->dev, "Memory region busy\n"); > + err = -EBUSY; > + goto fail; > + } > + > + /* enable the ADC clock */ > + tmp32 = ADC_READ(REG_CLKEN); > + tmp32 = tmp32 | 0x10000000; > + ADC_WRITE(REG_CLKEN, tmp32); > + > + w90p910_dev = input_allocate_device(); > + > + if (!w90p910_dev) { > + printk(KERN_ERR "w90p910_dev: not enough memory\n"); > + err = -ENOMEM; > + goto fail; 'fail' does not free the memory region you requested though... > + } > + > + w90p910_dev->name = "W90P910 TouchScreen"; > + w90p910_dev->phys = "input/event0"; Umm, not specific enough for 'phys'... "w90p910_ts/input0" maybe? > + w90p910_dev->id.bustype = BUS_HOST; > + w90p910_dev->id.vendor = 0x0005; > + w90p910_dev->id.product = 0x0001; > + w90p910_dev->id.version = 0x0100; w90p910_dev->dev.parent = &pdev->dev; > + > + w90p910_dev->open = wb_adc_open; > + w90p910_dev->close = wb_adc_close; > + > + w90p910_dev->evbit[0] = BIT_MASK(EV_KEY)| > + BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN); > + w90p910_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); > + > + input_set_abs_params(w90p910_dev, ABS_X, 0, 0x400, 0, 0); > + input_set_abs_params(w90p910_dev, ABS_Y, 0, 0x400, 0, 0); > + input_set_abs_params(w90p910_dev, ABS_PRESSURE, 0, 1000, 0, 0); > + > + result = request_irq(irq, wb_adc_irq, IRQF_DISABLED, DEV_NAME, NULL); > + if (result != 0) > + printk(KERN_ERR"register the wb_adc_irq failed!\n"); And..? Do we really want to continue? > + > + input_register_device(w90p910_dev); Error handling please. > + return 0; > + > +fail: > + input_free_device(w90p910_dev); > + return err; > +} > + > +static int w90x900ts_remove(struct platform_device *pdev) __devexit > +{ > + Extra blank line > + input_unregister_device(w90p910_dev); > + return 0; > +} > + > +static struct platform_driver w90x900ts_driver = { > + .probe = w90x900ts_probe, > + .remove = w90x900ts_remove, __devexit_p() > + .driver = { > + .name = "w90x900-ts", > + .owner = THIS_MODULE, > + }, > +}; > + > +int __init w90x900ts_init(void) static > +{ > + return platform_driver_register(&w90x900ts_driver); > +} > + > +static void __exit w90x900ts_exit(void) > +{ > + platform_driver_unregister(&w90x900ts_driver); > +} > + > +module_init(w90x900ts_init); > +module_exit(w90x900ts_exit); > + > +MODULE_AUTHOR("PT50 zswan <mcuos.com@gmail.com>"); > +MODULE_DESCRIPTION("w90p910 touch screen driver!"); > +MODULE_LICENSE("GPL"); > Also, please run the patch through scripts/checkpatch.pl and make sure it does not complain. Thanks! -- Dmitry ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Add support for touch screen on W90P910 ARM platform 2009-05-08 3:41 ` Dmitry Torokhov @ 2009-05-09 1:30 ` Wan ZongShun 2009-05-09 19:54 ` Dmitry Torokhov 0 siblings, 1 reply; 10+ messages in thread From: Wan ZongShun @ 2009-05-09 1:30 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: linux-input Dear Dmitry, Thank you very much for your reviewing my patch. According to your advice,I have re-modified this ts driver and submitted it again. I have run the patch through scripts/checkpatch.pl and make sure it does not complain. Thanks! -- drivers/input/touchscreen/Kconfig | 6 drivers/input/touchscreen/Makefile | 1 drivers/input/touchscreen/w90p910_ts.c | 279 +++++++++++++++++++++++ 3 files changed, 286 insertions(+) --- patch text: Add touchscreen drivers for w90p910 platform. Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> diff -Npur linux-2.6.29/drivers/input/touchscreen/Kconfig linux-2.6.30/drivers/input/touchscreen/Kconfig --- linux-2.6.29/drivers/input/touchscreen/Kconfig 2009-05-05 18:32:26.000000000 +0800 +++ linux-2.6.30/drivers/input/touchscreen/Kconfig 2009-05-09 07:33:32.000000000 +0800 @@ -466,4 +466,10 @@ config TOUCHSCREEN_TSC2007 To compile this driver as a module, choose M here: the module will be called tsc2007. +config TOUCHSCREEN_W90X900 + tristate "W90P910 touchscreens" + depends on CPU_W90P910 + help + Compile this driver to support W90P910 touchscreen. + endif diff -Npur linux-2.6.29/drivers/input/touchscreen/Makefile linux-2.6.30/drivers/input/touchscreen/Makefile --- linux-2.6.29/drivers/input/touchscreen/Makefile 2009-05-05 18:32:26.000000000 +0800 +++ linux-2.6.30/drivers/input/touchscreen/Makefile 2009-05-09 07:34:12.000000000 +0800 @@ -37,3 +37,4 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) + wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o +obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o diff -Npur linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c --- linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c 2009-05-09 08:48:01.000000000 +0800 @@ -0,0 +1,279 @@ +/* + * linux/driver/input/w90x900_ts.c + * + * Copyright (c) 2008 Nuvoton technology corporation. + * + * Wan ZongShun <mcuos.com@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation;version 2 of the License. + * + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/input.h> +#include <linux/interrupt.h> + +#include <mach/hardware.h> + +/*adc state define*/ +#define NO_PRESS 0 +#define START_READX 1 +#define START_READY 2 + +/*adc controller bit define*/ +#define ADC_DELAY 0xf00 +#define ADC_DOWN 0x01 +#define ADC_TSC_Y (0x01<<8) +#define ADC_TSC_X (0x00<<8) +#define TSC_FOURWIRE (~(0x03<<1)) +#define ADC_CLK_EN (0x01<<28)/*adc clock*/ +#define ADC_READ_CON (0x01<<12) +#define ADC_CONV (0x01<<13) +#define ADC_SEMIAUTO (0x01<<14) +#define ADC_WAITTRIG (0x03<<14) +#define ADC_RST1 (0x01<<16) +#define ADC_RST0 (0x00<<16) +#define ADC_EN (0x01<<17) +#define ADC_INT (0x01<<18) +#define WT_INT (0x01<<20) +#define ADC_INT_EN (0x01<<21) +#define LVD_INT_EN (0x01<<22) +#define WT_INT_EN (0x01<<23) +#define ADC_DIV (0x04<<1)/*div=6*/ + +static DEFINE_SPINLOCK(touch_lock); + +struct ts_event { + short pressure; + short x; + short y; +}; + +struct w90p910drv_ts { + struct input_dev *input; + struct timer_list timer; + struct ts_event tc; + unsigned int ts_state; + int irq_num; + int pendown; + int clocken; + void __iomem *ts_reg; +}; + +static void new_data(struct w90p910drv_ts *w90p910_ts) +{ + struct input_dev *dev = w90p910_ts->input; + + input_report_abs(dev, ABS_X, w90p910_ts->tc.x); + input_report_abs(dev, ABS_Y, w90p910_ts->tc.y); + input_report_key(dev, BTN_TOUCH, w90p910_ts->pendown); + input_sync(dev); +} + +static void w90p910_ts_interrupt(struct w90p910drv_ts *w90p910_ts, int isTimer) +{ + if ((__raw_readl(w90p910_ts->ts_reg)&WT_INT) && !w90p910_ts->ts_state) { + w90p910_ts->pendown = 1; + w90p910_ts->ts_state = START_READX; + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&0xFF6F7FFF, + w90p910_ts->ts_reg); + } else { + if (__raw_readl(w90p910_ts->ts_reg+0x04)&ADC_DOWN) { + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); + + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&0xFF7F7FFF, + w90p910_ts->ts_reg); + w90p910_ts->ts_state = START_READX; + w90p910_ts->pendown = 1; + } else { + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_WAITTRIG|WT_INT_EN)&0xFFCBFFFF, + w90p910_ts->ts_reg); + w90p910_ts->ts_state = NO_PRESS; + w90p910_ts->pendown = 0; + } + } + + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && + w90p910_ts->ts_state == START_READX) { + w90p910_ts->ts_state = START_READY; + __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg+0x04); + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&0xFF7B7FFF, + w90p910_ts->ts_reg); + } + + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && + w90p910_ts->ts_state == START_READY) { + new_data(w90p910_ts); + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_WAITTRIG)&0xFF5BFFFF, w90p910_ts->ts_reg); + mod_timer(&w90p910_ts->timer, jiffies + 4*HZ / 100); + } +} + +static void w90p910_ts_timer(unsigned long data) +{ + struct w90p910drv_ts *w90p910_data = (struct w90p910drv_ts *) data; + unsigned long flags; + + spin_lock_irqsave(&touch_lock, flags); + + w90p910_ts_interrupt(w90p910_data, 1); + + spin_unlock_irqrestore(&touch_lock, flags); +} + +static irqreturn_t ts_interrupt(int irq, void *dev_id) +{ + struct w90p910drv_ts *w90p910_data = dev_id; + + w90p910_ts_interrupt(w90p910_data, 0); + return IRQ_HANDLED; +} + +static int __devinit w90x900ts_probe(struct platform_device *pdev) +{ + struct w90p910drv_ts *w90p910_ts; + struct input_dev *input_dev; + int err = -ENOMEM; + struct resource *res; + + w90p910_ts = kzalloc(sizeof(struct w90p910drv_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!w90p910_ts || !input_dev) + goto fail1; + + platform_set_drvdata(pdev, w90p910_ts); + + w90p910_ts->input = input_dev; + + init_timer(&w90p910_ts->timer); + w90p910_ts->timer.data = (unsigned long) w90p910_ts; + w90p910_ts->timer.function = w90p910_ts_timer; + + w90p910_ts->ts_state = NO_PRESS; + w90p910_ts->clocken = (int)W90X900_VA_CLKPWR; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENXIO; + goto fail1; + } + + if (!request_mem_region(res->start, res->end - res->start + 1, + pdev->name)) { + err = -EBUSY; + goto fail1; + } + + w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1); + if (!w90p910_ts->ts_reg) { + err = -ENOMEM; + goto fail2; + } + + /* enable the ADC clock */ + __raw_writel(__raw_readl(w90p910_ts->clocken)|ADC_CLK_EN, + w90p910_ts->clocken); + + input_dev->name = "W90P910 TouchScreen"; + input_dev->phys = "w90p910ts/event0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0005; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->dev.parent = &pdev->dev; + input_dev->evbit[0] = BIT_MASK(EV_KEY)| + BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0); + + w90p910_ts->irq_num = platform_get_irq(pdev, 0); + if (request_irq(w90p910_ts->irq_num, ts_interrupt, IRQF_DISABLED, + "w90p910ts", w90p910_ts)) { + err = -EBUSY; + goto fail3; + } + + err = input_register_device(w90p910_ts->input); + if (err) + goto fail4; + + __raw_writel(ADC_RST1, w90p910_ts->ts_reg); + udelay(1000); + __raw_writel(ADC_RST0, w90p910_ts->ts_reg); + udelay(1000); + + /* set delay and screen type */ + __raw_writel(__raw_readl(w90p910_ts->ts_reg+0x04) & TSC_FOURWIRE, + (w90p910_ts->ts_reg+0x04)); + __raw_writel(ADC_DELAY, (w90p910_ts->ts_reg+0x08)); + /* waitting for trigger mode */ + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_WAITTRIG|ADC_DIV|ADC_EN|WT_INT_EN) & 0xFFEBFF09, + w90p910_ts->ts_reg); + return 0; + +fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); +fail3: iounmap(w90p910_ts->ts_reg); +fail2: release_mem_region(res->start, res->end - res->start + 1); +fail1: input_free_device(input_dev); + kfree(w90p910_ts); + return err; +} + +static int __devexit w90x900ts_remove(struct platform_device *pdev) +{ + struct w90p910drv_ts *w90p910_ts = platform_get_drvdata(pdev); + struct resource *res; + + free_irq(w90p910_ts->irq_num, w90p910_ts); + del_timer_sync(&w90p910_ts->timer); + iounmap(w90p910_ts->ts_reg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + + input_unregister_device(w90p910_ts->input); + kfree(w90p910_ts); + + return 0; +} + +static struct platform_driver w90x900ts_driver = { + .probe = w90x900ts_probe, + .remove = __devexit_p(w90x900ts_remove), + .driver = { + .name = "w90x900-ts", + .owner = THIS_MODULE, + }, +}; + +static int __init w90x900ts_init(void) +{ + return platform_driver_register(&w90x900ts_driver); +} + +static void __exit w90x900ts_exit(void) +{ + platform_driver_unregister(&w90x900ts_driver); +} + +module_init(w90x900ts_init); +module_exit(w90x900ts_exit); + +MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); +MODULE_DESCRIPTION("w90p910 touch screen driver!"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:w90p910-ts"); ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Add support for touch screen on W90P910 ARM platform 2009-05-09 1:30 ` Wan ZongShun @ 2009-05-09 19:54 ` Dmitry Torokhov 2009-05-10 10:35 ` Wan ZongShun 0 siblings, 1 reply; 10+ messages in thread From: Dmitry Torokhov @ 2009-05-09 19:54 UTC (permalink / raw) To: Wan ZongShun; +Cc: linux-input Hi Wan, On Sat, May 09, 2009 at 09:30:14AM +0800, Wan ZongShun wrote: > Dear Dmitry, > > Thank you very much for your reviewing my patch. > According to your advice,I have re-modified this > ts driver and submitted it again. > > I have run the patch through scripts/checkpatch.pl > and make sure it does not complain. Thanks! > Thank you very much for addressing my comments, the driver looks much better now. Still have a few more though ;) > -- > drivers/input/touchscreen/Kconfig | 6 > drivers/input/touchscreen/Makefile | 1 > drivers/input/touchscreen/w90p910_ts.c | 279 +++++++++++++++++++++++ > 3 files changed, 286 insertions(+) > --- > patch text: > > Add touchscreen drivers for w90p910 platform. > > Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> > > diff -Npur linux-2.6.29/drivers/input/touchscreen/Kconfig linux-2.6.30/drivers/input/touchscreen/Kconfig > --- linux-2.6.29/drivers/input/touchscreen/Kconfig 2009-05-05 18:32:26.000000000 +0800 > +++ linux-2.6.30/drivers/input/touchscreen/Kconfig 2009-05-09 07:33:32.000000000 +0800 > @@ -466,4 +466,10 @@ config TOUCHSCREEN_TSC2007 > To compile this driver as a module, choose M here: the > module will be called tsc2007. > > +config TOUCHSCREEN_W90X900 > + tristate "W90P910 touchscreens" > + depends on CPU_W90P910 > + help > + Compile this driver to support W90P910 touchscreen. > + "To compile this driver as a module..." > endif > diff -Npur linux-2.6.29/drivers/input/touchscreen/Makefile linux-2.6.30/drivers/input/touchscreen/Makefile > --- linux-2.6.29/drivers/input/touchscreen/Makefile 2009-05-05 18:32:26.000000000 +0800 > +++ linux-2.6.30/drivers/input/touchscreen/Makefile 2009-05-09 07:34:12.000000000 +0800 > @@ -37,3 +37,4 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) + > wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o > obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o > obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o > +obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o > diff -Npur linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c > --- linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c 1970-01-01 08:00:00.000000000 +0800 > +++ linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c 2009-05-09 08:48:01.000000000 +0800 > @@ -0,0 +1,279 @@ > +/* > + * linux/driver/input/w90x900_ts.c We prefer not to have file paths in comments. > + * > + * Copyright (c) 2008 Nuvoton technology corporation. > + * > + * Wan ZongShun <mcuos.com@gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation;version 2 of the License. > + * > + */ > + > +#include <linux/delay.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/io.h> > +#include <linux/input.h> > +#include <linux/interrupt.h> > + > +#include <mach/hardware.h> > + > +/*adc state define*/ > +#define NO_PRESS 0 > +#define START_READX 1 > +#define START_READY 2 That could probably be made an enum... > + > +/*adc controller bit define*/ > +#define ADC_DELAY 0xf00 > +#define ADC_DOWN 0x01 > +#define ADC_TSC_Y (0x01<<8) > +#define ADC_TSC_X (0x00<<8) Could we plerase have spaces around operations (like '0x01 << 8') - it makes it easier to read. I thought checkpatch.pl warned about this, I must be mistaken... > +#define TSC_FOURWIRE (~(0x03<<1)) > +#define ADC_CLK_EN (0x01<<28)/*adc clock*/ > +#define ADC_READ_CON (0x01<<12) > +#define ADC_CONV (0x01<<13) > +#define ADC_SEMIAUTO (0x01<<14) > +#define ADC_WAITTRIG (0x03<<14) > +#define ADC_RST1 (0x01<<16) > +#define ADC_RST0 (0x00<<16) > +#define ADC_EN (0x01<<17) > +#define ADC_INT (0x01<<18) > +#define WT_INT (0x01<<20) > +#define ADC_INT_EN (0x01<<21) > +#define LVD_INT_EN (0x01<<22) > +#define WT_INT_EN (0x01<<23) > +#define ADC_DIV (0x04<<1)/*div=6*/ > + > +static DEFINE_SPINLOCK(touch_lock); Since you have driver-specific structure this spinlock should go there as well. > + > +struct ts_event { > + short pressure; Not used anymore. Probably the whole structure is not needed anymore, just move x and y into w90p910drv_ts. > + short x; > + short y; > +}; > + > +struct w90p910drv_ts { > + struct input_dev *input; > + struct timer_list timer; > + struct ts_event tc; > + unsigned int ts_state; > + int irq_num; > + int pendown; > + int clocken; > + void __iomem *ts_reg; > +}; > + > +static void new_data(struct w90p910drv_ts *w90p910_ts) This should be called w90p910_report_event(). But I must say, I don't see anything modifying tc.x and tc.y anywhere... > +{ > + struct input_dev *dev = w90p910_ts->input; > + > + input_report_abs(dev, ABS_X, w90p910_ts->tc.x); > + input_report_abs(dev, ABS_Y, w90p910_ts->tc.y); > + input_report_key(dev, BTN_TOUCH, w90p910_ts->pendown); > + input_sync(dev); > +} > + > +static void w90p910_ts_interrupt(struct w90p910drv_ts *w90p910_ts, int isTimer) I don't see anything using isTimer flag. > +{ > + if ((__raw_readl(w90p910_ts->ts_reg)&WT_INT) && !w90p910_ts->ts_state) { > + w90p910_ts->pendown = 1; > + w90p910_ts->ts_state = START_READX; > + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&0xFF6F7FFF, Still uses magic constants... what does 0xFF6F7FFF mean? > + w90p910_ts->ts_reg); > + } else { > + if (__raw_readl(w90p910_ts->ts_reg+0x04)&ADC_DOWN) { > + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); > + > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&0xFF7F7FFF, > + w90p910_ts->ts_reg); > + w90p910_ts->ts_state = START_READX; > + w90p910_ts->pendown = 1; > + } else { > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_WAITTRIG|WT_INT_EN)&0xFFCBFFFF, > + w90p910_ts->ts_reg); > + w90p910_ts->ts_state = NO_PRESS; > + w90p910_ts->pendown = 0; > + } > + } > + > + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && > + w90p910_ts->ts_state == START_READX) { > + w90p910_ts->ts_state = START_READY; > + __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg+0x04); > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&0xFF7B7FFF, > + w90p910_ts->ts_reg); > + } > + > + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && > + w90p910_ts->ts_state == START_READY) { > + new_data(w90p910_ts); Hm, why do you wait till here to call new_data()? Why can't you do it right where you set w90p910_ts->ts_state = START_READY? I guess I am having hard tome figuring out how the device is supposed to work... > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_WAITTRIG)&0xFF5BFFFF, w90p910_ts->ts_reg); > + mod_timer(&w90p910_ts->timer, jiffies + 4*HZ / 100); please use msecs_to_jiffies() here, otheriwse you won't get the delay you expected if HZ value changes. > + } > +} > + > +static void w90p910_ts_timer(unsigned long data) > +{ > + struct w90p910drv_ts *w90p910_data = (struct w90p910drv_ts *) data; > + unsigned long flags; > + > + spin_lock_irqsave(&touch_lock, flags); > + > + w90p910_ts_interrupt(w90p910_data, 1); > + > + spin_unlock_irqrestore(&touch_lock, flags); > +} > + > +static irqreturn_t ts_interrupt(int irq, void *dev_id) > +{ > + struct w90p910drv_ts *w90p910_data = dev_id; > + > + w90p910_ts_interrupt(w90p910_data, 0); > + return IRQ_HANDLED; > +} > + > +static int __devinit w90x900ts_probe(struct platform_device *pdev) > +{ > + struct w90p910drv_ts *w90p910_ts; > + struct input_dev *input_dev; > + int err = -ENOMEM; > + struct resource *res; > + > + w90p910_ts = kzalloc(sizeof(struct w90p910drv_ts), GFP_KERNEL); > + input_dev = input_allocate_device(); > + if (!w90p910_ts || !input_dev) > + goto fail1; > + > + platform_set_drvdata(pdev, w90p910_ts); > + > + w90p910_ts->input = input_dev; > + > + init_timer(&w90p910_ts->timer); > + w90p910_ts->timer.data = (unsigned long) w90p910_ts; > + w90p910_ts->timer.function = w90p910_ts_timer; setup_timer(). > + > + w90p910_ts->ts_state = NO_PRESS; > + w90p910_ts->clocken = (int)W90X900_VA_CLKPWR; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + err = -ENXIO; > + goto fail1; > + } > + > + if (!request_mem_region(res->start, res->end - res->start + 1, > + pdev->name)) { > + err = -EBUSY; > + goto fail1; > + } > + > + w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1); > + if (!w90p910_ts->ts_reg) { > + err = -ENOMEM; > + goto fail2; > + } > + > + /* enable the ADC clock */ > + __raw_writel(__raw_readl(w90p910_ts->clocken)|ADC_CLK_EN, > + w90p910_ts->clocken); > + > + input_dev->name = "W90P910 TouchScreen"; > + input_dev->phys = "w90p910ts/event0"; > + input_dev->id.bustype = BUS_HOST; > + input_dev->id.vendor = 0x0005; > + input_dev->id.product = 0x0001; > + input_dev->id.version = 0x0100; > + input_dev->dev.parent = &pdev->dev; > + input_dev->evbit[0] = BIT_MASK(EV_KEY)| > + BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN); > + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); > + > + input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0); > + input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0); > + > + w90p910_ts->irq_num = platform_get_irq(pdev, 0); > + if (request_irq(w90p910_ts->irq_num, ts_interrupt, IRQF_DISABLED, > + "w90p910ts", w90p910_ts)) { > + err = -EBUSY; > + goto fail3; > + } > + > + err = input_register_device(w90p910_ts->input); > + if (err) > + goto fail4; > + > + __raw_writel(ADC_RST1, w90p910_ts->ts_reg); > + udelay(1000); msleep() instead? > + __raw_writel(ADC_RST0, w90p910_ts->ts_reg); > + udelay(1000); Same here. > + > + /* set delay and screen type */ > + __raw_writel(__raw_readl(w90p910_ts->ts_reg+0x04) & TSC_FOURWIRE, > + (w90p910_ts->ts_reg+0x04)); > + __raw_writel(ADC_DELAY, (w90p910_ts->ts_reg+0x08)); > + /* waitting for trigger mode */ > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_WAITTRIG|ADC_DIV|ADC_EN|WT_INT_EN) & 0xFFEBFF09, > + w90p910_ts->ts_reg); > + return 0; > + > +fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); > +fail3: iounmap(w90p910_ts->ts_reg); > +fail2: release_mem_region(res->start, res->end - res->start + 1); > +fail1: input_free_device(input_dev); > + kfree(w90p910_ts); > + return err; > +} > + > +static int __devexit w90x900ts_remove(struct platform_device *pdev) > +{ > + struct w90p910drv_ts *w90p910_ts = platform_get_drvdata(pdev); > + struct resource *res; > + > + free_irq(w90p910_ts->irq_num, w90p910_ts); > + del_timer_sync(&w90p910_ts->timer); > + iounmap(w90p910_ts->ts_reg); > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + release_mem_region(res->start, res->end - res->start + 1); > + > + input_unregister_device(w90p910_ts->input); > + kfree(w90p910_ts); > + > + return 0; > +} > + > +static struct platform_driver w90x900ts_driver = { > + .probe = w90x900ts_probe, > + .remove = __devexit_p(w90x900ts_remove), > + .driver = { > + .name = "w90x900-ts", > + .owner = THIS_MODULE, > + }, > +}; > + > +static int __init w90x900ts_init(void) > +{ > + return platform_driver_register(&w90x900ts_driver); > +} > + > +static void __exit w90x900ts_exit(void) > +{ > + platform_driver_unregister(&w90x900ts_driver); > +} > + > +module_init(w90x900ts_init); > +module_exit(w90x900ts_exit); > + > +MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); > +MODULE_DESCRIPTION("w90p910 touch screen driver!"); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:w90p910-ts"); Thanks! -- Dmitry ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Add support for touch screen on W90P910 ARM platform 2009-05-09 19:54 ` Dmitry Torokhov @ 2009-05-10 10:35 ` Wan ZongShun 2009-05-10 20:15 ` Dmitry Torokhov 0 siblings, 1 reply; 10+ messages in thread From: Wan ZongShun @ 2009-05-10 10:35 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: linux-input, mcuos.com Dear Dmitry, Thank your for giving me very precious suggestion, and you have helped me perfect my ts driver.Thanks. According to your advice,I have modified my patch. About your some doubt,I explain some following for you: Base on w90p910 ts spec,the ts can work in two mode,wait trigger mode and auto-semi mode.When no press acts on LCD,the ts is stll in wait trigger mode, and if press occurs,the ts can give a WT_INT interrupt,at this time, my driver must catch this irq and prepare to gain X value,if the X value was obtained successfully,ts will give a ADC_INT interrupt.When the Y value was obtained successfully,the second ADC_INT interrupt will be gave. If we want to gain this X and Y values,we must change the mode to auto-semi mode. The following code is my driver: static void w90p910_ts_interrupt(struct w90p910drv_ts *w90p910_ts) { /*the section indicates WT_INT occurs,and previous state is NO_PRESS,but current state is having a press. */ if ((__raw_readl(w90p910_ts->ts_reg)&WT_INT) && w90p910_ts->state == NO_PRESS) { w90p910_ts->pendown = 1; __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); /*change the mode to auto-semi and prepare to gain X value and set this state to CAN_READX*/ __raw_writel((__raw_readl(w90p910_ts->ts_reg)| ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV), w90p910_ts->ts_reg); w90p910_ts->state = CAN_READX; } /*I think this section can be called by timer function and to judge if the pen still keep down... */ else { if (__raw_readl(w90p910_ts->ts_reg+0x04)&ADC_DOWN) { __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); __raw_writel((__raw_readl(w90p910_ts->ts_reg)| ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV), w90p910_ts->ts_reg); w90p910_ts->pendown = 1; w90p910_ts->state = CAN_READX; } else { __raw_writel((__raw_readl(w90p910_ts->ts_reg)| ADC_WAITTRIG|WT_INT_EN), w90p910_ts->ts_reg); w90p910_ts->pendown = 0; w90p910_ts->state = NO_PRESS; } } /*if the ADC_INT occurs ,at the time,the w90p910_ts->state equal to CAN_READX, this state indicates X value have been obtained successfully and preparing to gain Y value. */ if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && w90p910_ts->state == CAN_READX) { __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg+0x04); __raw_writel((__raw_readl(w90p910_ts->ts_reg)| ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV), w90p910_ts->ts_reg); w90p910_ts->state = CAN_READY; } /*if another ADC_INT occurs ,at the time,the w90p910_ts->state equal to CAN_READY, this state indicates X and Y values have been obtained successfully and preparing to submit those values to user,so I think i must put this w90p910_report_event() here and submit x and y values to user at the same time. */ if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && w90p910_ts->state == CAN_READY) { w90p910_report_event(w90p910_ts); __raw_writel((__raw_readl(w90p910_ts->ts_reg)| ADC_WAITTRIG), w90p910_ts->ts_reg); mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(40)); } } Mmm,I am a wordy speaker and didn't know if you can understand my idea, this driver can make my ts works well. :) --- Add touchscreen drivers for w90p910 platform. Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> diff -Npur linux-2.6.29/drivers/input/touchscreen/Kconfig linux-2.6.30/drivers/input/touchscreen/Kconfig --- linux-2.6.29/drivers/input/touchscreen/Kconfig 2009-05-01 12:28:54.000000000 +0800 +++ linux-2.6.30/drivers/input/touchscreen/Kconfig 2009-05-10 14:47:07.000000000 +0800 @@ -466,4 +466,11 @@ config TOUCHSCREEN_TSC2007 To compile this driver as a module, choose M here: the module will be called tsc2007. +config TOUCHSCREEN_W90X900 + tristate "W90P910 touchscreen driver" + depends on CPU_W90P910 + help + To compile this driver as a module, choose M here: the + module will be called w90p910-ts. + endif diff -Npur linux-2.6.29/drivers/input/touchscreen/Makefile linux-2.6.30/drivers/input/touchscreen/Makefile --- linux-2.6.29/drivers/input/touchscreen/Makefile 2009-05-01 12:28:54.000000000 +0800 +++ linux-2.6.30/drivers/input/touchscreen/Makefile 2009-05-09 07:34:12.000000000 +0800 @@ -37,3 +37,4 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) + wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o +obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o diff -Npur linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c --- linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c 2009-05-10 15:41:00.000000000 +0800 @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2008 Nuvoton technology corporation. + * + * Wan ZongShun <mcuos.com@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation;version 2 of the License. + * + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/input.h> +#include <linux/interrupt.h> + +#include <mach/hardware.h> + +/*adc controller bit define*/ +#define ADC_DELAY 0xf00 +#define ADC_DOWN 0x01 +#define ADC_TSC_Y (0x01 << 8) +#define ADC_TSC_X (0x00 << 8) +#define TSC_FOURWIRE (~(0x03 << 1)) +#define ADC_CLK_EN (0x01 << 28)/*adc clock*/ +#define ADC_READ_CON (0x01 << 12) +#define ADC_CONV (0x01 << 13) +#define ADC_SEMIAUTO (0x01 << 14) +#define ADC_WAITTRIG (0x03 << 14) +#define ADC_RST1 (0x01 << 16) +#define ADC_RST0 (0x00 << 16) +#define ADC_EN (0x01 << 17) +#define ADC_INT (0x01 << 18) +#define WT_INT (0x01 << 20) +#define ADC_INT_EN (0x01 << 21) +#define LVD_INT_EN (0x01 << 22) +#define WT_INT_EN (0x01 << 23) +#define ADC_DIV (0x04 << 1)/*div=6*/ + +/*adc state define*/ +enum ts_state { NO_PRESS, CAN_READX, CAN_READY }; + +struct w90p910drv_ts { + struct input_dev *input; + struct timer_list timer; + int irq_num; + int pendown; + int clocken; + void __iomem *ts_reg; + short x; + short y; + spinlock_t lock; + enum ts_state state; +}; + +static void w90p910_report_event(struct w90p910drv_ts *w90p910_ts) +{ + struct input_dev *dev = w90p910_ts->input; + + w90p910_ts->x = __raw_readl(w90p910_ts->ts_reg+0x0c); + w90p910_ts->y = __raw_readl(w90p910_ts->ts_reg+0x10); + + input_report_abs(dev, ABS_X, w90p910_ts->x); + input_report_abs(dev, ABS_Y, w90p910_ts->y); + input_report_key(dev, BTN_TOUCH, w90p910_ts->pendown); + input_sync(dev); +} + +static void w90p910_ts_interrupt(struct w90p910drv_ts *w90p910_ts) +{ + if ((__raw_readl(w90p910_ts->ts_reg)&WT_INT) && + w90p910_ts->state == NO_PRESS) { + w90p910_ts->pendown = 1; + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV), + w90p910_ts->ts_reg); + w90p910_ts->state = CAN_READX; + } else { + if (__raw_readl(w90p910_ts->ts_reg+0x04)&ADC_DOWN) { + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); + + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV), + w90p910_ts->ts_reg); + w90p910_ts->pendown = 1; + w90p910_ts->state = CAN_READX; + } else { + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_WAITTRIG|WT_INT_EN), w90p910_ts->ts_reg); + w90p910_ts->pendown = 0; + w90p910_ts->state = NO_PRESS; + } + } + + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && + w90p910_ts->state == CAN_READX) { + __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg+0x04); + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV), w90p910_ts->ts_reg); + w90p910_ts->state = CAN_READY; + } + + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && + w90p910_ts->state == CAN_READY) { + w90p910_report_event(w90p910_ts); + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_WAITTRIG), w90p910_ts->ts_reg); + mod_timer(&w90p910_ts->timer, jiffies + + msecs_to_jiffies(40)); + } +} + +static void w90p910_ts_timer(unsigned long data) +{ + struct w90p910drv_ts *w90p910_data = (struct w90p910drv_ts *) data; + unsigned long flags; + + spin_lock_irqsave(&w90p910_data->lock, flags); + + w90p910_ts_interrupt(w90p910_data); + + spin_unlock_irqrestore(&w90p910_data->lock, flags); +} + +static irqreturn_t ts_interrupt(int irq, void *dev_id) +{ + struct w90p910drv_ts *w90p910_data = dev_id; + + w90p910_ts_interrupt(w90p910_data); + return IRQ_HANDLED; +} + +static int __devinit w90x900ts_probe(struct platform_device *pdev) +{ + struct w90p910drv_ts *w90p910_ts; + struct input_dev *input_dev; + int err = -ENOMEM; + struct resource *res; + + w90p910_ts = kzalloc(sizeof(struct w90p910drv_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!w90p910_ts || !input_dev) + goto fail1; + + platform_set_drvdata(pdev, w90p910_ts); + + w90p910_ts->input = input_dev; + w90p910_ts->state = NO_PRESS; + w90p910_ts->clocken = (int)W90X900_VA_CLKPWR; + spin_lock_init(&w90p910_ts->lock); + setup_timer(&w90p910_ts->timer, w90p910_ts_timer, + (unsigned long)w90p910_ts); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENXIO; + goto fail1; + } + + if (!request_mem_region(res->start, res->end - res->start + 1, + pdev->name)) { + err = -EBUSY; + goto fail1; + } + + w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1); + if (!w90p910_ts->ts_reg) { + err = -ENOMEM; + goto fail2; + } + + /* enable the ADC clock */ + __raw_writel(__raw_readl(w90p910_ts->clocken)|ADC_CLK_EN, + w90p910_ts->clocken); + + input_dev->name = "W90P910 TouchScreen"; + input_dev->phys = "w90p910ts/event0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0005; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->dev.parent = &pdev->dev; + input_dev->evbit[0] = BIT_MASK(EV_KEY)| + BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0); + + w90p910_ts->irq_num = platform_get_irq(pdev, 0); + if (request_irq(w90p910_ts->irq_num, ts_interrupt, IRQF_DISABLED, + "w90p910ts", w90p910_ts)) { + err = -EBUSY; + goto fail3; + } + + err = input_register_device(w90p910_ts->input); + if (err) + goto fail4; + + __raw_writel(ADC_RST1, w90p910_ts->ts_reg); + msleep(1); + __raw_writel(ADC_RST0, w90p910_ts->ts_reg); + msleep(1); + + /* set delay and screen type */ + __raw_writel(__raw_readl(w90p910_ts->ts_reg+0x04) & TSC_FOURWIRE, + (w90p910_ts->ts_reg+0x04)); + __raw_writel(ADC_DELAY, (w90p910_ts->ts_reg+0x08)); + /* waitting for trigger mode */ + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_WAITTRIG|ADC_DIV|ADC_EN|WT_INT_EN), w90p910_ts->ts_reg); + return 0; + +fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); +fail3: iounmap(w90p910_ts->ts_reg); +fail2: release_mem_region(res->start, res->end - res->start + 1); +fail1: input_free_device(input_dev); + kfree(w90p910_ts); + return err; +} + +static int __devexit w90x900ts_remove(struct platform_device *pdev) +{ + struct w90p910drv_ts *w90p910_ts = platform_get_drvdata(pdev); + struct resource *res; + + free_irq(w90p910_ts->irq_num, w90p910_ts); + del_timer_sync(&w90p910_ts->timer); + iounmap(w90p910_ts->ts_reg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + + input_unregister_device(w90p910_ts->input); + kfree(w90p910_ts); + + return 0; +} + +static struct platform_driver w90x900ts_driver = { + .probe = w90x900ts_probe, + .remove = __devexit_p(w90x900ts_remove), + .driver = { + .name = "w90x900-ts", + .owner = THIS_MODULE, + }, +}; + +static int __init w90x900ts_init(void) +{ + return platform_driver_register(&w90x900ts_driver); +} + +static void __exit w90x900ts_exit(void) +{ + platform_driver_unregister(&w90x900ts_driver); +} + +module_init(w90x900ts_init); +module_exit(w90x900ts_exit); + +MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); +MODULE_DESCRIPTION("w90p910 touch screen driver!"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:w90p910-ts"); ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Add support for touch screen on W90P910 ARM platform 2009-05-10 10:35 ` Wan ZongShun @ 2009-05-10 20:15 ` Dmitry Torokhov 2009-05-11 3:58 ` Wan ZongShun 0 siblings, 1 reply; 10+ messages in thread From: Dmitry Torokhov @ 2009-05-10 20:15 UTC (permalink / raw) To: Wan ZongShun; +Cc: linux-input Hi Wan, On Sunday 10 May 2009 03:35:00 Wan ZongShun wrote: > if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && > w90p910_ts->state == CAN_READY) { > w90p910_report_event(w90p910_ts); > __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > ADC_WAITTRIG), w90p910_ts->ts_reg); Thank you very much for the explanation. Could you please tell me when you issue ADC_WAITTRIG do you expect to see WT_INT or ADC_INT condition? Thanks. -- Dmitry ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Add support for touch screen on W90P910 ARM platform 2009-05-10 20:15 ` Dmitry Torokhov @ 2009-05-11 3:58 ` Wan ZongShun 2009-05-12 1:07 ` Wan ZongShun 0 siblings, 1 reply; 10+ messages in thread From: Wan ZongShun @ 2009-05-11 3:58 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: linux-input, mcuos.com Dear Dmitry, Modifying the magic constants to use #defines form,but I forget to re-patch it in previous patch, so i re-submit this patch again. about you doubt: if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && w90p910_ts->state == CAN_READY) { w90p910_report_event(w90p910_ts); __raw_writel((__raw_readl(w90p910_ts->ts_reg)| ADC_WAITTRIG)&(~ADC_INT|~WT_INT_EN|~ADC_INT_EN), w90p910_ts->ts_reg); mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(40)); } When changing to wait trigger mode(ADC_WAITTRIG),I have to close wait trigger(WT_INT) and ADC interrupt(ADC_INT), and start the timer to execute timer function,if pen still keep down,then opening the ADC interrupt again,so that it can continue to get values of X and Y,but if pen keep up,opening wait trigger interrupt and closing ADC interrupt,so that we can wait the next pen in down. MY PATCH text: Add touchscreen drivers for w90p910 platform. Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> diff -Npur linux-2.6.29/drivers/input/touchscreen/Kconfig linux-2.6.30/drivers/input/touchscreen/Kconfig --- linux-2.6.29/drivers/input/touchscreen/Kconfig 2009-05-01 12:28:54.000000000 +0800 +++ linux-2.6.30/drivers/input/touchscreen/Kconfig 2009-05-10 14:47:07.000000000 +0800 @@ -466,4 +466,11 @@ config TOUCHSCREEN_TSC2007 To compile this driver as a module, choose M here: the module will be called tsc2007. +config TOUCHSCREEN_W90X900 + tristate "W90P910 touchscreen driver" + depends on CPU_W90P910 + help + To compile this driver as a module, choose M here: the + module will be called w90p910-ts. + endif diff -Npur linux-2.6.29/drivers/input/touchscreen/Makefile linux-2.6.30/drivers/input/touchscreen/Makefile --- linux-2.6.29/drivers/input/touchscreen/Makefile 2009-05-01 12:28:54.000000000 +0800 +++ linux-2.6.30/drivers/input/touchscreen/Makefile 2009-05-09 07:34:12.000000000 +0800 @@ -37,3 +37,4 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) + wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o +obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o diff -Npur linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c --- linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c 1970-01-01 08:00:00.000000000 +0800 +++ linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c 2009-05-11 11:12:48.000000000 +0800 @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2008 Nuvoton technology corporation. + * + * Wan ZongShun <mcuos.com@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation;version 2 of the License. + * + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/input.h> +#include <linux/interrupt.h> + +#include <mach/hardware.h> + +/*adc controller bit define*/ +#define ADC_DELAY 0xf00 +#define ADC_DOWN 0x01 +#define ADC_TSC_Y (0x01 << 8) +#define ADC_TSC_X (0x00 << 8) +#define TSC_FOURWIRE (~(0x03 << 1)) +#define ADC_CLK_EN (0x01 << 28)/*adc clock*/ +#define ADC_READ_CON (0x01 << 12) +#define ADC_CONV (0x01 << 13) +#define ADC_SEMIAUTO (0x01 << 14) +#define ADC_WAITTRIG (0x03 << 14) +#define ADC_RST1 (0x01 << 16) +#define ADC_RST0 (0x00 << 16) +#define ADC_EN (0x01 << 17) +#define ADC_INT (0x01 << 18)/*adc int status*/ +#define WT_INT (0x01 << 20)/*wait trig int status*/ +#define ADC_INT_EN (0x01 << 21)/*enable ADC_INT irq*/ +#define LVD_INT_EN (0x01 << 22) +#define WT_INT_EN (0x01 << 23)/*enable WT_INT irq*/ +#define ADC_DIV (0x04 << 1)/*div=6*/ + +/*adc state define*/ +enum ts_state { NO_PRESS, CAN_READX, CAN_READY }; + +struct w90p910drv_ts { + struct input_dev *input; + struct timer_list timer; + int irq_num; + int pendown; + int clocken; + void __iomem *ts_reg; + short x; + short y; + spinlock_t lock; + enum ts_state state; +}; + +static void w90p910_report_event(struct w90p910drv_ts *w90p910_ts) +{ + struct input_dev *dev = w90p910_ts->input; + + w90p910_ts->x = __raw_readl(w90p910_ts->ts_reg+0x0c); + w90p910_ts->y = __raw_readl(w90p910_ts->ts_reg+0x10); + + input_report_abs(dev, ABS_X, w90p910_ts->x); + input_report_abs(dev, ABS_Y, w90p910_ts->y); + input_report_key(dev, BTN_TOUCH, w90p910_ts->pendown); + input_sync(dev); +} + +static void w90p910_ts_interrupt(struct w90p910drv_ts *w90p910_ts) +{ + if ((__raw_readl(w90p910_ts->ts_reg)&WT_INT) && + w90p910_ts->state == NO_PRESS) { + w90p910_ts->pendown = 1; + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&(~WT_INT|~WT_INT_EN), + w90p910_ts->ts_reg); + w90p910_ts->state = CAN_READX; + } else { + if (__raw_readl(w90p910_ts->ts_reg+0x04)&ADC_DOWN) { + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); + + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&(~WT_INT_EN), + w90p910_ts->ts_reg); + w90p910_ts->pendown = 1; + w90p910_ts->state = CAN_READX; + } else { + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_WAITTRIG|WT_INT_EN)&(~ADC_INT_EN| + ~WT_INT|~ADC_INT), w90p910_ts->ts_reg); + w90p910_ts->pendown = 0; + w90p910_ts->state = NO_PRESS; + } + } + + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && + w90p910_ts->state == CAN_READX) { + __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg+0x04); + __raw_writel((__raw_readl(w90p910_ts->ts_reg)|ADC_SEMIAUTO| + ADC_INT_EN|ADC_CONV)&(~ADC_INT|~WT_INT_EN), + w90p910_ts->ts_reg); + w90p910_ts->state = CAN_READY; + } + + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && + w90p910_ts->state == CAN_READY) { + w90p910_report_event(w90p910_ts); + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_WAITTRIG)&(~ADC_INT|~WT_INT_EN|~ADC_INT_EN), + w90p910_ts->ts_reg); + mod_timer(&w90p910_ts->timer, jiffies + + msecs_to_jiffies(40)); + } +} + +static void w90p910_ts_timer(unsigned long data) +{ + struct w90p910drv_ts *w90p910_data = (struct w90p910drv_ts *) data; + unsigned long flags; + + spin_lock_irqsave(&w90p910_data->lock, flags); + + w90p910_ts_interrupt(w90p910_data); + + spin_unlock_irqrestore(&w90p910_data->lock, flags); +} + +static irqreturn_t ts_interrupt(int irq, void *dev_id) +{ + struct w90p910drv_ts *w90p910_data = dev_id; + + w90p910_ts_interrupt(w90p910_data); + return IRQ_HANDLED; +} + +static int __devinit w90x900ts_probe(struct platform_device *pdev) +{ + struct w90p910drv_ts *w90p910_ts; + struct input_dev *input_dev; + int err = -ENOMEM; + struct resource *res; + + w90p910_ts = kzalloc(sizeof(struct w90p910drv_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!w90p910_ts || !input_dev) + goto fail1; + + platform_set_drvdata(pdev, w90p910_ts); + + w90p910_ts->input = input_dev; + w90p910_ts->state = NO_PRESS; + w90p910_ts->clocken = (int)W90X900_VA_CLKPWR; + spin_lock_init(&w90p910_ts->lock); + setup_timer(&w90p910_ts->timer, w90p910_ts_timer, + (unsigned long)w90p910_ts); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENXIO; + goto fail1; + } + + if (!request_mem_region(res->start, res->end - res->start + 1, + pdev->name)) { + err = -EBUSY; + goto fail1; + } + + w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1); + if (!w90p910_ts->ts_reg) { + err = -ENOMEM; + goto fail2; + } + + /* enable the ADC clock */ + __raw_writel(__raw_readl(w90p910_ts->clocken)|ADC_CLK_EN, + w90p910_ts->clocken); + + input_dev->name = "W90P910 TouchScreen"; + input_dev->phys = "w90p910ts/event0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0005; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->dev.parent = &pdev->dev; + input_dev->evbit[0] = BIT_MASK(EV_KEY)| + BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0); + + w90p910_ts->irq_num = platform_get_irq(pdev, 0); + if (request_irq(w90p910_ts->irq_num, ts_interrupt, IRQF_DISABLED, + "w90p910ts", w90p910_ts)) { + err = -EBUSY; + goto fail3; + } + + err = input_register_device(w90p910_ts->input); + if (err) + goto fail4; + + __raw_writel(ADC_RST1, w90p910_ts->ts_reg); + msleep(1); + __raw_writel(ADC_RST0, w90p910_ts->ts_reg); + msleep(1); + + /* set delay and screen type */ + __raw_writel(__raw_readl(w90p910_ts->ts_reg+0x04) & TSC_FOURWIRE, + (w90p910_ts->ts_reg+0x04)); + __raw_writel(ADC_DELAY, (w90p910_ts->ts_reg+0x08)); + /* waitting for trigger mode */ + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| + ADC_WAITTRIG|ADC_DIV|ADC_EN|WT_INT_EN), w90p910_ts->ts_reg); + return 0; + +fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); +fail3: iounmap(w90p910_ts->ts_reg); +fail2: release_mem_region(res->start, res->end - res->start + 1); +fail1: input_free_device(input_dev); + kfree(w90p910_ts); + return err; +} + +static int __devexit w90x900ts_remove(struct platform_device *pdev) +{ + struct w90p910drv_ts *w90p910_ts = platform_get_drvdata(pdev); + struct resource *res; + + free_irq(w90p910_ts->irq_num, w90p910_ts); + del_timer_sync(&w90p910_ts->timer); + iounmap(w90p910_ts->ts_reg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + + input_unregister_device(w90p910_ts->input); + kfree(w90p910_ts); + + return 0; +} + +static struct platform_driver w90x900ts_driver = { + .probe = w90x900ts_probe, + .remove = __devexit_p(w90x900ts_remove), + .driver = { + .name = "w90x900-ts", + .owner = THIS_MODULE, + }, +}; + +static int __init w90x900ts_init(void) +{ + return platform_driver_register(&w90x900ts_driver); +} + +static void __exit w90x900ts_exit(void) +{ + platform_driver_unregister(&w90x900ts_driver); +} + +module_init(w90x900ts_init); +module_exit(w90x900ts_exit); + +MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); +MODULE_DESCRIPTION("w90p910 touch screen driver!"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:w90p910-ts"); ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Add support for touch screen on W90P910 ARM platform 2009-05-11 3:58 ` Wan ZongShun @ 2009-05-12 1:07 ` Wan ZongShun [not found] ` <e68bb3470905172007i47a5435x7b87383323a1cf1a@mail.gmail.com> 0 siblings, 1 reply; 10+ messages in thread From: Wan ZongShun @ 2009-05-12 1:07 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: linux-input, mcuos.com Dear Dmitry, Did you have any else advice given to me about this patch? Can it be accepted by you now? 2009/5/11 Wan ZongShun <mcuos.com@gmail.com>: > Dear Dmitry, > > Modifying the magic constants to use #defines form,but I forget to re-patch it in previous patch, > so i re-submit this patch again. > > about you doubt: > > if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && > w90p910_ts->state == CAN_READY) { > w90p910_report_event(w90p910_ts); > __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > ADC_WAITTRIG)&(~ADC_INT|~WT_INT_EN|~ADC_INT_EN), > w90p910_ts->ts_reg); > mod_timer(&w90p910_ts->timer, jiffies + > msecs_to_jiffies(40)); > } > > When changing to wait trigger mode(ADC_WAITTRIG),I have to close wait trigger(WT_INT) and ADC interrupt(ADC_INT), and start the timer to execute timer function,if pen still keep down,then opening the ADC interrupt again,so that it can continue to get values of X and > Y,but if pen keep up,opening wait trigger interrupt and closing ADC interrupt,so that we can wait the next pen in down. > > MY PATCH text: > > Add touchscreen drivers for w90p910 platform. > > Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> > > diff -Npur linux-2.6.29/drivers/input/touchscreen/Kconfig linux-2.6.30/drivers/input/touchscreen/Kconfig > --- linux-2.6.29/drivers/input/touchscreen/Kconfig 2009-05-01 12:28:54.000000000 +0800 > +++ linux-2.6.30/drivers/input/touchscreen/Kconfig 2009-05-10 14:47:07.000000000 +0800 > @@ -466,4 +466,11 @@ config TOUCHSCREEN_TSC2007 > To compile this driver as a module, choose M here: the > module will be called tsc2007. > > +config TOUCHSCREEN_W90X900 > + tristate "W90P910 touchscreen driver" > + depends on CPU_W90P910 > + help > + To compile this driver as a module, choose M here: the > + module will be called w90p910-ts. > + > endif > diff -Npur linux-2.6.29/drivers/input/touchscreen/Makefile linux-2.6.30/drivers/input/touchscreen/Makefile > --- linux-2.6.29/drivers/input/touchscreen/Makefile 2009-05-01 12:28:54.000000000 +0800 > +++ linux-2.6.30/drivers/input/touchscreen/Makefile 2009-05-09 07:34:12.000000000 +0800 > @@ -37,3 +37,4 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) + > wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o > obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o > obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o > +obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o > diff -Npur linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c > --- linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c 1970-01-01 08:00:00.000000000 +0800 > +++ linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c 2009-05-11 11:12:48.000000000 +0800 > @@ -0,0 +1,272 @@ > +/* > + * Copyright (c) 2008 Nuvoton technology corporation. > + * > + * Wan ZongShun <mcuos.com@gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation;version 2 of the License. > + * > + */ > + > +#include <linux/delay.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/io.h> > +#include <linux/input.h> > +#include <linux/interrupt.h> > + > +#include <mach/hardware.h> > + > +/*adc controller bit define*/ > +#define ADC_DELAY 0xf00 > +#define ADC_DOWN 0x01 > +#define ADC_TSC_Y (0x01 << 8) > +#define ADC_TSC_X (0x00 << 8) > +#define TSC_FOURWIRE (~(0x03 << 1)) > +#define ADC_CLK_EN (0x01 << 28)/*adc clock*/ > +#define ADC_READ_CON (0x01 << 12) > +#define ADC_CONV (0x01 << 13) > +#define ADC_SEMIAUTO (0x01 << 14) > +#define ADC_WAITTRIG (0x03 << 14) > +#define ADC_RST1 (0x01 << 16) > +#define ADC_RST0 (0x00 << 16) > +#define ADC_EN (0x01 << 17) > +#define ADC_INT (0x01 << 18)/*adc int status*/ > +#define WT_INT (0x01 << 20)/*wait trig int status*/ > +#define ADC_INT_EN (0x01 << 21)/*enable ADC_INT irq*/ > +#define LVD_INT_EN (0x01 << 22) > +#define WT_INT_EN (0x01 << 23)/*enable WT_INT irq*/ > +#define ADC_DIV (0x04 << 1)/*div=6*/ > + > +/*adc state define*/ > +enum ts_state { NO_PRESS, CAN_READX, CAN_READY }; > + > +struct w90p910drv_ts { > + struct input_dev *input; > + struct timer_list timer; > + int irq_num; > + int pendown; > + int clocken; > + void __iomem *ts_reg; > + short x; > + short y; > + spinlock_t lock; > + enum ts_state state; > +}; > + > +static void w90p910_report_event(struct w90p910drv_ts *w90p910_ts) > +{ > + struct input_dev *dev = w90p910_ts->input; > + > + w90p910_ts->x = __raw_readl(w90p910_ts->ts_reg+0x0c); > + w90p910_ts->y = __raw_readl(w90p910_ts->ts_reg+0x10); > + > + input_report_abs(dev, ABS_X, w90p910_ts->x); > + input_report_abs(dev, ABS_Y, w90p910_ts->y); > + input_report_key(dev, BTN_TOUCH, w90p910_ts->pendown); > + input_sync(dev); > +} > + > +static void w90p910_ts_interrupt(struct w90p910drv_ts *w90p910_ts) > +{ > + if ((__raw_readl(w90p910_ts->ts_reg)&WT_INT) && > + w90p910_ts->state == NO_PRESS) { > + w90p910_ts->pendown = 1; > + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&(~WT_INT|~WT_INT_EN), > + w90p910_ts->ts_reg); > + w90p910_ts->state = CAN_READX; > + } else { > + if (__raw_readl(w90p910_ts->ts_reg+0x04)&ADC_DOWN) { > + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg+0x04); > + > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_SEMIAUTO|ADC_INT_EN|ADC_CONV)&(~WT_INT_EN), > + w90p910_ts->ts_reg); > + w90p910_ts->pendown = 1; > + w90p910_ts->state = CAN_READX; > + } else { > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_WAITTRIG|WT_INT_EN)&(~ADC_INT_EN| > + ~WT_INT|~ADC_INT), w90p910_ts->ts_reg); > + w90p910_ts->pendown = 0; > + w90p910_ts->state = NO_PRESS; > + } > + } > + > + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && > + w90p910_ts->state == CAN_READX) { > + __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg+0x04); > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)|ADC_SEMIAUTO| > + ADC_INT_EN|ADC_CONV)&(~ADC_INT|~WT_INT_EN), > + w90p910_ts->ts_reg); > + w90p910_ts->state = CAN_READY; > + } > + > + if ((__raw_readl(w90p910_ts->ts_reg)&ADC_INT) && > + w90p910_ts->state == CAN_READY) { > + w90p910_report_event(w90p910_ts); > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_WAITTRIG)&(~ADC_INT|~WT_INT_EN|~ADC_INT_EN), > + w90p910_ts->ts_reg); > + mod_timer(&w90p910_ts->timer, jiffies + > + msecs_to_jiffies(40)); > + } > +} > + > +static void w90p910_ts_timer(unsigned long data) > +{ > + struct w90p910drv_ts *w90p910_data = (struct w90p910drv_ts *) data; > + unsigned long flags; > + > + spin_lock_irqsave(&w90p910_data->lock, flags); > + > + w90p910_ts_interrupt(w90p910_data); > + > + spin_unlock_irqrestore(&w90p910_data->lock, flags); > +} > + > +static irqreturn_t ts_interrupt(int irq, void *dev_id) > +{ > + struct w90p910drv_ts *w90p910_data = dev_id; > + > + w90p910_ts_interrupt(w90p910_data); > + return IRQ_HANDLED; > +} > + > +static int __devinit w90x900ts_probe(struct platform_device *pdev) > +{ > + struct w90p910drv_ts *w90p910_ts; > + struct input_dev *input_dev; > + int err = -ENOMEM; > + struct resource *res; > + > + w90p910_ts = kzalloc(sizeof(struct w90p910drv_ts), GFP_KERNEL); > + input_dev = input_allocate_device(); > + if (!w90p910_ts || !input_dev) > + goto fail1; > + > + platform_set_drvdata(pdev, w90p910_ts); > + > + w90p910_ts->input = input_dev; > + w90p910_ts->state = NO_PRESS; > + w90p910_ts->clocken = (int)W90X900_VA_CLKPWR; > + spin_lock_init(&w90p910_ts->lock); > + setup_timer(&w90p910_ts->timer, w90p910_ts_timer, > + (unsigned long)w90p910_ts); > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + err = -ENXIO; > + goto fail1; > + } > + > + if (!request_mem_region(res->start, res->end - res->start + 1, > + pdev->name)) { > + err = -EBUSY; > + goto fail1; > + } > + > + w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1); > + if (!w90p910_ts->ts_reg) { > + err = -ENOMEM; > + goto fail2; > + } > + > + /* enable the ADC clock */ > + __raw_writel(__raw_readl(w90p910_ts->clocken)|ADC_CLK_EN, > + w90p910_ts->clocken); > + > + input_dev->name = "W90P910 TouchScreen"; > + input_dev->phys = "w90p910ts/event0"; > + input_dev->id.bustype = BUS_HOST; > + input_dev->id.vendor = 0x0005; > + input_dev->id.product = 0x0001; > + input_dev->id.version = 0x0100; > + input_dev->dev.parent = &pdev->dev; > + input_dev->evbit[0] = BIT_MASK(EV_KEY)| > + BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN); > + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); > + > + input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0); > + input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0); > + > + w90p910_ts->irq_num = platform_get_irq(pdev, 0); > + if (request_irq(w90p910_ts->irq_num, ts_interrupt, IRQF_DISABLED, > + "w90p910ts", w90p910_ts)) { > + err = -EBUSY; > + goto fail3; > + } > + > + err = input_register_device(w90p910_ts->input); > + if (err) > + goto fail4; > + > + __raw_writel(ADC_RST1, w90p910_ts->ts_reg); > + msleep(1); > + __raw_writel(ADC_RST0, w90p910_ts->ts_reg); > + msleep(1); > + > + /* set delay and screen type */ > + __raw_writel(__raw_readl(w90p910_ts->ts_reg+0x04) & TSC_FOURWIRE, > + (w90p910_ts->ts_reg+0x04)); > + __raw_writel(ADC_DELAY, (w90p910_ts->ts_reg+0x08)); > + /* waitting for trigger mode */ > + __raw_writel((__raw_readl(w90p910_ts->ts_reg)| > + ADC_WAITTRIG|ADC_DIV|ADC_EN|WT_INT_EN), w90p910_ts->ts_reg); > + return 0; > + > +fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); > +fail3: iounmap(w90p910_ts->ts_reg); > +fail2: release_mem_region(res->start, res->end - res->start + 1); > +fail1: input_free_device(input_dev); > + kfree(w90p910_ts); > + return err; > +} > + > +static int __devexit w90x900ts_remove(struct platform_device *pdev) > +{ > + struct w90p910drv_ts *w90p910_ts = platform_get_drvdata(pdev); > + struct resource *res; > + > + free_irq(w90p910_ts->irq_num, w90p910_ts); > + del_timer_sync(&w90p910_ts->timer); > + iounmap(w90p910_ts->ts_reg); > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + release_mem_region(res->start, res->end - res->start + 1); > + > + input_unregister_device(w90p910_ts->input); > + kfree(w90p910_ts); > + > + return 0; > +} > + > +static struct platform_driver w90x900ts_driver = { > + .probe = w90x900ts_probe, > + .remove = __devexit_p(w90x900ts_remove), > + .driver = { > + .name = "w90x900-ts", > + .owner = THIS_MODULE, > + }, > +}; > + > +static int __init w90x900ts_init(void) > +{ > + return platform_driver_register(&w90x900ts_driver); > +} > + > +static void __exit w90x900ts_exit(void) > +{ > + platform_driver_unregister(&w90x900ts_driver); > +} > + > +module_init(w90x900ts_init); > +module_exit(w90x900ts_exit); > + > +MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); > +MODULE_DESCRIPTION("w90p910 touch screen driver!"); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:w90p910-ts"); > -- embedded forum http://mcuos.com -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <e68bb3470905172007i47a5435x7b87383323a1cf1a@mail.gmail.com>]
[parent not found: <200905181600.07651.dmitry.torokhov@gmail.com>]
[parent not found: <e68bb3470905182054g6d9dba05kabc6c588d35b3548@mail.gmail.com>]
[parent not found: <20090527141220.GA18589@dtor-d630.eng.vmware.com>]
[parent not found: <4A24C0A4.3040704@gmail.com>]
[parent not found: <20090602092031.GA2647@dtor-d630.eng.vmware.com>]
* Re: [PATCH] Add support for touch screen on W90P910 ARM platform [not found] ` <20090602092031.GA2647@dtor-d630.eng.vmware.com> @ 2009-06-02 11:13 ` Wan ZongShun 2009-06-02 13:57 ` Dmitry Torokhov 0 siblings, 1 reply; 10+ messages in thread From: Wan ZongShun @ 2009-06-02 11:13 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: linux-input, Vincent Wan Dear Dmitry , Thank you for giving me help again. 2009/6/2, Dmitry Torokhov <dmitry.torokhov@gmail.com>: > Hi Wan, > > On Tue, Jun 02, 2009 at 02:03:16PM +0800, Wan ZongShun wrote: > > Dear Dmitry, > > > > Thank you for your clear patch,it looks much better than mine. > > > > For to make this driver work well,I have modified a piece of code > > and made a patch based on your patch given me. > > > > Hope to get some advice from you again. thanks a lot. > > > > --- > > w90p910 touch screen driver patch. > > > > Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> > > > > --- linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c > > +++ linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c > > @@ -76,7 +76,7 @@ > > __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg + 0x04); > > ctlreg = __raw_readl(w90p910_ts->ts_reg); > > ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; > > - ctlreg &= ~(ADC_WAITTRIG | WT_INT_EN); > > + ctlreg &= ~(WT_INT|ADC_WAITTRIG | WT_INT_EN); > > Do we really need to reset WT_INT bit? I would think it was a read-only > bit set by the hardware... >From the w90p910 spec ,WT_INT should be clear by soft, and set by hardware, so I have to add code to clear it here. > > > __raw_writel(ctlreg, w90p910_ts->ts_reg); > > > > w90p910_ts->state = TS_WAIT_X_COORD; > > @@ -89,7 +89,7 @@ > > __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg + 0x04); > > ctlreg = __raw_readl(w90p910_ts->ts_reg); > > ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; > > - ctlreg &= ~(ADC_WAITTRIG | WT_INT_EN); > > + ctlreg &= ~(ADC_INT|ADC_WAITTRIG | WT_INT_EN); > > Same here with ADC_INT. >From the w90p910 spec ,ADC_INT should be clear by soft, and set by hardware, so I have to add code to clear it here too. > > > __raw_writel(ctlreg, w90p910_ts->ts_reg); > > > > w90p910_ts->state = TS_WAIT_Y_COORD; > > @@ -110,21 +110,14 @@ > > static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id) > > { > > struct w90p910_ts *w90p910_ts = dev_id; > > - unsigned long flags; > > + unsigned long flags, val; > > > > spin_lock_irqsave(&w90p910_ts->lock, flags); > > > > switch (w90p910_ts->state) { > > case TS_WAIT_NEW_PACKET: > > - if (__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN) { > > - w90p910_prepare_x_reading(w90p910_ts); > > - } else { > > - w90p910_report_event(w90p910_ts, false); > > - del_timer(&w90p910_ts->timer); > > - w90p910_prepare_next_packet(w90p910_ts); > > - } > > + w90p910_prepare_x_reading(w90p910_ts); > > OK, so it is not possible to get an interrupt when pen leaves the > screen, it only generates interrupts while we are touching it, > correct? Okay,you are right, according to the spec,only the interrupt can occur when touching it . > > > break; > > - > > > > case TS_WAIT_X_COORD: > > w90p910_prepare_y_reading(w90p910_ts); > > @@ -132,7 +125,15 @@ > > > > case TS_WAIT_Y_COORD: > > w90p910_report_event(w90p910_ts, true); > > - w90p910_prepare_next_packet(w90p910_ts); > > + > > + /* When timer starts,it should disable all ts > > + * interrupt and change mode to wait trigger. > > + */ > > + val = __raw_readl(w90p910_ts->ts_reg); > > + val |= ADC_WAITTRIG; > > + val &= ~(ADC_INT | ADC_INT_EN | WT_INT_EN); > > + __raw_writel(val, w90p910_ts->ts_reg); > > + > > I am not sure about this... are you positive that we can't continue > working the device in interrupt mode and have to resort to polling > after the first touch has been registered? After the first touch occur, with the help of the timer callback function, I want to know if the pen still keep down.and if it keep up,I will think the first touch has finished and I will close timer, change mode to wait trigger and enable the WT interrupt for waitting next touch, so next touch also rely on the WT interrupt. I assume a situation that I make a line by pen in my touchscreen and get all values of x and y to user regarding the line,for that,I need to press my pen and keep it down and moving for making the line,then I put up my pen,so the lines has been finished. I think the timer should be in one shot mode and only does the judge whether my pen still keep down or up. and if pen keep down, we can enable the ADC interrupt and continue to read values (x and y) of the line,contrarily(if pen up),I think the line has been finished and have to change to wait trigger mode and enable WT interrupt and wait next touch occur. > > > mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(40)); > > break; > > > > @@ -152,11 +153,11 @@ > > > > spin_lock_irqsave(&w90p910_ts->lock, flags); > > > > - if (w90p910_ts->state == TS_WAIT_NEW_PACKET && > > - !(__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN)) { > > - > > + if (!(__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN)) { > > w90p910_report_event(w90p910_ts, false); > > w90p910_prepare_next_packet(w90p910_ts); > > + } else { > > + w90p910_prepare_x_reading(w90p910_ts); > > } > > > > spin_unlock_irqrestore(&w90p910_ts->lock, flags); > > @@ -185,6 +186,9 @@ > > val = __raw_readl(w90p910_ts->ts_reg); > > val |= ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN; > > __raw_writel(val, w90p910_ts->ts_reg); > > + > > + /* set a waitting new press state */ > > + w90p910_ts->state = TS_WAIT_NEW_PACKET; > > > > return 0; > > } > > > > Thanks! > > -- > Dmitry > -- embedded forum http://mcuos.com ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Add support for touch screen on W90P910 ARM platform 2009-06-02 11:13 ` Wan ZongShun @ 2009-06-02 13:57 ` Dmitry Torokhov 0 siblings, 0 replies; 10+ messages in thread From: Dmitry Torokhov @ 2009-06-02 13:57 UTC (permalink / raw) To: Wan ZongShun; +Cc: linux-input On Tue, Jun 02, 2009 at 07:13:20PM +0800, Wan ZongShun wrote: > Dear Dmitry , > > Thank you for giving me help again. > > 2009/6/2, Dmitry Torokhov <dmitry.torokhov@gmail.com>: > > Hi Wan, > > > > On Tue, Jun 02, 2009 at 02:03:16PM +0800, Wan ZongShun wrote: > > > Dear Dmitry, > > > > > > Thank you for your clear patch,it looks much better than mine. > > > > > > For to make this driver work well,I have modified a piece of code > > > and made a patch based on your patch given me. > > > > > > Hope to get some advice from you again. thanks a lot. > > > > > > --- > > > w90p910 touch screen driver patch. > > > > > > Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> > > > > > > --- linux-2.6.29/drivers/input/touchscreen/w90p910_ts.c > > > +++ linux-2.6.30/drivers/input/touchscreen/w90p910_ts.c > > > @@ -76,7 +76,7 @@ > > > __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg + 0x04); > > > ctlreg = __raw_readl(w90p910_ts->ts_reg); > > > ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; > > > - ctlreg &= ~(ADC_WAITTRIG | WT_INT_EN); > > > + ctlreg &= ~(WT_INT|ADC_WAITTRIG | WT_INT_EN); > > > > Do we really need to reset WT_INT bit? I would think it was a read-only > > bit set by the hardware... > > From the w90p910 spec ,WT_INT should be clear by soft, and set by hardware, > so I have to add code to clear it here. > I see. > > > > > __raw_writel(ctlreg, w90p910_ts->ts_reg); > > > > > > w90p910_ts->state = TS_WAIT_X_COORD; > > > @@ -89,7 +89,7 @@ > > > __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg + 0x04); > > > ctlreg = __raw_readl(w90p910_ts->ts_reg); > > > ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; > > > - ctlreg &= ~(ADC_WAITTRIG | WT_INT_EN); > > > + ctlreg &= ~(ADC_INT|ADC_WAITTRIG | WT_INT_EN); > > > > Same here with ADC_INT. > > From the w90p910 spec ,ADC_INT should be clear by soft, and set by hardware, > so I have to add code to clear it here too. > OK. > > > > > __raw_writel(ctlreg, w90p910_ts->ts_reg); > > > > > > w90p910_ts->state = TS_WAIT_Y_COORD; > > > @@ -110,21 +110,14 @@ > > > static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id) > > > { > > > struct w90p910_ts *w90p910_ts = dev_id; > > > - unsigned long flags; > > > + unsigned long flags, val; > > > > > > spin_lock_irqsave(&w90p910_ts->lock, flags); > > > > > > switch (w90p910_ts->state) { > > > case TS_WAIT_NEW_PACKET: > > > - if (__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN) { > > > - w90p910_prepare_x_reading(w90p910_ts); > > > - } else { > > > - w90p910_report_event(w90p910_ts, false); > > > - del_timer(&w90p910_ts->timer); > > > - w90p910_prepare_next_packet(w90p910_ts); > > > - } > > > + w90p910_prepare_x_reading(w90p910_ts); > > > > OK, so it is not possible to get an interrupt when pen leaves the > > screen, it only generates interrupts while we are touching it, > > correct? > > Okay,you are right, according to the spec,only the interrupt can occur > when touching it . > I see. > > > > > break; > > > - > > > > > > case TS_WAIT_X_COORD: > > > w90p910_prepare_y_reading(w90p910_ts); > > > @@ -132,7 +125,15 @@ > > > > > > case TS_WAIT_Y_COORD: > > > w90p910_report_event(w90p910_ts, true); > > > - w90p910_prepare_next_packet(w90p910_ts); > > > + > > > + /* When timer starts,it should disable all ts > > > + * interrupt and change mode to wait trigger. > > > + */ > > > + val = __raw_readl(w90p910_ts->ts_reg); > > > + val |= ADC_WAITTRIG; > > > + val &= ~(ADC_INT | ADC_INT_EN | WT_INT_EN); > > > + __raw_writel(val, w90p910_ts->ts_reg); > > > + > > > > I am not sure about this... are you positive that we can't continue > > working the device in interrupt mode and have to resort to polling > > after the first touch has been registered? > > After the first touch occur, with the help of the timer callback > function, I want to know if the pen still keep down.and if it keep > up,I will think the first touch has finished and I will close timer, > change mode to wait trigger and enable the WT interrupt for waitting > next touch, so next touch also rely on the WT interrupt. > > I assume a situation that I make a line by pen in my touchscreen and > get all values of x and y to user regarding the line,for that,I need > to press my pen and keep it down and moving for making the line,then I > put up my pen,so the lines has been finished. > > I think the timer should be in one shot mode and only does the judge > whether my pen still keep down or up. and if pen keep down, we can > enable the ADC interrupt and continue to read values (x and y) of the > line,contrarily(if pen up),I think the line has been finished and have > to change to wait trigger mode and enable WT interrupt and wait next > touch occur. > I see what are you trying to do here, but you you seem to be polling your device every 40 ms. I wonder if we rely on interrupts to give us the continuous stream of coordinates while the pen is touching the screen and make timer to poll for "pen up" event every 200 msecs would not give better results with lesser load on the system? - Dmitry ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2009-06-02 13:57 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-04-27 15:03 [PATCH] Add support for touch screen on W90P910 ARM platform Wan ZongShun 2009-05-08 3:41 ` Dmitry Torokhov 2009-05-09 1:30 ` Wan ZongShun 2009-05-09 19:54 ` Dmitry Torokhov 2009-05-10 10:35 ` Wan ZongShun 2009-05-10 20:15 ` Dmitry Torokhov 2009-05-11 3:58 ` Wan ZongShun 2009-05-12 1:07 ` Wan ZongShun [not found] ` <e68bb3470905172007i47a5435x7b87383323a1cf1a@mail.gmail.com> [not found] ` <200905181600.07651.dmitry.torokhov@gmail.com> [not found] ` <e68bb3470905182054g6d9dba05kabc6c588d35b3548@mail.gmail.com> [not found] ` <20090527141220.GA18589@dtor-d630.eng.vmware.com> [not found] ` <4A24C0A4.3040704@gmail.com> [not found] ` <20090602092031.GA2647@dtor-d630.eng.vmware.com> 2009-06-02 11:13 ` Wan ZongShun 2009-06-02 13:57 ` Dmitry Torokhov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).