Re: [PATCH] Add support for touch screen on W90P910 ARM platform

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx>
> 
> 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@xxxxxxxxx>
> + *
> + * 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@xxxxxxxxx>
> + *
> + * 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@xxxxxxxxx>");
> +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
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux