From 72398e4b1a4cf55d3698a4f265b638093a470b04 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 7 Jul 2009 22:04:55 -0700 Subject: Input: use resource_size when allocating resources Use the function resource_size, which reduces the chance of introducing off-by-one errors in calculating the resource size. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ struct resource *res; @@ - (res->end - res->start) + 1 + resource_size(res) // Signed-off-by: Julia Lawall Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_tsadcc.c | 8 ++++---- drivers/input/touchscreen/w90p910_ts.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 055969e..9c7fce4 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -204,14 +204,14 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) goto err_free_dev; } - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), "atmel tsadcc regs")) { dev_err(&pdev->dev, "resources is unavailable.\n"); err = -EBUSY; goto err_free_dev; } - tsc_base = ioremap(res->start, res->end - res->start + 1); + tsc_base = ioremap(res->start, resource_size(res)); if (!tsc_base) { dev_err(&pdev->dev, "failed to map registers.\n"); err = -ENOMEM; @@ -286,7 +286,7 @@ err_free_irq: err_unmap_regs: iounmap(tsc_base); err_release_mem: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); err_free_dev: input_free_device(ts_dev->input); err_free_mem: @@ -305,7 +305,7 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap(tsc_base); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); clk_disable(ts_dev->clk); clk_put(ts_dev->clk); diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index 6071f58..b3e782f 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -241,13 +241,13 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) goto fail1; } - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { err = -EBUSY; goto fail1; } - w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1); + w90p910_ts->ts_reg = ioremap(res->start, resource_size(res)); if (!w90p910_ts->ts_reg) { err = -ENOMEM; goto fail2; @@ -296,7 +296,7 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) 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); +fail2: release_mem_region(res->start, resource_size(res)); fail1: input_free_device(input_dev); kfree(w90p910_ts); return err; @@ -312,7 +312,7 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev) iounmap(w90p910_ts->ts_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); input_unregister_device(w90p910_ts->input); kfree(w90p910_ts); -- cgit v1.1 From f7370699fbbb18f97442d6f47cc2d478a911ad6f Mon Sep 17 00:00:00 2001 From: Jim Persson Date: Tue, 7 Jul 2009 22:07:59 -0700 Subject: Input: usbtouchscreen - support for JASTEC/DigiTech DTR-02U USB touch controllers Add support for the JASTEC/DigiTech DTR-02U USB touch screen controllers. Signed-off-by: Jim Persson Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 6 ++++++ drivers/input/touchscreen/usbtouchscreen.c | 32 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 72e2712..a66e50a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -406,6 +406,7 @@ config TOUCHSCREEN_USB_COMPOSITE - IRTOUCHSYSTEMS/UNITOP - IdealTEK URTC1000 - GoTop Super_Q2/GogoPen/PenPower tablets + - JASTEC USB Touch Controller/DigiTech DTR-02U Have a look at for a usage description and the required user-space stuff. @@ -468,6 +469,11 @@ config TOUCHSCREEN_USB_GOTOP bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE +config TOUCHSCREEN_USB_JASTEC + default y + bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + config TOUCHSCREEN_TOUCHIT213 tristate "Sahara TouchIT-213 touchscreen" select SERIO diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index fb7cb9b..c07be07 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -13,6 +13,7 @@ * - IdealTEK URTC1000 * - General Touch * - GoTop Super_Q2/GogoPen/PenPower tablets + * - JASTEC USB touch controller/DigiTech DTR-02U * * Copyright (C) 2004-2007 by Daniel Ritz * Copyright (C) by Todd E. Johnson (mtouchusb.c) @@ -118,6 +119,7 @@ enum { DEVTYPE_IDEALTEK, DEVTYPE_GENERAL_TOUCH, DEVTYPE_GOTOP, + DEVTYPE_JASTEC, }; #define USB_DEVICE_HID_CLASS(vend, prod) \ @@ -191,6 +193,10 @@ static struct usb_device_id usbtouch_devices[] = { {USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP}, #endif +#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC + {USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC}, +#endif + {} }; @@ -559,6 +565,21 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt) dev->x = ((pkt[1] & 0x38) << 4) | pkt[2]; dev->y = ((pkt[1] & 0x07) << 7) | pkt[3]; dev->touch = pkt[0] & 0x01; + + return 1; +} +#endif + +/***************************************************************************** + * JASTEC Part + */ +#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC +static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f); + dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f); + dev->touch = (pkt[0] & 0x40) >> 6; + return 1; } #endif @@ -702,6 +723,17 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .read_data = gotop_read_data, }, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC + [DEVTYPE_JASTEC] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .rept_size = 4, + .read_data = jastec_read_data, + }, +#endif }; -- cgit v1.1 From f9c22736940cdc8f5e2db0109fc9493e0cbd895d Mon Sep 17 00:00:00 2001 From: "Hans J. Koch" Date: Sun, 12 Jul 2009 20:51:25 -0700 Subject: Input: ucb1400_ts - fix a misleading function name The driver for UCB1400 touchscreen controllers contains a function named ucb1400_ts_pen_down(), but it returns 0 if the pen is down and 1 if it's up. This causes confusion, especially since it's used as a boolean truth value later in the code. This patch renames it. Signed-off-by: Hans J. Koch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ucb1400_ts.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 6954f55..e854835 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -128,9 +128,10 @@ static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb) return ucb1400_adc_read(ucb->ac97, 0, adcsync); } -static inline int ucb1400_ts_pen_down(struct snd_ac97 *ac97) +static inline int ucb1400_ts_pen_up(struct snd_ac97 *ac97) { unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR); + return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW); } @@ -209,7 +210,7 @@ static int ucb1400_ts_thread(void *_ucb) msleep(10); - if (ucb1400_ts_pen_down(ucb->ac97)) { + if (ucb1400_ts_pen_up(ucb->ac97)) { ucb1400_ts_irq_enable(ucb->ac97); /* -- cgit v1.1 From b7788c5ff9e7676dc98ca6dce437ae16b79c6726 Mon Sep 17 00:00:00 2001 From: Wan ZongShun Date: Sun, 12 Jul 2009 20:52:19 -0700 Subject: Input: w90p910_ts - use clk API Now that clk API is available on ARM we can use it in the driver. Signed-off-by: Wan ZongShun Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 1 + drivers/input/touchscreen/w90p910_ts.c | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a66e50a..1c05b32 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -498,6 +498,7 @@ config TOUCHSCREEN_TSC2007 config TOUCHSCREEN_W90X900 tristate "W90P910 touchscreen driver" + depends on HAVE_CLK help Say Y here if you have a W90P910 based touchscreen. diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index b3e782f..dc4c9d6 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -47,8 +48,8 @@ enum ts_state { struct w90p910_ts { struct input_dev *input; struct timer_list timer; + struct clk *clk; int irq_num; - void __iomem *clocken; void __iomem *ts_reg; spinlock_t lock; enum ts_state state; @@ -166,8 +167,7 @@ static int w90p910_open(struct input_dev *dev) unsigned long val; /* enable the ADC clock */ - val = __raw_readl(w90p910_ts->clocken); - __raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken); + clk_enable(w90p910_ts->clk); __raw_writel(ADC_RST1, w90p910_ts->ts_reg); msleep(1); @@ -211,8 +211,7 @@ static void w90p910_close(struct input_dev *dev) del_timer_sync(&w90p910_ts->timer); /* stop the ADC clock */ - val = __raw_readl(w90p910_ts->clocken); - __raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken); + clk_disable(w90p910_ts->clk); } static int __devinit w90x900ts_probe(struct platform_device *pdev) @@ -253,14 +252,12 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) goto fail2; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - err = -ENXIO; + w90p910_ts->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(w90p910_ts->clk)) { + err = PTR_ERR(w90p910_ts->clk); goto fail3; } - w90p910_ts->clocken = (void __iomem *)res->start; - input_dev->name = "W90P910 TouchScreen"; input_dev->phys = "w90p910ts/event0"; input_dev->id.bustype = BUS_HOST; @@ -283,18 +280,19 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt, IRQF_DISABLED, "w90p910ts", w90p910_ts)) { err = -EBUSY; - goto fail3; + goto fail4; } err = input_register_device(w90p910_ts->input); if (err) - goto fail4; + goto fail5; platform_set_drvdata(pdev, w90p910_ts); return 0; -fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); +fail5: free_irq(w90p910_ts->irq_num, w90p910_ts); +fail4: clk_put(w90p910_ts->clk); fail3: iounmap(w90p910_ts->ts_reg); fail2: release_mem_region(res->start, resource_size(res)); fail1: input_free_device(input_dev); @@ -311,6 +309,8 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev) del_timer_sync(&w90p910_ts->timer); iounmap(w90p910_ts->ts_reg); + clk_put(w90p910_ts->clk); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); -- cgit v1.1 From b833306febc7d9b805a89aff29f1e410a64981c4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 20 Jul 2009 22:26:37 -0700 Subject: Input: wm97xx - add Palm support to Mainstone accelerated touch This patch refactors the Mainstone accelerated touch code a little and adds support for interrupt driven touchscreen on Palm LifeDrive, TX and Tungsten T5. Signed-off-by: Marek Vasut Acked-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 4 +-- drivers/input/touchscreen/mainstone-wm97xx.c | 50 ++++++++++++++++++---------- 2 files changed, 35 insertions(+), 19 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1c05b32..07703bc 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -366,11 +366,11 @@ config TOUCHSCREEN_WM97XX_ATMEL be called atmel-wm97xx. config TOUCHSCREEN_WM97XX_MAINSTONE - tristate "WM97xx Mainstone accelerated touch" + tristate "WM97xx Mainstone/Palm accelerated touch" depends on TOUCHSCREEN_WM97XX && ARCH_PXA help Say Y here for support for streaming mode with WM97xx touchscreens - on Mainstone systems. + on Mainstone, Palm Tungsten T5, TX and LifeDrive systems. If unsure, say N. diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index 4cc047a..c797bc0 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -31,9 +31,11 @@ #include #include #include +#include + #include -#define VERSION "0.13" +#include struct continuous { u16 id; /* codec id */ @@ -62,6 +64,7 @@ static const struct continuous cinfo[] = { /* continuous speed index */ static int sp_idx; static u16 last, tries; +static int irq; /* * Pen sampling frequency (Hz) in continuous mode. @@ -171,7 +174,7 @@ up: static int wm97xx_acc_startup(struct wm97xx *wm) { - int idx = 0; + int idx = 0, ret = 0; /* check we have a codec */ if (wm->ac97 == NULL) @@ -191,18 +194,37 @@ static int wm97xx_acc_startup(struct wm97xx *wm) "mainstone accelerated touchscreen driver, %d samples/sec\n", cinfo[sp_idx].speed); + /* IRQ driven touchscreen is used on Palm hardware */ + if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) { + pen_int = 1; + irq = 27; + } else if (machine_is_mainstone() && pen_int) + irq = 4; + + if (irq) { + ret = gpio_request(irq, "Touchscreen IRQ"); + if (ret) + goto out; + + ret = gpio_direction_input(irq); + if (ret) { + gpio_free(irq); + goto out; + } + + wm->pen_irq = gpio_to_irq(irq); + set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); + } else /* pen irq not supported */ + pen_int = 0; + /* codec specific irq config */ if (pen_int) { switch (wm->id) { case WM9705_ID2: - wm->pen_irq = IRQ_GPIO(4); - set_irq_type(IRQ_GPIO(4), IRQ_TYPE_EDGE_BOTH); break; case WM9712_ID2: case WM9713_ID2: - /* enable pen down interrupt */ /* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */ - wm->pen_irq = MAINSTONE_AC97_IRQ; wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_STICKY, @@ -220,23 +242,17 @@ static int wm97xx_acc_startup(struct wm97xx *wm) } } - return 0; +out: + return ret; } static void wm97xx_acc_shutdown(struct wm97xx *wm) { /* codec specific deconfig */ if (pen_int) { - switch (wm->id & 0xffff) { - case WM9705_ID2: - wm->pen_irq = 0; - break; - case WM9712_ID2: - case WM9713_ID2: - /* disable interrupt */ - wm->pen_irq = 0; - break; - } + if (irq) + gpio_free(irq); + wm->pen_irq = 0; } } -- cgit v1.1 From 99fde513f57db2c8e1b202ade4be7d47033ff09b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 20 Jul 2009 22:28:50 -0700 Subject: Input: wm97xx - add possibility to control the GPIO_STATUS shift This patch allows tweaking the behaviour of GPIO_STATUS register shift quirk that's in wm97xx-core. The problem with GPIO_STATUS register being shifted by one doesn't appear on all hardware it seems and causes problems with accelerated touchscreen drivers on Palm hardware. Therefore an accelerated touchscreen driver can select if the shift is/isn't happening on the hardware. Signed-off-by: Marek Vasut Acked-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mainstone-wm97xx.c | 3 +++ drivers/input/touchscreen/wm97xx-core.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index c797bc0..8fc3b08 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -198,6 +198,9 @@ static int wm97xx_acc_startup(struct wm97xx *wm) if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) { pen_int = 1; irq = 27; + /* There is some obscure mutant of WM9712 interbred with WM9713 + * used on Palm HW */ + wm->variant = WM97xx_WM1613; } else if (machine_is_mainstone() && pen_int) irq = 4; diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 2957d48..252eb11 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -204,7 +204,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, else reg &= ~gpio; - if (wm->id == WM9712_ID2) + if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613) wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1); else wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg); @@ -307,7 +307,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) WM97XX_GPIO_13); } - if (wm->id == WM9712_ID2) + if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613) wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status & ~WM97XX_GPIO_13) << 1); else @@ -582,6 +582,8 @@ static int wm97xx_probe(struct device *dev) wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2); + wm->variant = WM97xx_GENERIC; + dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff); switch (wm->id & 0xff) { -- cgit v1.1 From 75fba3b05d6ed82b975c1f8df8f8e08d5d81dee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20R=C3=B6jfors?= Date: Fri, 24 Jul 2009 22:01:39 -0700 Subject: Input: tsc2007 - remove HR timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since it's not allowed to do synchronous I2C in the HR timer callback context we have to switch to using the global workqueue. The work is scheduled every 1ms when polling rather than 5 us. Signed-off-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 48 ++++++++++--------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 880f58c..b512697 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -21,15 +21,13 @@ */ #include -#include #include #include #include #include #include -#define TS_POLL_DELAY (10 * 1000) /* ns delay before the first sample */ -#define TS_POLL_PERIOD (5 * 1000) /* ns delay between samples */ +#define TS_POLL_PERIOD msecs_to_jiffies(1) /* ms delay between samples */ #define TSC2007_MEASURE_TEMP0 (0x0 << 4) #define TSC2007_MEASURE_AUX (0x2 << 4) @@ -70,13 +68,11 @@ struct ts_event { struct tsc2007 { struct input_dev *input; char phys[32]; - struct hrtimer timer; + struct delayed_work work; struct ts_event tc; struct i2c_client *client; - spinlock_t lock; - u16 model; u16 x_plate_ohms; @@ -142,8 +138,7 @@ static void tsc2007_send_event(void *tsc) if (rt > MAX_12BIT) { dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); + schedule_delayed_work(&ts->work, TS_POLL_PERIOD); return; } @@ -153,7 +148,7 @@ static void tsc2007_send_event(void *tsc) * in some cases may not even settle at the expected value. * * The only safe way to check for the pen up condition is in the - * timer by reading the pen signal state (it's a GPIO _and_ IRQ). + * work function by reading the pen signal state (it's a GPIO and IRQ). */ if (rt) { struct input_dev *input = ts->input; @@ -175,8 +170,7 @@ static void tsc2007_send_event(void *tsc) x, y, rt); } - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); + schedule_delayed_work(&ts->work, TS_POLL_PERIOD); } static int tsc2007_read_values(struct tsc2007 *tsc) @@ -197,13 +191,10 @@ static int tsc2007_read_values(struct tsc2007 *tsc) return 0; } -static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle) +static void tsc2007_work(struct work_struct *work) { - struct tsc2007 *ts = container_of(handle, struct tsc2007, timer); - unsigned long flags; - - spin_lock_irqsave(&ts->lock, flags); - + struct tsc2007 *ts = + container_of(to_delayed_work(work), struct tsc2007, work); if (unlikely(!ts->get_pendown_state() && ts->pendown)) { struct input_dev *input = ts->input; @@ -222,30 +213,20 @@ static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle) tsc2007_read_values(ts); tsc2007_send_event(ts); } - - spin_unlock_irqrestore(&ts->lock, flags); - - return HRTIMER_NORESTART; } static irqreturn_t tsc2007_irq(int irq, void *handle) { struct tsc2007 *ts = handle; - unsigned long flags; - - spin_lock_irqsave(&ts->lock, flags); if (likely(ts->get_pendown_state())) { disable_irq_nosync(ts->irq); - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), - HRTIMER_MODE_REL); + schedule_delayed_work(&ts->work, 0); } if (ts->clear_penirq) ts->clear_penirq(); - spin_unlock_irqrestore(&ts->lock, flags); - return IRQ_HANDLED; } @@ -278,11 +259,6 @@ static int tsc2007_probe(struct i2c_client *client, ts->input = input_dev; - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ts->timer.function = tsc2007_timer; - - spin_lock_init(&ts->lock); - ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; ts->get_pendown_state = pdata->get_pendown_state; @@ -308,6 +284,8 @@ static int tsc2007_probe(struct i2c_client *client, ts->irq = client->irq; + INIT_DELAYED_WORK(&ts->work, tsc2007_work); + err = request_irq(ts->irq, tsc2007_irq, 0, client->dev.driver->name, ts); if (err < 0) { @@ -325,7 +303,6 @@ static int tsc2007_probe(struct i2c_client *client, err_free_irq: free_irq(ts->irq, ts); - hrtimer_cancel(&ts->timer); err_free_mem: input_free_device(input_dev); kfree(ts); @@ -337,11 +314,12 @@ static int tsc2007_remove(struct i2c_client *client) struct tsc2007 *ts = i2c_get_clientdata(client); struct tsc2007_platform_data *pdata; + cancel_delayed_work_sync(&ts->work); + pdata = client->dev.platform_data; pdata->exit_platform_hw(); free_irq(ts->irq, ts); - hrtimer_cancel(&ts->timer); input_unregister_device(ts->input); kfree(ts); -- cgit v1.1 From 141586bc57f6083f36c18d86e1cfa5916a1e7c05 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Jul 2009 23:14:16 -0700 Subject: Input: tsc2007 - properly shut off interrupts/delayed work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Properly shut off interrupts/delayed work by free-ing IRQ first and then ensuring that enable/disable is balanced. Also add __devinit/__devexit markings, restore poll delay/period scheduling logic, make sure we call exit_platform_hw() method when probe fails. Tested-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 72 +++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 30 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index b512697..75fbd75 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -27,7 +27,8 @@ #include #include -#define TS_POLL_PERIOD msecs_to_jiffies(1) /* ms delay between samples */ +#define TS_POLL_DELAY 1 /* ms delay between samples */ +#define TS_POLL_PERIOD 1 /* ms delay between samples */ #define TSC2007_MEASURE_TEMP0 (0x0 << 4) #define TSC2007_MEASURE_AUX (0x2 << 4) @@ -76,7 +77,7 @@ struct tsc2007 { u16 model; u16 x_plate_ohms; - unsigned pendown; + bool pendown; int irq; int (*get_pendown_state)(void); @@ -131,18 +132,18 @@ static void tsc2007_send_event(void *tsc) } else rt = 0; - /* Sample found inconsistent by debouncing or pressure is beyond + /* + * Sample found inconsistent by debouncing or pressure is beyond * the maximum. Don't report it to user space, repeat at least * once more the measurement */ if (rt > MAX_12BIT) { dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); - - schedule_delayed_work(&ts->work, TS_POLL_PERIOD); return; } - /* NOTE: We can't rely on the pressure to determine the pen down + /* + * NOTE: We can't rely on the pressure to determine the pen down * state, even this controller has a pressure sensor. The pressure * value can fluctuate for quite a while after lifting the pen and * in some cases may not even settle at the expected value. @@ -157,7 +158,7 @@ static void tsc2007_send_event(void *tsc) dev_dbg(&ts->client->dev, "DOWN\n"); input_report_key(input, BTN_TOUCH, 1); - ts->pendown = 1; + ts->pendown = true; } input_report_abs(input, ABS_X, x); @@ -169,8 +170,6 @@ static void tsc2007_send_event(void *tsc) dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n", x, y, rt); } - - schedule_delayed_work(&ts->work, TS_POLL_PERIOD); } static int tsc2007_read_values(struct tsc2007 *tsc) @@ -195,6 +194,7 @@ static void tsc2007_work(struct work_struct *work) { struct tsc2007 *ts = container_of(to_delayed_work(work), struct tsc2007, work); + if (unlikely(!ts->get_pendown_state() && ts->pendown)) { struct input_dev *input = ts->input; @@ -204,7 +204,7 @@ static void tsc2007_work(struct work_struct *work) input_report_abs(input, ABS_PRESSURE, 0); input_sync(input); - ts->pendown = 0; + ts->pendown = false; enable_irq(ts->irq); } else { /* pen is still down, continue with the measurement */ @@ -212,6 +212,9 @@ static void tsc2007_work(struct work_struct *work) tsc2007_read_values(ts); tsc2007_send_event(ts); + + schedule_delayed_work(&ts->work, + msecs_to_jiffies(TS_POLL_PERIOD)); } } @@ -221,7 +224,8 @@ static irqreturn_t tsc2007_irq(int irq, void *handle) if (likely(ts->get_pendown_state())) { disable_irq_nosync(ts->irq); - schedule_delayed_work(&ts->work, 0); + schedule_delayed_work(&ts->work, + msecs_to_jiffies(TS_POLL_DELAY)); } if (ts->clear_penirq) @@ -230,8 +234,21 @@ static irqreturn_t tsc2007_irq(int irq, void *handle) return IRQ_HANDLED; } -static int tsc2007_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static void tsc2007_free_irq(struct tsc2007 *ts) +{ + free_irq(ts->irq, ts); + if (cancel_delayed_work_sync(&ts->work)) { + /* + * Work was pending, therefore we need to enable + * IRQ here to balance the disable_irq() done in the + * interrupt handler. + */ + enable_irq(ts->irq); + } +} + +static int __devinit tsc2007_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tsc2007 *ts; struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data; @@ -255,17 +272,15 @@ static int tsc2007_probe(struct i2c_client *client, } ts->client = client; - i2c_set_clientdata(client, ts); - + ts->irq = client->irq; ts->input = input_dev; + INIT_DELAYED_WORK(&ts->work, tsc2007_work); ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; ts->get_pendown_state = pdata->get_pendown_state; ts->clear_penirq = pdata->clear_penirq; - pdata->init_platform_hw(); - snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); @@ -280,11 +295,7 @@ static int tsc2007_probe(struct i2c_client *client, input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); - tsc2007_read_values(ts); - - ts->irq = client->irq; - - INIT_DELAYED_WORK(&ts->work, tsc2007_work); + pdata->init_platform_hw(); err = request_irq(ts->irq, tsc2007_irq, 0, client->dev.driver->name, ts); @@ -297,29 +308,30 @@ static int tsc2007_probe(struct i2c_client *client, if (err) goto err_free_irq; - dev_info(&client->dev, "registered with irq (%d)\n", ts->irq); + i2c_set_clientdata(client, ts); + + tsc2007_read_values(ts); return 0; err_free_irq: - free_irq(ts->irq, ts); + tsc2007_free_irq(ts); + pdata->exit_platform_hw(); err_free_mem: input_free_device(input_dev); kfree(ts); return err; } -static int tsc2007_remove(struct i2c_client *client) +static int __devexit tsc2007_remove(struct i2c_client *client) { struct tsc2007 *ts = i2c_get_clientdata(client); - struct tsc2007_platform_data *pdata; + struct tsc2007_platform_data *pdata = client->dev.platform_data; - cancel_delayed_work_sync(&ts->work); + tsc2007_free_irq(ts); - pdata = client->dev.platform_data; pdata->exit_platform_hw(); - free_irq(ts->irq, ts); input_unregister_device(ts->input); kfree(ts); @@ -340,7 +352,7 @@ static struct i2c_driver tsc2007_driver = { }, .id_table = tsc2007_idtable, .probe = tsc2007_probe, - .remove = tsc2007_remove, + .remove = __devexit_p(tsc2007_remove), }; static int __init tsc2007_init(void) -- cgit v1.1 From cad065fd1e95003444e8528f801f52164cb78561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20R=C3=B6jfors?= Date: Fri, 24 Jul 2009 23:14:17 -0700 Subject: Input: tsc2007 - make init/exit platform hw callbacks optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make init_platform_hw and exit_platform_hw callbacks optional since they are not needed on all platforms. Signed-off-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 75fbd75..8105bf6 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -295,7 +295,8 @@ static int __devinit tsc2007_probe(struct i2c_client *client, input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); - pdata->init_platform_hw(); + if (pdata->init_platform_hw) + pdata->init_platform_hw(); err = request_irq(ts->irq, tsc2007_irq, 0, client->dev.driver->name, ts); @@ -316,7 +317,8 @@ static int __devinit tsc2007_probe(struct i2c_client *client, err_free_irq: tsc2007_free_irq(ts); - pdata->exit_platform_hw(); + if (pdata->exit_platform_hw) + pdata->exit_platform_hw(); err_free_mem: input_free_device(input_dev); kfree(ts); @@ -330,7 +332,8 @@ static int __devexit tsc2007_remove(struct i2c_client *client) tsc2007_free_irq(ts); - pdata->exit_platform_hw(); + if (pdata->exit_platform_hw) + pdata->exit_platform_hw(); input_unregister_device(ts->input); kfree(ts); -- cgit v1.1 From 703490ff7eaff03e412683da3d8367b5190a71ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20R=C3=B6jfors?= Date: Fri, 24 Jul 2009 23:14:17 -0700 Subject: Input: tsc2007 - do not read coordinates during probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't read coordinates during probe of the driver, just power down the controller and wait for interrupts. Signed-off-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 8105bf6..f710af4 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -184,7 +184,7 @@ static int tsc2007_read_values(struct tsc2007 *tsc) tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1); tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2); - /* power down */ + /* Prepare for next touch reading - power down ADC, enable PENIRQ */ tsc2007_xfer(tsc, PWRDOWN); return 0; @@ -311,7 +311,8 @@ static int __devinit tsc2007_probe(struct i2c_client *client, i2c_set_clientdata(client, ts); - tsc2007_read_values(ts); + /* Prepare for touch readings - power down ADC and enable PENIRQ */ + tsc2007_xfer(ts, PWRDOWN); return 0; -- cgit v1.1 From 9e3b25837a20f4d48fef57b0cb8bf750a8cfa8e2 Mon Sep 17 00:00:00 2001 From: Florian Echtler Date: Mon, 27 Jul 2009 17:35:39 -0700 Subject: Input: usbtouchscreen - add support for e2i touchscreen controller This patch adds support for the e2i touchscreen controller used in the Mimo 740 (and probably in other e2i touchscreen products). Tested on Mimo 740. Signed-off-by: Florian Echtler Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 5 +++ drivers/input/touchscreen/usbtouchscreen.c | 49 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 07703bc..87a1ae6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -474,6 +474,11 @@ config TOUCHSCREEN_USB_JASTEC bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE +config TOUCHSCREEN_USB_E2I + default y + bool "e2i Touchscreen controller (e.g. from Mimo 740)" + depends on TOUCHSCREEN_USB_COMPOSITE + config TOUCHSCREEN_TOUCHIT213 tristate "Sahara TouchIT-213 touchscreen" select SERIO diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index c07be07..68ece58 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -120,6 +120,7 @@ enum { DEVTYPE_GENERAL_TOUCH, DEVTYPE_GOTOP, DEVTYPE_JASTEC, + DEVTYPE_E2I, }; #define USB_DEVICE_HID_CLASS(vend, prod) \ @@ -197,11 +198,47 @@ static struct usb_device_id usbtouch_devices[] = { {USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC}, #endif +#ifdef CONFIG_TOUCHSCREEN_USB_E2I + {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I}, +#endif {} }; /***************************************************************************** + * e2i Part + */ + +#ifdef CONFIG_TOUCHSCREEN_USB_E2I +static int e2i_init(struct usbtouch_usb *usbtouch) +{ + int ret; + + ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), + 0x01, 0x02, 0x0000, 0x0081, + NULL, 0, USB_CTRL_SET_TIMEOUT); + + dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d", + __func__, ret); + return ret; +} + +static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + int tmp = (pkt[0] << 8) | pkt[1]; + dev->x = (pkt[2] << 8) | pkt[3]; + dev->y = (pkt[4] << 8) | pkt[5]; + + tmp = tmp - 0xA000; + dev->touch = (tmp > 0); + dev->press = (tmp > 0 ? tmp : 0); + + return 1; +} +#endif + + +/***************************************************************************** * eGalax part */ @@ -734,6 +771,18 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .read_data = jastec_read_data, }, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_E2I + [DEVTYPE_E2I] = { + .min_xc = 0x0, + .max_xc = 0x7fff, + .min_yc = 0x0, + .max_yc = 0x7fff, + .rept_size = 6, + .init = e2i_init, + .read_data = e2i_read_data, + }, +#endif }; -- cgit v1.1 From d570e9ef84e559b09e729f27f5381b6868f6cc5f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 4 Aug 2009 22:07:26 -0700 Subject: Input: tsc2007 - make get_pendown_state platform callback optional In cases when get_pendown_state callback is not available have the driver to fallback on pressure calculation to determine if the pen is up. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 172 +++++++++++++++++++----------------- 1 file changed, 93 insertions(+), 79 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index f710af4..3714d19 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -70,7 +70,6 @@ struct tsc2007 { struct input_dev *input; char phys[32]; struct delayed_work work; - struct ts_event tc; struct i2c_client *client; @@ -106,51 +105,96 @@ static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd) return val; } -static void tsc2007_send_event(void *tsc) +static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) { - struct tsc2007 *ts = tsc; - u32 rt; - u16 x, y, z1, z2; + /* y- still on; turn on only y+ (and ADC) */ + tc->y = tsc2007_xfer(tsc, READ_Y); + + /* turn y- off, x+ on, then leave in lowpower */ + tc->x = tsc2007_xfer(tsc, READ_X); + + /* turn y+ off, x- on; we'll use formula #1 */ + tc->z1 = tsc2007_xfer(tsc, READ_Z1); + tc->z2 = tsc2007_xfer(tsc, READ_Z2); - x = ts->tc.x; - y = ts->tc.y; - z1 = ts->tc.z1; - z2 = ts->tc.z2; + /* Prepare for next touch reading - power down ADC, enable PENIRQ */ + tsc2007_xfer(tsc, PWRDOWN); +} + +static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) +{ + u32 rt = 0; /* range filtering */ - if (x == MAX_12BIT) - x = 0; + if (tc->x == MAX_12BIT) + tc->x = 0; - if (likely(x && z1)) { + if (likely(tc->x && tc->z1)) { /* compute touch pressure resistance using equation #1 */ - rt = z2; - rt -= z1; - rt *= x; - rt *= ts->x_plate_ohms; - rt /= z1; + rt = tc->z2 - tc->z1; + rt *= tc->x; + rt *= tsc->x_plate_ohms; + rt /= tc->z1; rt = (rt + 2047) >> 12; - } else - rt = 0; - - /* - * Sample found inconsistent by debouncing or pressure is beyond - * the maximum. Don't report it to user space, repeat at least - * once more the measurement - */ - if (rt > MAX_12BIT) { - dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); - return; } + return rt; +} + +static void tsc2007_send_up_event(struct tsc2007 *tsc) +{ + struct input_dev *input = tsc->input; + + dev_dbg(&tsc->client->dev, "UP\n"); + + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_sync(input); +} + +static void tsc2007_work(struct work_struct *work) +{ + struct tsc2007 *ts = + container_of(to_delayed_work(work), struct tsc2007, work); + struct ts_event tc; + u32 rt; + /* * NOTE: We can't rely on the pressure to determine the pen down - * state, even this controller has a pressure sensor. The pressure - * value can fluctuate for quite a while after lifting the pen and - * in some cases may not even settle at the expected value. + * state, even though this controller has a pressure sensor. + * The pressure value can fluctuate for quite a while after + * lifting the pen and in some cases may not even settle at the + * expected value. * * The only safe way to check for the pen up condition is in the - * work function by reading the pen signal state (it's a GPIO and IRQ). + * work function by reading the pen signal state (it's a GPIO + * and IRQ). Unfortunately such callback is not always available, + * in that case we have rely on the pressure anyway. */ + if (ts->get_pendown_state) { + if (unlikely(!ts->get_pendown_state())) { + tsc2007_send_up_event(ts); + ts->pendown = false; + goto out; + } + + dev_dbg(&ts->client->dev, "pen is still down\n"); + } + + tsc2007_read_values(ts, &tc); + + rt = tsc2007_calculate_pressure(ts, &tc); + if (rt > MAX_12BIT) { + /* + * Sample found inconsistent by debouncing or pressure is + * beyond the maximum. Don't report it to user space, + * repeat at least once more the measurement. + */ + dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); + goto out; + + } + if (rt) { struct input_dev *input = ts->input; @@ -161,68 +205,38 @@ static void tsc2007_send_event(void *tsc) ts->pendown = true; } - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_X, tc.x); + input_report_abs(input, ABS_Y, tc.y); input_report_abs(input, ABS_PRESSURE, rt); input_sync(input); dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n", - x, y, rt); - } -} - -static int tsc2007_read_values(struct tsc2007 *tsc) -{ - /* y- still on; turn on only y+ (and ADC) */ - tsc->tc.y = tsc2007_xfer(tsc, READ_Y); - - /* turn y- off, x+ on, then leave in lowpower */ - tsc->tc.x = tsc2007_xfer(tsc, READ_X); - - /* turn y+ off, x- on; we'll use formula #1 */ - tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1); - tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2); - - /* Prepare for next touch reading - power down ADC, enable PENIRQ */ - tsc2007_xfer(tsc, PWRDOWN); - - return 0; -} - -static void tsc2007_work(struct work_struct *work) -{ - struct tsc2007 *ts = - container_of(to_delayed_work(work), struct tsc2007, work); - - if (unlikely(!ts->get_pendown_state() && ts->pendown)) { - struct input_dev *input = ts->input; - - dev_dbg(&ts->client->dev, "UP\n"); - - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_sync(input); + tc.x, tc.y, rt); + } else if (!ts->get_pendown_state && ts->pendown) { + /* + * We don't have callback to check pendown state, so we + * have to assume that since pressure reported is 0 the + * pen was lifted up. + */ + tsc2007_send_up_event(ts); ts->pendown = false; - enable_irq(ts->irq); - } else { - /* pen is still down, continue with the measurement */ - dev_dbg(&ts->client->dev, "pen is still down\n"); - - tsc2007_read_values(ts); - tsc2007_send_event(ts); + } + out: + if (ts->pendown) schedule_delayed_work(&ts->work, msecs_to_jiffies(TS_POLL_PERIOD)); - } + else + enable_irq(ts->irq); } static irqreturn_t tsc2007_irq(int irq, void *handle) { struct tsc2007 *ts = handle; - if (likely(ts->get_pendown_state())) { + if (!ts->get_pendown_state || likely(ts->get_pendown_state())) { disable_irq_nosync(ts->irq); schedule_delayed_work(&ts->work, msecs_to_jiffies(TS_POLL_DELAY)); @@ -255,7 +269,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client, struct input_dev *input_dev; int err; - if (!pdata || !pdata->get_pendown_state) { + if (!pdata) { dev_err(&client->dev, "platform data is required!\n"); return -EINVAL; } -- cgit v1.1 From cf5f439b48f82c230dcd81d0061e00664cbb6d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20R=C3=B6jfors?= Date: Tue, 4 Aug 2009 22:34:10 -0700 Subject: Input: tsc2007 - check if I2C communication works during probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the result when sending the power down command to the controller. Signed-off-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 3714d19..7ef0d14 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -319,15 +319,17 @@ static int __devinit tsc2007_probe(struct i2c_client *client, goto err_free_mem; } + /* Prepare for touch readings - power down ADC and enable PENIRQ */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) + goto err_free_irq; + err = input_register_device(input_dev); if (err) goto err_free_irq; i2c_set_clientdata(client, ts); - /* Prepare for touch readings - power down ADC and enable PENIRQ */ - tsc2007_xfer(ts, PWRDOWN); - return 0; err_free_irq: -- cgit v1.1 From dd0d5443da02b091636e967407805f0b7712fd44 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 5 Aug 2009 00:30:26 -0700 Subject: Input: serio - don't use serio->write() directly We have a nice wrapper for that. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/h3600_ts_input.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 4d3139e..b4d7f63 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -148,9 +148,10 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) struct h3600_dev *ts = input_get_drvdata(dev); /* Must be in this order */ - ts->serio->write(ts->serio, 1); - ts->serio->write(ts->serio, pwr); - ts->serio->write(ts->serio, brightness); + serio_write(ts->serio, 1); + serio_write(ts->serio, pwr); + serio_write(ts->serio, brightness); + return 0; } @@ -262,7 +263,7 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type, switch (type) { case EV_LED: { - // ts->serio->write(ts->serio, SOME_CMD); + // serio_write(ts->serio, SOME_CMD); return 0; } } -- cgit v1.1 From 25a70e38cd57952b09a013bf070e03705ee4f2ff Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 12 Aug 2009 00:50:09 -0700 Subject: Input: eeti_ts - allow active high irq lines This adds a struct eeti_ts_platform_data which currently holds only one value to specify the interrupt polarity. The driver has a fallback if no platform data is passed in via the i2c_board_info, so no regression is caused. Signed-off-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 3ab9222..9029bd3 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -32,6 +32,7 @@ #include #include #include +#include static int flip_x; module_param(flip_x, bool, 0644); @@ -46,7 +47,7 @@ struct eeti_ts_priv { struct input_dev *input; struct work_struct work; struct mutex mutex; - int irq; + int irq, irq_active_high; }; #define EETI_TS_BITDEPTH (11) @@ -58,6 +59,11 @@ struct eeti_ts_priv { #define REPORT_BIT_HAS_PRESSURE (1 << 6) #define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH) +static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv) +{ + return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high; +} + static void eeti_ts_read(struct work_struct *work) { char buf[6]; @@ -67,7 +73,7 @@ static void eeti_ts_read(struct work_struct *work) mutex_lock(&priv->mutex); - while (!gpio_get_value(irq_to_gpio(priv->irq)) && --to) + while (eeti_ts_irq_active(priv) && --to) i2c_master_recv(priv->client, buf, sizeof(buf)); if (!to) { @@ -140,8 +146,10 @@ static void eeti_ts_close(struct input_dev *dev) static int __devinit eeti_ts_probe(struct i2c_client *client, const struct i2c_device_id *idp) { + struct eeti_ts_platform_data *pdata; struct eeti_ts_priv *priv; struct input_dev *input; + unsigned int irq_flags; int err = -ENOMEM; /* In contrast to what's described in the datasheet, there seems @@ -180,6 +188,14 @@ static int __devinit eeti_ts_probe(struct i2c_client *client, priv->input = input; priv->irq = client->irq; + pdata = client->dev.platform_data; + + if (pdata) + priv->irq_active_high = pdata->irq_active_high; + + irq_flags = priv->irq_active_high ? + IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + INIT_WORK(&priv->work, eeti_ts_read); i2c_set_clientdata(client, priv); input_set_drvdata(input, priv); @@ -188,7 +204,7 @@ static int __devinit eeti_ts_probe(struct i2c_client *client, if (err) goto err1; - err = request_irq(priv->irq, eeti_ts_isr, IRQF_TRIGGER_FALLING, + err = request_irq(priv->irq, eeti_ts_isr, irq_flags, client->name, priv); if (err) { dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); -- cgit v1.1 From 41c372dcad935fe7c27ec45211bad810515110bd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 3 Sep 2009 17:22:03 -0700 Subject: Input: wacom_w8001 - simplify querying logic There is no need for locking when we send query and start commands to the touchscreen since there is no concurrency. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wacom_w8001.c | 121 +++++++++++--------------------- 1 file changed, 40 insertions(+), 81 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 2f33a01..56dc35c 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -25,18 +25,16 @@ MODULE_AUTHOR("Jaya Kumar "); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -/* - * Definitions & global arrays. - */ - #define W8001_MAX_LENGTH 11 -#define W8001_PACKET_LEN 11 -#define W8001_LEAD_MASK 0x80 -#define W8001_LEAD_BYTE 0x80 -#define W8001_TAB_MASK 0x40 -#define W8001_TAB_BYTE 0x40 +#define W8001_LEAD_MASK 0x80 +#define W8001_LEAD_BYTE 0x80 +#define W8001_TAB_MASK 0x40 +#define W8001_TAB_BYTE 0x40 -#define W8001_QUERY_PACKET 0x20 +#define W8001_QUERY_PACKET 0x20 + +#define W8001_CMD_START '1' +#define W8001_CMD_QUERY '*' struct w8001_coord { u8 rdy; @@ -57,18 +55,19 @@ struct w8001_coord { struct w8001 { struct input_dev *dev; struct serio *serio; - struct mutex cmd_mutex; struct completion cmd_done; int id; int idx; - unsigned char expected_packet; + unsigned char response_type; + unsigned char response[W8001_MAX_LENGTH]; unsigned char data[W8001_MAX_LENGTH]; - unsigned char response[W8001_PACKET_LEN]; char phys[32]; }; -static int parse_data(u8 *data, struct w8001_coord *coord) +static void parse_data(u8 *data, struct w8001_coord *coord) { + memset(coord, 0, sizeof(*coord)); + coord->rdy = data[0] & 0x20; coord->tsw = data[0] & 0x01; coord->f1 = data[0] & 0x02; @@ -87,15 +86,15 @@ static int parse_data(u8 *data, struct w8001_coord *coord) coord->tilt_x = data[7] & 0x7F; coord->tilt_y = data[8] & 0x7F; - - return 0; } -static void w8001_process_data(struct w8001 *w8001, unsigned char data) +static irqreturn_t w8001_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) { + struct w8001 *w8001 = serio_get_drvdata(serio); struct input_dev *dev = w8001->dev; - u8 tmp; struct w8001_coord coord; + unsigned char tmp; w8001->data[w8001->idx] = data; switch (w8001->idx++) { @@ -105,12 +104,13 @@ static void w8001_process_data(struct w8001 *w8001, unsigned char data) w8001->idx = 0; } break; + case 8: tmp = w8001->data[0] & W8001_TAB_MASK; if (unlikely(tmp == W8001_TAB_BYTE)) break; + w8001->idx = 0; - memset(&coord, 0, sizeof(coord)); parse_data(w8001->data, &coord); input_report_abs(dev, ABS_X, coord.x); input_report_abs(dev, ABS_Y, coord.y); @@ -118,86 +118,48 @@ static void w8001_process_data(struct w8001 *w8001, unsigned char data) input_report_key(dev, BTN_TOUCH, coord.tsw); input_sync(dev); break; + case 10: w8001->idx = 0; - memcpy(w8001->response, &w8001->data, W8001_PACKET_LEN); - w8001->expected_packet = W8001_QUERY_PACKET; + memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH); + w8001->response_type = W8001_QUERY_PACKET; complete(&w8001->cmd_done); break; } -} - - -static irqreturn_t w8001_interrupt(struct serio *serio, - unsigned char data, unsigned int flags) -{ - struct w8001 *w8001 = serio_get_drvdata(serio); - - w8001_process_data(w8001, data); return IRQ_HANDLED; } -static int w8001_async_command(struct w8001 *w8001, unsigned char *packet, - int len) -{ - int rc = -1; - int i; - - mutex_lock(&w8001->cmd_mutex); - - for (i = 0; i < len; i++) { - if (serio_write(w8001->serio, packet[i])) - goto out; - } - rc = 0; - -out: - mutex_unlock(&w8001->cmd_mutex); - return rc; -} - -static int w8001_command(struct w8001 *w8001, unsigned char *packet, int len) +static int w8001_command(struct w8001 *w8001, unsigned char command, + bool wait_response) { - int rc = -1; - int i; + int rc; - mutex_lock(&w8001->cmd_mutex); - - serio_pause_rx(w8001->serio); + w8001->response_type = 0; init_completion(&w8001->cmd_done); - serio_continue_rx(w8001->serio); - - for (i = 0; i < len; i++) { - if (serio_write(w8001->serio, packet[i])) - goto out; - } - wait_for_completion_timeout(&w8001->cmd_done, HZ); + rc = serio_write(w8001->serio, command); + if (rc == 0 && wait_response) { - if (w8001->expected_packet == W8001_QUERY_PACKET) { - /* We are back in reporting mode, the query was ACKed */ - memcpy(packet, w8001->response, W8001_PACKET_LEN); - rc = 0; + wait_for_completion_timeout(&w8001->cmd_done, HZ); + if (w8001->response_type != W8001_QUERY_PACKET) + rc = -EIO; } -out: - mutex_unlock(&w8001->cmd_mutex); return rc; } static int w8001_setup(struct w8001 *w8001) { - struct w8001_coord coord; struct input_dev *dev = w8001->dev; - unsigned char start[1] = { '1' }; - unsigned char query[11] = { '*' }; + struct w8001_coord coord; + int error; - if (w8001_command(w8001, query, 1)) - return -1; + error = w8001_command(w8001, W8001_CMD_QUERY, true); + if (error) + return error; - memset(&coord, 0, sizeof(coord)); - parse_data(query, &coord); + parse_data(w8001->response, &coord); input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); @@ -205,10 +167,7 @@ static int w8001_setup(struct w8001 *w8001) input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); - if (w8001_async_command(w8001, start, 1)) - return -1; - - return 0; + return w8001_command(w8001, W8001_CMD_START, false); } /* @@ -249,7 +208,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) w8001->serio = serio; w8001->id = serio->id.id; w8001->dev = input_dev; - mutex_init(&w8001->cmd_mutex); init_completion(&w8001->cmd_done); snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); @@ -269,7 +227,8 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) if (err) goto fail2; - if (w8001_setup(w8001)) + err = w8001_setup(w8001); + if (err) goto fail3; err = input_register_device(w8001->dev); -- cgit v1.1