From d9105c2b01eedb620cae96073dde4f760367817f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Va=C5=A1ut?= Date: Sun, 3 Aug 2008 21:34:08 +0100 Subject: [ARM] 5184/1: Split ucb1400_ts into core and touchscreen This patch splits ucb1400_ts into ucb1400_ts and ucb1400_core. Since this chip supports more features than only touchscreen, it was necessary to prepare it for feature addition. The previous functionality is preserved by applying this patch. [Build fixes for non-ARM by Stephen Rothwell and Takashi Iwai] Signed-off-by: Marek Vasut Signed-off-by: Russell King --- drivers/input/touchscreen/Kconfig | 1 + drivers/input/touchscreen/ucb1400_ts.c | 382 ++++++++++++--------------------- 2 files changed, 135 insertions(+), 248 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6e60a97a234..fcabff9b39b 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -220,6 +220,7 @@ config TOUCHSCREEN_ATMEL_TSADCC config TOUCHSCREEN_UCB1400 tristate "Philips UCB1400 touchscreen" select AC97_BUS + depends on UCB1400_CORE help This enables support for the Philips UCB1400 touchscreen interface. The UCB1400 is an AC97 audio codec. The touchscreen interface diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index bce018e45bc..54986627def 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -5,6 +5,10 @@ * Created: September 25, 2006 * Copyright: MontaVista Software, Inc. * + * Spliting done by: Marek Vasut + * If something doesnt work and it worked before spliting, e-mail me, + * dont bother Nicolas please ;-) + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -25,124 +29,16 @@ #include #include #include - -#include -#include - - -/* - * Interesting UCB1400 AC-link registers - */ - -#define UCB_IE_RIS 0x5e -#define UCB_IE_FAL 0x60 -#define UCB_IE_STATUS 0x62 -#define UCB_IE_CLEAR 0x62 -#define UCB_IE_ADC (1 << 11) -#define UCB_IE_TSPX (1 << 12) - -#define UCB_TS_CR 0x64 -#define UCB_TS_CR_TSMX_POW (1 << 0) -#define UCB_TS_CR_TSPX_POW (1 << 1) -#define UCB_TS_CR_TSMY_POW (1 << 2) -#define UCB_TS_CR_TSPY_POW (1 << 3) -#define UCB_TS_CR_TSMX_GND (1 << 4) -#define UCB_TS_CR_TSPX_GND (1 << 5) -#define UCB_TS_CR_TSMY_GND (1 << 6) -#define UCB_TS_CR_TSPY_GND (1 << 7) -#define UCB_TS_CR_MODE_INT (0 << 8) -#define UCB_TS_CR_MODE_PRES (1 << 8) -#define UCB_TS_CR_MODE_POS (2 << 8) -#define UCB_TS_CR_BIAS_ENA (1 << 11) -#define UCB_TS_CR_TSPX_LOW (1 << 12) -#define UCB_TS_CR_TSMX_LOW (1 << 13) - -#define UCB_ADC_CR 0x66 -#define UCB_ADC_SYNC_ENA (1 << 0) -#define UCB_ADC_VREFBYP_CON (1 << 1) -#define UCB_ADC_INP_TSPX (0 << 2) -#define UCB_ADC_INP_TSMX (1 << 2) -#define UCB_ADC_INP_TSPY (2 << 2) -#define UCB_ADC_INP_TSMY (3 << 2) -#define UCB_ADC_INP_AD0 (4 << 2) -#define UCB_ADC_INP_AD1 (5 << 2) -#define UCB_ADC_INP_AD2 (6 << 2) -#define UCB_ADC_INP_AD3 (7 << 2) -#define UCB_ADC_EXT_REF (1 << 5) -#define UCB_ADC_START (1 << 7) -#define UCB_ADC_ENA (1 << 15) - -#define UCB_ADC_DATA 0x68 -#define UCB_ADC_DAT_VALID (1 << 15) -#define UCB_ADC_DAT_VALUE(x) ((x) & 0x3ff) - -#define UCB_ID 0x7e -#define UCB_ID_1400 0x4304 - - -struct ucb1400 { - struct snd_ac97 *ac97; - struct input_dev *ts_idev; - - int irq; - - wait_queue_head_t ts_wait; - struct task_struct *ts_task; - - unsigned int irq_pending; /* not bit field shared */ - unsigned int ts_restart:1; - unsigned int adcsync:1; -}; +#include static int adcsync; static int ts_delay = 55; /* us */ static int ts_delay_pressure; /* us */ -static inline u16 ucb1400_reg_read(struct ucb1400 *ucb, u16 reg) -{ - return ucb->ac97->bus->ops->read(ucb->ac97, reg); -} - -static inline void ucb1400_reg_write(struct ucb1400 *ucb, u16 reg, u16 val) -{ - ucb->ac97->bus->ops->write(ucb->ac97, reg, val); -} - -static inline void ucb1400_adc_enable(struct ucb1400 *ucb) -{ - ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA); -} - -static unsigned int ucb1400_adc_read(struct ucb1400 *ucb, u16 adc_channel) -{ - unsigned int val; - - if (ucb->adcsync) - adc_channel |= UCB_ADC_SYNC_ENA; - - ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | adc_channel); - ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | adc_channel | UCB_ADC_START); - - for (;;) { - val = ucb1400_reg_read(ucb, UCB_ADC_DATA); - if (val & UCB_ADC_DAT_VALID) - break; - /* yield to other processes */ - schedule_timeout_uninterruptible(1); - } - - return UCB_ADC_DAT_VALUE(val); -} - -static inline void ucb1400_adc_disable(struct ucb1400 *ucb) -{ - ucb1400_reg_write(ucb, UCB_ADC_CR, 0); -} - /* Switch to interrupt mode. */ -static inline void ucb1400_ts_mode_int(struct ucb1400 *ucb) +static inline void ucb1400_ts_mode_int(struct snd_ac97 *ac97) { - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ac97, UCB_TS_CR, UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | UCB_TS_CR_MODE_INT); @@ -152,14 +48,14 @@ static inline void ucb1400_ts_mode_int(struct ucb1400 *ucb) * Switch to pressure mode, and read pressure. We don't need to wait * here, since both plates are being driven. */ -static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400 *ucb) +static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb) { - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); udelay(ts_delay_pressure); - return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY); + return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync); } /* @@ -168,21 +64,21 @@ static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400 *ucb) * gives a faster response time. Even so, we need to wait about 55us * for things to stabilise. */ -static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400 *ucb) +static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb) { - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); udelay(ts_delay); - return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY); + return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync); } /* @@ -191,63 +87,63 @@ static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400 *ucb) * gives a faster response time. Even so, we need to wait about 55us * for things to stabilise. */ -static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400 *ucb) +static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb) { - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); udelay(ts_delay); - return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPX); + return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPX, adcsync); } /* * Switch to X plate resistance mode. Set MX to ground, PX to * supply. Measure current. */ -static inline unsigned int ucb1400_ts_read_xres(struct ucb1400 *ucb) +static inline unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb) { - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - return ucb1400_adc_read(ucb, 0); + return ucb1400_adc_read(ucb->ac97, 0, adcsync); } /* * Switch to Y plate resistance mode. Set MY to ground, PY to * supply. Measure current. */ -static inline unsigned int ucb1400_ts_read_yres(struct ucb1400 *ucb) +static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb) { - ucb1400_reg_write(ucb, UCB_TS_CR, + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - return ucb1400_adc_read(ucb, 0); + return ucb1400_adc_read(ucb->ac97, 0, adcsync); } -static inline int ucb1400_ts_pen_down(struct ucb1400 *ucb) +static inline int ucb1400_ts_pen_down(struct snd_ac97 *ac97) { - unsigned short val = ucb1400_reg_read(ucb, UCB_TS_CR); - return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)); + unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR); + return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW); } -static inline void ucb1400_ts_irq_enable(struct ucb1400 *ucb) +static inline void ucb1400_ts_irq_enable(struct snd_ac97 *ac97) { - ucb1400_reg_write(ucb, UCB_IE_CLEAR, UCB_IE_TSPX); - ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0); - ucb1400_reg_write(ucb, UCB_IE_FAL, UCB_IE_TSPX); + ucb1400_reg_write(ac97, UCB_IE_CLEAR, UCB_IE_TSPX); + ucb1400_reg_write(ac97, UCB_IE_CLEAR, 0); + ucb1400_reg_write(ac97, UCB_IE_FAL, UCB_IE_TSPX); } -static inline void ucb1400_ts_irq_disable(struct ucb1400 *ucb) +static inline void ucb1400_ts_irq_disable(struct snd_ac97 *ac97) { - ucb1400_reg_write(ucb, UCB_IE_FAL, 0); + ucb1400_reg_write(ac97, UCB_IE_FAL, 0); } static void ucb1400_ts_evt_add(struct input_dev *idev, u16 pressure, u16 x, u16 y) @@ -264,25 +160,24 @@ static void ucb1400_ts_event_release(struct input_dev *idev) input_sync(idev); } -static void ucb1400_handle_pending_irq(struct ucb1400 *ucb) +static void ucb1400_handle_pending_irq(struct ucb1400_ts *ucb) { unsigned int isr; - isr = ucb1400_reg_read(ucb, UCB_IE_STATUS); - ucb1400_reg_write(ucb, UCB_IE_CLEAR, isr); - ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0); + isr = ucb1400_reg_read(ucb->ac97, UCB_IE_STATUS); + ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, isr); + ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); - if (isr & UCB_IE_TSPX) - ucb1400_ts_irq_disable(ucb); - else + if (isr & UCB_IE_TSPX) { + ucb1400_ts_irq_disable(ucb->ac97); + enable_irq(ucb->irq); + } else printk(KERN_ERR "ucb1400: unexpected IE_STATUS = %#x\n", isr); - - enable_irq(ucb->irq); } static int ucb1400_ts_thread(void *_ucb) { - struct ucb1400 *ucb = _ucb; + struct ucb1400_ts *ucb = _ucb; struct task_struct *tsk = current; int valid = 0; struct sched_param param = { .sched_priority = 1 }; @@ -301,19 +196,19 @@ static int ucb1400_ts_thread(void *_ucb) ucb1400_handle_pending_irq(ucb); } - ucb1400_adc_enable(ucb); + ucb1400_adc_enable(ucb->ac97); x = ucb1400_ts_read_xpos(ucb); y = ucb1400_ts_read_ypos(ucb); p = ucb1400_ts_read_pressure(ucb); - ucb1400_adc_disable(ucb); + ucb1400_adc_disable(ucb->ac97); /* Switch back to interrupt mode. */ - ucb1400_ts_mode_int(ucb); + ucb1400_ts_mode_int(ucb->ac97); msleep(10); - if (ucb1400_ts_pen_down(ucb)) { - ucb1400_ts_irq_enable(ucb); + if (ucb1400_ts_pen_down(ucb->ac97)) { + ucb1400_ts_irq_enable(ucb->ac97); /* * If we spat out a valid sample set last time, @@ -332,8 +227,8 @@ static int ucb1400_ts_thread(void *_ucb) } wait_event_freezable_timeout(ucb->ts_wait, - ucb->irq_pending || ucb->ts_restart || kthread_should_stop(), - timeout); + ucb->irq_pending || ucb->ts_restart || + kthread_should_stop(), timeout); } /* Send the "pen off" if we are stopping with the pen still active */ @@ -356,7 +251,7 @@ static int ucb1400_ts_thread(void *_ucb) */ static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid) { - struct ucb1400 *ucb = devid; + struct ucb1400_ts *ucb = devid; if (irqnr == ucb->irq) { disable_irq(ucb->irq); @@ -369,7 +264,7 @@ static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid) static int ucb1400_ts_open(struct input_dev *idev) { - struct ucb1400 *ucb = input_get_drvdata(idev); + struct ucb1400_ts *ucb = input_get_drvdata(idev); int ret = 0; BUG_ON(ucb->ts_task); @@ -385,34 +280,14 @@ static int ucb1400_ts_open(struct input_dev *idev) static void ucb1400_ts_close(struct input_dev *idev) { - struct ucb1400 *ucb = input_get_drvdata(idev); + struct ucb1400_ts *ucb = input_get_drvdata(idev); if (ucb->ts_task) kthread_stop(ucb->ts_task); - ucb1400_ts_irq_disable(ucb); - ucb1400_reg_write(ucb, UCB_TS_CR, 0); -} - -#ifdef CONFIG_PM -static int ucb1400_ts_resume(struct device *dev) -{ - struct ucb1400 *ucb = dev_get_drvdata(dev); - - if (ucb->ts_task) { - /* - * Restart the TS thread to ensure the - * TS interrupt mode is set up again - * after sleep. - */ - ucb->ts_restart = 1; - wake_up(&ucb->ts_wait); - } - return 0; + ucb1400_ts_irq_disable(ucb->ac97); + ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0); } -#else -#define ucb1400_ts_resume NULL -#endif #ifndef NO_IRQ #define NO_IRQ 0 @@ -422,25 +297,26 @@ static int ucb1400_ts_resume(struct device *dev) * Try to probe our interrupt, rather than relying on lots of * hard-coded machine dependencies. */ -static int ucb1400_detect_irq(struct ucb1400 *ucb) +static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb) { unsigned long mask, timeout; mask = probe_irq_on(); /* Enable the ADC interrupt. */ - ucb1400_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC); - ucb1400_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC); - ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0xffff); - ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0); + ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, UCB_IE_ADC); + ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_ADC); + ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff); + ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); /* Cause an ADC interrupt. */ - ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA); - ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); + ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA); + ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); /* Wait for the conversion to complete. */ timeout = jiffies + HZ/2; - while (!(ucb1400_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VALID)) { + while (!(ucb1400_reg_read(ucb->ac97, UCB_ADC_DATA) & + UCB_ADC_DAT_VALID)) { cpu_relax(); if (time_after(jiffies, timeout)) { printk(KERN_ERR "ucb1400: timed out in IRQ probe\n"); @@ -448,13 +324,13 @@ static int ucb1400_detect_irq(struct ucb1400 *ucb) return -ENODEV; } } - ucb1400_reg_write(ucb, UCB_ADC_CR, 0); + ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, 0); /* Disable and clear interrupt. */ - ucb1400_reg_write(ucb, UCB_IE_RIS, 0); - ucb1400_reg_write(ucb, UCB_IE_FAL, 0); - ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0xffff); - ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0); + ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, 0); + ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0); + ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff); + ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); /* Read triggered interrupt. */ ucb->irq = probe_irq_off(mask); @@ -464,36 +340,25 @@ static int ucb1400_detect_irq(struct ucb1400 *ucb) return 0; } -static int ucb1400_ts_probe(struct device *dev) +static int ucb1400_ts_probe(struct platform_device *dev) { - struct ucb1400 *ucb; - struct input_dev *idev; - int error, id, x_res, y_res; + int error, x_res, y_res; + struct ucb1400_ts *ucb = dev->dev.platform_data; - ucb = kzalloc(sizeof(struct ucb1400), GFP_KERNEL); - idev = input_allocate_device(); - if (!ucb || !idev) { + ucb->ts_idev = input_allocate_device(); + if (!ucb->ts_idev) { error = -ENOMEM; - goto err_free_devs; + goto err; } - ucb->ts_idev = idev; - ucb->adcsync = adcsync; - ucb->ac97 = to_ac97_t(dev); - init_waitqueue_head(&ucb->ts_wait); - - id = ucb1400_reg_read(ucb, UCB_ID); - if (id != UCB_ID_1400) { - error = -ENODEV; - goto err_free_devs; - } - - error = ucb1400_detect_irq(ucb); + error = ucb1400_ts_detect_irq(ucb); if (error) { printk(KERN_ERR "UCB1400: IRQ probe failed\n"); goto err_free_devs; } + init_waitqueue_head(&ucb->ts_wait); + error = request_irq(ucb->irq, ucb1400_hard_irq, IRQF_TRIGGER_RISING, "UCB1400", ucb); if (error) { @@ -503,80 +368,101 @@ static int ucb1400_ts_probe(struct device *dev) } printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq); - input_set_drvdata(idev, ucb); + input_set_drvdata(ucb->ts_idev, ucb); - idev->dev.parent = dev; - idev->name = "UCB1400 touchscreen interface"; - idev->id.vendor = ucb1400_reg_read(ucb, AC97_VENDOR_ID1); - idev->id.product = id; - idev->open = ucb1400_ts_open; - idev->close = ucb1400_ts_close; - idev->evbit[0] = BIT_MASK(EV_ABS); + ucb->ts_idev->dev.parent = &dev->dev; + ucb->ts_idev->name = "UCB1400 touchscreen interface"; + ucb->ts_idev->id.vendor = ucb1400_reg_read(ucb->ac97, + AC97_VENDOR_ID1); + ucb->ts_idev->id.product = ucb->id; + ucb->ts_idev->open = ucb1400_ts_open; + ucb->ts_idev->close = ucb1400_ts_close; + ucb->ts_idev->evbit[0] = BIT_MASK(EV_ABS); - ucb1400_adc_enable(ucb); + ucb1400_adc_enable(ucb->ac97); x_res = ucb1400_ts_read_xres(ucb); y_res = ucb1400_ts_read_yres(ucb); - ucb1400_adc_disable(ucb); + ucb1400_adc_disable(ucb->ac97); printk(KERN_DEBUG "UCB1400: x/y = %d/%d\n", x_res, y_res); - input_set_abs_params(idev, ABS_X, 0, x_res, 0, 0); - input_set_abs_params(idev, ABS_Y, 0, y_res, 0, 0); - input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0); + input_set_abs_params(ucb->ts_idev, ABS_X, 0, x_res, 0, 0); + input_set_abs_params(ucb->ts_idev, ABS_Y, 0, y_res, 0, 0); + input_set_abs_params(ucb->ts_idev, ABS_PRESSURE, 0, 0, 0, 0); - error = input_register_device(idev); + error = input_register_device(ucb->ts_idev); if (error) goto err_free_irq; - dev_set_drvdata(dev, ucb); return 0; - err_free_irq: +err_free_irq: free_irq(ucb->irq, ucb); - err_free_devs: - input_free_device(idev); - kfree(ucb); +err_free_devs: + input_free_device(ucb->ts_idev); +err: return error; + } -static int ucb1400_ts_remove(struct device *dev) +static int ucb1400_ts_remove(struct platform_device *dev) { - struct ucb1400 *ucb = dev_get_drvdata(dev); + struct ucb1400_ts *ucb = dev->dev.platform_data; free_irq(ucb->irq, ucb); input_unregister_device(ucb->ts_idev); - dev_set_drvdata(dev, NULL); - kfree(ucb); return 0; } -static struct device_driver ucb1400_ts_driver = { - .name = "ucb1400_ts", - .owner = THIS_MODULE, - .bus = &ac97_bus_type, - .probe = ucb1400_ts_probe, - .remove = ucb1400_ts_remove, - .resume = ucb1400_ts_resume, +#ifdef CONFIG_PM +static int ucb1400_ts_resume(struct platform_device *dev) +{ + struct ucb1400_ts *ucb = platform_get_drvdata(dev); + + if (ucb->ts_task) { + /* + * Restart the TS thread to ensure the + * TS interrupt mode is set up again + * after sleep. + */ + ucb->ts_restart = 1; + wake_up(&ucb->ts_wait); + } + return 0; +} +#else +#define ucb1400_ts_resume NULL +#endif + +static struct platform_driver ucb1400_ts_driver = { + .probe = ucb1400_ts_probe, + .remove = ucb1400_ts_remove, + .resume = ucb1400_ts_resume, + .driver = { + .name = "ucb1400_ts", + }, }; static int __init ucb1400_ts_init(void) { - return driver_register(&ucb1400_ts_driver); + return platform_driver_register(&ucb1400_ts_driver); } static void __exit ucb1400_ts_exit(void) { - driver_unregister(&ucb1400_ts_driver); + platform_driver_unregister(&ucb1400_ts_driver); } module_param(adcsync, bool, 0444); MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin."); module_param(ts_delay, int, 0444); -MODULE_PARM_DESC(ts_delay, "Delay between panel setup and position read. Default = 55us."); +MODULE_PARM_DESC(ts_delay, "Delay between panel setup and" + " position read. Default = 55us."); module_param(ts_delay_pressure, int, 0444); MODULE_PARM_DESC(ts_delay_pressure, - "delay between panel setup and pressure read. Default = 0us."); + "delay between panel setup and pressure read." + " Default = 0us."); module_init(ucb1400_ts_init); module_exit(ucb1400_ts_exit); -- cgit v1.2.3 From cd72ad3f57c400baa2ddb78b4fc2781cf68ffb6f Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sun, 14 Sep 2008 11:52:44 -0400 Subject: Input: bcm5974 - switch back to normal mode when closing Staying in multi-touch mode after closing the device sometimes makes the keyboard drop keys or repeat keys irratically. The conjecture is that some internal buffer starts to overflow, resulting in undefined behavior. Switching back to normal mode when closing the device makes the problem go away. Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/bcm5974.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 18f4d7f6ce6..2998a6ac9ae 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -351,8 +351,9 @@ static int report_tp_state(struct bcm5974 *dev, int size) #define BCM5974_WELLSPRING_MODE_REQUEST_VALUE 0x300 #define BCM5974_WELLSPRING_MODE_REQUEST_INDEX 0 #define BCM5974_WELLSPRING_MODE_VENDOR_VALUE 0x01 +#define BCM5974_WELLSPRING_MODE_NORMAL_VALUE 0x08 -static int bcm5974_wellspring_mode(struct bcm5974 *dev) +static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on) { char *data = kmalloc(8, GFP_KERNEL); int retval = 0, size; @@ -377,7 +378,9 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev) } /* apply the mode switch */ - data[0] = BCM5974_WELLSPRING_MODE_VENDOR_VALUE; + data[0] = on ? + BCM5974_WELLSPRING_MODE_VENDOR_VALUE : + BCM5974_WELLSPRING_MODE_NORMAL_VALUE; /* write configuration */ size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), @@ -392,7 +395,8 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev) goto out; } - dprintk(2, "bcm5974: switched to wellspring mode.\n"); + dprintk(2, "bcm5974: switched to %s mode.\n", + on ? "wellspring" : "normal"); out: kfree(data); @@ -481,7 +485,7 @@ exit: */ static int bcm5974_start_traffic(struct bcm5974 *dev) { - if (bcm5974_wellspring_mode(dev)) { + if (bcm5974_wellspring_mode(dev, true)) { dprintk(1, "bcm5974: mode switch failed\n"); goto error; } @@ -504,6 +508,7 @@ static void bcm5974_pause_traffic(struct bcm5974 *dev) { usb_kill_urb(dev->tp_urb); usb_kill_urb(dev->bt_urb); + bcm5974_wellspring_mode(dev, false); } /* -- cgit v1.2.3 From 1577e4b70a04cce39f296cc714da5ad5d272105a Mon Sep 17 00:00:00 2001 From: Kristoffer Ericson Date: Tue, 16 Sep 2008 14:19:25 -0400 Subject: Input: jornada720_ts - fix build error ( LONG() usage ) This patch removes the usage of LONG() which is deprecated; we also replace BIT() with BIT_MASK(). signed-off-by: Kristoffer Ericson Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/jornada720_ts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index 1aca108b103..b7f1260738a 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -119,8 +119,8 @@ static int __devinit jornada720_ts_probe(struct platform_device *pdev) input_dev->id.bustype = BUS_HOST; input_dev->dev.parent = &pdev->dev; - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0); input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0); -- cgit v1.2.3 From 6ae19b04ab41a4db0f0c48ec0b78950f6b028823 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Wed, 10 Sep 2008 12:06:15 -0400 Subject: Input: ads7846 - introduce .gpio_pendown to get pendown state The GPIO connected to ADS7846 nPENIRQ signal is usually used to get the pendown state as well. Introduce a .gpio_pendown, and use this to decide the pendown state if .get_pendown_state is NULL. Signed-off-by: Eric Miao Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 68 +++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 14 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ce6f48c695f..8583c766d56 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -116,6 +117,7 @@ struct ads7846 { void *filter_data; void (*filter_cleanup)(void *data); int (*get_pendown_state)(void); + int gpio_pendown; }; /* leave chip selected when we're done, for quicker re-select? */ @@ -491,6 +493,14 @@ static struct attribute_group ads784x_attr_group = { /*--------------------------------------------------------------------------*/ +static int get_pendown_state(struct ads7846 *ts) +{ + if (ts->get_pendown_state) + return ts->get_pendown_state(); + + return !gpio_get_value(ts->gpio_pendown); +} + /* * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, * to retrieve touchscreen status. @@ -550,7 +560,7 @@ static void ads7846_rx(void *ads) */ if (ts->penirq_recheck_delay_usecs) { udelay(ts->penirq_recheck_delay_usecs); - if (!ts->get_pendown_state()) + if (!get_pendown_state(ts)) Rt = 0; } @@ -677,7 +687,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) spin_lock_irq(&ts->lock); - if (unlikely(!ts->get_pendown_state() || + if (unlikely(!get_pendown_state(ts) || device_suspended(&ts->spi->dev))) { if (ts->pendown) { struct input_dev *input = ts->input; @@ -716,7 +726,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) unsigned long flags; spin_lock_irqsave(&ts->lock, flags); - if (likely(ts->get_pendown_state())) { + if (likely(get_pendown_state(ts))) { if (!ts->irq_disabled) { /* The ARM do_simple_IRQ() dispatcher doesn't act * like the other dispatchers: it will report IRQs @@ -806,6 +816,36 @@ static int ads7846_resume(struct spi_device *spi) return 0; } +static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts) +{ + struct ads7846_platform_data *pdata = spi->dev.platform_data; + int err; + + /* REVISIT when the irq can be triggered active-low, or if for some + * reason the touchscreen isn't hooked up, we don't need to access + * the pendown state. + */ + if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) { + dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); + return -EINVAL; + } + + if (pdata->get_pendown_state) { + ts->get_pendown_state = pdata->get_pendown_state; + return 0; + } + + err = gpio_request(pdata->gpio_pendown, "ads7846_pendown"); + if (err) { + dev_err(&spi->dev, "failed to request pendown GPIO%d\n", + pdata->gpio_pendown); + return err; + } + + ts->gpio_pendown = pdata->gpio_pendown; + return 0; +} + static int __devinit ads7846_probe(struct spi_device *spi) { struct ads7846 *ts; @@ -833,15 +873,6 @@ static int __devinit ads7846_probe(struct spi_device *spi) return -EINVAL; } - /* REVISIT when the irq can be triggered active-low, or if for some - * reason the touchscreen isn't hooked up, we don't need to access - * the pendown state. - */ - if (pdata->get_pendown_state == NULL) { - dev_dbg(&spi->dev, "no get_pendown_state function?\n"); - return -EINVAL; - } - /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except * that even if the hardware can do that, the SPI controller driver * may not. So we stick to very-portable 8 bit words, both RX and TX. @@ -893,7 +924,10 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->filter_data = ts; } else ts->filter = ads7846_no_filter; - ts->get_pendown_state = pdata->get_pendown_state; + + err = setup_pendown(spi, ts); + if (err) + goto err_cleanup_filter; if (pdata->penirq_recheck_delay_usecs) ts->penirq_recheck_delay_usecs = @@ -1085,7 +1119,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) spi->dev.driver->name, ts)) { dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); err = -EBUSY; - goto err_cleanup_filter; + goto err_free_gpio; } err = ads784x_hwmon_register(spi, ts); @@ -1116,6 +1150,9 @@ static int __devinit ads7846_probe(struct spi_device *spi) ads784x_hwmon_unregister(spi, ts); err_free_irq: free_irq(spi->irq, ts); + err_free_gpio: + if (ts->gpio_pendown != -1) + gpio_free(ts->gpio_pendown); err_cleanup_filter: if (ts->filter_cleanup) ts->filter_cleanup(ts->filter_data); @@ -1140,6 +1177,9 @@ static int __devexit ads7846_remove(struct spi_device *spi) /* suspend left the IRQ disabled */ enable_irq(ts->spi->irq); + if (ts->gpio_pendown != -1) + gpio_free(ts->gpio_pendown); + if (ts->filter_cleanup) ts->filter_cleanup(ts->filter_data); -- cgit v1.2.3 From 73b610affe0b24ecb808ef68a1b0a436a4cf7bd5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 25 Sep 2008 13:35:27 +0100 Subject: [ARM] pxa: remove references to pxa_gpio_mode() in comments Signed-off-by: Russell King --- drivers/input/keyboard/corgikbd.c | 6 +++--- drivers/input/keyboard/spitzkbd.c | 6 +++--- drivers/input/keyboard/tosakbd.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 134e67bf6a9..c8ed065ea0c 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -80,9 +80,9 @@ struct corgikbd { #define KB_ACTIVATE_DELAY 10 /* Helper functions for reading the keyboard matrix - * Note: We should really be using pxa_gpio_mode to alter GPDR but it - * requires a function call per GPIO bit which is excessive - * when we need to access 12 bits at once multiple times. + * Note: We should really be using the generic gpio functions to alter + * GPDR but it requires a function call per GPIO bit which is + * excessive when we need to access 12 bits at once, multiple times. * These functions must be called within local_irq_save()/local_irq_restore() * or similar. */ diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index de67b8e0a79..c48b76a46a5 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -101,9 +101,9 @@ struct spitzkbd { #define KB_ACTIVATE_DELAY 10 /* Helper functions for reading the keyboard matrix - * Note: We should really be using pxa_gpio_mode to alter GPDR but it - * requires a function call per GPIO bit which is excessive - * when we need to access 11 bits at once, multiple times. + * Note: We should really be using the generic gpio functions to alter + * GPDR but it requires a function call per GPIO bit which is + * excessive when we need to access 11 bits at once, multiple times. * These functions must be called within local_irq_save()/local_irq_restore() * or similar. */ diff --git a/drivers/input/keyboard/tosakbd.c b/drivers/input/keyboard/tosakbd.c index 44cb50af3ce..677276b1202 100644 --- a/drivers/input/keyboard/tosakbd.c +++ b/drivers/input/keyboard/tosakbd.c @@ -59,9 +59,9 @@ struct tosakbd { /* Helper functions for reading the keyboard matrix - * Note: We should really be using pxa_gpio_mode to alter GPDR but it - * requires a function call per GPIO bit which is excessive - * when we need to access 12 bits at once, multiple times. + * Note: We should really be using the generic gpio functions to alter + * GPDR but it requires a function call per GPIO bit which is + * excessive when we need to access 12 bits at once, multiple times. * These functions must be called within local_irq_save()/local_irq_restore() * or similar. */ -- cgit v1.2.3