All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch 03/22] input: AD7879 Touchscreen driver
@ 2009-03-04 19:58 akpm
  2009-03-06  9:48 ` Hennerich, Michael
  0 siblings, 1 reply; 6+ messages in thread
From: akpm @ 2009-03-04 19:58 UTC (permalink / raw)
  To: dtor; +Cc: linux-input, akpm, michael.hennerich, cooloney, randy.dunlap

From: Michael Hennerich <michael.hennerich@analog.com>

[randy.dunlap@oracle.com: touchscreen/ad787x: don't use bus_id]
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Cc: Dmitry Torokhov <dtor@mail.ru>
Cc: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 drivers/input/touchscreen/Kconfig  |   32 +
 drivers/input/touchscreen/Makefile |    1 
 drivers/input/touchscreen/ad7877.c |    6 
 drivers/input/touchscreen/ad7879.c |  797 +++++++++++++++++++++++++++
 include/linux/spi/ad7879.h         |   35 +
 5 files changed, 868 insertions(+), 3 deletions(-)

diff -puN drivers/input/touchscreen/Kconfig~input-ad7879-touchscreen-driver drivers/input/touchscreen/Kconfig
--- a/drivers/input/touchscreen/Kconfig~input-ad7879-touchscreen-driver
+++ a/drivers/input/touchscreen/Kconfig
@@ -42,6 +42,38 @@ config TOUCHSCREEN_AD7877
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7877.
 
+config TOUCHSCREEN_AD7879_I2C
+	tristate "AD7879 based touchscreens: AD7879-1 I2C Interface"
+	depends on I2C
+	select TOUCHSCREEN_AD7879
+	help
+	  Say Y here if you have a touchscreen interface using the
+	  AD7879-1 controller, and your board-specific initialization
+	  code includes that in its table of I2C devices.
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7879.
+
+config TOUCHSCREEN_AD7879_SPI
+	tristate "AD7879 based touchscreens: AD7879 SPI Interface"
+	depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n
+	select TOUCHSCREEN_AD7879
+	help
+	  Say Y here if you have a touchscreen interface using the
+	  AD7879 controller, and your board-specific initialization
+	  code includes that in its table of SPI devices.
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7879.
+
+config TOUCHSCREEN_AD7879
+	tristate
+	default n
+
 config TOUCHSCREEN_BITSY
 	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
 	depends on SA1100_BITSY
diff -puN drivers/input/touchscreen/Makefile~input-ad7879-touchscreen-driver drivers/input/touchscreen/Makefile
--- a/drivers/input/touchscreen/Makefile~input-ad7879-touchscreen-driver
+++ a/drivers/input/touchscreen/Makefile
@@ -7,6 +7,7 @@
 wm97xx-ts-y := wm97xx-core.o
 
 obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879)	+= ad7879.o
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
diff -puN drivers/input/touchscreen/ad7877.c~input-ad7879-touchscreen-driver drivers/input/touchscreen/ad7877.c
--- a/drivers/input/touchscreen/ad7877.c~input-ad7879-touchscreen-driver
+++ a/drivers/input/touchscreen/ad7877.c
@@ -713,7 +713,7 @@ static int __devinit ad7877_probe(struct
 	ts->averaging = pdata->averaging;
 	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
 
-	snprintf(ts->phys, sizeof(ts->phys), "%s/inputX", spi->dev.bus_id);
+	snprintf(ts->phys, sizeof(ts->phys), "%s/inputX", dev_name(&spi->dev));
 
 	input_dev->name = "AD7877 Touchscreen";
 	input_dev->phys = ts->phys;
@@ -740,8 +740,8 @@ static int __devinit ad7877_probe(struct
 	verify = ad7877_read(spi, AD7877_REG_SEQ1);
 
 	if (verify != AD7877_MM_SEQUENCE){
-		dev_err(&spi->dev, "%s: Failed to probe %s\n", spi->dev.bus_id,
-			 input_dev->name);
+		dev_err(&spi->dev, "%s: Failed to probe %s\n",
+			dev_name(&spi->dev), input_dev->name);
 		err = -ENODEV;
 		goto err_free_mem;
 	}
diff -puN /dev/null drivers/input/touchscreen/ad7879.c
--- /dev/null
+++ a/drivers/input/touchscreen/ad7879.c
@@ -0,0 +1,797 @@
+/*
+ * File:        drivers/input/touchscreen/ad7879.c
+ *
+ *		Copyright (C) 2008 Michael Hennerich, Analog Devices Inc.
+ *
+ * Description:	AD7879 based touchscreen, and GPIO driver (I2C/SPI Interface)
+ *
+ * Bugs:        Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * History:
+ * Copyright (c) 2005 David Brownell
+ * Copyright (c) 2006 Nokia Corporation
+ * Various changes: Imre Deak <imre.deak@nokia.com>
+ *
+ * Using code from:
+ *  - corgi_ts.c
+ *	Copyright (C) 2004-2005 Richard Purdie
+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
+ *	Copyright (C) 2002 MontaVista Software
+ *	Copyright (C) 2004 Texas Instruments
+ *	Copyright (C) 2005 Dirk Behme
+ *  - ad7877.c
+ * 	Copyright (C) 2006-2008 Analog Devices Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+
+#include <linux/spi/ad7879.h>
+
+#define AD7879_REG_ZEROS		0
+#define AD7879_REG_CTRL1		1
+#define AD7879_REG_CTRL2		2
+#define AD7879_REG_CTRL3		3
+#define AD7879_REG_AUX1HIGH		4
+#define AD7879_REG_AUX1LOW		5
+#define AD7879_REG_TEMP1HIGH		6
+#define AD7879_REG_TEMP1LOW		7
+#define AD7879_REG_XPLUS		8
+#define AD7879_REG_YPLUS		9
+#define AD7879_REG_Z1			10
+#define AD7879_REG_Z2			11
+#define AD7879_REG_AUXVBAT		12
+#define AD7879_REG_TEMP			13
+#define AD7879_REG_REVID		14
+
+/* Control REG 1 */
+#define AD7879_TMR(x)			((x & 0xFF) << 0)
+#define AD7879_ACQ(x)			((x & 0x3) << 8)
+#define AD7879_MODE_NOC  		(0 << 10)	/* Do not convert */
+#define AD7879_MODE_SCC  		(1 << 10)	/* Single channel conversion */
+#define AD7879_MODE_SEQ0 		(2 << 10)	/* Sequence 0 in Slave Mode */
+#define AD7879_MODE_SEQ1 		(3 << 10)	/* Sequence 1 in Master Mode */
+#define AD7879_MODE_INT 		(1 << 15)	/* PENIRQ disabled INT enabled */
+
+/* Control REG 2 */
+#define AD7879_FCD(x)			((x & 0x3) << 0)
+#define AD7879_RESET			(1 << 4)
+#define AD7879_MFS(x)			((x & 0x3) << 5)
+#define AD7879_AVG(x)			((x & 0x3) << 7)
+#define	AD7879_SER			(1 << 9)	/* non-differential */
+#define	AD7879_DFR			(0 << 9)	/* differential */
+#define AD7879_GPIOPOL			(1 << 10)
+#define AD7879_GPIODIR			(1 << 11)
+#define AD7879_GPIO_DATA		(1 << 12)
+#define AD7879_GPIO_EN			(1 << 13)
+#define AD7879_PM(x)			((x & 0x3) << 14)
+#define AD7879_PM_SHUTDOWN		(0)
+#define AD7879_PM_DYN			(1)
+#define AD7879_PM_FULLON		(2)
+
+/* Control REG 3 */
+#define AD7879_TEMPMASK_BIT		(1<<15)
+#define AD7879_AUXVBATMASK_BIT		(1<<14)
+#define AD7879_INTMODE_BIT		(1<<13)
+#define AD7879_GPIOALERTMASK_BIT	(1<<12)
+#define AD7879_AUXLOW_BIT		(1<<11)
+#define AD7879_AUXHIGH_BIT		(1<<10)
+#define AD7879_TEMPLOW_BIT		(1<<9)
+#define AD7879_TEMPHIGH_BIT		(1<<8)
+#define AD7879_YPLUS_BIT		(1<<7)
+#define AD7879_XPLUS_BIT		(1<<6)
+#define AD7879_Z1_BIT			(1<<5)
+#define AD7879_Z2_BIT			(1<<4)
+#define AD7879_AUX_BIT			(1<<3)
+#define AD7879_VBAT_BIT			(1<<2)
+#define AD7879_TEMP_BIT			(1<<1)
+
+enum {
+	AD7879_SEQ_XPOS  = 0,
+	AD7879_SEQ_YPOS  = 1,
+	AD7879_SEQ_Z1    = 2,
+	AD7879_SEQ_Z2    = 3,
+	AD7879_NR_SENSE  = 4,
+};
+
+#define	MAX_12BIT			((1<<12)-1)
+#define	TS_PEN_UP_TIMEOUT		msecs_to_jiffies(50)
+
+#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
+#define AD7879_DEVID		0x7A
+typedef struct spi_device	bus_device;
+#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
+#define AD7879_DEVID		0x79
+typedef struct i2c_client	bus_device;
+#endif
+
+struct ad7879 {
+	bus_device 		*bus;
+	struct input_dev	*input;
+	struct work_struct	work;
+	struct timer_list	timer;
+	spinlock_t		lock;
+
+#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
+	struct spi_message	msg;
+	struct spi_transfer	xfer[AD7879_NR_SENSE + 1];
+	u16			cmd;
+#endif
+	u16 			conversion_data[AD7879_NR_SENSE];
+	char			phys[32];
+	u8			first_conversion_delay;
+	u8			acquisition_time;
+	u8			averaging;
+	u8			pen_down_acc_interval;
+	u8			median;
+	u16			x_plate_ohms;
+	u16			pressure_max;
+	u16			gpio_init;
+	u16			cmd_crtl1;
+	u16			cmd_crtl2;
+	u16			cmd_crtl3;
+	unsigned		disabled:1;	/* P: lock */
+	unsigned		gpio:1;
+};
+
+static int ad7879_read(bus_device *, u8);
+static int ad7879_write(bus_device *, u8, u16);
+static void ad7879_collect(struct ad7879 *);
+
+static void ad7879_report(struct ad7879 *ts)
+{
+	struct input_dev	*input_dev = ts->input;
+	unsigned		Rt;
+	u16			x, y, z1, z2;
+
+	x = ts->conversion_data[AD7879_SEQ_XPOS] & MAX_12BIT;
+	y = ts->conversion_data[AD7879_SEQ_YPOS] & MAX_12BIT;
+	z1 = ts->conversion_data[AD7879_SEQ_Z1] & MAX_12BIT;
+	z2 = ts->conversion_data[AD7879_SEQ_Z2] & MAX_12BIT;
+
+	/*
+	 * The samples processed here are already preprocessed by the AD7879.
+	 * The preprocessing function consists of a median and an averaging filter.
+	 * The combination of these two techniques provides a robust solution,
+	 * discarding the spurious noise in the signal and keeping only the data of interest.
+	 * The size of both filters is programmable. (dev.platform_data, see linux/spi/ad7879.h)
+	 * Other user-programmable conversion controls include variable acquisition time,
+	 * and first conversion delay. Up to 16 averages can be taken per conversion.
+	 */
+
+	if (likely(x && z1)) {
+		/* compute touch pressure resistance using equation #1 */
+		Rt = (z2 - z1) * x * ts->x_plate_ohms;
+		Rt /= z1;
+		Rt = (Rt + 2047) >> 12;
+	} else
+		Rt = 0;
+
+	if (Rt) {
+		input_report_abs(input_dev, ABS_X, x);
+		input_report_abs(input_dev, ABS_Y, y);
+		input_report_abs(input_dev, ABS_PRESSURE, Rt);
+		input_sync(input_dev);
+	}
+}
+
+static void ad7879_work(struct work_struct *work)
+{
+	struct ad7879 *ts = container_of(work, struct ad7879, work);
+
+	/* use keventd context to read the result registers */
+	ad7879_collect(ts);
+	ad7879_report(ts);
+	mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+}
+
+static void ad7879_ts_event_release(struct ad7879 *ts)
+{
+	struct input_dev *input_dev = ts->input;
+
+	input_report_abs(input_dev, ABS_PRESSURE, 0);
+	input_sync(input_dev);
+}
+
+static void ad7879_timer(unsigned long handle)
+{
+	struct ad7879	*ts = (void *)handle;
+
+	ad7879_ts_event_release(ts);
+}
+
+static irqreturn_t ad7879_irq(int irq, void *handle)
+{
+	struct ad7879 *ts = handle;
+
+	/* The repeated conversion sequencer controlled by TMR kicked off too fast.
+	 * We ignore the last and process the sample sequence currently in the queue.
+	 * It can't be older than 9.4ms
+	 */
+
+	if (!work_pending(&ts->work))
+		schedule_work(&ts->work);
+
+	return IRQ_HANDLED;
+}
+
+static void ad7879_disable(struct ad7879 *ts)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ts->lock, flags);
+	if (ts->disabled) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return;
+	}
+
+	ts->disabled = 1;
+	disable_irq(ts->bus->irq);
+	spin_unlock_irqrestore(&ts->lock, flags);
+
+	cancel_work_sync(&ts->work);
+
+	if (del_timer_sync(&ts->timer))
+		ad7879_ts_event_release(ts);
+
+	/* we know the chip's in lowpower mode since we always
+	 * leave it that way after every request
+	 */
+}
+
+static void ad7879_enable(struct ad7879 *ts)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ts->lock, flags);
+	if (ts->disabled) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return;
+	}
+	ts->disabled = 0;
+	enable_irq(ts->bus->irq);
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static ssize_t ad7879_disable_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t ad7879_disable_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+	unsigned long val;
+	int ret;
+
+	ret = strict_strtoul(buf, 10, &val);
+
+	if (ret)
+		return ret;
+
+	if (val)
+		ad7879_disable(ts);
+	else
+		ad7879_enable(ts);
+
+	return count;
+}
+
+static DEVICE_ATTR(disable, 0664, ad7879_disable_show, ad7879_disable_store);
+
+static ssize_t ad7879_gpio_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ts->gpio);
+}
+
+static ssize_t ad7879_gpio_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+	unsigned long val;
+	int ret;
+
+	ret = strict_strtoul(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	ts->gpio = !!val;
+
+	ret = ad7879_write(ts->bus, AD7879_REG_CTRL2,
+			ts->gpio ? ts->cmd_crtl2 & ~AD7879_GPIO_DATA
+			: ts->cmd_crtl2 | AD7879_GPIO_DATA);
+
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static DEVICE_ATTR(gpio, 0664, ad7879_gpio_show, ad7879_gpio_store);
+
+static struct attribute *ad7879_attributes[] = {
+	&dev_attr_disable.attr,
+	&dev_attr_gpio.attr,
+	NULL
+};
+
+static const struct attribute_group ad7879_attr_group = {
+	.attrs = ad7879_attributes,
+};
+
+static void ad7879_setup(bus_device *bus, struct ad7879 *ts)
+{
+	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
+			AD7879_XPLUS_BIT |
+			AD7879_Z2_BIT |
+			AD7879_Z1_BIT |
+			AD7879_TEMPMASK_BIT |
+			AD7879_AUXVBATMASK_BIT |
+			AD7879_GPIOALERTMASK_BIT;
+
+	ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
+			AD7879_AVG(ts->averaging) |
+			AD7879_MFS(ts->median) |
+			AD7879_FCD(ts->first_conversion_delay) |
+			ts->gpio_init;
+
+	ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
+			AD7879_ACQ(ts->acquisition_time) |
+			AD7879_TMR(ts->pen_down_acc_interval);
+
+	ad7879_write(bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	ad7879_write(bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
+	ad7879_write(bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
+}
+
+static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
+{
+	struct input_dev *input_dev;
+	struct ad7879_platform_data *pdata = bus->dev.platform_data;
+	int err;
+	u16 revid;
+
+	if (!bus->irq) {
+		dev_err(&bus->dev, "no IRQ?\n");
+		return -ENODEV;
+	}
+
+	if (!pdata) {
+		dev_err(&bus->dev, "no platform data?\n");
+		return -ENODEV;
+	}
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	ts->input = input_dev;
+
+	setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
+	INIT_WORK(&ts->work, ad7879_work);
+	spin_lock_init(&ts->lock);
+
+	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+	ts->pressure_max = pdata->pressure_max ? : ~0;
+
+	ts->first_conversion_delay = pdata->first_conversion_delay;
+	ts->acquisition_time = pdata->acquisition_time;
+	ts->averaging = pdata->averaging;
+	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
+	ts->median = pdata->median;
+
+	if (pdata->gpio_output)
+		ts->gpio_init = AD7879_GPIO_EN |
+				(pdata->gpio_default ? 0 : AD7879_GPIO_DATA);
+	else
+		ts->gpio_init = AD7879_GPIO_EN | AD7879_GPIODIR;
+
+	snprintf(ts->phys, sizeof(ts->phys), "%s/inputX", dev_name(&bus->dev));
+
+	input_dev->name = "AD7879 Touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->dev.parent = &bus->dev;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(ABS_X, input_dev->absbit);
+	__set_bit(ABS_Y, input_dev->absbit);
+	__set_bit(ABS_PRESSURE, input_dev->absbit);
+
+	input_set_abs_params(input_dev, ABS_X,
+			pdata->x_min ? : 0,
+			pdata->x_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			pdata->y_min ? : 0,
+			pdata->y_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE,
+			pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+	err = ad7879_write(bus, AD7879_REG_CTRL2, AD7879_RESET);
+
+	if (err < 0) {
+		dev_err(&bus->dev, "Failed to write %s\n", input_dev->name);
+		goto err_free_mem;
+	}
+
+	revid = ad7879_read(bus, AD7879_REG_REVID);
+
+	if ((revid & 0xFF) != AD7879_DEVID) {
+		dev_err(&bus->dev, "Failed to probe %s\n", input_dev->name);
+		err = -ENODEV;
+		goto err_free_mem;
+	}
+
+	ad7879_setup(bus, ts);
+
+	err = request_irq(bus->irq, ad7879_irq, IRQF_TRIGGER_FALLING |
+		IRQF_SAMPLE_RANDOM, bus->dev.driver->name, ts);
+
+	if (err) {
+		dev_err(&bus->dev, "irq %d busy?\n", bus->irq);
+		goto err_free_mem;
+	}
+
+	err = sysfs_create_group(&bus->dev.kobj, &ad7879_attr_group);
+	if (err)
+		goto err_free_irq;
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_remove_attr;
+
+	dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
+		revid >> 8, bus->irq);
+
+	return 0;
+
+err_remove_attr:
+	sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group);
+err_free_irq:
+	free_irq(bus->irq, ts);
+err_free_mem:
+	input_free_device(input_dev);
+
+	return err;
+}
+
+static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts)
+{
+	ad7879_disable(ts);
+	ad7879_write(ts->bus, AD7879_REG_CTRL2,
+			AD7879_PM(AD7879_PM_SHUTDOWN));
+	sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
+	free_irq(ts->bus->irq, ts);
+	input_unregister_device(ts->input);
+	dev_dbg(&bus->dev, "unregistered touchscreen\n");
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ad7879_suspend(bus_device *bus, pm_message_t message)
+{
+	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
+
+	ad7879_disable(ts);
+	ad7879_write(bus, AD7879_REG_CTRL2,
+			AD7879_PM(AD7879_PM_SHUTDOWN));
+
+	return 0;
+}
+
+static int ad7879_resume(bus_device *bus)
+{
+	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
+
+	ad7879_setup(bus, ts);
+	ad7879_enable(ts);
+
+	return 0;
+}
+#else
+#define ad7879_suspend NULL
+#define ad7879_resume  NULL
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
+#define MAX_SPI_FREQ_HZ		5000000
+#define AD7879_CMD_MAGIC	0xE000
+#define AD7879_CMD_READ		(1 << 10)
+#define AD7879_WRITECMD(reg)  	(AD7879_CMD_MAGIC | (reg & 0xF))
+#define AD7879_READCMD(reg)  	(AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF))
+
+struct ser_req {
+	u16			command;
+	u16			data;
+	struct spi_message	msg;
+	struct spi_transfer	xfer[2];
+};
+
+/*
+ * ad7879_read/write are only used for initial setup and for sysfs controls.
+ * The main traffic is done in ad7879_collect().
+ */
+
+static int ad7879_read(struct spi_device *spi, u8 reg)
+{
+	struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
+	int status, ret;
+
+	if (!req)
+		return -ENOMEM;
+
+	spi_message_init(&req->msg);
+
+	req->command = (u16) AD7879_READCMD(reg);
+	req->xfer[0].tx_buf = &req->command;
+	req->xfer[0].len = 2;
+
+	req->xfer[1].rx_buf = &req->data;
+	req->xfer[1].len = 2;
+
+	spi_message_add_tail(&req->xfer[0], &req->msg);
+	spi_message_add_tail(&req->xfer[1], &req->msg);
+
+	status = spi_sync(spi, &req->msg);
+
+	if (status == 0)
+		status = req->msg.status;
+
+	ret = status ? status : req->data;
+	kfree(req);
+
+	return ret;
+}
+
+static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
+{
+	struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
+	int status;
+
+	if (!req)
+		return -ENOMEM;
+
+	spi_message_init(&req->msg);
+
+	req->command = (u16) AD7879_WRITECMD(reg);
+	req->xfer[0].tx_buf = &req->command;
+	req->xfer[0].len = 2;
+
+	req->data = val;
+	req->xfer[1].tx_buf = &req->data;
+	req->xfer[1].len = 2;
+
+	spi_message_add_tail(&req->xfer[0], &req->msg);
+	spi_message_add_tail(&req->xfer[1], &req->msg);
+
+	status = spi_sync(spi, &req->msg);
+
+	if (status == 0)
+		status = req->msg.status;
+
+	kfree(req);
+
+	return status;
+}
+
+static void ad7879_collect(struct ad7879 *ts)
+{
+	int status = spi_sync(ts->bus, &ts->msg);
+	if (status)
+		dev_err(&ts->bus->dev, "spi_sync --> %d\n", status);
+}
+
+static void ad7879_setup_ts_def_msg(struct ad7879 *ts)
+{
+	struct spi_message *m;
+	int i;
+
+	ts->cmd = (u16) AD7879_READCMD(AD7879_REG_XPLUS);
+
+	m = &ts->msg;
+	spi_message_init(m);
+	ts->xfer[0].tx_buf = &ts->cmd;
+	ts->xfer[0].len = 2;
+
+	spi_message_add_tail(&ts->xfer[0], m);
+
+	for (i = 0; i < AD7879_NR_SENSE; i++) {
+		ts->xfer[i + 1].rx_buf = &ts->conversion_data[i];
+		ts->xfer[i + 1].len = 2;
+		spi_message_add_tail(&ts->xfer[i + 1], m);
+	}
+}
+
+static int __devinit ad7879_probe(struct spi_device *spi)
+{
+	struct ad7879 *ts;
+	int ret;
+
+	/* don't exceed max specified SPI CLK frequency */
+	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+		dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
+		return -EINVAL;
+	}
+
+	ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	dev_set_drvdata(&spi->dev, ts);
+	ts->bus = spi;
+
+	ad7879_setup_ts_def_msg(ts);
+
+	ret = ad7879_construct(spi, ts);
+	if (!ret)
+		return ret;
+
+	dev_set_drvdata(&spi->dev, NULL);
+	kfree(ts);
+
+	return ret;
+}
+
+static int __devexit ad7879_remove(struct spi_device *spi)
+{
+	struct ad7879 *ts = dev_get_drvdata(&spi->dev);
+
+	ad7879_destroy(spi, ts);
+	dev_set_drvdata(&spi->dev, NULL);
+	kfree(ts);
+	return 0;
+}
+
+static struct spi_driver ad7879_driver = {
+	.driver = {
+		.name	= "ad7879",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad7879_probe,
+	.remove		= __devexit_p(ad7879_remove),
+	.suspend	= ad7879_suspend,
+	.resume		= ad7879_resume,
+};
+
+static int __init ad7879_init(void)
+{
+	return spi_register_driver(&ad7879_driver);
+}
+module_init(ad7879_init);
+
+static void __exit ad7879_exit(void)
+{
+	spi_unregister_driver(&ad7879_driver);
+}
+module_exit(ad7879_exit);
+
+#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
+
+/* All registers are word-sized.
+ * AD7879 uses a high-byte first convention.
+ */
+static int ad7879_read(struct i2c_client *client, u8 reg)
+{
+	return swab16(i2c_smbus_read_word_data(client, reg));
+}
+
+static int ad7879_write(struct i2c_client *client, u8 reg, u16 val)
+{
+	return i2c_smbus_write_word_data(client, reg, swab16(val));
+}
+
+static void ad7879_collect(struct ad7879 *ts)
+{
+	int i;
+	for (i = 0; i < AD7879_NR_SENSE; i++)
+		ts->conversion_data[i] =
+			ad7879_read(ts->bus, AD7879_REG_XPLUS + i);
+}
+
+static int __devinit ad7879_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct ad7879 *ts;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+					I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+		return -EIO;
+	}
+
+	ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, ts);
+	ts->bus = client;
+
+	ret = ad7879_construct(client, ts);
+	if (!ret)
+		return ret;
+
+	i2c_set_clientdata(client, NULL);
+	kfree(ts);
+
+	return ret;
+}
+
+static int __devexit ad7879_remove(struct i2c_client *client)
+{
+	struct ad7879 *ts = dev_get_drvdata(&client->dev);
+
+	ad7879_destroy(client, ts);
+	i2c_set_clientdata(client, NULL);
+	kfree(ts);
+	return 0;
+}
+static const struct i2c_device_id ad7979_id[] = {
+	{ "ad7879", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad7979_id);
+
+static struct i2c_driver ad7879_driver = {
+	.driver = {
+		.name	= "ad7879",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad7879_probe,
+	.remove		= __devexit_p(ad7879_remove),
+	.suspend	= ad7879_suspend,
+	.resume		= ad7879_resume,
+	.id_table 	= ad7979_id,
+};
+
+static int __init ad7879_init(void)
+{
+	return i2c_add_driver(&ad7879_driver);
+}
+module_init(ad7879_init);
+
+static void __exit ad7879_exit(void)
+{
+	i2c_del_driver(&ad7879_driver);
+}
+module_exit(ad7879_exit);
+#endif
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
+MODULE_LICENSE("GPL");
diff -puN /dev/null include/linux/spi/ad7879.h
--- /dev/null
+++ a/include/linux/spi/ad7879.h
@@ -0,0 +1,35 @@
+/* linux/spi/ad7879.h */
+
+/* Touchscreen characteristics vary between boards and models.  The
+ * platform_data for the device's "struct device" holds this information.
+ *
+ * It's OK if the min/max values are zero.
+ */
+struct ad7879_platform_data {
+	u16	model;			/* 7879 */
+	u16	x_plate_ohms;
+	u16	x_min, x_max;
+	u16	y_min, y_max;
+	u16	pressure_min, pressure_max;
+
+	/* [0..255] 0=OFF Starts at 1=550us and goes
+	 * all the way to 9.440ms in steps of 35us.
+	 */
+	u8	pen_down_acc_interval;
+	/* [0..15] Starts at 0=128us and goes all the
+	 * way to 4.096ms in steps of 128us.
+	 */
+	u8	first_conversion_delay;
+	/* [0..3] 0 = 2us, 1 = 4us, 2 = 8us, 3 = 16us */
+	u8	acquisition_time;
+	/* [0..3] Average X middle samples 0 = 2, 1 = 4, 2 = 8, 3 = 16 */
+	u8	averaging;
+	/* [0..3] Perform X measurements 0 = OFF,
+	 * 1 = 4, 2 = 8, 3 = 16 (median > averaging)
+	 */
+	u8	median;
+	/* 1 = AUX/VBAT/GPIO set to GPIO Output */
+	u8	gpio_output;
+	/* Initial GPIO pin state (valid if gpio_output = 1) */
+	u8	gpio_default;
+};
_

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [patch 03/22] input: AD7879 Touchscreen driver
  2009-03-04 19:58 [patch 03/22] input: AD7879 Touchscreen driver akpm
@ 2009-03-06  9:48 ` Hennerich, Michael
  2009-03-06 10:05   ` Dmitry Torokhov
  0 siblings, 1 reply; 6+ messages in thread
From: Hennerich, Michael @ 2009-03-06  9:48 UTC (permalink / raw)
  To: akpm, dtor, dmitry.torokhov
  Cc: linux-input, michael.hennerich, cooloney, randy.dunlap


Hi Dmitry,

Is there a schedule when this and my other patch get merged mainline?

[patch 01/22] input/touchscreen driver: add support AD7877 touchscreen
driver

Do you have any concerns or is there something that should be done
differently?

Best regards,
Michael 


>From: akpm@linux-foundation.org [mailto:akpm@linux-foundation.org]
>Subject: [patch 03/22] input: AD7879 Touchscreen driver
>
>From: Michael Hennerich <michael.hennerich@analog.com>
>
>[randy.dunlap@oracle.com: touchscreen/ad787x: don't use bus_id]
>Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>Signed-off-by: Bryan Wu <cooloney@kernel.org>
>Cc: Dmitry Torokhov <dtor@mail.ru>
>Cc: Michael Hennerich <michael.hennerich@analog.com>
>Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
>Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
>---
>
> drivers/input/touchscreen/Kconfig  |   32 +
> drivers/input/touchscreen/Makefile |    1
> drivers/input/touchscreen/ad7877.c |    6
> drivers/input/touchscreen/ad7879.c |  797 +++++++++++++++++++++++++++
> include/linux/spi/ad7879.h         |   35 +
> 5 files changed, 868 insertions(+), 3 deletions(-)
>
>diff -puN
drivers/input/touchscreen/Kconfig~input-ad7879-touchscreen-driver
>drivers/input/touchscreen/Kconfig
>--- a/drivers/input/touchscreen/Kconfig~input-ad7879-touchscreen-driver
>+++ a/drivers/input/touchscreen/Kconfig
>@@ -42,6 +42,38 @@ config TOUCHSCREEN_AD7877
> 	  To compile this driver as a module, choose M here: the
> 	  module will be called ad7877.
>
>+config TOUCHSCREEN_AD7879_I2C
>+	tristate "AD7879 based touchscreens: AD7879-1 I2C Interface"
>+	depends on I2C
>+	select TOUCHSCREEN_AD7879
>+	help
>+	  Say Y here if you have a touchscreen interface using the
>+	  AD7879-1 controller, and your board-specific initialization
>+	  code includes that in its table of I2C devices.
>+
>+	  If unsure, say N (but it's safe to say "Y").
>+
>+	  To compile this driver as a module, choose M here: the
>+	  module will be called ad7879.
>+
>+config TOUCHSCREEN_AD7879_SPI
>+	tristate "AD7879 based touchscreens: AD7879 SPI Interface"
>+	depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n
>+	select TOUCHSCREEN_AD7879
>+	help
>+	  Say Y here if you have a touchscreen interface using the
>+	  AD7879 controller, and your board-specific initialization
>+	  code includes that in its table of SPI devices.
>+
>+	  If unsure, say N (but it's safe to say "Y").
>+
>+	  To compile this driver as a module, choose M here: the
>+	  module will be called ad7879.
>+
>+config TOUCHSCREEN_AD7879
>+	tristate
>+	default n
>+
> config TOUCHSCREEN_BITSY
> 	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
> 	depends on SA1100_BITSY
>diff -puN drivers/input/touchscreen/Makefile~input-ad7879-touchscreen-
>driver drivers/input/touchscreen/Makefile
>---
a/drivers/input/touchscreen/Makefile~input-ad7879-touchscreen-driver
>+++ a/drivers/input/touchscreen/Makefile
>@@ -7,6 +7,7 @@
> wm97xx-ts-y := wm97xx-core.o
>
> obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
>+obj-$(CONFIG_TOUCHSCREEN_AD7879)	+= ad7879.o
> obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
> obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
> obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
>diff -puN drivers/input/touchscreen/ad7877.c~input-ad7879-touchscreen-
>driver drivers/input/touchscreen/ad7877.c
>---
a/drivers/input/touchscreen/ad7877.c~input-ad7879-touchscreen-driver
>+++ a/drivers/input/touchscreen/ad7877.c
>@@ -713,7 +713,7 @@ static int __devinit ad7877_probe(struct
> 	ts->averaging = pdata->averaging;
> 	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
>
>-	snprintf(ts->phys, sizeof(ts->phys), "%s/inputX",
spi->dev.bus_id);
>+	snprintf(ts->phys, sizeof(ts->phys), "%s/inputX", dev_name(&spi-
>>dev));
>
> 	input_dev->name = "AD7877 Touchscreen";
> 	input_dev->phys = ts->phys;
>@@ -740,8 +740,8 @@ static int __devinit ad7877_probe(struct
> 	verify = ad7877_read(spi, AD7877_REG_SEQ1);
>
> 	if (verify != AD7877_MM_SEQUENCE){
>-		dev_err(&spi->dev, "%s: Failed to probe %s\n",
spi->dev.bus_id,
>-			 input_dev->name);
>+		dev_err(&spi->dev, "%s: Failed to probe %s\n",
>+			dev_name(&spi->dev), input_dev->name);
> 		err = -ENODEV;
> 		goto err_free_mem;
> 	}
>diff -puN /dev/null drivers/input/touchscreen/ad7879.c
>--- /dev/null
>+++ a/drivers/input/touchscreen/ad7879.c
>@@ -0,0 +1,797 @@
>+/*
>+ * File:        drivers/input/touchscreen/ad7879.c
>+ *
>+ *		Copyright (C) 2008 Michael Hennerich, Analog Devices
Inc.
>+ *
>+ * Description:	AD7879 based touchscreen, and GPIO driver
(I2C/SPI
>Interface)
>+ *
>+ * Bugs:        Enter bugs at http://blackfin.uclinux.org/
>+ *
>+ * 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.
>+ *
>+ * This program is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+ * GNU General Public License for more details.
>+ *
>+ * You should have received a copy of the GNU General Public License
>+ * along with this program; if not, see the file COPYING, or write
>+ * to the Free Software Foundation, Inc.,
>+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
>+ *
>+ * History:
>+ * Copyright (c) 2005 David Brownell
>+ * Copyright (c) 2006 Nokia Corporation
>+ * Various changes: Imre Deak <imre.deak@nokia.com>
>+ *
>+ * Using code from:
>+ *  - corgi_ts.c
>+ *	Copyright (C) 2004-2005 Richard Purdie
>+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
>+ *	Copyright (C) 2002 MontaVista Software
>+ *	Copyright (C) 2004 Texas Instruments
>+ *	Copyright (C) 2005 Dirk Behme
>+ *  - ad7877.c
>+ * 	Copyright (C) 2006-2008 Analog Devices Inc.
>+ */
>+
>+#include <linux/device.h>
>+#include <linux/init.h>
>+#include <linux/delay.h>
>+#include <linux/input.h>
>+#include <linux/interrupt.h>
>+#include <linux/irq.h>
>+#include <linux/slab.h>
>+#include <linux/workqueue.h>
>+#include <linux/spi/spi.h>
>+#include <linux/i2c.h>
>+
>+#include <linux/spi/ad7879.h>
>+
>+#define AD7879_REG_ZEROS		0
>+#define AD7879_REG_CTRL1		1
>+#define AD7879_REG_CTRL2		2
>+#define AD7879_REG_CTRL3		3
>+#define AD7879_REG_AUX1HIGH		4
>+#define AD7879_REG_AUX1LOW		5
>+#define AD7879_REG_TEMP1HIGH		6
>+#define AD7879_REG_TEMP1LOW		7
>+#define AD7879_REG_XPLUS		8
>+#define AD7879_REG_YPLUS		9
>+#define AD7879_REG_Z1			10
>+#define AD7879_REG_Z2			11
>+#define AD7879_REG_AUXVBAT		12
>+#define AD7879_REG_TEMP			13
>+#define AD7879_REG_REVID		14
>+
>+/* Control REG 1 */
>+#define AD7879_TMR(x)			((x & 0xFF) << 0)
>+#define AD7879_ACQ(x)			((x & 0x3) << 8)
>+#define AD7879_MODE_NOC  		(0 << 10)	/* Do not
convert */
>+#define AD7879_MODE_SCC  		(1 << 10)	/* Single
channel
>conversion */
>+#define AD7879_MODE_SEQ0 		(2 << 10)	/* Sequence 0 in
Slave Mode
>*/
>+#define AD7879_MODE_SEQ1 		(3 << 10)	/* Sequence 1 in
Master
>Mode */
>+#define AD7879_MODE_INT 		(1 << 15)	/* PENIRQ
disabled INT
>enabled */
>+
>+/* Control REG 2 */
>+#define AD7879_FCD(x)			((x & 0x3) << 0)
>+#define AD7879_RESET			(1 << 4)
>+#define AD7879_MFS(x)			((x & 0x3) << 5)
>+#define AD7879_AVG(x)			((x & 0x3) << 7)
>+#define	AD7879_SER			(1 << 9)	/*
non-differential */
>+#define	AD7879_DFR			(0 << 9)	/*
differential */
>+#define AD7879_GPIOPOL			(1 << 10)
>+#define AD7879_GPIODIR			(1 << 11)
>+#define AD7879_GPIO_DATA		(1 << 12)
>+#define AD7879_GPIO_EN			(1 << 13)
>+#define AD7879_PM(x)			((x & 0x3) << 14)
>+#define AD7879_PM_SHUTDOWN		(0)
>+#define AD7879_PM_DYN			(1)
>+#define AD7879_PM_FULLON		(2)
>+
>+/* Control REG 3 */
>+#define AD7879_TEMPMASK_BIT		(1<<15)
>+#define AD7879_AUXVBATMASK_BIT		(1<<14)
>+#define AD7879_INTMODE_BIT		(1<<13)
>+#define AD7879_GPIOALERTMASK_BIT	(1<<12)
>+#define AD7879_AUXLOW_BIT		(1<<11)
>+#define AD7879_AUXHIGH_BIT		(1<<10)
>+#define AD7879_TEMPLOW_BIT		(1<<9)
>+#define AD7879_TEMPHIGH_BIT		(1<<8)
>+#define AD7879_YPLUS_BIT		(1<<7)
>+#define AD7879_XPLUS_BIT		(1<<6)
>+#define AD7879_Z1_BIT			(1<<5)
>+#define AD7879_Z2_BIT			(1<<4)
>+#define AD7879_AUX_BIT			(1<<3)
>+#define AD7879_VBAT_BIT			(1<<2)
>+#define AD7879_TEMP_BIT			(1<<1)
>+
>+enum {
>+	AD7879_SEQ_XPOS  = 0,
>+	AD7879_SEQ_YPOS  = 1,
>+	AD7879_SEQ_Z1    = 2,
>+	AD7879_SEQ_Z2    = 3,
>+	AD7879_NR_SENSE  = 4,
>+};
>+
>+#define	MAX_12BIT			((1<<12)-1)
>+#define	TS_PEN_UP_TIMEOUT		msecs_to_jiffies(50)
>+
>+#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) ||
>defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
>+#define AD7879_DEVID		0x7A
>+typedef struct spi_device	bus_device;
>+#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) ||
>defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
>+#define AD7879_DEVID		0x79
>+typedef struct i2c_client	bus_device;
>+#endif
>+
>+struct ad7879 {
>+	bus_device 		*bus;
>+	struct input_dev	*input;
>+	struct work_struct	work;
>+	struct timer_list	timer;
>+	spinlock_t		lock;
>+
>+#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) ||
>defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
>+	struct spi_message	msg;
>+	struct spi_transfer	xfer[AD7879_NR_SENSE + 1];
>+	u16			cmd;
>+#endif
>+	u16 			conversion_data[AD7879_NR_SENSE];
>+	char			phys[32];
>+	u8			first_conversion_delay;
>+	u8			acquisition_time;
>+	u8			averaging;
>+	u8			pen_down_acc_interval;
>+	u8			median;
>+	u16			x_plate_ohms;
>+	u16			pressure_max;
>+	u16			gpio_init;
>+	u16			cmd_crtl1;
>+	u16			cmd_crtl2;
>+	u16			cmd_crtl3;
>+	unsigned		disabled:1;	/* P: lock */
>+	unsigned		gpio:1;
>+};
>+
>+static int ad7879_read(bus_device *, u8);
>+static int ad7879_write(bus_device *, u8, u16);
>+static void ad7879_collect(struct ad7879 *);
>+
>+static void ad7879_report(struct ad7879 *ts)
>+{
>+	struct input_dev	*input_dev = ts->input;
>+	unsigned		Rt;
>+	u16			x, y, z1, z2;
>+
>+	x = ts->conversion_data[AD7879_SEQ_XPOS] & MAX_12BIT;
>+	y = ts->conversion_data[AD7879_SEQ_YPOS] & MAX_12BIT;
>+	z1 = ts->conversion_data[AD7879_SEQ_Z1] & MAX_12BIT;
>+	z2 = ts->conversion_data[AD7879_SEQ_Z2] & MAX_12BIT;
>+
>+	/*
>+	 * The samples processed here are already preprocessed by the
AD7879.
>+	 * The preprocessing function consists of a median and an
averaging
>filter.
>+	 * The combination of these two techniques provides a robust
>solution,
>+	 * discarding the spurious noise in the signal and keeping only
the
>data of interest.
>+	 * The size of both filters is programmable. (dev.platform_data,
see
>linux/spi/ad7879.h)
>+	 * Other user-programmable conversion controls include variable
>acquisition time,
>+	 * and first conversion delay. Up to 16 averages can be taken
per
>conversion.
>+	 */
>+
>+	if (likely(x && z1)) {
>+		/* compute touch pressure resistance using equation #1
*/
>+		Rt = (z2 - z1) * x * ts->x_plate_ohms;
>+		Rt /= z1;
>+		Rt = (Rt + 2047) >> 12;
>+	} else
>+		Rt = 0;
>+
>+	if (Rt) {
>+		input_report_abs(input_dev, ABS_X, x);
>+		input_report_abs(input_dev, ABS_Y, y);
>+		input_report_abs(input_dev, ABS_PRESSURE, Rt);
>+		input_sync(input_dev);
>+	}
>+}
>+
>+static void ad7879_work(struct work_struct *work)
>+{
>+	struct ad7879 *ts = container_of(work, struct ad7879, work);
>+
>+	/* use keventd context to read the result registers */
>+	ad7879_collect(ts);
>+	ad7879_report(ts);
>+	mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
>+}
>+
>+static void ad7879_ts_event_release(struct ad7879 *ts)
>+{
>+	struct input_dev *input_dev = ts->input;
>+
>+	input_report_abs(input_dev, ABS_PRESSURE, 0);
>+	input_sync(input_dev);
>+}
>+
>+static void ad7879_timer(unsigned long handle)
>+{
>+	struct ad7879	*ts = (void *)handle;
>+
>+	ad7879_ts_event_release(ts);
>+}
>+
>+static irqreturn_t ad7879_irq(int irq, void *handle)
>+{
>+	struct ad7879 *ts = handle;
>+
>+	/* The repeated conversion sequencer controlled by TMR kicked
off too
>fast.
>+	 * We ignore the last and process the sample sequence currently
in
>the queue.
>+	 * It can't be older than 9.4ms
>+	 */
>+
>+	if (!work_pending(&ts->work))
>+		schedule_work(&ts->work);
>+
>+	return IRQ_HANDLED;
>+}
>+
>+static void ad7879_disable(struct ad7879 *ts)
>+{
>+	unsigned long flags;
>+
>+	spin_lock_irqsave(&ts->lock, flags);
>+	if (ts->disabled) {
>+		spin_unlock_irqrestore(&ts->lock, flags);
>+		return;
>+	}
>+
>+	ts->disabled = 1;
>+	disable_irq(ts->bus->irq);
>+	spin_unlock_irqrestore(&ts->lock, flags);
>+
>+	cancel_work_sync(&ts->work);
>+
>+	if (del_timer_sync(&ts->timer))
>+		ad7879_ts_event_release(ts);
>+
>+	/* we know the chip's in lowpower mode since we always
>+	 * leave it that way after every request
>+	 */
>+}
>+
>+static void ad7879_enable(struct ad7879 *ts)
>+{
>+	unsigned long flags;
>+
>+	spin_lock_irqsave(&ts->lock, flags);
>+	if (ts->disabled) {
>+		spin_unlock_irqrestore(&ts->lock, flags);
>+		return;
>+	}
>+	ts->disabled = 0;
>+	enable_irq(ts->bus->irq);
>+	spin_unlock_irqrestore(&ts->lock, flags);
>+}
>+
>+static ssize_t ad7879_disable_show(struct device *dev,
>+				     struct device_attribute *attr, char
*buf)
>+{
>+	struct ad7879 *ts = dev_get_drvdata(dev);
>+
>+	return sprintf(buf, "%u\n", ts->disabled);
>+}
>+
>+static ssize_t ad7879_disable_store(struct device *dev,
>+				     struct device_attribute *attr,
>+				     const char *buf, size_t count)
>+{
>+	struct ad7879 *ts = dev_get_drvdata(dev);
>+	unsigned long val;
>+	int ret;
>+
>+	ret = strict_strtoul(buf, 10, &val);
>+
>+	if (ret)
>+		return ret;
>+
>+	if (val)
>+		ad7879_disable(ts);
>+	else
>+		ad7879_enable(ts);
>+
>+	return count;
>+}
>+
>+static DEVICE_ATTR(disable, 0664, ad7879_disable_show,
>ad7879_disable_store);
>+
>+static ssize_t ad7879_gpio_show(struct device *dev,
>+				     struct device_attribute *attr, char
*buf)
>+{
>+	struct ad7879 *ts = dev_get_drvdata(dev);
>+
>+	return sprintf(buf, "%u\n", ts->gpio);
>+}
>+
>+static ssize_t ad7879_gpio_store(struct device *dev,
>+				     struct device_attribute *attr,
>+				     const char *buf, size_t count)
>+{
>+	struct ad7879 *ts = dev_get_drvdata(dev);
>+	unsigned long val;
>+	int ret;
>+
>+	ret = strict_strtoul(buf, 10, &val);
>+	if (ret)
>+		return ret;
>+
>+	ts->gpio = !!val;
>+
>+	ret = ad7879_write(ts->bus, AD7879_REG_CTRL2,
>+			ts->gpio ? ts->cmd_crtl2 & ~AD7879_GPIO_DATA
>+			: ts->cmd_crtl2 | AD7879_GPIO_DATA);
>+
>+	if (ret)
>+		return ret;
>+
>+	return count;
>+}
>+
>+static DEVICE_ATTR(gpio, 0664, ad7879_gpio_show, ad7879_gpio_store);
>+
>+static struct attribute *ad7879_attributes[] = {
>+	&dev_attr_disable.attr,
>+	&dev_attr_gpio.attr,
>+	NULL
>+};
>+
>+static const struct attribute_group ad7879_attr_group = {
>+	.attrs = ad7879_attributes,
>+};
>+
>+static void ad7879_setup(bus_device *bus, struct ad7879 *ts)
>+{
>+	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
>+			AD7879_XPLUS_BIT |
>+			AD7879_Z2_BIT |
>+			AD7879_Z1_BIT |
>+			AD7879_TEMPMASK_BIT |
>+			AD7879_AUXVBATMASK_BIT |
>+			AD7879_GPIOALERTMASK_BIT;
>+
>+	ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
>+			AD7879_AVG(ts->averaging) |
>+			AD7879_MFS(ts->median) |
>+			AD7879_FCD(ts->first_conversion_delay) |
>+			ts->gpio_init;
>+
>+	ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
>+			AD7879_ACQ(ts->acquisition_time) |
>+			AD7879_TMR(ts->pen_down_acc_interval);
>+
>+	ad7879_write(bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
>+	ad7879_write(bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
>+	ad7879_write(bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
>+}
>+
>+static int __devinit ad7879_construct(bus_device *bus, struct ad7879
*ts)
>+{
>+	struct input_dev *input_dev;
>+	struct ad7879_platform_data *pdata = bus->dev.platform_data;
>+	int err;
>+	u16 revid;
>+
>+	if (!bus->irq) {
>+		dev_err(&bus->dev, "no IRQ?\n");
>+		return -ENODEV;
>+	}
>+
>+	if (!pdata) {
>+		dev_err(&bus->dev, "no platform data?\n");
>+		return -ENODEV;
>+	}
>+
>+	input_dev = input_allocate_device();
>+	if (!input_dev)
>+		return -ENOMEM;
>+
>+	ts->input = input_dev;
>+
>+	setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
>+	INIT_WORK(&ts->work, ad7879_work);
>+	spin_lock_init(&ts->lock);
>+
>+	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
>+	ts->pressure_max = pdata->pressure_max ? : ~0;
>+
>+	ts->first_conversion_delay = pdata->first_conversion_delay;
>+	ts->acquisition_time = pdata->acquisition_time;
>+	ts->averaging = pdata->averaging;
>+	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
>+	ts->median = pdata->median;
>+
>+	if (pdata->gpio_output)
>+		ts->gpio_init = AD7879_GPIO_EN |
>+				(pdata->gpio_default ? 0 :
AD7879_GPIO_DATA);
>+	else
>+		ts->gpio_init = AD7879_GPIO_EN | AD7879_GPIODIR;
>+
>+	snprintf(ts->phys, sizeof(ts->phys), "%s/inputX", dev_name(&bus-
>>dev));
>+
>+	input_dev->name = "AD7879 Touchscreen";
>+	input_dev->phys = ts->phys;
>+	input_dev->dev.parent = &bus->dev;
>+
>+	__set_bit(EV_ABS, input_dev->evbit);
>+	__set_bit(ABS_X, input_dev->absbit);
>+	__set_bit(ABS_Y, input_dev->absbit);
>+	__set_bit(ABS_PRESSURE, input_dev->absbit);
>+
>+	input_set_abs_params(input_dev, ABS_X,
>+			pdata->x_min ? : 0,
>+			pdata->x_max ? : MAX_12BIT,
>+			0, 0);
>+	input_set_abs_params(input_dev, ABS_Y,
>+			pdata->y_min ? : 0,
>+			pdata->y_max ? : MAX_12BIT,
>+			0, 0);
>+	input_set_abs_params(input_dev, ABS_PRESSURE,
>+			pdata->pressure_min, pdata->pressure_max, 0, 0);
>+
>+	err = ad7879_write(bus, AD7879_REG_CTRL2, AD7879_RESET);
>+
>+	if (err < 0) {
>+		dev_err(&bus->dev, "Failed to write %s\n",
input_dev->name);
>+		goto err_free_mem;
>+	}
>+
>+	revid = ad7879_read(bus, AD7879_REG_REVID);
>+
>+	if ((revid & 0xFF) != AD7879_DEVID) {
>+		dev_err(&bus->dev, "Failed to probe %s\n",
input_dev->name);
>+		err = -ENODEV;
>+		goto err_free_mem;
>+	}
>+
>+	ad7879_setup(bus, ts);
>+
>+	err = request_irq(bus->irq, ad7879_irq, IRQF_TRIGGER_FALLING |
>+		IRQF_SAMPLE_RANDOM, bus->dev.driver->name, ts);
>+
>+	if (err) {
>+		dev_err(&bus->dev, "irq %d busy?\n", bus->irq);
>+		goto err_free_mem;
>+	}
>+
>+	err = sysfs_create_group(&bus->dev.kobj, &ad7879_attr_group);
>+	if (err)
>+		goto err_free_irq;
>+
>+	err = input_register_device(input_dev);
>+	if (err)
>+		goto err_remove_attr;
>+
>+	dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
>+		revid >> 8, bus->irq);
>+
>+	return 0;
>+
>+err_remove_attr:
>+	sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group);
>+err_free_irq:
>+	free_irq(bus->irq, ts);
>+err_free_mem:
>+	input_free_device(input_dev);
>+
>+	return err;
>+}
>+
>+static int __devexit ad7879_destroy(bus_device *bus, struct ad7879
*ts)
>+{
>+	ad7879_disable(ts);
>+	ad7879_write(ts->bus, AD7879_REG_CTRL2,
>+			AD7879_PM(AD7879_PM_SHUTDOWN));
>+	sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
>+	free_irq(ts->bus->irq, ts);
>+	input_unregister_device(ts->input);
>+	dev_dbg(&bus->dev, "unregistered touchscreen\n");
>+
>+	return 0;
>+}
>+
>+#ifdef CONFIG_PM
>+static int ad7879_suspend(bus_device *bus, pm_message_t message)
>+{
>+	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
>+
>+	ad7879_disable(ts);
>+	ad7879_write(bus, AD7879_REG_CTRL2,
>+			AD7879_PM(AD7879_PM_SHUTDOWN));
>+
>+	return 0;
>+}
>+
>+static int ad7879_resume(bus_device *bus)
>+{
>+	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
>+
>+	ad7879_setup(bus, ts);
>+	ad7879_enable(ts);
>+
>+	return 0;
>+}
>+#else
>+#define ad7879_suspend NULL
>+#define ad7879_resume  NULL
>+#endif
>+
>+#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) ||
>defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
>+#define MAX_SPI_FREQ_HZ		5000000
>+#define AD7879_CMD_MAGIC	0xE000
>+#define AD7879_CMD_READ		(1 << 10)
>+#define AD7879_WRITECMD(reg)  	(AD7879_CMD_MAGIC | (reg & 0xF))
>+#define AD7879_READCMD(reg)  	(AD7879_CMD_MAGIC | AD7879_CMD_READ |
>(reg & 0xF))
>+
>+struct ser_req {
>+	u16			command;
>+	u16			data;
>+	struct spi_message	msg;
>+	struct spi_transfer	xfer[2];
>+};
>+
>+/*
>+ * ad7879_read/write are only used for initial setup and for sysfs
>controls.
>+ * The main traffic is done in ad7879_collect().
>+ */
>+
>+static int ad7879_read(struct spi_device *spi, u8 reg)
>+{
>+	struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
>+	int status, ret;
>+
>+	if (!req)
>+		return -ENOMEM;
>+
>+	spi_message_init(&req->msg);
>+
>+	req->command = (u16) AD7879_READCMD(reg);
>+	req->xfer[0].tx_buf = &req->command;
>+	req->xfer[0].len = 2;
>+
>+	req->xfer[1].rx_buf = &req->data;
>+	req->xfer[1].len = 2;
>+
>+	spi_message_add_tail(&req->xfer[0], &req->msg);
>+	spi_message_add_tail(&req->xfer[1], &req->msg);
>+
>+	status = spi_sync(spi, &req->msg);
>+
>+	if (status == 0)
>+		status = req->msg.status;
>+
>+	ret = status ? status : req->data;
>+	kfree(req);
>+
>+	return ret;
>+}
>+
>+static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
>+{
>+	struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
>+	int status;
>+
>+	if (!req)
>+		return -ENOMEM;
>+
>+	spi_message_init(&req->msg);
>+
>+	req->command = (u16) AD7879_WRITECMD(reg);
>+	req->xfer[0].tx_buf = &req->command;
>+	req->xfer[0].len = 2;
>+
>+	req->data = val;
>+	req->xfer[1].tx_buf = &req->data;
>+	req->xfer[1].len = 2;
>+
>+	spi_message_add_tail(&req->xfer[0], &req->msg);
>+	spi_message_add_tail(&req->xfer[1], &req->msg);
>+
>+	status = spi_sync(spi, &req->msg);
>+
>+	if (status == 0)
>+		status = req->msg.status;
>+
>+	kfree(req);
>+
>+	return status;
>+}
>+
>+static void ad7879_collect(struct ad7879 *ts)
>+{
>+	int status = spi_sync(ts->bus, &ts->msg);
>+	if (status)
>+		dev_err(&ts->bus->dev, "spi_sync --> %d\n", status);
>+}
>+
>+static void ad7879_setup_ts_def_msg(struct ad7879 *ts)
>+{
>+	struct spi_message *m;
>+	int i;
>+
>+	ts->cmd = (u16) AD7879_READCMD(AD7879_REG_XPLUS);
>+
>+	m = &ts->msg;
>+	spi_message_init(m);
>+	ts->xfer[0].tx_buf = &ts->cmd;
>+	ts->xfer[0].len = 2;
>+
>+	spi_message_add_tail(&ts->xfer[0], m);
>+
>+	for (i = 0; i < AD7879_NR_SENSE; i++) {
>+		ts->xfer[i + 1].rx_buf = &ts->conversion_data[i];
>+		ts->xfer[i + 1].len = 2;
>+		spi_message_add_tail(&ts->xfer[i + 1], m);
>+	}
>+}
>+
>+static int __devinit ad7879_probe(struct spi_device *spi)
>+{
>+	struct ad7879 *ts;
>+	int ret;
>+
>+	/* don't exceed max specified SPI CLK frequency */
>+	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
>+		dev_err(&spi->dev, "SPI CLK %d Hz?\n",
spi->max_speed_hz);
>+		return -EINVAL;
>+	}
>+
>+	ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
>+	if (!ts)
>+		return -ENOMEM;
>+
>+	dev_set_drvdata(&spi->dev, ts);
>+	ts->bus = spi;
>+
>+	ad7879_setup_ts_def_msg(ts);
>+
>+	ret = ad7879_construct(spi, ts);
>+	if (!ret)
>+		return ret;
>+
>+	dev_set_drvdata(&spi->dev, NULL);
>+	kfree(ts);
>+
>+	return ret;
>+}
>+
>+static int __devexit ad7879_remove(struct spi_device *spi)
>+{
>+	struct ad7879 *ts = dev_get_drvdata(&spi->dev);
>+
>+	ad7879_destroy(spi, ts);
>+	dev_set_drvdata(&spi->dev, NULL);
>+	kfree(ts);
>+	return 0;
>+}
>+
>+static struct spi_driver ad7879_driver = {
>+	.driver = {
>+		.name	= "ad7879",
>+		.bus	= &spi_bus_type,
>+		.owner	= THIS_MODULE,
>+	},
>+	.probe		= ad7879_probe,
>+	.remove		= __devexit_p(ad7879_remove),
>+	.suspend	= ad7879_suspend,
>+	.resume		= ad7879_resume,
>+};
>+
>+static int __init ad7879_init(void)
>+{
>+	return spi_register_driver(&ad7879_driver);
>+}
>+module_init(ad7879_init);
>+
>+static void __exit ad7879_exit(void)
>+{
>+	spi_unregister_driver(&ad7879_driver);
>+}
>+module_exit(ad7879_exit);
>+
>+#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) ||
>defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
>+
>+/* All registers are word-sized.
>+ * AD7879 uses a high-byte first convention.
>+ */
>+static int ad7879_read(struct i2c_client *client, u8 reg)
>+{
>+	return swab16(i2c_smbus_read_word_data(client, reg));
>+}
>+
>+static int ad7879_write(struct i2c_client *client, u8 reg, u16 val)
>+{
>+	return i2c_smbus_write_word_data(client, reg, swab16(val));
>+}
>+
>+static void ad7879_collect(struct ad7879 *ts)
>+{
>+	int i;
>+	for (i = 0; i < AD7879_NR_SENSE; i++)
>+		ts->conversion_data[i] =
>+			ad7879_read(ts->bus, AD7879_REG_XPLUS + i);
>+}
>+
>+static int __devinit ad7879_probe(struct i2c_client *client,
>+					const struct i2c_device_id *id)
>+{
>+	struct ad7879 *ts;
>+	int ret;
>+
>+	if (!i2c_check_functionality(client->adapter,
>+					I2C_FUNC_SMBUS_WORD_DATA)) {
>+		dev_err(&client->dev, "SMBUS Word Data not
Supported\n");
>+		return -EIO;
>+	}
>+
>+	ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
>+	if (!ts)
>+		return -ENOMEM;
>+
>+	i2c_set_clientdata(client, ts);
>+	ts->bus = client;
>+
>+	ret = ad7879_construct(client, ts);
>+	if (!ret)
>+		return ret;
>+
>+	i2c_set_clientdata(client, NULL);
>+	kfree(ts);
>+
>+	return ret;
>+}
>+
>+static int __devexit ad7879_remove(struct i2c_client *client)
>+{
>+	struct ad7879 *ts = dev_get_drvdata(&client->dev);
>+
>+	ad7879_destroy(client, ts);
>+	i2c_set_clientdata(client, NULL);
>+	kfree(ts);
>+	return 0;
>+}
>+static const struct i2c_device_id ad7979_id[] = {
>+	{ "ad7879", 0 },
>+	{ }
>+};
>+MODULE_DEVICE_TABLE(i2c, ad7979_id);
>+
>+static struct i2c_driver ad7879_driver = {
>+	.driver = {
>+		.name	= "ad7879",
>+		.owner	= THIS_MODULE,
>+	},
>+	.probe		= ad7879_probe,
>+	.remove		= __devexit_p(ad7879_remove),
>+	.suspend	= ad7879_suspend,
>+	.resume		= ad7879_resume,
>+	.id_table 	= ad7979_id,
>+};
>+
>+static int __init ad7879_init(void)
>+{
>+	return i2c_add_driver(&ad7879_driver);
>+}
>+module_init(ad7879_init);
>+
>+static void __exit ad7879_exit(void)
>+{
>+	i2c_del_driver(&ad7879_driver);
>+}
>+module_exit(ad7879_exit);
>+#endif
>+
>+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
>+MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
>+MODULE_LICENSE("GPL");
>diff -puN /dev/null include/linux/spi/ad7879.h
>--- /dev/null
>+++ a/include/linux/spi/ad7879.h
>@@ -0,0 +1,35 @@
>+/* linux/spi/ad7879.h */
>+
>+/* Touchscreen characteristics vary between boards and models.  The
>+ * platform_data for the device's "struct device" holds this
information.
>+ *
>+ * It's OK if the min/max values are zero.
>+ */
>+struct ad7879_platform_data {
>+	u16	model;			/* 7879 */
>+	u16	x_plate_ohms;
>+	u16	x_min, x_max;
>+	u16	y_min, y_max;
>+	u16	pressure_min, pressure_max;
>+
>+	/* [0..255] 0=OFF Starts at 1=550us and goes
>+	 * all the way to 9.440ms in steps of 35us.
>+	 */
>+	u8	pen_down_acc_interval;
>+	/* [0..15] Starts at 0=128us and goes all the
>+	 * way to 4.096ms in steps of 128us.
>+	 */
>+	u8	first_conversion_delay;
>+	/* [0..3] 0 = 2us, 1 = 4us, 2 = 8us, 3 = 16us */
>+	u8	acquisition_time;
>+	/* [0..3] Average X middle samples 0 = 2, 1 = 4, 2 = 8, 3 = 16
*/
>+	u8	averaging;
>+	/* [0..3] Perform X measurements 0 = OFF,
>+	 * 1 = 4, 2 = 8, 3 = 16 (median > averaging)
>+	 */
>+	u8	median;
>+	/* 1 = AUX/VBAT/GPIO set to GPIO Output */
>+	u8	gpio_output;
>+	/* Initial GPIO pin state (valid if gpio_output = 1) */
>+	u8	gpio_default;
>+};
>_

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch 03/22] input: AD7879 Touchscreen driver
  2009-03-06  9:48 ` Hennerich, Michael
@ 2009-03-06 10:05   ` Dmitry Torokhov
  2009-03-06 10:07     ` Hennerich, Michael
  0 siblings, 1 reply; 6+ messages in thread
From: Dmitry Torokhov @ 2009-03-06 10:05 UTC (permalink / raw)
  To: Hennerich, Michael; +Cc: akpm, linux-input, cooloney, randy.dunlap

Hi Michael,

On Fri, Mar 06, 2009 at 09:48:17AM -0000, Hennerich, Michael wrote:
> 
> Hi Dmitry,
> 
> Is there a schedule when this and my other patch get merged mainline?
> 
> [patch 01/22] input/touchscreen driver: add support AD7877 touchscreen
> driver
> 
> Do you have any concerns or is there something that should be done
> differently?

I have some concerns with regard to locking in the driver. I had a
preliminary patch but I need to look at it again.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [patch 03/22] input: AD7879 Touchscreen driver
  2009-03-06 10:05   ` Dmitry Torokhov
@ 2009-03-06 10:07     ` Hennerich, Michael
  2009-03-08  7:24       ` Dmitry Torokhov
  0 siblings, 1 reply; 6+ messages in thread
From: Hennerich, Michael @ 2009-03-06 10:07 UTC (permalink / raw)
  To: Dmitry Torokhov, Hennerich, Michael
  Cc: akpm, linux-input, cooloney, randy.dunlap



>From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
>
>Hi Michael,
>
>On Fri, Mar 06, 2009 at 09:48:17AM -0000, Hennerich, Michael wrote:
>>
>> Hi Dmitry,
>>
>> Is there a schedule when this and my other patch get merged mainline?
>>
>> [patch 01/22] input/touchscreen driver: add support AD7877
touchscreen
>> driver
>>
>> Do you have any concerns or is there something that should be done
>> differently?
>
>I have some concerns with regard to locking in the driver. I had a
>preliminary patch but I need to look at it again.
>
>--
>Dmitry

Hi Dmitry,

I reworked the locking, it's now done differently.

-Michael

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch 03/22] input: AD7879 Touchscreen driver
  2009-03-06 10:07     ` Hennerich, Michael
@ 2009-03-08  7:24       ` Dmitry Torokhov
  2009-03-09 15:50         ` Hennerich, Michael
  0 siblings, 1 reply; 6+ messages in thread
From: Dmitry Torokhov @ 2009-03-08  7:24 UTC (permalink / raw)
  To: Hennerich, Michael; +Cc: akpm, linux-input, cooloney, randy.dunlap

On Fri, Mar 06, 2009 at 10:07:36AM -0000, Hennerich, Michael wrote:
> 
> 
> >From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> >
> >Hi Michael,
> >
> >On Fri, Mar 06, 2009 at 09:48:17AM -0000, Hennerich, Michael wrote:
> >>
> >> Hi Dmitry,
> >>
> >> Is there a schedule when this and my other patch get merged mainline?
> >>
> >> [patch 01/22] input/touchscreen driver: add support AD7877
> touchscreen
> >> driver
> >>
> >> Do you have any concerns or is there something that should be done
> >> differently?
> >
> >I have some concerns with regard to locking in the driver. I had a
> >preliminary patch but I need to look at it again.
> >
> >--
> >Dmitry
> 
> Hi Dmitry,
> 
> I reworked the locking, it's now done differently.
> 

I see, it is indeed much better. I have same comment about mutual
exclusion between enable and disable as with 7877 driver. Could you
please try the patch below and let me know if I broke the driver or
not? ;)

Thanks!

-- 
Dmitry

Input: ad7879 fixups

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/input/touchscreen/ad7879.c |  193 +++++++++++++++++-------------------
 1 files changed, 89 insertions(+), 104 deletions(-)


diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 19287af..30b0159 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -1,7 +1,5 @@
 /*
- * File:        drivers/input/touchscreen/ad7879.c
- *
- *		Copyright (C) 2008 Michael Hennerich, Analog Devices Inc.
+ * Copyright (C) 2008 Michael Hennerich, Analog Devices Inc.
  *
  * Description:	AD7879 based touchscreen, and GPIO driver (I2C/SPI Interface)
  *
@@ -35,7 +33,7 @@
  *	Copyright (C) 2004 Texas Instruments
  *	Copyright (C) 2005 Dirk Behme
  *  - ad7877.c
- * 	Copyright (C) 2006-2008 Analog Devices Inc.
+ *	Copyright (C) 2006-2008 Analog Devices Inc.
  */
 
 #include <linux/device.h>
@@ -70,11 +68,11 @@
 /* Control REG 1 */
 #define AD7879_TMR(x)			((x & 0xFF) << 0)
 #define AD7879_ACQ(x)			((x & 0x3) << 8)
-#define AD7879_MODE_NOC  		(0 << 10)	/* Do not convert */
-#define AD7879_MODE_SCC  		(1 << 10)	/* Single channel conversion */
-#define AD7879_MODE_SEQ0 		(2 << 10)	/* Sequence 0 in Slave Mode */
-#define AD7879_MODE_SEQ1 		(3 << 10)	/* Sequence 1 in Master Mode */
-#define AD7879_MODE_INT 		(1 << 15)	/* PENIRQ disabled INT enabled */
+#define AD7879_MODE_NOC			(0 << 10)	/* Do not convert */
+#define AD7879_MODE_SCC			(1 << 10)	/* Single channel conversion */
+#define AD7879_MODE_SEQ0		(2 << 10)	/* Sequence 0 in Slave Mode */
+#define AD7879_MODE_SEQ1		(3 << 10)	/* Sequence 1 in Master Mode */
+#define AD7879_MODE_INT			(1 << 15)	/* PENIRQ disabled INT enabled */
 
 /* Control REG 2 */
 #define AD7879_FCD(x)			((x & 0x3) << 0)
@@ -129,18 +127,20 @@ typedef struct i2c_client	bus_device;
 #endif
 
 struct ad7879 {
-	bus_device 		*bus;
+	bus_device		*bus;
 	struct input_dev	*input;
 	struct work_struct	work;
 	struct timer_list	timer;
-	spinlock_t		lock;
+
+	struct mutex		mutex;
+	unsigned		disabled:1;	/* P: mutex */
 
 #if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
 	struct spi_message	msg;
 	struct spi_transfer	xfer[AD7879_NR_SENSE + 1];
 	u16			cmd;
 #endif
-	u16 			conversion_data[AD7879_NR_SENSE];
+	u16			conversion_data[AD7879_NR_SENSE];
 	char			phys[32];
 	u8			first_conversion_delay;
 	u8			acquisition_time;
@@ -153,7 +153,6 @@ struct ad7879 {
 	u16			cmd_crtl1;
 	u16			cmd_crtl2;
 	u16			cmd_crtl3;
-	unsigned		disabled:1;	/* P: lock */
 	unsigned		gpio:1;
 };
 
@@ -163,9 +162,9 @@ static void ad7879_collect(struct ad7879 *);
 
 static void ad7879_report(struct ad7879 *ts)
 {
-	struct input_dev	*input_dev = ts->input;
-	unsigned		Rt;
-	u16			x, y, z1, z2;
+	struct input_dev *input_dev = ts->input;
+	unsigned Rt;
+	u16 x, y, z1, z2;
 
 	x = ts->conversion_data[AD7879_SEQ_XPOS] & MAX_12BIT;
 	y = ts->conversion_data[AD7879_SEQ_YPOS] & MAX_12BIT;
@@ -187,10 +186,7 @@ static void ad7879_report(struct ad7879 *ts)
 		Rt = (z2 - z1) * x * ts->x_plate_ohms;
 		Rt /= z1;
 		Rt = (Rt + 2047) >> 12;
-	} else
-		Rt = 0;
 
-	if (Rt) {
 		input_report_abs(input_dev, ABS_X, x);
 		input_report_abs(input_dev, ABS_Y, y);
 		input_report_abs(input_dev, ABS_PRESSURE, Rt);
@@ -218,7 +214,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
 
 static void ad7879_timer(unsigned long handle)
 {
-	struct ad7879	*ts = (void *)handle;
+	struct ad7879 *ts = (void *)handle;
 
 	ad7879_ts_event_release(ts);
 }
@@ -240,40 +236,36 @@ static irqreturn_t ad7879_irq(int irq, void *handle)
 
 static void ad7879_disable(struct ad7879 *ts)
 {
-	unsigned long flags;
+	mutex_lock(&ts->mutex);
 
-	spin_lock_irqsave(&ts->lock, flags);
-	if (ts->disabled) {
-		spin_unlock_irqrestore(&ts->lock, flags);
-		return;
-	}
+	if (!ts->disabled) {
 
-	ts->disabled = 1;
-	disable_irq(ts->bus->irq);
-	spin_unlock_irqrestore(&ts->lock, flags);
+		ts->disabled = 1;
+		disable_irq(ts->bus->irq);
 
-	cancel_work_sync(&ts->work);
+		cancel_work_sync(&ts->work);
 
-	if (del_timer_sync(&ts->timer))
-		ad7879_ts_event_release(ts);
+		if (del_timer_sync(&ts->timer))
+			ad7879_ts_event_release(ts);
 
-	/* we know the chip's in lowpower mode since we always
-	 * leave it that way after every request
-	 */
+		ad7879_write(ts->bus, AD7879_REG_CTRL2,
+			     AD7879_PM(AD7879_PM_SHUTDOWN));
+	}
+
+	mutex_unlock(&ts->mutex);
 }
 
 static void ad7879_enable(struct ad7879 *ts)
 {
-	unsigned long flags;
+	mutex_lock(&ts->mutex);
 
-	spin_lock_irqsave(&ts->lock, flags);
 	if (ts->disabled) {
-		spin_unlock_irqrestore(&ts->lock, flags);
-		return;
+		ad7879_setup(ts);
+		ts->disabled = 0;
+		enable_irq(ts->bus->irq);
 	}
-	ts->disabled = 0;
-	enable_irq(ts->bus->irq);
-	spin_unlock_irqrestore(&ts->lock, flags);
+
+	mutex_unlock(&ts->mutex);
 }
 
 static ssize_t ad7879_disable_show(struct device *dev,
@@ -290,12 +282,11 @@ static ssize_t ad7879_disable_store(struct device *dev,
 {
 	struct ad7879 *ts = dev_get_drvdata(dev);
 	unsigned long val;
-	int ret;
-
-	ret = strict_strtoul(buf, 10, &val);
+	int error;
 
-	if (ret)
-		return ret;
+	error = strict_strtoul(buf, 10, &val);
+	if (error)
+		return error;
 
 	if (val)
 		ad7879_disable(ts);
@@ -321,22 +312,21 @@ static ssize_t ad7879_gpio_store(struct device *dev,
 {
 	struct ad7879 *ts = dev_get_drvdata(dev);
 	unsigned long val;
-	int ret;
+	int error;
 
-	ret = strict_strtoul(buf, 10, &val);
-	if (ret)
-		return ret;
+	error = strict_strtoul(buf, 10, &val);
+	if (error)
+		return error;
 
+	mutex_lock(&ts->mutex);
 	ts->gpio = !!val;
+	error = ad7879_write(ts->bus, AD7879_REG_CTRL2,
+			   ts->gpio ?
+				ts->cmd_crtl2 & ~AD7879_GPIO_DATA :
+				ts->cmd_crtl2 | AD7879_GPIO_DATA);
+	mutex_unlock(&ts->mutex);
 
-	ret = ad7879_write(ts->bus, AD7879_REG_CTRL2,
-			ts->gpio ? ts->cmd_crtl2 & ~AD7879_GPIO_DATA
-			: ts->cmd_crtl2 | AD7879_GPIO_DATA);
-
-	if (ret)
-		return ret;
-
-	return count;
+	return error ? : count;
 }
 
 static DEVICE_ATTR(gpio, 0664, ad7879_gpio_show, ad7879_gpio_store);
@@ -351,7 +341,7 @@ static const struct attribute_group ad7879_attr_group = {
 	.attrs = ad7879_attributes,
 };
 
-static void ad7879_setup(bus_device *bus, struct ad7879 *ts)
+static void ad7879_setup(struct ad7879 *ts)
 {
 	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
 			AD7879_XPLUS_BIT |
@@ -371,9 +361,9 @@ static void ad7879_setup(bus_device *bus, struct ad7879 *ts)
 			AD7879_ACQ(ts->acquisition_time) |
 			AD7879_TMR(ts->pen_down_acc_interval);
 
-	ad7879_write(bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
-	ad7879_write(bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
-	ad7879_write(bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
+	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
+	ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
 }
 
 static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
@@ -401,7 +391,7 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 
 	setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
 	INIT_WORK(&ts->work, ad7879_work);
-	spin_lock_init(&ts->lock);
+	mutex_init(&ts->mutex);
 
 	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
 	ts->pressure_max = pdata->pressure_max ? : ~0;
@@ -418,7 +408,7 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 	else
 		ts->gpio_init = AD7879_GPIO_EN | AD7879_GPIODIR;
 
-	snprintf(ts->phys, sizeof(ts->phys), "%s/inputX", dev_name(&bus->dev));
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus->dev));
 
 	input_dev->name = "AD7879 Touchscreen";
 	input_dev->phys = ts->phys;
@@ -455,10 +445,11 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 		goto err_free_mem;
 	}
 
-	ad7879_setup(bus, ts);
+	ad7879_setup(ts);
 
-	err = request_irq(bus->irq, ad7879_irq, IRQF_TRIGGER_FALLING |
-		IRQF_SAMPLE_RANDOM, bus->dev.driver->name, ts);
+	err = request_irq(bus->irq, ad7879_irq,
+			  IRQF_TRIGGER_FALLING | IRQF_SAMPLE_RANDOM,
+			  bus->dev.driver->name, ts);
 
 	if (err) {
 		dev_err(&bus->dev, "irq %d busy?\n", bus->irq);
@@ -474,7 +465,7 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 		goto err_remove_attr;
 
 	dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
-		revid >> 8, bus->irq);
+		 revid >> 8, bus->irq);
 
 	return 0;
 
@@ -491,8 +482,6 @@ err_free_mem:
 static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts)
 {
 	ad7879_disable(ts);
-	ad7879_write(ts->bus, AD7879_REG_CTRL2,
-			AD7879_PM(AD7879_PM_SHUTDOWN));
 	sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
 	free_irq(ts->bus->irq, ts);
 	input_unregister_device(ts->input);
@@ -507,8 +496,6 @@ static int ad7879_suspend(bus_device *bus, pm_message_t message)
 	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
 
 	ad7879_disable(ts);
-	ad7879_write(bus, AD7879_REG_CTRL2,
-			AD7879_PM(AD7879_PM_SHUTDOWN));
 
 	return 0;
 }
@@ -517,7 +504,6 @@ static int ad7879_resume(bus_device *bus)
 {
 	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
 
-	ad7879_setup(bus, ts);
 	ad7879_enable(ts);
 
 	return 0;
@@ -531,8 +517,8 @@ static int ad7879_resume(bus_device *bus)
 #define MAX_SPI_FREQ_HZ		5000000
 #define AD7879_CMD_MAGIC	0xE000
 #define AD7879_CMD_READ		(1 << 10)
-#define AD7879_WRITECMD(reg)  	(AD7879_CMD_MAGIC | (reg & 0xF))
-#define AD7879_READCMD(reg)  	(AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF))
+#define AD7879_WRITECMD(reg)	(AD7879_CMD_MAGIC | (reg & 0xF))
+#define AD7879_READCMD(reg)	(AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF))
 
 struct ser_req {
 	u16			command;
@@ -548,9 +534,10 @@ struct ser_req {
 
 static int ad7879_read(struct spi_device *spi, u8 reg)
 {
-	struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
+	struct ser_req *req;
 	int status, ret;
 
+	req = kzalloc(sizeof *req, GFP_KERNEL);
 	if (!req)
 		return -ENOMEM;
 
@@ -567,11 +554,8 @@ static int ad7879_read(struct spi_device *spi, u8 reg)
 	spi_message_add_tail(&req->xfer[1], &req->msg);
 
 	status = spi_sync(spi, &req->msg);
+	ret = status ? : req->data;
 
-	if (status == 0)
-		status = req->msg.status;
-
-	ret = status ? status : req->data;
 	kfree(req);
 
 	return ret;
@@ -579,9 +563,10 @@ static int ad7879_read(struct spi_device *spi, u8 reg)
 
 static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
 {
-	struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
+	struct ser_req *req;
 	int status;
 
+	req = kzalloc(sizeof *req, GFP_KERNEL);
 	if (!req)
 		return -ENOMEM;
 
@@ -600,9 +585,6 @@ static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
 
 	status = spi_sync(spi, &req->msg);
 
-	if (status == 0)
-		status = req->msg.status;
-
 	kfree(req);
 
 	return status;
@@ -611,6 +593,7 @@ static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
 static void ad7879_collect(struct ad7879 *ts)
 {
 	int status = spi_sync(ts->bus, &ts->msg);
+
 	if (status)
 		dev_err(&ts->bus->dev, "spi_sync --> %d\n", status);
 }
@@ -639,7 +622,7 @@ static void ad7879_setup_ts_def_msg(struct ad7879 *ts)
 static int __devinit ad7879_probe(struct spi_device *spi)
 {
 	struct ad7879 *ts;
-	int ret;
+	int error;
 
 	/* don't exceed max specified SPI CLK frequency */
 	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
@@ -656,14 +639,13 @@ static int __devinit ad7879_probe(struct spi_device *spi)
 
 	ad7879_setup_ts_def_msg(ts);
 
-	ret = ad7879_construct(spi, ts);
-	if (!ret)
-		return ret;
-
-	dev_set_drvdata(&spi->dev, NULL);
-	kfree(ts);
+	error = ad7879_construct(spi, ts);
+	if (error) {
+		dev_set_drvdata(&spi->dev, NULL);
+		kfree(ts);
+	}
 
-	return ret;
+	return 0;
 }
 
 static int __devexit ad7879_remove(struct spi_device *spi)
@@ -673,6 +655,7 @@ static int __devexit ad7879_remove(struct spi_device *spi)
 	ad7879_destroy(spi, ts);
 	dev_set_drvdata(&spi->dev, NULL);
 	kfree(ts);
+
 	return 0;
 }
 
@@ -718,16 +701,17 @@ static int ad7879_write(struct i2c_client *client, u8 reg, u16 val)
 static void ad7879_collect(struct ad7879 *ts)
 {
 	int i;
+
 	for (i = 0; i < AD7879_NR_SENSE; i++)
-		ts->conversion_data[i] =
-			ad7879_read(ts->bus, AD7879_REG_XPLUS + i);
+		ts->conversion_data[i] = ad7879_read(ts->bus,
+						     AD7879_REG_XPLUS + i);
 }
 
 static int __devinit ad7879_probe(struct i2c_client *client,
 					const struct i2c_device_id *id)
 {
 	struct ad7879 *ts;
-	int ret;
+	int error;
 
 	if (!i2c_check_functionality(client->adapter,
 					I2C_FUNC_SMBUS_WORD_DATA)) {
@@ -742,14 +726,13 @@ static int __devinit ad7879_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, ts);
 	ts->bus = client;
 
-	ret = ad7879_construct(client, ts);
-	if (!ret)
-		return ret;
-
-	i2c_set_clientdata(client, NULL);
-	kfree(ts);
+	error = ad7879_construct(client, ts);
+	if (error) {
+		i2c_set_clientdata(client, NULL);
+		kfree(ts);
+	}
 
-	return ret;
+	return 0;
 }
 
 static int __devexit ad7879_remove(struct i2c_client *client)
@@ -759,8 +742,10 @@ static int __devexit ad7879_remove(struct i2c_client *client)
 	ad7879_destroy(client, ts);
 	i2c_set_clientdata(client, NULL);
 	kfree(ts);
+
 	return 0;
 }
+
 static const struct i2c_device_id ad7979_id[] = {
 	{ "ad7879", 0 },
 	{ }
@@ -776,7 +761,7 @@ static struct i2c_driver ad7879_driver = {
 	.remove		= __devexit_p(ad7879_remove),
 	.suspend	= ad7879_suspend,
 	.resume		= ad7879_resume,
-	.id_table 	= ad7979_id,
+	.id_table	= ad7979_id,
 };
 
 static int __init ad7879_init(void)

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* RE: [patch 03/22] input: AD7879 Touchscreen driver
  2009-03-08  7:24       ` Dmitry Torokhov
@ 2009-03-09 15:50         ` Hennerich, Michael
  0 siblings, 0 replies; 6+ messages in thread
From: Hennerich, Michael @ 2009-03-09 15:50 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: akpm, linux-input, cooloney, randy.dunlap

[-- Attachment #1: Type: text/plain, Size: 19827 bytes --]

Hi Dmitry,

>I see, it is indeed much better. I have same comment about mutual
>exclusion between enable and disable as with 7877 driver. Could you
>please try the patch below and let me know if I broke the driver or
>not? ;)

Thanks for your efforts.
The driver still works. Please apply the patch below, on top of your
patch.
It fixes a build error and a typo. (ad7879_setup referenced before
defined) 

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>

Best regards,
Michael

--- drivers/input/touchscreen/ad7879_dtor.c     2009-03-09
16:13:06.000000000 +0100

+++ drivers/input/touchscreen/ad7879.c  2009-03-09 16:14:20.000000000
+0100

@@ -234,6 +234,31 @@ static irqreturn_t ad7879_irq(int irq, v

        return IRQ_HANDLED;

 }

 

+static void ad7879_setup(struct ad7879 *ts)

+{

+       ts->cmd_crtl3 = AD7879_YPLUS_BIT |

+                       AD7879_XPLUS_BIT |

+                       AD7879_Z2_BIT |

+                       AD7879_Z1_BIT |

+                       AD7879_TEMPMASK_BIT |

+                       AD7879_AUXVBATMASK_BIT |

+                       AD7879_GPIOALERTMASK_BIT;

+

+       ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |

+                       AD7879_AVG(ts->averaging) |

+                       AD7879_MFS(ts->median) |

+                       AD7879_FCD(ts->first_conversion_delay) |

+                       ts->gpio_init;

+

+       ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |

+                       AD7879_ACQ(ts->acquisition_time) |

+                       AD7879_TMR(ts->pen_down_acc_interval);

+

+       ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);

+       ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);

+       ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);

+}

+

 static void ad7879_disable(struct ad7879 *ts)

 {

        mutex_lock(&ts->mutex);

@@ -341,31 +366,6 @@ static const struct attribute_group ad78

        .attrs = ad7879_attributes,

 };

 

-static void ad7879_setup(struct ad7879 *ts)

-{

-       ts->cmd_crtl3 = AD7879_YPLUS_BIT |

-                       AD7879_XPLUS_BIT |

-                       AD7879_Z2_BIT |

-                       AD7879_Z1_BIT |

-                       AD7879_TEMPMASK_BIT |

-                       AD7879_AUXVBATMASK_BIT |

-                       AD7879_GPIOALERTMASK_BIT;

-

-       ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |

-                       AD7879_AVG(ts->averaging) |

-                       AD7879_MFS(ts->median) |

-                       AD7879_FCD(ts->first_conversion_delay) |

-                       ts->gpio_init;

-

-       ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |

-                       AD7879_ACQ(ts->acquisition_time) |

-                       AD7879_TMR(ts->pen_down_acc_interval);
-
-       ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
-       ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
-       ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
-}
-
 static int __devinit ad7879_construct(bus_device *bus, struct ad7879
*ts)
 {
        struct input_dev *input_dev;
@@ -746,11 +746,11 @@ static int __devexit ad7879_remove(struc
        return 0;
 }

-static const struct i2c_device_id ad7979_id[] = {
+static const struct i2c_device_id ad7879_id[] = {
        { "ad7879", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(i2c, ad7979_id);
+MODULE_DEVICE_TABLE(i2c, ad7879_id);

 static struct i2c_driver ad7879_driver = {
        .driver = {
@@ -761,7 +761,7 @@ static struct i2c_driver ad7879_driver =
        .remove         = __devexit_p(ad7879_remove),
        .suspend        = ad7879_suspend,
        .resume         = ad7879_resume,
-       .id_table       = ad7979_id,
+       .id_table       = ad7879_id,
 };

 static int __init ad7879_init(void)

>-----Original Message-----
>From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
>Sent: Sunday, March 08, 2009 8:25 AM
>To: Hennerich, Michael
>Cc: akpm@linux-foundation.org; linux-input@vger.kernel.org;
>cooloney@kernel.org; randy.dunlap@oracle.com
>Subject: Re: [patch 03/22] input: AD7879 Touchscreen driver
>
>On Fri, Mar 06, 2009 at 10:07:36AM -0000, Hennerich, Michael wrote:
>>
>>
>> >From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
>> >
>> >Hi Michael,
>> >
>> >On Fri, Mar 06, 2009 at 09:48:17AM -0000, Hennerich, Michael wrote:
>> >>
>> >> Hi Dmitry,
>> >>
>> >> Is there a schedule when this and my other patch get merged
mainline?
>> >>
>> >> [patch 01/22] input/touchscreen driver: add support AD7877
>> touchscreen
>> >> driver
>> >>
>> >> Do you have any concerns or is there something that should be done
>> >> differently?
>> >
>> >I have some concerns with regard to locking in the driver. I had a
>> >preliminary patch but I need to look at it again.
>> >
>> >--
>> >Dmitry
>>
>> Hi Dmitry,
>>
>> I reworked the locking, it's now done differently.
>>
>
>I see, it is indeed much better. I have same comment about mutual
>exclusion between enable and disable as with 7877 driver. Could you
>please try the patch below and let me know if I broke the driver or
>not? ;)
>
>Thanks!
>
>--
>Dmitry
>
>Input: ad7879 fixups
>
>Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
>---
>
> drivers/input/touchscreen/ad7879.c |  193
+++++++++++++++++---------------
>----
> 1 files changed, 89 insertions(+), 104 deletions(-)
>
>
>diff --git a/drivers/input/touchscreen/ad7879.c
>b/drivers/input/touchscreen/ad7879.c
>index 19287af..30b0159 100644
>--- a/drivers/input/touchscreen/ad7879.c
>+++ b/drivers/input/touchscreen/ad7879.c
>@@ -1,7 +1,5 @@
> /*
>- * File:        drivers/input/touchscreen/ad7879.c
>- *
>- *		Copyright (C) 2008 Michael Hennerich, Analog Devices
Inc.
>+ * Copyright (C) 2008 Michael Hennerich, Analog Devices Inc.
>  *
>  * Description:	AD7879 based touchscreen, and GPIO driver
(I2C/SPI
>Interface)
>  *
>@@ -35,7 +33,7 @@
>  *	Copyright (C) 2004 Texas Instruments
>  *	Copyright (C) 2005 Dirk Behme
>  *  - ad7877.c
>- * 	Copyright (C) 2006-2008 Analog Devices Inc.
>+ *	Copyright (C) 2006-2008 Analog Devices Inc.
>  */
>
> #include <linux/device.h>
>@@ -70,11 +68,11 @@
> /* Control REG 1 */
> #define AD7879_TMR(x)			((x & 0xFF) << 0)
> #define AD7879_ACQ(x)			((x & 0x3) << 8)
>-#define AD7879_MODE_NOC  		(0 << 10)	/* Do not
convert */
>-#define AD7879_MODE_SCC  		(1 << 10)	/* Single
channel
>conversion */
>-#define AD7879_MODE_SEQ0 		(2 << 10)	/* Sequence 0 in
Slave Mode
>*/
>-#define AD7879_MODE_SEQ1 		(3 << 10)	/* Sequence 1 in
Master
>Mode */
>-#define AD7879_MODE_INT 		(1 << 15)	/* PENIRQ
disabled INT
>enabled */
>+#define AD7879_MODE_NOC			(0 << 10)	/* Do
not convert */
>+#define AD7879_MODE_SCC			(1 << 10)	/*
Single channel
>conversion */
>+#define AD7879_MODE_SEQ0		(2 << 10)	/* Sequence 0 in
Slave Mode
>*/
>+#define AD7879_MODE_SEQ1		(3 << 10)	/* Sequence 1 in
Master
>Mode */
>+#define AD7879_MODE_INT			(1 << 15)	/*
PENIRQ disabled
>INT enabled */
>
> /* Control REG 2 */
> #define AD7879_FCD(x)			((x & 0x3) << 0)
>@@ -129,18 +127,20 @@ typedef struct i2c_client	bus_device;
> #endif
>
> struct ad7879 {
>-	bus_device 		*bus;
>+	bus_device		*bus;
> 	struct input_dev	*input;
> 	struct work_struct	work;
> 	struct timer_list	timer;
>-	spinlock_t		lock;
>+
>+	struct mutex		mutex;
>+	unsigned		disabled:1;	/* P: mutex */
>
> #if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) ||
>defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
> 	struct spi_message	msg;
> 	struct spi_transfer	xfer[AD7879_NR_SENSE + 1];
> 	u16			cmd;
> #endif
>-	u16 			conversion_data[AD7879_NR_SENSE];
>+	u16			conversion_data[AD7879_NR_SENSE];
> 	char			phys[32];
> 	u8			first_conversion_delay;
> 	u8			acquisition_time;
>@@ -153,7 +153,6 @@ struct ad7879 {
> 	u16			cmd_crtl1;
> 	u16			cmd_crtl2;
> 	u16			cmd_crtl3;
>-	unsigned		disabled:1;	/* P: lock */
> 	unsigned		gpio:1;
> };
>
>@@ -163,9 +162,9 @@ static void ad7879_collect(struct ad7879 *);
>
> static void ad7879_report(struct ad7879 *ts)
> {
>-	struct input_dev	*input_dev = ts->input;
>-	unsigned		Rt;
>-	u16			x, y, z1, z2;
>+	struct input_dev *input_dev = ts->input;
>+	unsigned Rt;
>+	u16 x, y, z1, z2;
>
> 	x = ts->conversion_data[AD7879_SEQ_XPOS] & MAX_12BIT;
> 	y = ts->conversion_data[AD7879_SEQ_YPOS] & MAX_12BIT;
>@@ -187,10 +186,7 @@ static void ad7879_report(struct ad7879 *ts)
> 		Rt = (z2 - z1) * x * ts->x_plate_ohms;
> 		Rt /= z1;
> 		Rt = (Rt + 2047) >> 12;
>-	} else
>-		Rt = 0;
>
>-	if (Rt) {
> 		input_report_abs(input_dev, ABS_X, x);
> 		input_report_abs(input_dev, ABS_Y, y);
> 		input_report_abs(input_dev, ABS_PRESSURE, Rt);
>@@ -218,7 +214,7 @@ static void ad7879_ts_event_release(struct ad7879
*ts)
>
> static void ad7879_timer(unsigned long handle)
> {
>-	struct ad7879	*ts = (void *)handle;
>+	struct ad7879 *ts = (void *)handle;
>
> 	ad7879_ts_event_release(ts);
> }
>@@ -240,40 +236,36 @@ static irqreturn_t ad7879_irq(int irq, void
*handle)
>
> static void ad7879_disable(struct ad7879 *ts)
> {
>-	unsigned long flags;
>+	mutex_lock(&ts->mutex);
>
>-	spin_lock_irqsave(&ts->lock, flags);
>-	if (ts->disabled) {
>-		spin_unlock_irqrestore(&ts->lock, flags);
>-		return;
>-	}
>+	if (!ts->disabled) {
>
>-	ts->disabled = 1;
>-	disable_irq(ts->bus->irq);
>-	spin_unlock_irqrestore(&ts->lock, flags);
>+		ts->disabled = 1;
>+		disable_irq(ts->bus->irq);
>
>-	cancel_work_sync(&ts->work);
>+		cancel_work_sync(&ts->work);
>
>-	if (del_timer_sync(&ts->timer))
>-		ad7879_ts_event_release(ts);
>+		if (del_timer_sync(&ts->timer))
>+			ad7879_ts_event_release(ts);
>
>-	/* we know the chip's in lowpower mode since we always
>-	 * leave it that way after every request
>-	 */
>+		ad7879_write(ts->bus, AD7879_REG_CTRL2,
>+			     AD7879_PM(AD7879_PM_SHUTDOWN));
>+	}
>+
>+	mutex_unlock(&ts->mutex);
> }
>
> static void ad7879_enable(struct ad7879 *ts)
> {
>-	unsigned long flags;
>+	mutex_lock(&ts->mutex);
>
>-	spin_lock_irqsave(&ts->lock, flags);
> 	if (ts->disabled) {
>-		spin_unlock_irqrestore(&ts->lock, flags);
>-		return;
>+		ad7879_setup(ts);
>+		ts->disabled = 0;
>+		enable_irq(ts->bus->irq);
> 	}
>-	ts->disabled = 0;
>-	enable_irq(ts->bus->irq);
>-	spin_unlock_irqrestore(&ts->lock, flags);
>+
>+	mutex_unlock(&ts->mutex);
> }
>
> static ssize_t ad7879_disable_show(struct device *dev,
>@@ -290,12 +282,11 @@ static ssize_t ad7879_disable_store(struct device
>*dev,
> {
> 	struct ad7879 *ts = dev_get_drvdata(dev);
> 	unsigned long val;
>-	int ret;
>-
>-	ret = strict_strtoul(buf, 10, &val);
>+	int error;
>
>-	if (ret)
>-		return ret;
>+	error = strict_strtoul(buf, 10, &val);
>+	if (error)
>+		return error;
>
> 	if (val)
> 		ad7879_disable(ts);
>@@ -321,22 +312,21 @@ static ssize_t ad7879_gpio_store(struct device
*dev,
> {
> 	struct ad7879 *ts = dev_get_drvdata(dev);
> 	unsigned long val;
>-	int ret;
>+	int error;
>
>-	ret = strict_strtoul(buf, 10, &val);
>-	if (ret)
>-		return ret;
>+	error = strict_strtoul(buf, 10, &val);
>+	if (error)
>+		return error;
>
>+	mutex_lock(&ts->mutex);
> 	ts->gpio = !!val;
>+	error = ad7879_write(ts->bus, AD7879_REG_CTRL2,
>+			   ts->gpio ?
>+				ts->cmd_crtl2 & ~AD7879_GPIO_DATA :
>+				ts->cmd_crtl2 | AD7879_GPIO_DATA);
>+	mutex_unlock(&ts->mutex);
>
>-	ret = ad7879_write(ts->bus, AD7879_REG_CTRL2,
>-			ts->gpio ? ts->cmd_crtl2 & ~AD7879_GPIO_DATA
>-			: ts->cmd_crtl2 | AD7879_GPIO_DATA);
>-
>-	if (ret)
>-		return ret;
>-
>-	return count;
>+	return error ? : count;
> }
>
> static DEVICE_ATTR(gpio, 0664, ad7879_gpio_show, ad7879_gpio_store);
>@@ -351,7 +341,7 @@ static const struct attribute_group
ad7879_attr_group =
>{
> 	.attrs = ad7879_attributes,
> };
>
>-static void ad7879_setup(bus_device *bus, struct ad7879 *ts)
>+static void ad7879_setup(struct ad7879 *ts)
> {
> 	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
> 			AD7879_XPLUS_BIT |
>@@ -371,9 +361,9 @@ static void ad7879_setup(bus_device *bus, struct
ad7879
>*ts)
> 			AD7879_ACQ(ts->acquisition_time) |
> 			AD7879_TMR(ts->pen_down_acc_interval);
>
>-	ad7879_write(bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
>-	ad7879_write(bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
>-	ad7879_write(bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
>+	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
>+	ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
>+	ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
> }
>
> static int __devinit ad7879_construct(bus_device *bus, struct ad7879
*ts)
>@@ -401,7 +391,7 @@ static int __devinit ad7879_construct(bus_device
*bus,
>struct ad7879 *ts)
>
> 	setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
> 	INIT_WORK(&ts->work, ad7879_work);
>-	spin_lock_init(&ts->lock);
>+	mutex_init(&ts->mutex);
>
> 	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
> 	ts->pressure_max = pdata->pressure_max ? : ~0;
>@@ -418,7 +408,7 @@ static int __devinit ad7879_construct(bus_device
*bus,
>struct ad7879 *ts)
> 	else
> 		ts->gpio_init = AD7879_GPIO_EN | AD7879_GPIODIR;
>
>-	snprintf(ts->phys, sizeof(ts->phys), "%s/inputX", dev_name(&bus-
>>dev));
>+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus-
>>dev));
>
> 	input_dev->name = "AD7879 Touchscreen";
> 	input_dev->phys = ts->phys;
>@@ -455,10 +445,11 @@ static int __devinit ad7879_construct(bus_device
>*bus, struct ad7879 *ts)
> 		goto err_free_mem;
> 	}
>
>-	ad7879_setup(bus, ts);
>+	ad7879_setup(ts);
>
>-	err = request_irq(bus->irq, ad7879_irq, IRQF_TRIGGER_FALLING |
>-		IRQF_SAMPLE_RANDOM, bus->dev.driver->name, ts);
>+	err = request_irq(bus->irq, ad7879_irq,
>+			  IRQF_TRIGGER_FALLING | IRQF_SAMPLE_RANDOM,
>+			  bus->dev.driver->name, ts);
>
> 	if (err) {
> 		dev_err(&bus->dev, "irq %d busy?\n", bus->irq);
>@@ -474,7 +465,7 @@ static int __devinit ad7879_construct(bus_device
*bus,
>struct ad7879 *ts)
> 		goto err_remove_attr;
>
> 	dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
>-		revid >> 8, bus->irq);
>+		 revid >> 8, bus->irq);
>
> 	return 0;
>
>@@ -491,8 +482,6 @@ err_free_mem:
> static int __devexit ad7879_destroy(bus_device *bus, struct ad7879
*ts)
> {
> 	ad7879_disable(ts);
>-	ad7879_write(ts->bus, AD7879_REG_CTRL2,
>-			AD7879_PM(AD7879_PM_SHUTDOWN));
> 	sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
> 	free_irq(ts->bus->irq, ts);
> 	input_unregister_device(ts->input);
>@@ -507,8 +496,6 @@ static int ad7879_suspend(bus_device *bus,
pm_message_t
>message)
> 	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
>
> 	ad7879_disable(ts);
>-	ad7879_write(bus, AD7879_REG_CTRL2,
>-			AD7879_PM(AD7879_PM_SHUTDOWN));
>
> 	return 0;
> }
>@@ -517,7 +504,6 @@ static int ad7879_resume(bus_device *bus)
> {
> 	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
>
>-	ad7879_setup(bus, ts);
> 	ad7879_enable(ts);
>
> 	return 0;
>@@ -531,8 +517,8 @@ static int ad7879_resume(bus_device *bus)
> #define MAX_SPI_FREQ_HZ		5000000
> #define AD7879_CMD_MAGIC	0xE000
> #define AD7879_CMD_READ		(1 << 10)
>-#define AD7879_WRITECMD(reg)  	(AD7879_CMD_MAGIC | (reg & 0xF))
>-#define AD7879_READCMD(reg)  	(AD7879_CMD_MAGIC | AD7879_CMD_READ |
>(reg & 0xF))
>+#define AD7879_WRITECMD(reg)	(AD7879_CMD_MAGIC | (reg & 0xF))
>+#define AD7879_READCMD(reg)	(AD7879_CMD_MAGIC | AD7879_CMD_READ |
(reg &
>0xF))
>
> struct ser_req {
> 	u16			command;
>@@ -548,9 +534,10 @@ struct ser_req {
>
> static int ad7879_read(struct spi_device *spi, u8 reg)
> {
>-	struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
>+	struct ser_req *req;
> 	int status, ret;
>
>+	req = kzalloc(sizeof *req, GFP_KERNEL);
> 	if (!req)
> 		return -ENOMEM;
>
>@@ -567,11 +554,8 @@ static int ad7879_read(struct spi_device *spi, u8
reg)
> 	spi_message_add_tail(&req->xfer[1], &req->msg);
>
> 	status = spi_sync(spi, &req->msg);
>+	ret = status ? : req->data;
>
>-	if (status == 0)
>-		status = req->msg.status;
>-
>-	ret = status ? status : req->data;
> 	kfree(req);
>
> 	return ret;
>@@ -579,9 +563,10 @@ static int ad7879_read(struct spi_device *spi, u8
reg)
>
> static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
> {
>-	struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
>+	struct ser_req *req;
> 	int status;
>
>+	req = kzalloc(sizeof *req, GFP_KERNEL);
> 	if (!req)
> 		return -ENOMEM;
>
>@@ -600,9 +585,6 @@ static int ad7879_write(struct spi_device *spi, u8
reg,
>u16 val)
>
> 	status = spi_sync(spi, &req->msg);
>
>-	if (status == 0)
>-		status = req->msg.status;
>-
> 	kfree(req);
>
> 	return status;
>@@ -611,6 +593,7 @@ static int ad7879_write(struct spi_device *spi, u8
reg,
>u16 val)
> static void ad7879_collect(struct ad7879 *ts)
> {
> 	int status = spi_sync(ts->bus, &ts->msg);
>+
> 	if (status)
> 		dev_err(&ts->bus->dev, "spi_sync --> %d\n", status);
> }
>@@ -639,7 +622,7 @@ static void ad7879_setup_ts_def_msg(struct ad7879
*ts)
> static int __devinit ad7879_probe(struct spi_device *spi)
> {
> 	struct ad7879 *ts;
>-	int ret;
>+	int error;
>
> 	/* don't exceed max specified SPI CLK frequency */
> 	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
>@@ -656,14 +639,13 @@ static int __devinit ad7879_probe(struct
spi_device
>*spi)
>
> 	ad7879_setup_ts_def_msg(ts);
>
>-	ret = ad7879_construct(spi, ts);
>-	if (!ret)
>-		return ret;
>-
>-	dev_set_drvdata(&spi->dev, NULL);
>-	kfree(ts);
>+	error = ad7879_construct(spi, ts);
>+	if (error) {
>+		dev_set_drvdata(&spi->dev, NULL);
>+		kfree(ts);
>+	}
>
>-	return ret;
>+	return 0;
> }
>
> static int __devexit ad7879_remove(struct spi_device *spi)
>@@ -673,6 +655,7 @@ static int __devexit ad7879_remove(struct
spi_device
>*spi)
> 	ad7879_destroy(spi, ts);
> 	dev_set_drvdata(&spi->dev, NULL);
> 	kfree(ts);
>+
> 	return 0;
> }
>
>@@ -718,16 +701,17 @@ static int ad7879_write(struct i2c_client
*client, u8
>reg, u16 val)
> static void ad7879_collect(struct ad7879 *ts)
> {
> 	int i;
>+
> 	for (i = 0; i < AD7879_NR_SENSE; i++)
>-		ts->conversion_data[i] =
>-			ad7879_read(ts->bus, AD7879_REG_XPLUS + i);
>+		ts->conversion_data[i] = ad7879_read(ts->bus,
>+						     AD7879_REG_XPLUS +
i);
> }
>
> static int __devinit ad7879_probe(struct i2c_client *client,
> 					const struct i2c_device_id *id)
> {
> 	struct ad7879 *ts;
>-	int ret;
>+	int error;
>
> 	if (!i2c_check_functionality(client->adapter,
> 					I2C_FUNC_SMBUS_WORD_DATA)) {
>@@ -742,14 +726,13 @@ static int __devinit ad7879_probe(struct
i2c_client
>*client,
> 	i2c_set_clientdata(client, ts);
> 	ts->bus = client;
>
>-	ret = ad7879_construct(client, ts);
>-	if (!ret)
>-		return ret;
>-
>-	i2c_set_clientdata(client, NULL);
>-	kfree(ts);
>+	error = ad7879_construct(client, ts);
>+	if (error) {
>+		i2c_set_clientdata(client, NULL);
>+		kfree(ts);
>+	}
>
>-	return ret;
>+	return 0;
> }
>
> static int __devexit ad7879_remove(struct i2c_client *client)
>@@ -759,8 +742,10 @@ static int __devexit ad7879_remove(struct
i2c_client
>*client)
> 	ad7879_destroy(client, ts);
> 	i2c_set_clientdata(client, NULL);
> 	kfree(ts);
>+
> 	return 0;
> }
>+
> static const struct i2c_device_id ad7979_id[] = {
> 	{ "ad7879", 0 },
> 	{ }
>@@ -776,7 +761,7 @@ static struct i2c_driver ad7879_driver = {
> 	.remove		= __devexit_p(ad7879_remove),
> 	.suspend	= ad7879_suspend,
> 	.resume		= ad7879_resume,
>-	.id_table 	= ad7979_id,
>+	.id_table	= ad7979_id,
> };
>
> static int __init ad7879_init(void)

[-- Attachment #2: input-ad7879-fixups-fix-typos.patch --]
[-- Type: application/octet-stream, Size: 2602 bytes --]

--- drivers/input/touchscreen/ad7879_dtor.c	2009-03-09 16:13:06.000000000 +0100
+++ drivers/input/touchscreen/ad7879.c	2009-03-09 16:14:20.000000000 +0100
@@ -234,6 +234,31 @@ static irqreturn_t ad7879_irq(int irq, v
 	return IRQ_HANDLED;
 }
 
+static void ad7879_setup(struct ad7879 *ts)
+{
+	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
+			AD7879_XPLUS_BIT |
+			AD7879_Z2_BIT |
+			AD7879_Z1_BIT |
+			AD7879_TEMPMASK_BIT |
+			AD7879_AUXVBATMASK_BIT |
+			AD7879_GPIOALERTMASK_BIT;
+
+	ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
+			AD7879_AVG(ts->averaging) |
+			AD7879_MFS(ts->median) |
+			AD7879_FCD(ts->first_conversion_delay) |
+			ts->gpio_init;
+
+	ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
+			AD7879_ACQ(ts->acquisition_time) |
+			AD7879_TMR(ts->pen_down_acc_interval);
+
+	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
+	ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
+}
+
 static void ad7879_disable(struct ad7879 *ts)
 {
 	mutex_lock(&ts->mutex);
@@ -341,31 +366,6 @@ static const struct attribute_group ad78
 	.attrs = ad7879_attributes,
 };
 
-static void ad7879_setup(struct ad7879 *ts)
-{
-	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
-			AD7879_XPLUS_BIT |
-			AD7879_Z2_BIT |
-			AD7879_Z1_BIT |
-			AD7879_TEMPMASK_BIT |
-			AD7879_AUXVBATMASK_BIT |
-			AD7879_GPIOALERTMASK_BIT;
-
-	ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
-			AD7879_AVG(ts->averaging) |
-			AD7879_MFS(ts->median) |
-			AD7879_FCD(ts->first_conversion_delay) |
-			ts->gpio_init;
-
-	ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
-			AD7879_ACQ(ts->acquisition_time) |
-			AD7879_TMR(ts->pen_down_acc_interval);
-
-	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
-	ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
-	ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
-}
-
 static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 {
 	struct input_dev *input_dev;
@@ -746,11 +746,11 @@ static int __devexit ad7879_remove(struc
 	return 0;
 }
 
-static const struct i2c_device_id ad7979_id[] = {
+static const struct i2c_device_id ad7879_id[] = {
 	{ "ad7879", 0 },
 	{ }
 };
-MODULE_DEVICE_TABLE(i2c, ad7979_id);
+MODULE_DEVICE_TABLE(i2c, ad7879_id);
 
 static struct i2c_driver ad7879_driver = {
 	.driver = {
@@ -761,7 +761,7 @@ static struct i2c_driver ad7879_driver =
 	.remove		= __devexit_p(ad7879_remove),
 	.suspend	= ad7879_suspend,
 	.resume		= ad7879_resume,
-	.id_table	= ad7979_id,
+	.id_table	= ad7879_id,
 };
 
 static int __init ad7879_init(void)

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2009-03-09 15:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-03-04 19:58 [patch 03/22] input: AD7879 Touchscreen driver akpm
2009-03-06  9:48 ` Hennerich, Michael
2009-03-06 10:05   ` Dmitry Torokhov
2009-03-06 10:07     ` Hennerich, Michael
2009-03-08  7:24       ` Dmitry Torokhov
2009-03-09 15:50         ` Hennerich, Michael

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.