diff options
Diffstat (limited to 'drivers/input/touchscreen')
60 files changed, 3478 insertions, 1635 deletions
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index f7de14a268b..0d4a9fad4a7 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -16,6 +16,7 @@  #include <linux/input.h>  #include <linux/mfd/88pm860x.h>  #include <linux/slab.h> +#include <linux/device.h>  #define MEAS_LEN		(8)  #define ACCURATE_BIT		(12) @@ -172,7 +173,7 @@ static int pm860x_touch_dt_init(struct platform_device *pdev,  static int pm860x_touch_probe(struct platform_device *pdev)  {  	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); -	struct pm860x_touch_pdata *pdata = pdev->dev.platform_data; +	struct pm860x_touch_pdata *pdata = dev_get_platdata(&pdev->dev);  	struct pm860x_touch *touch;  	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \  				 : chip->companion; @@ -234,16 +235,17 @@ static int pm860x_touch_probe(struct platform_device *pdev)  	if (ret)  		return ret; -	touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); -	if (touch == NULL) +	touch = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_touch), +			     GFP_KERNEL); +	if (!touch)  		return -ENOMEM; +  	platform_set_drvdata(pdev, touch); -	touch->idev = input_allocate_device(); -	if (touch->idev == NULL) { +	touch->idev = devm_input_allocate_device(&pdev->dev); +	if (!touch->idev) {  		dev_err(&pdev->dev, "Failed to allocate input device!\n"); -		ret = -ENOMEM; -		goto out; +		return -ENOMEM;  	}  	touch->idev->name = "88pm860x-touch"; @@ -258,10 +260,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)  	touch->res_x = res_x;  	input_set_drvdata(touch->idev, touch); -	ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler, -				   IRQF_ONESHOT, "touch", touch); +	ret = devm_request_threaded_irq(&pdev->dev, touch->irq, NULL, +					pm860x_touch_handler, IRQF_ONESHOT, +					"touch", touch);  	if (ret < 0) -		goto out_irq; +		return ret;  	__set_bit(EV_ABS, touch->idev->evbit);  	__set_bit(ABS_X, touch->idev->absbit); @@ -279,28 +282,11 @@ static int pm860x_touch_probe(struct platform_device *pdev)  	ret = input_register_device(touch->idev);  	if (ret < 0) {  		dev_err(chip->dev, "Failed to register touch!\n"); -		goto out_rg; +		return ret;  	}  	platform_set_drvdata(pdev, touch);  	return 0; -out_rg: -	free_irq(touch->irq, touch); -out_irq: -	input_free_device(touch->idev); -out: -	kfree(touch); -	return ret; -} - -static int pm860x_touch_remove(struct platform_device *pdev) -{ -	struct pm860x_touch *touch = platform_get_drvdata(pdev); - -	input_unregister_device(touch->idev); -	free_irq(touch->irq, touch); -	kfree(touch); -	return 0;  }  static struct platform_driver pm860x_touch_driver = { @@ -309,7 +295,6 @@ static struct platform_driver pm860x_touch_driver = {  		.owner	= THIS_MODULE,  	},  	.probe	= pm860x_touch_probe, -	.remove	= pm860x_touch_remove,  };  module_platform_driver(pm860x_touch_driver); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index e09ec67957a..a23a94bb4bc 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -11,6 +11,10 @@ menuconfig INPUT_TOUCHSCREEN  if INPUT_TOUCHSCREEN +config OF_TOUCHSCREEN +	def_tristate INPUT +	depends on INPUT && OF +  config TOUCHSCREEN_88PM860X  	tristate "Marvell 88PM860x touchscreen"  	depends on MFD_88PM860X @@ -89,6 +93,7 @@ config TOUCHSCREEN_AD7879_SPI  config TOUCHSCREEN_ATMEL_MXT  	tristate "Atmel mXT I2C Touchscreen"  	depends on I2C +	select FW_LOADER  	help  	  Say Y here if you have Atmel mXT series I2C touchscreen,  	  such as AT42QT602240/ATMXT224, connected to your system. @@ -514,15 +519,6 @@ config TOUCHSCREEN_MIGOR  	  To compile this driver as a module, choose M here: the  	  module will be called migor_ts. -config TOUCHSCREEN_TNETV107X -	tristate "TI TNETV107X touchscreen support" -	depends on ARCH_DAVINCI_TNETV107X -	help -	  Say Y here if you want to use the TNETV107X touchscreen. - -	  To compile this driver as a module, choose M here: the -	  module will be called tnetv107x-ts. -  config TOUCHSCREEN_TOUCHRIGHT  	tristate "Touchright serial touchscreen"  	select SERIO @@ -559,18 +555,6 @@ config TOUCHSCREEN_TI_AM335X_TSC  	  To compile this driver as a module, choose M here: the  	  module will be called ti_am335x_tsc. -config TOUCHSCREEN_ATMEL_TSADCC -	tristate "Atmel Touchscreen Interface" -	depends on ARCH_AT91 -	help -	  Say Y here if you have a 4-wire touchscreen connected to the -          ADC Controller on your Atmel SoC. - -	  If unsure, say N. - -	  To compile this driver as a module, choose M here: the -	  module will be called atmel_tsadcc. -  config TOUCHSCREEN_UCB1400  	tristate "Philips UCB1400 touchscreen"  	depends on AC97_BUS @@ -649,7 +633,7 @@ config TOUCHSCREEN_WM9713  config TOUCHSCREEN_WM97XX_ATMEL  	tristate "WM97xx Atmel accelerated touch" -	depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91) +	depends on TOUCHSCREEN_WM97XX && AVR32  	help  	  Say Y here for support for streaming mode with WM97xx touchscreens  	  on Atmel AT91 or AVR32 systems with an AC97C module. @@ -717,7 +701,7 @@ config TOUCHSCREEN_USB_COMPOSITE  config TOUCHSCREEN_MC13783  	tristate "Freescale MC13783 touchscreen input driver" -	depends on MFD_MC13783 +	depends on MFD_MC13XXX  	help  	  Say Y here if you have an Freescale MC13783 PMIC on your  	  board and want to use its touchscreen @@ -867,7 +851,7 @@ config TOUCHSCREEN_TSC2007  config TOUCHSCREEN_W90X900  	tristate "W90P910 touchscreen driver" -	depends on HAVE_CLK +	depends on ARCH_W90X900  	help  	  Say Y here if you have a W90P910 based touchscreen. @@ -906,6 +890,28 @@ config TOUCHSCREEN_STMPE  	  To compile this driver as a module, choose M here: the  	  module will be called stmpe-ts. +config TOUCHSCREEN_SUN4I +	tristate "Allwinner sun4i resistive touchscreen controller support" +	depends on ARCH_SUNXI || COMPILE_TEST +	depends on HWMON +	help +	  This selects support for the resistive touchscreen controller +	  found on Allwinner sunxi SoCs. + +	  To compile this driver as a module, choose M here: the +	  module will be called sun4i-ts. + +config TOUCHSCREEN_SUR40 +	tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" +	depends on USB +	select INPUT_POLLDEV +	help +	  Say Y here if you want support for the Samsung SUR40 touchscreen +	  (also known as Microsoft Surface 2.0 or Microsoft PixelSense). + +	  To compile this driver as a module, choose M here: the +	  module will be called sur40. +  config TOUCHSCREEN_TPS6507X  	tristate "TPS6507x based touchscreens"  	depends on I2C @@ -919,4 +925,17 @@ config TOUCHSCREEN_TPS6507X  	  To compile this driver as a module, choose M here: the  	  module will be called tps6507x_ts. +config TOUCHSCREEN_ZFORCE +	tristate "Neonode zForce infrared touchscreens" +	depends on I2C +	depends on GPIOLIB +	help +	  Say Y here if you have a touchscreen using the zforce +	  infraread technology from Neonode. + +	  If unsure, say N. + +	  To compile this driver as a module, choose M here: the +	  module will be called zforce_ts. +  endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index f5216c1bf53..126479d8c29 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -6,6 +6,7 @@  wm97xx-ts-y := wm97xx-core.o +obj-$(CONFIG_OF_TOUCHSCREEN)		+= of_touchscreen.o  obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o  obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o  obj-$(CONFIG_TOUCHSCREEN_AD7879)	+= ad7879.o @@ -13,7 +14,6 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C)	+= ad7879-i2c.o  obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)	+= ad7879-spi.o  obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o  obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT)	+= atmel_mxt_ts.o -obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o  obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)	+= auo-pixcir-ts.o  obj-$(CONFIG_TOUCHSCREEN_BU21013)	+= bu21013_ts.o  obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o @@ -54,8 +54,9 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR)	+= pixcir_i2c_ts.o  obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o  obj-$(CONFIG_TOUCHSCREEN_ST1232)	+= st1232.o  obj-$(CONFIG_TOUCHSCREEN_STMPE)		+= stmpe-ts.o +obj-$(CONFIG_TOUCHSCREEN_SUN4I)		+= sun4i-ts.o +obj-$(CONFIG_TOUCHSCREEN_SUR40)		+= sur40.o  obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC)	+= ti_am335x_tsc.o -obj-$(CONFIG_TOUCHSCREEN_TNETV107X)	+= tnetv107x-ts.o  obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o  obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o  obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)	+= touchwin.o @@ -75,3 +76,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)	+= mainstone-wm97xx.o  obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o +obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index f3a174a83c8..523865daa1d 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -37,7 +37,6 @@  #include <linux/device.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/input.h>  #include <linux/interrupt.h> @@ -211,11 +210,6 @@ static bool gpio3;  module_param(gpio3, bool, 0);  MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3"); -/* - * ad7877_read/write are only used for initial setup and for sysfs controls. - * The main traffic is done using spi_async() in the interrupt handler. - */ -  static int ad7877_read(struct spi_device *spi, u16 reg)  {  	struct ser_req *req; @@ -686,7 +680,7 @@ static int ad7877_probe(struct spi_device *spi)  {  	struct ad7877			*ts;  	struct input_dev		*input_dev; -	struct ad7877_platform_data	*pdata = spi->dev.platform_data; +	struct ad7877_platform_data	*pdata = dev_get_platdata(&spi->dev);  	int				err;  	u16				verify; @@ -806,7 +800,6 @@ err_free_irq:  err_free_mem:  	input_free_device(input_dev);  	kfree(ts); -	spi_set_drvdata(spi, NULL);  	return err;  } @@ -823,7 +816,6 @@ static int ad7877_remove(struct spi_device *spi)  	kfree(ts);  	dev_dbg(&spi->dev, "unregistered touchscreen\n"); -	spi_set_drvdata(spi, NULL);  	return 0;  } diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index 606da5bd611..1a7b1143536 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -142,7 +142,6 @@ static int ad7879_spi_remove(struct spi_device *spi)  	struct ad7879 *ts = spi_get_drvdata(spi);  	ad7879_remove(ts); -	spi_set_drvdata(spi, NULL);  	return 0;  } diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index facd3057b62..fce590677b7 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -22,7 +22,6 @@   */  #include <linux/device.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/input.h>  #include <linux/interrupt.h> @@ -470,7 +469,7 @@ static int ad7879_gpio_add(struct ad7879 *ts,  static void ad7879_gpio_remove(struct ad7879 *ts)  { -	const struct ad7879_platform_data *pdata = ts->dev->platform_data; +	const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev);  	int ret;  	if (pdata->gpio_export) { @@ -495,7 +494,7 @@ static inline void ad7879_gpio_remove(struct ad7879 *ts)  struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,  			    const struct ad7879_bus_ops *bops)  { -	struct ad7879_platform_data *pdata = dev->platform_data; +	struct ad7879_platform_data *pdata = dev_get_platdata(dev);  	struct ad7879 *ts;  	struct input_dev *input_dev;  	int err; diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ea195360747..da201b8e37d 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -19,7 +19,6 @@   */  #include <linux/types.h>  #include <linux/hwmon.h> -#include <linux/init.h>  #include <linux/err.h>  #include <linux/sched.h>  #include <linux/delay.h> @@ -101,8 +100,7 @@ struct ads7846 {  	struct spi_device	*spi;  	struct regulator	*reg; -#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) -	struct attribute_group	*attr_group; +#if IS_ENABLED(CONFIG_HWMON)  	struct device		*hwmon;  #endif @@ -421,13 +419,13 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)  	return status;  } -#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) +#if IS_ENABLED(CONFIG_HWMON)  #define SHOW(name, var, adjust) static ssize_t \  name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \  { \  	struct ads7846 *ts = dev_get_drvdata(dev); \ -	ssize_t v = ads7846_read12_ser(dev, \ +	ssize_t v = ads7846_read12_ser(&ts->spi->dev, \  			READ_12BIT_SER(var)); \  	if (v < 0) \  		return v; \ @@ -479,42 +477,36 @@ static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)  SHOW(in0_input, vaux, vaux_adjust)  SHOW(in1_input, vbatt, vbatt_adjust) -static struct attribute *ads7846_attributes[] = { -	&dev_attr_temp0.attr, -	&dev_attr_temp1.attr, -	&dev_attr_in0_input.attr, -	&dev_attr_in1_input.attr, -	NULL, -}; - -static struct attribute_group ads7846_attr_group = { -	.attrs = ads7846_attributes, -}; +static umode_t ads7846_is_visible(struct kobject *kobj, struct attribute *attr, +				  int index) +{ +	struct device *dev = container_of(kobj, struct device, kobj); +	struct ads7846 *ts = dev_get_drvdata(dev); -static struct attribute *ads7843_attributes[] = { -	&dev_attr_in0_input.attr, -	&dev_attr_in1_input.attr, -	NULL, -}; +	if (ts->model == 7843 && index < 2)	/* in0, in1 */ +		return 0; +	if (ts->model == 7845 && index != 2)	/* in0 */ +		return 0; -static struct attribute_group ads7843_attr_group = { -	.attrs = ads7843_attributes, -}; +	return attr->mode; +} -static struct attribute *ads7845_attributes[] = { -	&dev_attr_in0_input.attr, +static struct attribute *ads7846_attributes[] = { +	&dev_attr_temp0.attr,		/* 0 */ +	&dev_attr_temp1.attr,		/* 1 */ +	&dev_attr_in0_input.attr,	/* 2 */ +	&dev_attr_in1_input.attr,	/* 3 */  	NULL,  }; -static struct attribute_group ads7845_attr_group = { -	.attrs = ads7845_attributes, +static struct attribute_group ads7846_attr_group = { +	.attrs = ads7846_attributes, +	.is_visible = ads7846_is_visible,  }; +__ATTRIBUTE_GROUPS(ads7846_attr);  static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)  { -	struct device *hwmon; -	int err; -  	/* hwmon sensors need a reference voltage */  	switch (ts->model) {  	case 7846: @@ -535,43 +527,19 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)  		break;  	} -	/* different chips have different sensor groups */ -	switch (ts->model) { -	case 7846: -		ts->attr_group = &ads7846_attr_group; -		break; -	case 7845: -		ts->attr_group = &ads7845_attr_group; -		break; -	case 7843: -		ts->attr_group = &ads7843_attr_group; -		break; -	default: -		dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model); -		return 0; -	} - -	err = sysfs_create_group(&spi->dev.kobj, ts->attr_group); -	if (err) -		return err; - -	hwmon = hwmon_device_register(&spi->dev); -	if (IS_ERR(hwmon)) { -		sysfs_remove_group(&spi->dev.kobj, ts->attr_group); -		return PTR_ERR(hwmon); -	} +	ts->hwmon = hwmon_device_register_with_groups(&spi->dev, spi->modalias, +						      ts, ads7846_attr_groups); +	if (IS_ERR(ts->hwmon)) +		return PTR_ERR(ts->hwmon); -	ts->hwmon = hwmon;  	return 0;  }  static void ads784x_hwmon_unregister(struct spi_device *spi,  				     struct ads7846 *ts)  { -	if (ts->hwmon) { -		sysfs_remove_group(&spi->dev.kobj, ts->attr_group); +	if (ts->hwmon)  		hwmon_device_unregister(ts->hwmon); -	}  }  #else @@ -738,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts)  		m = &ts->msg[msg_idx];  		error = spi_sync(ts->spi, m);  		if (error) { -			dev_err(&ts->spi->dev, "spi_async --> %d\n", error); +			dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);  			packet->tc.ignore = true;  			return;  		} diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c index 268a35e55d7..279c0e42b8a 100644 --- a/drivers/input/touchscreen/atmel-wm97xx.c +++ b/drivers/input/touchscreen/atmel-wm97xx.c @@ -391,7 +391,7 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev)  }  #ifdef CONFIG_PM_SLEEP -static int atmel_wm97xx_suspend(struct *dev) +static int atmel_wm97xx_suspend(struct device *dev)  {  	struct platform_device *pdev = to_platform_device(dev);  	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 59aa24002c7..6e0b4a2120d 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2,6 +2,8 @@   * Atmel maXTouch Touchscreen driver   *   * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Copyright (C) 2012 Google, Inc. + *   * Author: Joonyoung Shim <jy0922.shim@samsung.com>   *   * This program is free software; you can redistribute  it and/or modify it @@ -13,6 +15,7 @@  #include <linux/module.h>  #include <linux/init.h> +#include <linux/completion.h>  #include <linux/delay.h>  #include <linux/firmware.h>  #include <linux/i2c.h> @@ -26,12 +29,6 @@  #define MXT_VER_21		21  #define MXT_VER_22		22 -/* Slave addresses */ -#define MXT_APP_LOW		0x4a -#define MXT_APP_HIGH		0x4b -#define MXT_BOOT_LOW		0x24 -#define MXT_BOOT_HIGH		0x25 -  /* Firmware */  #define MXT_FW_NAME		"maxtouch.fw" @@ -84,6 +81,9 @@  #define MXT_COMMAND_REPORTALL	3  #define MXT_COMMAND_DIAGNOSTIC	5 +/* Define for T6 status byte */ +#define MXT_T6_STATUS_RESET	(1 << 7) +  /* MXT_GEN_POWER_T7 field */  #define MXT_POWER_IDLEACQINT	0  #define MXT_POWER_ACTVACQINT	1 @@ -100,33 +100,26 @@  /* MXT_TOUCH_MULTI_T9 field */  #define MXT_TOUCH_CTRL		0 -#define MXT_TOUCH_XORIGIN	1 -#define MXT_TOUCH_YORIGIN	2 -#define MXT_TOUCH_XSIZE		3 -#define MXT_TOUCH_YSIZE		4 -#define MXT_TOUCH_BLEN		6 -#define MXT_TOUCH_TCHTHR	7 -#define MXT_TOUCH_TCHDI		8 -#define MXT_TOUCH_ORIENT	9 -#define MXT_TOUCH_MOVHYSTI	11 -#define MXT_TOUCH_MOVHYSTN	12 -#define MXT_TOUCH_NUMTOUCH	14 -#define MXT_TOUCH_MRGHYST	15 -#define MXT_TOUCH_MRGTHR	16 -#define MXT_TOUCH_AMPHYST	17 -#define MXT_TOUCH_XRANGE_LSB	18 -#define MXT_TOUCH_XRANGE_MSB	19 -#define MXT_TOUCH_YRANGE_LSB	20 -#define MXT_TOUCH_YRANGE_MSB	21 -#define MXT_TOUCH_XLOCLIP	22 -#define MXT_TOUCH_XHICLIP	23 -#define MXT_TOUCH_YLOCLIP	24 -#define MXT_TOUCH_YHICLIP	25 -#define MXT_TOUCH_XEDGECTRL	26 -#define MXT_TOUCH_XEDGEDIST	27 -#define MXT_TOUCH_YEDGECTRL	28 -#define MXT_TOUCH_YEDGEDIST	29 -#define MXT_TOUCH_JUMPLIMIT	30 +#define MXT_T9_ORIENT		9 +#define MXT_T9_RANGE		18 + +/* MXT_TOUCH_MULTI_T9 status */ +#define MXT_T9_UNGRIP		(1 << 0) +#define MXT_T9_SUPPRESS		(1 << 1) +#define MXT_T9_AMP		(1 << 2) +#define MXT_T9_VECTOR		(1 << 3) +#define MXT_T9_MOVE		(1 << 4) +#define MXT_T9_RELEASE		(1 << 5) +#define MXT_T9_PRESS		(1 << 6) +#define MXT_T9_DETECT		(1 << 7) + +struct t9_range { +	u16 x; +	u16 y; +} __packed; + +/* MXT_TOUCH_MULTI_T9 orient */ +#define MXT_T9_ORIENT_SWITCH	(1 << 0)  /* MXT_PROCI_GRIPFACE_T20 field */  #define MXT_GRIPFACE_CTRL	0 @@ -175,17 +168,16 @@  /* Define for MXT_GEN_COMMAND_T6 */  #define MXT_BOOT_VALUE		0xa5 +#define MXT_RESET_VALUE		0x01  #define MXT_BACKUP_VALUE	0x55 + +/* Delay times */  #define MXT_BACKUP_TIME		50	/* msec */  #define MXT_RESET_TIME		200	/* msec */ - -#define MXT_FWRESET_TIME	175	/* msec */ - -/* MXT_SPT_GPIOPWM_T19 field */ -#define MXT_GPIO0_MASK		0x04 -#define MXT_GPIO1_MASK		0x08 -#define MXT_GPIO2_MASK		0x10 -#define MXT_GPIO3_MASK		0x20 +#define MXT_RESET_TIMEOUT	3000	/* msec */ +#define MXT_CRC_TIMEOUT		1000	/* msec */ +#define MXT_FW_RESET_TIME	3000	/* msec */ +#define MXT_FW_CHG_TIMEOUT	300	/* msec */  /* Command to unlock bootloader */  #define MXT_UNLOCK_CMD_MSB	0xaa @@ -199,21 +191,8 @@  #define MXT_FRAME_CRC_PASS	0x04  #define MXT_APP_CRC_FAIL	0x40	/* valid 7 8 bit only */  #define MXT_BOOT_STATUS_MASK	0x3f - -/* Touch status */ -#define MXT_UNGRIP		(1 << 0) -#define MXT_SUPPRESS		(1 << 1) -#define MXT_AMP			(1 << 2) -#define MXT_VECTOR		(1 << 3) -#define MXT_MOVE		(1 << 4) -#define MXT_RELEASE		(1 << 5) -#define MXT_PRESS		(1 << 6) -#define MXT_DETECT		(1 << 7) - -/* Touch orient bits */ -#define MXT_XY_SWITCH		(1 << 0) -#define MXT_X_INVERT		(1 << 1) -#define MXT_Y_INVERT		(1 << 2) +#define MXT_BOOT_EXTENDED_ID	(1 << 5) +#define MXT_BOOT_ID_MASK	0x1f  /* Touchscreen absolute values */  #define MXT_MAX_AREA		0xff @@ -233,8 +212,8 @@ struct mxt_info {  struct mxt_object {  	u8 type;  	u16 start_address; -	u8 size;		/* Size of each instance - 1 */ -	u8 instances;		/* Number of instances - 1 */ +	u8 size_minus_one; +	u8 instances_minus_one;  	u8 num_report_ids;  } __packed; @@ -251,19 +230,40 @@ struct mxt_data {  	const struct mxt_platform_data *pdata;  	struct mxt_object *object_table;  	struct mxt_info info; -	bool is_tp; -  	unsigned int irq;  	unsigned int max_x;  	unsigned int max_y; +	bool in_bootloader; +	u32 config_crc; +	u8 bootloader_addr;  	/* Cached parameters from object table */  	u8 T6_reportid; +	u16 T6_address;  	u8 T9_reportid_min;  	u8 T9_reportid_max;  	u8 T19_reportid; + +	/* for fw update in bootloader */ +	struct completion bl_completion; + +	/* for reset handling */ +	struct completion reset_completion; + +	/* for config update handling */ +	struct completion crc_completion;  }; +static size_t mxt_obj_size(const struct mxt_object *obj) +{ +	return obj->size_minus_one + 1; +} + +static size_t mxt_obj_instances(const struct mxt_object *obj) +{ +	return obj->instances_minus_one + 1; +} +  static bool mxt_object_readable(unsigned int type)  {  	switch (type) { @@ -335,60 +335,190 @@ static void mxt_dump_message(struct device *dev,  		message->reportid, 7, message->message);  } -static int mxt_check_bootloader(struct i2c_client *client, -				     unsigned int state) +static int mxt_wait_for_completion(struct mxt_data *data, +				   struct completion *comp, +				   unsigned int timeout_ms) +{ +	struct device *dev = &data->client->dev; +	unsigned long timeout = msecs_to_jiffies(timeout_ms); +	long ret; + +	ret = wait_for_completion_interruptible_timeout(comp, timeout); +	if (ret < 0) { +		return ret; +	} else if (ret == 0) { +		dev_err(dev, "Wait for completion timed out.\n"); +		return -ETIMEDOUT; +	} +	return 0; +} + +static int mxt_bootloader_read(struct mxt_data *data, +			       u8 *val, unsigned int count) +{ +	int ret; +	struct i2c_msg msg; + +	msg.addr = data->bootloader_addr; +	msg.flags = data->client->flags & I2C_M_TEN; +	msg.flags |= I2C_M_RD; +	msg.len = count; +	msg.buf = val; + +	ret = i2c_transfer(data->client->adapter, &msg, 1); + +	if (ret == 1) { +		ret = 0; +	} else { +		ret = ret < 0 ? ret : -EIO; +		dev_err(&data->client->dev, "%s: i2c recv failed (%d)\n", +			__func__, ret); +	} + +	return ret; +} + +static int mxt_bootloader_write(struct mxt_data *data, +				const u8 * const val, unsigned int count) +{ +	int ret; +	struct i2c_msg msg; + +	msg.addr = data->bootloader_addr; +	msg.flags = data->client->flags & I2C_M_TEN; +	msg.len = count; +	msg.buf = (u8 *)val; + +	ret = i2c_transfer(data->client->adapter, &msg, 1); +	if (ret == 1) { +		ret = 0; +	} else { +		ret = ret < 0 ? ret : -EIO; +		dev_err(&data->client->dev, "%s: i2c send failed (%d)\n", +			__func__, ret); +	} + +	return ret; +} + +static int mxt_lookup_bootloader_address(struct mxt_data *data) +{ +	u8 appmode = data->client->addr; +	u8 bootloader; + +	switch (appmode) { +	case 0x4a: +	case 0x4b: +	case 0x4c: +	case 0x4d: +	case 0x5a: +	case 0x5b: +		bootloader = appmode - 0x26; +		break; +	default: +		dev_err(&data->client->dev, +			"Appmode i2c address 0x%02x not found\n", +			appmode); +		return -EINVAL; +	} + +	data->bootloader_addr = bootloader; +	return 0; +} + +static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val) +{ +	struct device *dev = &data->client->dev; +	u8 buf[3]; + +	if (val & MXT_BOOT_EXTENDED_ID) { +		if (mxt_bootloader_read(data, &buf[0], 3) != 0) { +			dev_err(dev, "%s: i2c failure\n", __func__); +			return val; +		} + +		dev_dbg(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]); + +		return buf[0]; +	} else { +		dev_dbg(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK); + +		return val; +	} +} + +static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)  { +	struct device *dev = &data->client->dev;  	u8 val; +	int ret;  recheck: -	if (i2c_master_recv(client, &val, 1) != 1) { -		dev_err(&client->dev, "%s: i2c recv failed\n", __func__); -		return -EIO; +	if (state != MXT_WAITING_BOOTLOAD_CMD) { +		/* +		 * In application update mode, the interrupt +		 * line signals state transitions. We must wait for the +		 * CHG assertion before reading the status byte. +		 * Once the status byte has been read, the line is deasserted. +		 */ +		ret = mxt_wait_for_completion(data, &data->bl_completion, +					      MXT_FW_CHG_TIMEOUT); +		if (ret) { +			/* +			 * TODO: handle -ERESTARTSYS better by terminating +			 * fw update process before returning to userspace +			 * by writing length 0x000 to device (iff we are in +			 * WAITING_FRAME_DATA state). +			 */ +			dev_err(dev, "Update wait error %d\n", ret); +			return ret; +		}  	} +	ret = mxt_bootloader_read(data, &val, 1); +	if (ret) +		return ret; + +	if (state == MXT_WAITING_BOOTLOAD_CMD) +		val = mxt_get_bootloader_version(data, val); +  	switch (state) {  	case MXT_WAITING_BOOTLOAD_CMD:  	case MXT_WAITING_FRAME_DATA:  		val &= ~MXT_BOOT_STATUS_MASK;  		break;  	case MXT_FRAME_CRC_PASS: -		if (val == MXT_FRAME_CRC_CHECK) +		if (val == MXT_FRAME_CRC_CHECK) {  			goto recheck; +		} else if (val == MXT_FRAME_CRC_FAIL) { +			dev_err(dev, "Bootloader CRC fail\n"); +			return -EINVAL; +		}  		break;  	default:  		return -EINVAL;  	}  	if (val != state) { -		dev_err(&client->dev, "Unvalid bootloader mode state\n"); +		dev_err(dev, "Invalid bootloader state %02X != %02X\n", +			val, state);  		return -EINVAL;  	}  	return 0;  } -static int mxt_unlock_bootloader(struct i2c_client *client) +static int mxt_unlock_bootloader(struct mxt_data *data)  { +	int ret;  	u8 buf[2];  	buf[0] = MXT_UNLOCK_CMD_LSB;  	buf[1] = MXT_UNLOCK_CMD_MSB; -	if (i2c_master_send(client, buf, 2) != 2) { -		dev_err(&client->dev, "%s: i2c send failed\n", __func__); -		return -EIO; -	} - -	return 0; -} - -static int mxt_fw_write(struct i2c_client *client, -			     const u8 *data, unsigned int frame_size) -{ -	if (i2c_master_send(client, data, frame_size) != frame_size) { -		dev_err(&client->dev, "%s: i2c send failed\n", __func__); -		return -EIO; -	} +	ret = mxt_bootloader_write(data, buf, 2); +	if (ret) +		return ret;  	return 0;  } @@ -428,11 +558,6 @@ static int __mxt_read_reg(struct i2c_client *client,  	return ret;  } -static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val) -{ -	return __mxt_read_reg(client, reg, 1, val); -} -  static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,  			   const void *val)  { @@ -480,7 +605,7 @@ mxt_get_object(struct mxt_data *data, u8 type)  			return object;  	} -	dev_err(&data->client->dev, "Invalid object type\n"); +	dev_err(&data->client->dev, "Invalid object type T%u\n", type);  	return NULL;  } @@ -506,7 +631,7 @@ static int mxt_write_object(struct mxt_data *data,  	u16 reg;  	object = mxt_get_object(data, type); -	if (!object || offset >= object->size + 1) +	if (!object || offset >= mxt_obj_size(object))  		return -EINVAL;  	reg = object->start_address; @@ -516,18 +641,25 @@ static int mxt_write_object(struct mxt_data *data,  static void mxt_input_button(struct mxt_data *data, struct mxt_message *message)  {  	struct input_dev *input = data->input_dev; +	const struct mxt_platform_data *pdata = data->pdata;  	bool button;  	int i;  	/* Active-low switch */ -	for (i = 0; i < MXT_NUM_GPIO; i++) { -		if (data->pdata->key_map[i] == KEY_RESERVED) +	for (i = 0; i < pdata->t19_num_keys; i++) { +		if (pdata->t19_keymap[i] == KEY_RESERVED)  			continue; -		button = !(message->message[0] & MXT_GPIO0_MASK << i); -		input_report_key(input, data->pdata->key_map[i], button); +		button = !(message->message[0] & (1 << i)); +		input_report_key(input, pdata->t19_keymap[i], button);  	}  } +static void mxt_input_sync(struct input_dev *input_dev) +{ +	input_mt_report_pointer_emulation(input_dev, false); +	input_sync(input_dev); +} +  static void mxt_input_touchevent(struct mxt_data *data,  				      struct mxt_message *message, int id)  { @@ -537,44 +669,60 @@ static void mxt_input_touchevent(struct mxt_data *data,  	int x;  	int y;  	int area; -	int pressure; +	int amplitude;  	x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);  	y = (message->message[2] << 4) | ((message->message[3] & 0xf)); + +	/* Handle 10/12 bit switching */  	if (data->max_x < 1024) -		x = x >> 2; +		x >>= 2;  	if (data->max_y < 1024) -		y = y >> 2; +		y >>= 2;  	area = message->message[4]; -	pressure = message->message[5]; +	amplitude = message->message[5];  	dev_dbg(dev,  		"[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n",  		id, -		(status & MXT_DETECT) ? 'D' : '.', -		(status & MXT_PRESS) ? 'P' : '.', -		(status & MXT_RELEASE) ? 'R' : '.', -		(status & MXT_MOVE) ? 'M' : '.', -		(status & MXT_VECTOR) ? 'V' : '.', -		(status & MXT_AMP) ? 'A' : '.', -		(status & MXT_SUPPRESS) ? 'S' : '.', -		(status & MXT_UNGRIP) ? 'U' : '.', -		x, y, area, pressure); +		(status & MXT_T9_DETECT) ? 'D' : '.', +		(status & MXT_T9_PRESS) ? 'P' : '.', +		(status & MXT_T9_RELEASE) ? 'R' : '.', +		(status & MXT_T9_MOVE) ? 'M' : '.', +		(status & MXT_T9_VECTOR) ? 'V' : '.', +		(status & MXT_T9_AMP) ? 'A' : '.', +		(status & MXT_T9_SUPPRESS) ? 'S' : '.', +		(status & MXT_T9_UNGRIP) ? 'U' : '.', +		x, y, area, amplitude);  	input_mt_slot(input_dev, id); -	input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, -				   status & MXT_DETECT); -	if (status & MXT_DETECT) { +	if (status & MXT_T9_DETECT) { +		/* +		 * Multiple bits may be set if the host is slow to read +		 * the status messages, indicating all the events that +		 * have happened. +		 */ +		if (status & MXT_T9_RELEASE) { +			input_mt_report_slot_state(input_dev, +						   MT_TOOL_FINGER, 0); +			mxt_input_sync(input_dev); +		} + +		/* Touch active */ +		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);  		input_report_abs(input_dev, ABS_MT_POSITION_X, x);  		input_report_abs(input_dev, ABS_MT_POSITION_Y, y); -		input_report_abs(input_dev, ABS_MT_PRESSURE, pressure); +		input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);  		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area); +	} else { +		/* Touch no longer active, close out slot */ +		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);  	}  } -static unsigned mxt_extract_T6_csum(const u8 *csum) +static u16 mxt_extract_T6_csum(const u8 *csum)  {  	return csum[0] | (csum[1] << 8) | (csum[2] << 16);  } @@ -585,28 +733,37 @@ static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg)  	return (id >= data->T9_reportid_min && id <= data->T9_reportid_max);  } -static irqreturn_t mxt_interrupt(int irq, void *dev_id) +static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)  { -	struct mxt_data *data = dev_id;  	struct mxt_message message;  	const u8 *payload = &message.message[0];  	struct device *dev = &data->client->dev;  	u8 reportid;  	bool update_input = false; +	u32 crc;  	do {  		if (mxt_read_message(data, &message)) {  			dev_err(dev, "Failed to read message\n"); -			goto end; +			return IRQ_NONE;  		}  		reportid = message.reportid;  		if (reportid == data->T6_reportid) {  			u8 status = payload[0]; -			unsigned csum = mxt_extract_T6_csum(&payload[1]); + +			crc = mxt_extract_T6_csum(&payload[1]); +			if (crc != data->config_crc) { +				data->config_crc = crc; +				complete(&data->crc_completion); +			} +  			dev_dbg(dev, "Status: %02x Config Checksum: %06x\n", -				status, csum); +				status, data->config_crc); + +			if (status & MXT_T6_STATUS_RESET) +				complete(&data->reset_completion);  		} else if (mxt_is_T9_message(data, &message)) {  			int id = reportid - data->T9_reportid_min;  			mxt_input_touchevent(data, &message, id); @@ -619,15 +776,96 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)  		}  	} while (reportid != 0xff); -	if (update_input) { -		input_mt_report_pointer_emulation(data->input_dev, false); -		input_sync(data->input_dev); -	} +	if (update_input) +		mxt_input_sync(data->input_dev); -end:  	return IRQ_HANDLED;  } +static irqreturn_t mxt_interrupt(int irq, void *dev_id) +{ +	struct mxt_data *data = dev_id; + +	if (data->in_bootloader) { +		/* bootloader state transition completion */ +		complete(&data->bl_completion); +		return IRQ_HANDLED; +	} + +	return mxt_process_messages_until_invalid(data); +} + +static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset, +			  u8 value, bool wait) +{ +	u16 reg; +	u8 command_register; +	int timeout_counter = 0; +	int ret; + +	reg = data->T6_address + cmd_offset; + +	ret = mxt_write_reg(data->client, reg, value); +	if (ret) +		return ret; + +	if (!wait) +		return 0; + +	do { +		msleep(20); +		ret = __mxt_read_reg(data->client, reg, 1, &command_register); +		if (ret) +			return ret; +	} while (command_register != 0 && timeout_counter++ <= 100); + +	if (timeout_counter > 100) { +		dev_err(&data->client->dev, "Command failed!\n"); +		return -EIO; +	} + +	return 0; +} + +static int mxt_soft_reset(struct mxt_data *data) +{ +	struct device *dev = &data->client->dev; +	int ret = 0; + +	dev_info(dev, "Resetting chip\n"); + +	reinit_completion(&data->reset_completion); + +	ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false); +	if (ret) +		return ret; + +	ret = mxt_wait_for_completion(data, &data->reset_completion, +				      MXT_RESET_TIMEOUT); +	if (ret) +		return ret; + +	return 0; +} + +static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value) +{ +	/* +	 * On failure, CRC is set to 0 and config will always be +	 * downloaded. +	 */ +	data->config_crc = 0; +	reinit_completion(&data->crc_completion); + +	mxt_t6_command(data, cmd, value, true); + +	/* +	 * Wait for crc message. On failure, CRC is set to 0 and config will +	 * always be downloaded. +	 */ +	mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT); +} +  static int mxt_check_reg_init(struct mxt_data *data)  {  	const struct mxt_platform_data *pdata = data->pdata; @@ -642,13 +880,23 @@ static int mxt_check_reg_init(struct mxt_data *data)  		return 0;  	} +	mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); + +	if (data->config_crc == pdata->config_crc) { +		dev_info(dev, "Config CRC 0x%06X: OK\n", data->config_crc); +		return 0; +	} + +	dev_info(dev, "Config CRC 0x%06X: does not match 0x%06X\n", +		 data->config_crc, pdata->config_crc); +  	for (i = 0; i < data->info.object_num; i++) {  		object = data->object_table + i;  		if (!mxt_object_writable(object->type))  			continue; -		size = (object->size + 1) * (object->instances + 1); +		size = mxt_obj_size(object) * mxt_obj_instances(object);  		if (index + size > pdata->config_length) {  			dev_err(dev, "Not enough config data!\n");  			return -EINVAL; @@ -661,6 +909,14 @@ static int mxt_check_reg_init(struct mxt_data *data)  		index += size;  	} +	mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); + +	ret = mxt_soft_reset(data); +	if (ret) +		return ret; + +	dev_info(dev, "Config successfully updated\n"); +  	return 0;  } @@ -686,54 +942,6 @@ static int mxt_make_highchg(struct mxt_data *data)  	return 0;  } -static void mxt_handle_pdata(struct mxt_data *data) -{ -	const struct mxt_platform_data *pdata = data->pdata; -	u8 voltage; - -	/* Set touchscreen lines */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_XSIZE, -			pdata->x_line); -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_YSIZE, -			pdata->y_line); - -	/* Set touchscreen orient */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_ORIENT, -			pdata->orient); - -	/* Set touchscreen burst length */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_BLEN, pdata->blen); - -	/* Set touchscreen threshold */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_TCHTHR, pdata->threshold); - -	/* Set touchscreen resolution */ -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); -	mxt_write_object(data, MXT_TOUCH_MULTI_T9, -			MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); - -	/* Set touchscreen voltage */ -	if (pdata->voltage) { -		if (pdata->voltage < MXT_VOLTAGE_DEFAULT) { -			voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) / -				MXT_VOLTAGE_STEP; -			voltage = 0xff - voltage + 1; -		} else -			voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) / -				MXT_VOLTAGE_STEP; - -		mxt_write_object(data, MXT_SPT_CTECONFIG_T28, -				MXT_CTE_VOLTAGE, voltage); -	} -} -  static int mxt_get_info(struct mxt_data *data)  {  	struct i2c_client *client = data->client; @@ -773,7 +981,7 @@ static int mxt_get_object_table(struct mxt_data *data)  		if (object->num_report_ids) {  			min_id = reportid;  			reportid += object->num_report_ids * -					(object->instances + 1); +					mxt_obj_instances(object);  			max_id = reportid - 1;  		} else {  			min_id = 0; @@ -781,13 +989,15 @@ static int mxt_get_object_table(struct mxt_data *data)  		}  		dev_dbg(&data->client->dev, -			"Type %2d Start %3d Size %3d Instances %2d ReportIDs %3u : %3u\n", -			object->type, object->start_address, object->size + 1, -			object->instances + 1, min_id, max_id); +			"T%u Start:%u Size:%zu Instances:%zu Report IDs:%u-%u\n", +			object->type, object->start_address, +			mxt_obj_size(object), mxt_obj_instances(object), +			min_id, max_id);  		switch (object->type) {  		case MXT_GEN_COMMAND_T6:  			data->T6_reportid = min_id; +			data->T6_address = object->start_address;  			break;  		case MXT_TOUCH_MULTI_T9:  			data->T9_reportid_min = min_id; @@ -812,12 +1022,59 @@ static void mxt_free_object_table(struct mxt_data *data)  	data->T19_reportid = 0;  } +static int mxt_read_t9_resolution(struct mxt_data *data) +{ +	struct i2c_client *client = data->client; +	int error; +	struct t9_range range; +	unsigned char orient; +	struct mxt_object *object; + +	object = mxt_get_object(data, MXT_TOUCH_MULTI_T9); +	if (!object) +		return -EINVAL; + +	error = __mxt_read_reg(client, +			       object->start_address + MXT_T9_RANGE, +			       sizeof(range), &range); +	if (error) +		return error; + +	le16_to_cpus(&range.x); +	le16_to_cpus(&range.y); + +	error =  __mxt_read_reg(client, +				object->start_address + MXT_T9_ORIENT, +				1, &orient); +	if (error) +		return error; + +	/* Handle default values */ +	if (range.x == 0) +		range.x = 1023; + +	if (range.y == 0) +		range.y = 1023; + +	if (orient & MXT_T9_ORIENT_SWITCH) { +		data->max_x = range.y; +		data->max_y = range.x; +	} else { +		data->max_x = range.x; +		data->max_y = range.y; +	} + +	dev_dbg(&client->dev, +		"Touchscreen size X%uY%u\n", data->max_x, data->max_y); + +	return 0; +} +  static int mxt_initialize(struct mxt_data *data)  {  	struct i2c_client *client = data->client;  	struct mxt_info *info = &data->info;  	int error; -	u8 val;  	error = mxt_get_info(data);  	if (error) @@ -833,47 +1090,29 @@ static int mxt_initialize(struct mxt_data *data)  	/* Get object table information */  	error = mxt_get_object_table(data); -	if (error) +	if (error) { +		dev_err(&client->dev, "Error %d reading object table\n", error);  		goto err_free_object_table; +	}  	/* Check register init values */  	error = mxt_check_reg_init(data); -	if (error) -		goto err_free_object_table; - -	mxt_handle_pdata(data); - -	/* Backup to memory */ -	mxt_write_object(data, MXT_GEN_COMMAND_T6, -			MXT_COMMAND_BACKUPNV, -			MXT_BACKUP_VALUE); -	msleep(MXT_BACKUP_TIME); - -	/* Soft reset */ -	mxt_write_object(data, MXT_GEN_COMMAND_T6, -			MXT_COMMAND_RESET, 1); -	msleep(MXT_RESET_TIME); - -	/* Update matrix size at info struct */ -	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val); -	if (error) +	if (error) { +		dev_err(&client->dev, "Error %d initializing configuration\n", +			error);  		goto err_free_object_table; -	info->matrix_xsize = val; +	} -	error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val); -	if (error) +	error = mxt_read_t9_resolution(data); +	if (error) { +		dev_err(&client->dev, "Failed to initialize T9 resolution\n");  		goto err_free_object_table; -	info->matrix_ysize = val; - -	dev_info(&client->dev, -			"Family ID: %u Variant ID: %u Major.Minor.Build: %u.%u.%02X\n", -			info->family_id, info->variant_id, info->version >> 4, -			info->version & 0xf, info->build); +	}  	dev_info(&client->dev, -			"Matrix X Size: %u Matrix Y Size: %u Object Num: %u\n", -			info->matrix_xsize, info->matrix_ysize, -			info->object_num); +		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n", +		 info->family_id, info->variant_id, info->version >> 4, +		 info->version & 0xf, info->build, info->object_num);  	return 0; @@ -882,20 +1121,6 @@ err_free_object_table:  	return error;  } -static void mxt_calc_resolution(struct mxt_data *data) -{ -	unsigned int max_x = data->pdata->x_size - 1; -	unsigned int max_y = data->pdata->y_size - 1; - -	if (data->pdata->orient & MXT_XY_SWITCH) { -		data->max_x = max_y; -		data->max_y = max_x; -	} else { -		data->max_x = max_x; -		data->max_y = max_y; -	} -} -  /* Firmware Version is returned as Major.Minor.Build */  static ssize_t mxt_fw_version_show(struct device *dev,  				   struct device_attribute *attr, char *buf) @@ -922,11 +1147,11 @@ static ssize_t mxt_show_instance(char *buf, int count,  {  	int i; -	if (object->instances > 0) +	if (mxt_obj_instances(object) > 1)  		count += scnprintf(buf + count, PAGE_SIZE - count,  				   "Instance %u\n", instance); -	for (i = 0; i < object->size + 1; i++) +	for (i = 0; i < mxt_obj_size(object); i++)  		count += scnprintf(buf + count, PAGE_SIZE - count,  				"\t[%2u]: %02x (%d)\n", i, val[i], val[i]);  	count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); @@ -959,8 +1184,8 @@ static ssize_t mxt_object_show(struct device *dev,  		count += scnprintf(buf + count, PAGE_SIZE - count,  				"T%u:\n", object->type); -		for (j = 0; j < object->instances + 1; j++) { -			u16 size = object->size + 1; +		for (j = 0; j < mxt_obj_instances(object); j++) { +			u16 size = mxt_obj_size(object);  			u16 addr = object->start_address + j * size;  			error = __mxt_read_reg(data->client, addr, size, obuf); @@ -976,13 +1201,38 @@ done:  	return error ?: count;  } +static int mxt_check_firmware_format(struct device *dev, +				     const struct firmware *fw) +{ +	unsigned int pos = 0; +	char c; + +	while (pos < fw->size) { +		c = *(fw->data + pos); + +		if (c < '0' || (c > '9' && c < 'A') || c > 'F') +			return 0; + +		pos++; +	} + +	/* +	 * To convert file try: +	 * xxd -r -p mXTXXX__APP_VX-X-XX.enc > maxtouch.fw +	 */ +	dev_err(dev, "Aborting: firmware file must be in binary format\n"); + +	return -EINVAL; +} +  static int mxt_load_fw(struct device *dev, const char *fn)  {  	struct mxt_data *data = dev_get_drvdata(dev); -	struct i2c_client *client = data->client;  	const struct firmware *fw = NULL;  	unsigned int frame_size;  	unsigned int pos = 0; +	unsigned int retry = 0; +	unsigned int frame = 0;  	int ret;  	ret = request_firmware(&fw, fn, dev); @@ -991,59 +1241,91 @@ static int mxt_load_fw(struct device *dev, const char *fn)  		return ret;  	} +	/* Check for incorrect enc file */ +	ret = mxt_check_firmware_format(dev, fw); +	if (ret) +		goto release_firmware; + +	ret = mxt_lookup_bootloader_address(data); +	if (ret) +		goto release_firmware; +  	/* Change to the bootloader mode */ -	mxt_write_object(data, MXT_GEN_COMMAND_T6, -			MXT_COMMAND_RESET, MXT_BOOT_VALUE); +	data->in_bootloader = true; + +	ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false); +	if (ret) +		goto release_firmware; +  	msleep(MXT_RESET_TIME); -	/* Change to slave address of bootloader */ -	if (client->addr == MXT_APP_LOW) -		client->addr = MXT_BOOT_LOW; -	else -		client->addr = MXT_BOOT_HIGH; +	reinit_completion(&data->bl_completion); -	ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD); +	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);  	if (ret) -		goto out; +		goto disable_irq;  	/* Unlock bootloader */ -	mxt_unlock_bootloader(client); +	mxt_unlock_bootloader(data);  	while (pos < fw->size) { -		ret = mxt_check_bootloader(client, -						MXT_WAITING_FRAME_DATA); +		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);  		if (ret) -			goto out; +			goto disable_irq;  		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); -		/* We should add 2 at frame size as the the firmware data is not -		 * included the CRC bytes. -		 */ +		/* Take account of CRC bytes */  		frame_size += 2;  		/* Write one frame to device */ -		mxt_fw_write(client, fw->data + pos, frame_size); - -		ret = mxt_check_bootloader(client, -						MXT_FRAME_CRC_PASS); +		ret = mxt_bootloader_write(data, fw->data + pos, frame_size);  		if (ret) -			goto out; +			goto disable_irq; -		pos += frame_size; +		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS); +		if (ret) { +			retry++; -		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size); +			/* Back off by 20ms per retry */ +			msleep(retry * 20); + +			if (retry > 20) { +				dev_err(dev, "Retry count exceeded\n"); +				goto disable_irq; +			} +		} else { +			retry = 0; +			pos += frame_size; +			frame++; +		} + +		if (frame % 50 == 0) +			dev_dbg(dev, "Sent %d frames, %d/%zd bytes\n", +				frame, pos, fw->size);  	} -out: -	release_firmware(fw); +	/* Wait for flash. */ +	ret = mxt_wait_for_completion(data, &data->bl_completion, +				      MXT_FW_RESET_TIME); +	if (ret) +		goto disable_irq; -	/* Change to slave address of application */ -	if (client->addr == MXT_BOOT_LOW) -		client->addr = MXT_APP_LOW; -	else -		client->addr = MXT_APP_HIGH; +	dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos); +	/* +	 * Wait for device to reset. Some bootloader versions do not assert +	 * the CHG line after bootloading has finished, so ignore potential +	 * errors. +	 */ +	mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME); + +	data->in_bootloader = false; + +disable_irq: +	disable_irq(data->irq); +release_firmware: +	release_firmware(fw);  	return ret;  } @@ -1054,28 +1336,23 @@ static ssize_t mxt_update_fw_store(struct device *dev,  	struct mxt_data *data = dev_get_drvdata(dev);  	int error; -	disable_irq(data->irq); -  	error = mxt_load_fw(dev, MXT_FW_NAME);  	if (error) {  		dev_err(dev, "The firmware update failed(%d)\n", error);  		count = error;  	} else { -		dev_dbg(dev, "The firmware update succeeded\n"); - -		/* Wait for reset */ -		msleep(MXT_FWRESET_TIME); +		dev_info(dev, "The firmware update succeeded\n");  		mxt_free_object_table(data);  		mxt_initialize(data); -	} -	enable_irq(data->irq); +		enable_irq(data->irq); -	error = mxt_make_highchg(data); -	if (error) -		return error; +		error = mxt_make_highchg(data); +		if (error) +			return error; +	}  	return count;  } @@ -1130,11 +1407,13 @@ static void mxt_input_close(struct input_dev *dev)  static int mxt_probe(struct i2c_client *client,  		const struct i2c_device_id *id)  { -	const struct mxt_platform_data *pdata = client->dev.platform_data; +	const struct mxt_platform_data *pdata = dev_get_platdata(&client->dev);  	struct mxt_data *data;  	struct input_dev *input_dev;  	int error;  	unsigned int num_mt_slots; +	unsigned int mt_flags = 0; +	int i;  	if (!pdata)  		return -EINVAL; @@ -1147,10 +1426,7 @@ static int mxt_probe(struct i2c_client *client,  		goto err_free_mem;  	} -	data->is_tp = pdata && pdata->is_tp; - -	input_dev->name = (data->is_tp) ? "Atmel maXTouch Touchpad" : -					  "Atmel maXTouch Touchscreen"; +	input_dev->name = "Atmel maXTouch Touchscreen";  	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",  		 client->adapter->nr, client->addr); @@ -1166,7 +1442,9 @@ static int mxt_probe(struct i2c_client *client,  	data->pdata = pdata;  	data->irq = client->irq; -	mxt_calc_resolution(data); +	init_completion(&data->bl_completion); +	init_completion(&data->reset_completion); +	init_completion(&data->crc_completion);  	error = mxt_initialize(data);  	if (error) @@ -1176,20 +1454,15 @@ static int mxt_probe(struct i2c_client *client,  	__set_bit(EV_KEY, input_dev->evbit);  	__set_bit(BTN_TOUCH, input_dev->keybit); -	if (data->is_tp) { -		int i; -		__set_bit(INPUT_PROP_POINTER, input_dev->propbit); +	if (pdata->t19_num_keys) {  		__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); -		for (i = 0; i < MXT_NUM_GPIO; i++) -			if (pdata->key_map[i] != KEY_RESERVED) -				__set_bit(pdata->key_map[i], input_dev->keybit); +		for (i = 0; i < pdata->t19_num_keys; i++) +			if (pdata->t19_keymap[i] != KEY_RESERVED) +				input_set_capability(input_dev, EV_KEY, +						     pdata->t19_keymap[i]); -		__set_bit(BTN_TOOL_FINGER, input_dev->keybit); -		__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); -		__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); -		__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); -		__set_bit(BTN_TOOL_QUINTTAP, input_dev->keybit); +		mt_flags |= INPUT_MT_POINTER;  		input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM);  		input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM); @@ -1197,6 +1470,8 @@ static int mxt_probe(struct i2c_client *client,  				  MXT_PIXELS_PER_MM);  		input_abs_set_res(input_dev, ABS_MT_POSITION_Y,  				  MXT_PIXELS_PER_MM); + +		input_dev->name = "Atmel maXTouch Touchpad";  	}  	/* For single touch */ @@ -1209,7 +1484,7 @@ static int mxt_probe(struct i2c_client *client,  	/* For multi touch */  	num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1; -	error = input_mt_init_slots(input_dev, num_mt_slots, 0); +	error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags);  	if (error)  		goto err_free_object;  	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, @@ -1237,12 +1512,18 @@ static int mxt_probe(struct i2c_client *client,  		goto err_free_irq;  	error = input_register_device(input_dev); -	if (error) +	if (error) { +		dev_err(&client->dev, "Error %d registering input device\n", +			error);  		goto err_free_irq; +	}  	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); -	if (error) +	if (error) { +		dev_err(&client->dev, "Failure %d creating sysfs group\n", +			error);  		goto err_unregister_device; +	}  	return 0; @@ -1295,11 +1576,7 @@ static int mxt_resume(struct device *dev)  	struct mxt_data *data = i2c_get_clientdata(client);  	struct input_dev *input_dev = data->input_dev; -	/* Soft reset */ -	mxt_write_object(data, MXT_GEN_COMMAND_T6, -			MXT_COMMAND_RESET, 1); - -	msleep(MXT_RESET_TIME); +	mxt_soft_reset(data);  	mutex_lock(&input_dev->mutex); diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c deleted file mode 100644 index bddabc59507..00000000000 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - *  Atmel Touch Screen Driver - * - *  Copyright (c) 2008 ATMEL - *  Copyright (c) 2008 Dan Liang - *  Copyright (c) 2008 TimeSys Corporation - *  Copyright (c) 2008 Justin Waters - * - *  Based on touchscreen code from Atmel Corporation. - * - *  This program is free software; you can redistribute it and/or modify - *  it under the terms of the GNU General Public License version 2 as - *  published by the Free Software Foundation. - */ -#include <linux/init.h> -#include <linux/err.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/input.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/platform_data/atmel.h> -#include <mach/cpu.h> - -/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ - -#define ATMEL_TSADCC_CR		0x00	/* Control register */ -#define   ATMEL_TSADCC_SWRST	(1 << 0)	/* Software Reset*/ -#define	  ATMEL_TSADCC_START	(1 << 1)	/* Start conversion */ - -#define ATMEL_TSADCC_MR		0x04	/* Mode register */ -#define	  ATMEL_TSADCC_TSAMOD	(3    <<  0)	/* ADC mode */ -#define	    ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE	(0x0)	/* ADC Mode */ -#define	    ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE	(0x1)	/* Touch Screen Only Mode */ -#define	  ATMEL_TSADCC_LOWRES	(1    <<  4)	/* Resolution selection */ -#define	  ATMEL_TSADCC_SLEEP	(1    <<  5)	/* Sleep mode */ -#define	  ATMEL_TSADCC_PENDET	(1    <<  6)	/* Pen Detect selection */ -#define	  ATMEL_TSADCC_PRES	(1    <<  7)	/* Pressure Measurement Selection */ -#define	  ATMEL_TSADCC_PRESCAL	(0x3f <<  8)	/* Prescalar Rate Selection */ -#define	  ATMEL_TSADCC_EPRESCAL	(0xff <<  8)	/* Prescalar Rate Selection (Extended) */ -#define	  ATMEL_TSADCC_STARTUP	(0x7f << 16)	/* Start Up time */ -#define	  ATMEL_TSADCC_SHTIM	(0xf  << 24)	/* Sample & Hold time */ -#define	  ATMEL_TSADCC_PENDBC	(0xf  << 28)	/* Pen Detect debouncing time */ - -#define ATMEL_TSADCC_TRGR	0x08	/* Trigger register */ -#define	  ATMEL_TSADCC_TRGMOD	(7      <<  0)	/* Trigger mode */ -#define	    ATMEL_TSADCC_TRGMOD_NONE		(0 << 0) -#define     ATMEL_TSADCC_TRGMOD_EXT_RISING	(1 << 0) -#define     ATMEL_TSADCC_TRGMOD_EXT_FALLING	(2 << 0) -#define     ATMEL_TSADCC_TRGMOD_EXT_ANY		(3 << 0) -#define     ATMEL_TSADCC_TRGMOD_PENDET		(4 << 0) -#define     ATMEL_TSADCC_TRGMOD_PERIOD		(5 << 0) -#define     ATMEL_TSADCC_TRGMOD_CONTINUOUS	(6 << 0) -#define   ATMEL_TSADCC_TRGPER	(0xffff << 16)	/* Trigger period */ - -#define ATMEL_TSADCC_TSR	0x0C	/* Touch Screen register */ -#define	  ATMEL_TSADCC_TSFREQ	(0xf <<  0)	/* TS Frequency in Interleaved mode */ -#define	  ATMEL_TSADCC_TSSHTIM	(0xf << 24)	/* Sample & Hold time */ - -#define ATMEL_TSADCC_CHER	0x10	/* Channel Enable register */ -#define ATMEL_TSADCC_CHDR	0x14	/* Channel Disable register */ -#define ATMEL_TSADCC_CHSR	0x18	/* Channel Status register */ -#define	  ATMEL_TSADCC_CH(n)	(1 << (n))	/* Channel number */ - -#define ATMEL_TSADCC_SR		0x1C	/* Status register */ -#define	  ATMEL_TSADCC_EOC(n)	(1 << ((n)+0))	/* End of conversion for channel N */ -#define	  ATMEL_TSADCC_OVRE(n)	(1 << ((n)+8))	/* Overrun error for channel N */ -#define	  ATMEL_TSADCC_DRDY	(1 << 16)	/* Data Ready */ -#define	  ATMEL_TSADCC_GOVRE	(1 << 17)	/* General Overrun Error */ -#define	  ATMEL_TSADCC_ENDRX	(1 << 18)	/* End of RX Buffer */ -#define	  ATMEL_TSADCC_RXBUFF	(1 << 19)	/* TX Buffer full */ -#define	  ATMEL_TSADCC_PENCNT	(1 << 20)	/* Pen contact */ -#define	  ATMEL_TSADCC_NOCNT	(1 << 21)	/* No contact */ - -#define ATMEL_TSADCC_LCDR	0x20	/* Last Converted Data register */ -#define	  ATMEL_TSADCC_DATA	(0x3ff << 0)	/* Channel data */ - -#define ATMEL_TSADCC_IER	0x24	/* Interrupt Enable register */ -#define ATMEL_TSADCC_IDR	0x28	/* Interrupt Disable register */ -#define ATMEL_TSADCC_IMR	0x2C	/* Interrupt Mask register */ -#define ATMEL_TSADCC_CDR0	0x30	/* Channel Data 0 */ -#define ATMEL_TSADCC_CDR1	0x34	/* Channel Data 1 */ -#define ATMEL_TSADCC_CDR2	0x38	/* Channel Data 2 */ -#define ATMEL_TSADCC_CDR3	0x3C	/* Channel Data 3 */ -#define ATMEL_TSADCC_CDR4	0x40	/* Channel Data 4 */ -#define ATMEL_TSADCC_CDR5	0x44	/* Channel Data 5 */ - -#define ATMEL_TSADCC_XPOS	0x50 -#define ATMEL_TSADCC_Z1DAT	0x54 -#define ATMEL_TSADCC_Z2DAT	0x58 - -#define PRESCALER_VAL(x)	((x) >> 8) - -#define ADC_DEFAULT_CLOCK	100000 - -struct atmel_tsadcc { -	struct input_dev	*input; -	char			phys[32]; -	struct clk		*clk; -	int			irq; -	unsigned int		prev_absx; -	unsigned int		prev_absy; -	unsigned char		bufferedmeasure; -}; - -static void __iomem		*tsc_base; - -#define atmel_tsadcc_read(reg)		__raw_readl(tsc_base + (reg)) -#define atmel_tsadcc_write(reg, val)	__raw_writel((val), tsc_base + (reg)) - -static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) -{ -	struct atmel_tsadcc	*ts_dev = (struct atmel_tsadcc *)dev; -	struct input_dev	*input_dev = ts_dev->input; - -	unsigned int status; -	unsigned int reg; - -	status = atmel_tsadcc_read(ATMEL_TSADCC_SR); -	status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR); - -	if (status & ATMEL_TSADCC_NOCNT) { -		/* Contact lost */ -		reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC; - -		atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); -		atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); -		atmel_tsadcc_write(ATMEL_TSADCC_IDR, -				   ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); -		atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); - -		input_report_key(input_dev, BTN_TOUCH, 0); -		ts_dev->bufferedmeasure = 0; -		input_sync(input_dev); - -	} else if (status & ATMEL_TSADCC_PENCNT) { -		/* Pen detected */ -		reg = atmel_tsadcc_read(ATMEL_TSADCC_MR); -		reg &= ~ATMEL_TSADCC_PENDBC; - -		atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT); -		atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); -		atmel_tsadcc_write(ATMEL_TSADCC_IER, -				   ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); -		atmel_tsadcc_write(ATMEL_TSADCC_TRGR, -				   ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16)); - -	} else if (status & ATMEL_TSADCC_EOC(3)) { -		/* Conversion finished */ - -		if (ts_dev->bufferedmeasure) { -			/* Last measurement is always discarded, since it can -			 * be erroneous. -			 * Always report previous measurement */ -			input_report_abs(input_dev, ABS_X, ts_dev->prev_absx); -			input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy); -			input_report_key(input_dev, BTN_TOUCH, 1); -			input_sync(input_dev); -		} else -			ts_dev->bufferedmeasure = 1; - -		/* Now make new measurement */ -		ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10; -		ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2); - -		ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10; -		ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0); -	} - -	return IRQ_HANDLED; -} - -/* - * The functions for inserting/removing us as a module. - */ - -static int atmel_tsadcc_probe(struct platform_device *pdev) -{ -	struct atmel_tsadcc	*ts_dev; -	struct input_dev	*input_dev; -	struct resource		*res; -	struct at91_tsadcc_data *pdata = pdev->dev.platform_data; -	int		err; -	unsigned int	prsc; -	unsigned int	reg; - -	if (!pdata) -		return -EINVAL; - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(&pdev->dev, "no mmio resource defined.\n"); -		return -ENXIO; -	} - -	/* Allocate memory for device */ -	ts_dev = kzalloc(sizeof(struct atmel_tsadcc), GFP_KERNEL); -	if (!ts_dev) { -		dev_err(&pdev->dev, "failed to allocate memory.\n"); -		return -ENOMEM; -	} -	platform_set_drvdata(pdev, ts_dev); - -	input_dev = input_allocate_device(); -	if (!input_dev) { -		dev_err(&pdev->dev, "failed to allocate input device.\n"); -		err = -EBUSY; -		goto err_free_mem; -	} - -	ts_dev->irq = platform_get_irq(pdev, 0); -	if (ts_dev->irq < 0) { -		dev_err(&pdev->dev, "no irq ID is designated.\n"); -		err = -ENODEV; -		goto err_free_dev; -	} - -	if (!request_mem_region(res->start, resource_size(res), -				"atmel tsadcc regs")) { -		dev_err(&pdev->dev, "resources is unavailable.\n"); -		err = -EBUSY; -		goto err_free_dev; -	} - -	tsc_base = ioremap(res->start, resource_size(res)); -	if (!tsc_base) { -		dev_err(&pdev->dev, "failed to map registers.\n"); -		err = -ENOMEM; -		goto err_release_mem; -	} - -	err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, 0, -			pdev->dev.driver->name, ts_dev); -	if (err) { -		dev_err(&pdev->dev, "failed to allocate irq.\n"); -		goto err_unmap_regs; -	} - -	ts_dev->clk = clk_get(&pdev->dev, "tsc_clk"); -	if (IS_ERR(ts_dev->clk)) { -		dev_err(&pdev->dev, "failed to get ts_clk\n"); -		err = PTR_ERR(ts_dev->clk); -		goto err_free_irq; -	} - -	ts_dev->input = input_dev; -	ts_dev->bufferedmeasure = 0; - -	snprintf(ts_dev->phys, sizeof(ts_dev->phys), -		 "%s/input0", dev_name(&pdev->dev)); - -	input_dev->name = "atmel touch screen controller"; -	input_dev->phys = ts_dev->phys; -	input_dev->dev.parent = &pdev->dev; - -	__set_bit(EV_ABS, input_dev->evbit); -	input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0); -	input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0); - -	input_set_capability(input_dev, EV_KEY, BTN_TOUCH); - -	/* clk_enable() always returns 0, no need to check it */ -	clk_enable(ts_dev->clk); - -	prsc = clk_get_rate(ts_dev->clk); -	dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); - -	if (!pdata->adc_clock) -		pdata->adc_clock = ADC_DEFAULT_CLOCK; - -	prsc = (prsc / (2 * pdata->adc_clock)) - 1; - -	/* saturate if this value is too high */ -	if (cpu_is_at91sam9rl()) { -		if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL)) -			prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL); -	} else { -		if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL)) -			prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL); -	} - -	dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc); - -	reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE		| -		((0x00 << 5) & ATMEL_TSADCC_SLEEP)	|	/* Normal Mode */ -		((0x01 << 6) & ATMEL_TSADCC_PENDET)	|	/* Enable Pen Detect */ -		(prsc << 8)				| -		((0x26 << 16) & ATMEL_TSADCC_STARTUP)	| -		((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC); - -	atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST); -	atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); -	atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); -	atmel_tsadcc_write(ATMEL_TSADCC_TSR, -		(pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM); - -	atmel_tsadcc_read(ATMEL_TSADCC_SR); -	atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); - -	/* All went ok, so register to the input system */ -	err = input_register_device(input_dev); -	if (err) -		goto err_fail; - -	return 0; - -err_fail: -	clk_disable(ts_dev->clk); -	clk_put(ts_dev->clk); -err_free_irq: -	free_irq(ts_dev->irq, ts_dev); -err_unmap_regs: -	iounmap(tsc_base); -err_release_mem: -	release_mem_region(res->start, resource_size(res)); -err_free_dev: -	input_free_device(input_dev); -err_free_mem: -	kfree(ts_dev); -	return err; -} - -static int atmel_tsadcc_remove(struct platform_device *pdev) -{ -	struct atmel_tsadcc *ts_dev = platform_get_drvdata(pdev); -	struct resource *res; - -	free_irq(ts_dev->irq, ts_dev); - -	input_unregister_device(ts_dev->input); - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	iounmap(tsc_base); -	release_mem_region(res->start, resource_size(res)); - -	clk_disable(ts_dev->clk); -	clk_put(ts_dev->clk); - -	kfree(ts_dev); - -	return 0; -} - -static struct platform_driver atmel_tsadcc_driver = { -	.probe		= atmel_tsadcc_probe, -	.remove		= atmel_tsadcc_remove, -	.driver		= { -		.name	= "atmel_tsadcc", -	}, -}; -module_platform_driver(atmel_tsadcc_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Atmel TouchScreen Driver"); -MODULE_AUTHOR("Dan Liang <dan.liang@atmel.com>"); - diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index d3f9f6b0f9b..7f3c9478778 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -679,7 +679,7 @@ static const struct i2c_device_id auo_pixcir_idtable[] = {  MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);  #ifdef CONFIG_OF -static struct of_device_id auo_pixcir_ts_dt_idtable[] = { +static const struct of_device_id auo_pixcir_ts_dt_idtable[] = {  	{ .compatible = "auo,auo_pixcir_ts" },  	{},  }; diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 8c651985a5c..5bf1aeeea82 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -178,7 +178,7 @@ static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)  static int cy8ctmg110_probe(struct i2c_client *client,  					const struct i2c_device_id *id)  { -	const struct cy8ctmg110_pdata *pdata = client->dev.platform_data; +	const struct cy8ctmg110_pdata *pdata = dev_get_platdata(&client->dev);  	struct cy8ctmg110 *ts;  	struct input_dev *input_dev;  	int err; diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c index d038575f49d..a035a390f8e 100644 --- a/drivers/input/touchscreen/cyttsp4_core.c +++ b/drivers/input/touchscreen/cyttsp4_core.c @@ -1246,8 +1246,7 @@ static void cyttsp4_watchdog_timer(unsigned long handle)  	dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__); -	if (!work_pending(&cd->watchdog_work)) -		schedule_work(&cd->watchdog_work); +	schedule_work(&cd->watchdog_work);  	return;  } @@ -2113,7 +2112,6 @@ error_startup:  error_request_irq:  	if (cd->cpdata->init)  		cd->cpdata->init(cd->cpdata, 0, dev); -	dev_set_drvdata(dev, NULL);  error_free_xfer:  	kfree(cd->xfer_buf);  error_free_cd: @@ -2151,7 +2149,6 @@ int cyttsp4_remove(struct cyttsp4 *cd)  	free_irq(cd->irq, cd);  	if (cd->cpdata->init)  		cd->cpdata->init(cd->cpdata, 0, dev); -	dev_set_drvdata(dev, NULL);  	cyttsp4_free_si_ptrs(cd);  	kfree(cd);  	return 0; diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c index a71e1141d63..b19434cebbf 100644 --- a/drivers/input/touchscreen/cyttsp4_spi.c +++ b/drivers/input/touchscreen/cyttsp4_spi.c @@ -171,10 +171,7 @@ static int cyttsp4_spi_probe(struct spi_device *spi)  	ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,  			  CY_SPI_DATA_BUF_SIZE); -	if (IS_ERR(ts)) -		return PTR_ERR(ts); - -	return 0; +	return PTR_ERR_OR_ZERO(ts);  }  static int cyttsp4_spi_remove(struct spi_device *spi) diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index d53e0b72a40..eee656f77a2 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c @@ -242,7 +242,7 @@ static int cyttsp_soft_reset(struct cyttsp *ts)  	int retval;  	/* wait for interrupt to set ready completion */ -	INIT_COMPLETION(ts->bl_ready); +	reinit_completion(&ts->bl_ready);  	ts->state = CY_BL_STATE;  	enable_irq(ts->irq); @@ -534,7 +534,7 @@ static void cyttsp_close(struct input_dev *dev)  struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,  			    struct device *dev, int irq, size_t xfer_buf_size)  { -	const struct cyttsp_platform_data *pdata = dev->platform_data; +	const struct cyttsp_platform_data *pdata = dev_get_platdata(dev);  	struct cyttsp *ts;  	struct input_dev *input_dev;  	int error; @@ -553,7 +553,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,  	ts->dev = dev;  	ts->input = input_dev; -	ts->pdata = dev->platform_data; +	ts->pdata = dev_get_platdata(dev);  	ts->bus_ops = bus_ops;  	ts->irq = irq; diff --git a/drivers/input/touchscreen/cyttsp_i2c_common.c b/drivers/input/touchscreen/cyttsp_i2c_common.c index 1d7b6f15416..ccefa56ca21 100644 --- a/drivers/input/touchscreen/cyttsp_i2c_common.c +++ b/drivers/input/touchscreen/cyttsp_i2c_common.c @@ -31,6 +31,8 @@  #include <linux/module.h>  #include <linux/types.h> +#include "cyttsp4_core.h" +  int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,  				      u16 addr, u8 length, void *values)  { diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c index 34ad84105e6..cf6f4b31db4 100644 --- a/drivers/input/touchscreen/da9034-ts.c +++ b/drivers/input/touchscreen/da9034-ts.c @@ -13,7 +13,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/platform_device.h>  #include <linux/input.h> @@ -299,13 +298,14 @@ static void da9034_touch_close(struct input_dev *dev)  static int da9034_touch_probe(struct platform_device *pdev)  { -	struct da9034_touch_pdata *pdata = pdev->dev.platform_data; +	struct da9034_touch_pdata *pdata = dev_get_platdata(&pdev->dev);  	struct da9034_touch *touch;  	struct input_dev *input_dev; -	int ret; +	int error; -	touch = kzalloc(sizeof(struct da9034_touch), GFP_KERNEL); -	if (touch == NULL) { +	touch = devm_kzalloc(&pdev->dev, sizeof(struct da9034_touch), +			     GFP_KERNEL); +	if (!touch) {  		dev_err(&pdev->dev, "failed to allocate driver data\n");  		return -ENOMEM;  	} @@ -316,18 +316,18 @@ static int da9034_touch_probe(struct platform_device *pdev)  		touch->interval_ms	= pdata->interval_ms;  		touch->x_inverted	= pdata->x_inverted;  		touch->y_inverted	= pdata->y_inverted; -	} else +	} else {  		/* fallback into default */  		touch->interval_ms	= 10; +	}  	INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);  	touch->notifier.notifier_call = da9034_touch_notifier; -	input_dev = input_allocate_device(); +	input_dev = devm_input_allocate_device(&pdev->dev);  	if (!input_dev) {  		dev_err(&pdev->dev, "failed to allocate input device\n"); -		ret = -ENOMEM; -		goto err_free_touch; +		return -ENOMEM;  	}  	input_dev->name		= pdev->name; @@ -347,26 +347,9 @@ static int da9034_touch_probe(struct platform_device *pdev)  	touch->input_dev = input_dev;  	input_set_drvdata(input_dev, touch); -	ret = input_register_device(input_dev); -	if (ret) -		goto err_free_input; - -	platform_set_drvdata(pdev, touch); -	return 0; - -err_free_input: -	input_free_device(input_dev); -err_free_touch: -	kfree(touch); -	return ret; -} - -static int da9034_touch_remove(struct platform_device *pdev) -{ -	struct da9034_touch *touch = platform_get_drvdata(pdev); - -	input_unregister_device(touch->input_dev); -	kfree(touch); +	error = input_register_device(input_dev); +	if (error) +		return error;  	return 0;  } @@ -377,7 +360,6 @@ static struct platform_driver da9034_touch_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= da9034_touch_probe, -	.remove		= da9034_touch_remove,  };  module_platform_driver(da9034_touch_driver); diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c index 1809677a651..86237a91087 100644 --- a/drivers/input/touchscreen/dynapro.c +++ b/drivers/input/touchscreen/dynapro.c @@ -24,7 +24,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Dynapro serial touchscreen driver" diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 83fa1b15a97..d4f33992ad8 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1,5 +1,7 @@  /*   * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de> + * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support) + * Lothar Waßmann <LW@KARO-electronics.de> (DT support)   *   * This software is licensed under the terms of the GNU General Public   * License version 2, as published by the Free Software Foundation, and @@ -33,6 +35,7 @@  #include <linux/debugfs.h>  #include <linux/slab.h>  #include <linux/gpio.h> +#include <linux/of_gpio.h>  #include <linux/input/mt.h>  #include <linux/input/edt-ft5x06.h> @@ -45,6 +48,14 @@  #define WORK_REGISTER_NUM_X		0x33  #define WORK_REGISTER_NUM_Y		0x34 +#define M09_REGISTER_THRESHOLD		0x80 +#define M09_REGISTER_GAIN		0x92 +#define M09_REGISTER_OFFSET		0x93 +#define M09_REGISTER_NUM_X		0x94 +#define M09_REGISTER_NUM_Y		0x95 + +#define NO_REGISTER			0xff +  #define WORK_REGISTER_OPMODE		0x3c  #define FACTORY_REGISTER_OPMODE		0x01 @@ -59,12 +70,30 @@  #define EDT_RAW_DATA_RETRIES		100  #define EDT_RAW_DATA_DELAY		1 /* msec */ +enum edt_ver { +	M06, +	M09, +}; + +struct edt_reg_addr { +	int reg_threshold; +	int reg_report_rate; +	int reg_gain; +	int reg_offset; +	int reg_num_x; +	int reg_num_y; +}; +  struct edt_ft5x06_ts_data {  	struct i2c_client *client;  	struct input_dev *input;  	u16 num_x;  	u16 num_y; +	int reset_pin; +	int irq_pin; +	int wake_pin; +  #if defined(CONFIG_DEBUG_FS)  	struct dentry *debug_dir;  	u8 *raw_buffer; @@ -79,6 +108,9 @@ struct edt_ft5x06_ts_data {  	int report_rate;  	char name[EDT_NAME_LEN]; + +	struct edt_reg_addr reg_addr; +	enum edt_ver version;  };  static int edt_ft5x06_ts_readwrite(struct i2c_client *client, @@ -136,33 +168,58 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)  {  	struct edt_ft5x06_ts_data *tsdata = dev_id;  	struct device *dev = &tsdata->client->dev; -	u8 cmd = 0xf9; -	u8 rdbuf[26]; +	u8 cmd; +	u8 rdbuf[29];  	int i, type, x, y, id; +	int offset, tplen, datalen;  	int error; +	switch (tsdata->version) { +	case M06: +		cmd = 0xf9; /* tell the controller to send touch data */ +		offset = 5; /* where the actual touch data starts */ +		tplen = 4;  /* data comes in so called frames */ +		datalen = 26; /* how much bytes to listen for */ +		break; + +	case M09: +		cmd = 0x02; +		offset = 1; +		tplen = 6; +		datalen = 29; +		break; + +	default: +		goto out; +	} +  	memset(rdbuf, 0, sizeof(rdbuf));  	error = edt_ft5x06_ts_readwrite(tsdata->client,  					sizeof(cmd), &cmd, -					sizeof(rdbuf), rdbuf); +					datalen, rdbuf);  	if (error) {  		dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",  				    error);  		goto out;  	} -	if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != 26) { -		dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n", -				    rdbuf[0], rdbuf[1], rdbuf[2]); -		goto out; -	} +	/* M09 does not send header or CRC */ +	if (tsdata->version == M06) { +		if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || +			rdbuf[2] != datalen) { +			dev_err_ratelimited(dev, +					"Unexpected header: %02x%02x%02x!\n", +					rdbuf[0], rdbuf[1], rdbuf[2]); +			goto out; +		} -	if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, 26)) -		goto out; +		if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) +			goto out; +	}  	for (i = 0; i < MAX_SUPPORT_POINTS; i++) { -		u8 *buf = &rdbuf[i * 4 + 5]; +		u8 *buf = &rdbuf[i * tplen + offset];  		bool down;  		type = buf[0] >> 6; @@ -170,10 +227,14 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)  		if (type == TOUCH_EVENT_RESERVED)  			continue; +		/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ +		if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN) +			continue; +  		x = ((buf[0] << 8) | buf[1]) & 0x0fff;  		y = ((buf[2] << 8) | buf[3]) & 0x0fff;  		id = (buf[2] >> 4) & 0x0f; -		down = (type != TOUCH_EVENT_UP); +		down = type != TOUCH_EVENT_UP;  		input_mt_slot(tsdata->input, id);  		input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down); @@ -197,12 +258,25 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,  {  	u8 wrbuf[4]; -	wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; -	wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; -	wrbuf[2] = value; -	wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; - -	return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL); +	switch (tsdata->version) { +	case M06: +		wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; +		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; +		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; +		wrbuf[2] = value; +		wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; +		return edt_ft5x06_ts_readwrite(tsdata->client, 4, +					wrbuf, 0, NULL); +	case M09: +		wrbuf[0] = addr; +		wrbuf[1] = value; + +		return edt_ft5x06_ts_readwrite(tsdata->client, 2, +					wrbuf, 0, NULL); + +	default: +		return -EINVAL; +	}  }  static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, @@ -211,19 +285,36 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,  	u8 wrbuf[2], rdbuf[2];  	int error; -	wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; -	wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; -	wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; +	switch (tsdata->version) { +	case M06: +		wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; +		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; +		wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; -	error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, rdbuf); -	if (error) -		return error; +		error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, +						rdbuf); +		if (error) +			return error; -	if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { -		dev_err(&tsdata->client->dev, -			"crc error: 0x%02x expected, got 0x%02x\n", -			wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], rdbuf[1]); -		return -EIO; +		if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { +			dev_err(&tsdata->client->dev, +				"crc error: 0x%02x expected, got 0x%02x\n", +				wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], +				rdbuf[1]); +			return -EIO; +		} +		break; + +	case M09: +		wrbuf[0] = addr; +		error = edt_ft5x06_ts_readwrite(tsdata->client, 1, +						wrbuf, 1, rdbuf); +		if (error) +			return error; +		break; + +	default: +		return -EINVAL;  	}  	return rdbuf[0]; @@ -234,19 +325,21 @@ struct edt_ft5x06_attribute {  	size_t field_offset;  	u8 limit_low;  	u8 limit_high; -	u8 addr; +	u8 addr_m06; +	u8 addr_m09;  }; -#define EDT_ATTR(_field, _mode, _addr, _limit_low, _limit_high)		\ +#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09,			\ +		_limit_low, _limit_high)				\  	struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = {	\  		.dattr = __ATTR(_field, _mode,				\  				edt_ft5x06_setting_show,		\  				edt_ft5x06_setting_store),		\ -		.field_offset =						\ -			offsetof(struct edt_ft5x06_ts_data, _field),	\ +		.field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ +		.addr_m06 = _addr_m06,					\ +		.addr_m09 = _addr_m09,					\  		.limit_low = _limit_low,				\  		.limit_high = _limit_high,				\ -		.addr = _addr,						\  	}  static ssize_t edt_ft5x06_setting_show(struct device *dev, @@ -257,10 +350,11 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,  	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);  	struct edt_ft5x06_attribute *attr =  			container_of(dattr, struct edt_ft5x06_attribute, dattr); -	u8 *field = (u8 *)((char *)tsdata + attr->field_offset); +	u8 *field = (u8 *)tsdata + attr->field_offset;  	int val;  	size_t count = 0;  	int error = 0; +	u8 addr;  	mutex_lock(&tsdata->mutex); @@ -269,15 +363,33 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,  		goto out;  	} -	val = edt_ft5x06_register_read(tsdata, attr->addr); -	if (val < 0) { -		error = val; -		dev_err(&tsdata->client->dev, -			"Failed to fetch attribute %s, error %d\n", -			dattr->attr.name, error); +	switch (tsdata->version) { +	case M06: +		addr = attr->addr_m06; +		break; + +	case M09: +		addr = attr->addr_m09; +		break; + +	default: +		error = -ENODEV;  		goto out;  	} +	if (addr != NO_REGISTER) { +		val = edt_ft5x06_register_read(tsdata, addr); +		if (val < 0) { +			error = val; +			dev_err(&tsdata->client->dev, +				"Failed to fetch attribute %s, error %d\n", +				dattr->attr.name, error); +			goto out; +		} +	} else { +		val = *field; +	} +  	if (val != *field) {  		dev_warn(&tsdata->client->dev,  			 "%s: read (%d) and stored value (%d) differ\n", @@ -299,9 +411,10 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,  	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);  	struct edt_ft5x06_attribute *attr =  			container_of(dattr, struct edt_ft5x06_attribute, dattr); -	u8 *field = (u8 *)((char *)tsdata + attr->field_offset); +	u8 *field = (u8 *)tsdata + attr->field_offset;  	unsigned int val;  	int error; +	u8 addr;  	mutex_lock(&tsdata->mutex); @@ -319,14 +432,29 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,  		goto out;  	} -	error = edt_ft5x06_register_write(tsdata, attr->addr, val); -	if (error) { -		dev_err(&tsdata->client->dev, -			"Failed to update attribute %s, error: %d\n", -			dattr->attr.name, error); +	switch (tsdata->version) { +	case M06: +		addr = attr->addr_m06; +		break; + +	case M09: +		addr = attr->addr_m09; +		break; + +	default: +		error = -ENODEV;  		goto out;  	} +	if (addr != NO_REGISTER) { +		error = edt_ft5x06_register_write(tsdata, addr, val); +		if (error) { +			dev_err(&tsdata->client->dev, +				"Failed to update attribute %s, error: %d\n", +				dattr->attr.name, error); +			goto out; +		} +	}  	*field = val;  out: @@ -334,12 +462,14 @@ out:  	return error ?: count;  } -static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 0, 31); -static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 0, 31); -static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, -		WORK_REGISTER_THRESHOLD, 20, 80); -static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, -		WORK_REGISTER_REPORT_RATE, 3, 14); +static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, +		M09_REGISTER_GAIN, 0, 31); +static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, +		M09_REGISTER_OFFSET, 0, 31); +static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, +		M09_REGISTER_THRESHOLD, 20, 80); +static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, +		NO_REGISTER, 3, 14);  static struct attribute *edt_ft5x06_attrs[] = {  	&edt_ft5x06_attr_gain.dattr.attr, @@ -374,6 +504,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)  	}  	/* mode register is 0x3c when in the work mode */ +	if (tsdata->version == M09) +		goto m09_out; +  	error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);  	if (error) {  		dev_err(&client->dev, @@ -406,12 +539,18 @@ err_out:  	enable_irq(client->irq);  	return error; + +m09_out: +	dev_err(&client->dev, "No factory mode support for M09\n"); +	return -EINVAL; +  }  static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)  {  	struct i2c_client *client = tsdata->client;  	int retries = EDT_SWITCH_MODE_RETRIES; +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;  	int ret;  	int error; @@ -444,13 +583,14 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)  	tsdata->raw_buffer = NULL;  	/* restore parameters */ -	edt_ft5x06_register_write(tsdata, WORK_REGISTER_THRESHOLD, +	edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold,  				  tsdata->threshold); -	edt_ft5x06_register_write(tsdata, WORK_REGISTER_GAIN, +	edt_ft5x06_register_write(tsdata, reg_addr->reg_gain,  				  tsdata->gain); -	edt_ft5x06_register_write(tsdata, WORK_REGISTER_OFFSET, +	edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,  				  tsdata->offset); -	edt_ft5x06_register_write(tsdata, WORK_REGISTER_REPORT_RATE, +	if (reg_addr->reg_report_rate) +		edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,  				  tsdata->report_rate);  	enable_irq(client->irq); @@ -479,7 +619,7 @@ static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)  	if (mode != tsdata->factory_mode) {  		retval = mode ? edt_ft5x06_factory_mode(tsdata) : -			        edt_ft5x06_work_mode(tsdata); +				edt_ft5x06_work_mode(tsdata);  	}  	mutex_unlock(&tsdata->mutex); @@ -568,7 +708,6 @@ out:  	return error ?: read;  }; -  static const struct file_operations debugfs_raw_data_fops = {  	.open = simple_open,  	.read = edt_ft5x06_debugfs_raw_data_read, @@ -614,57 +753,100 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)  #endif /* CONFIG_DEBUGFS */ - -  static int edt_ft5x06_ts_reset(struct i2c_client *client, -					 int reset_pin) +			struct edt_ft5x06_ts_data *tsdata)  {  	int error; -	if (gpio_is_valid(reset_pin)) { +	if (gpio_is_valid(tsdata->wake_pin)) { +		error = devm_gpio_request_one(&client->dev, +					tsdata->wake_pin, GPIOF_OUT_INIT_LOW, +					"edt-ft5x06 wake"); +		if (error) { +			dev_err(&client->dev, +				"Failed to request GPIO %d as wake pin, error %d\n", +				tsdata->wake_pin, error); +			return error; +		} + +		msleep(5); +		gpio_set_value(tsdata->wake_pin, 1); +	} +	if (gpio_is_valid(tsdata->reset_pin)) {  		/* this pulls reset down, enabling the low active reset */ -		error = gpio_request_one(reset_pin, GPIOF_OUT_INIT_LOW, -					 "edt-ft5x06 reset"); +		error = devm_gpio_request_one(&client->dev, +					tsdata->reset_pin, GPIOF_OUT_INIT_LOW, +					"edt-ft5x06 reset");  		if (error) {  			dev_err(&client->dev,  				"Failed to request GPIO %d as reset pin, error %d\n", -				reset_pin, error); +				tsdata->reset_pin, error);  			return error;  		} -		mdelay(50); -		gpio_set_value(reset_pin, 1); -		mdelay(100); +		msleep(5); +		gpio_set_value(tsdata->reset_pin, 1); +		msleep(300);  	}  	return 0;  }  static int edt_ft5x06_ts_identify(struct i2c_client *client, -					    char *model_name, -					    char *fw_version) +					struct edt_ft5x06_ts_data *tsdata, +					char *fw_version)  {  	u8 rdbuf[EDT_NAME_LEN];  	char *p;  	int error; +	char *model_name = tsdata->name; +	/* see what we find if we assume it is a M06 * +	 * if we get less than EDT_NAME_LEN, we don't want +	 * to have garbage in there +	 */ +	memset(rdbuf, 0, sizeof(rdbuf));  	error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",  					EDT_NAME_LEN - 1, rdbuf);  	if (error)  		return error; -	/* remove last '$' end marker */ -	rdbuf[EDT_NAME_LEN - 1] = '\0'; -	if (rdbuf[EDT_NAME_LEN - 2] == '$') -		rdbuf[EDT_NAME_LEN - 2] = '\0'; +	/* if we find something consistent, stay with that assumption +	 * at least M09 won't send 3 bytes here +	 */ +	if (!(strnicmp(rdbuf + 1, "EP0", 3))) { +		tsdata->version = M06; + +		/* remove last '$' end marker */ +		rdbuf[EDT_NAME_LEN - 1] = '\0'; +		if (rdbuf[EDT_NAME_LEN - 2] == '$') +			rdbuf[EDT_NAME_LEN - 2] = '\0'; + +		/* look for Model/Version separator */ +		p = strchr(rdbuf, '*'); +		if (p) +			*p++ = '\0'; +		strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); +		strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); +	} else { +		/* since there are only two versions around (M06, M09) */ +		tsdata->version = M09; + +		error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", +						2, rdbuf); +		if (error) +			return error; -	/* look for Model/Version separator */ -	p = strchr(rdbuf, '*'); -	if (p) -		*p++ = '\0'; +		strlcpy(fw_version, rdbuf, 2); -	strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); -	strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); +		error = edt_ft5x06_ts_readwrite(client, 1, "\xA8", +						1, rdbuf); +		if (error) +			return error; + +		snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", +			rdbuf[0] >> 4, rdbuf[0] & 0x0F); +	}  	return 0;  } @@ -674,38 +856,109 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,  	    pdata->name <= edt_ft5x06_attr_##name.limit_high)		\  		edt_ft5x06_register_write(tsdata, reg, pdata->name) +#define EDT_GET_PROP(name, reg) {				\ +	u32 val;						\ +	if (of_property_read_u32(np, #name, &val) == 0)		\ +		edt_ft5x06_register_write(tsdata, reg, val);	\ +} + +static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np, +					struct edt_ft5x06_ts_data *tsdata) +{ +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + +	EDT_GET_PROP(threshold, reg_addr->reg_threshold); +	EDT_GET_PROP(gain, reg_addr->reg_gain); +	EDT_GET_PROP(offset, reg_addr->reg_offset); +} +  static void  edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,  			   const struct edt_ft5x06_platform_data *pdata)  { +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr; +  	if (!pdata->use_parameters)  		return;  	/* pick up defaults from the platform data */ -	EDT_ATTR_CHECKSET(threshold, WORK_REGISTER_THRESHOLD); -	EDT_ATTR_CHECKSET(gain, WORK_REGISTER_GAIN); -	EDT_ATTR_CHECKSET(offset, WORK_REGISTER_OFFSET); -	EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE); +	EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold); +	EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain); +	EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset); +	if (reg_addr->reg_report_rate != NO_REGISTER) +		EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate);  }  static void  edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)  { +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr; +  	tsdata->threshold = edt_ft5x06_register_read(tsdata, -						     WORK_REGISTER_THRESHOLD); -	tsdata->gain = edt_ft5x06_register_read(tsdata, WORK_REGISTER_GAIN); -	tsdata->offset = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OFFSET); -	tsdata->report_rate = edt_ft5x06_register_read(tsdata, -						WORK_REGISTER_REPORT_RATE); -	tsdata->num_x = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_X); -	tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y); +						     reg_addr->reg_threshold); +	tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); +	tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); +	if (reg_addr->reg_report_rate != NO_REGISTER) +		tsdata->report_rate = edt_ft5x06_register_read(tsdata, +						reg_addr->reg_report_rate); +	tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); +	tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); +} + +static void +edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) +{ +	struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + +	switch (tsdata->version) { +	case M06: +		reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; +		reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; +		reg_addr->reg_gain = WORK_REGISTER_GAIN; +		reg_addr->reg_offset = WORK_REGISTER_OFFSET; +		reg_addr->reg_num_x = WORK_REGISTER_NUM_X; +		reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; +		break; + +	case M09: +		reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; +		reg_addr->reg_gain = M09_REGISTER_GAIN; +		reg_addr->reg_offset = M09_REGISTER_OFFSET; +		reg_addr->reg_num_x = M09_REGISTER_NUM_X; +		reg_addr->reg_num_y = M09_REGISTER_NUM_Y; +		break; +	} +} + +#ifdef CONFIG_OF +static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, +				struct edt_ft5x06_ts_data *tsdata) +{ +	struct device_node *np = dev->of_node; + +	/* +	 * irq_pin is not needed for DT setup. +	 * irq is associated via 'interrupts' property in DT +	 */ +	tsdata->irq_pin = -EINVAL; +	tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0); +	tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0); + +	return 0;  } +#else +static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, +					struct edt_ft5x06_ts_data *tsdata) +{ +	return -ENODEV; +} +#endif  static int edt_ft5x06_ts_probe(struct i2c_client *client,  					 const struct i2c_device_id *id)  {  	const struct edt_ft5x06_platform_data *pdata = -						client->dev.platform_data; +						dev_get_platdata(&client->dev);  	struct edt_ft5x06_ts_data *tsdata;  	struct input_dev *input;  	int error; @@ -713,32 +966,44 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,  	dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); +	tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); +	if (!tsdata) { +		dev_err(&client->dev, "failed to allocate driver data.\n"); +		return -ENOMEM; +	} +  	if (!pdata) { -		dev_err(&client->dev, "no platform data?\n"); -		return -EINVAL; +		error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata); +		if (error) { +			dev_err(&client->dev, +				"DT probe failed and no platform data present\n"); +			return error; +		} +	} else { +		tsdata->reset_pin = pdata->reset_pin; +		tsdata->irq_pin = pdata->irq_pin; +		tsdata->wake_pin = -EINVAL;  	} -	error = edt_ft5x06_ts_reset(client, pdata->reset_pin); +	error = edt_ft5x06_ts_reset(client, tsdata);  	if (error)  		return error; -	if (gpio_is_valid(pdata->irq_pin)) { -		error = gpio_request_one(pdata->irq_pin, -					 GPIOF_IN, "edt-ft5x06 irq"); +	if (gpio_is_valid(tsdata->irq_pin)) { +		error = devm_gpio_request_one(&client->dev, tsdata->irq_pin, +					GPIOF_IN, "edt-ft5x06 irq");  		if (error) {  			dev_err(&client->dev,  				"Failed to request GPIO %d, error %d\n", -				pdata->irq_pin, error); +				tsdata->irq_pin, error);  			return error;  		}  	} -	tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL); -	input = input_allocate_device(); -	if (!tsdata || !input) { -		dev_err(&client->dev, "failed to allocate driver data.\n"); -		error = -ENOMEM; -		goto err_free_mem; +	input = devm_input_allocate_device(&client->dev); +	if (!input) { +		dev_err(&client->dev, "failed to allocate input device.\n"); +		return -ENOMEM;  	}  	mutex_init(&tsdata->mutex); @@ -746,13 +1011,19 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,  	tsdata->input = input;  	tsdata->factory_mode = false; -	error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version); +	error = edt_ft5x06_ts_identify(client, tsdata, fw_version);  	if (error) {  		dev_err(&client->dev, "touchscreen probe failed\n"); -		goto err_free_mem; +		return error;  	} -	edt_ft5x06_ts_get_defaults(tsdata, pdata); +	edt_ft5x06_ts_set_regs(tsdata); + +	if (!pdata) +		edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata); +	else +		edt_ft5x06_ts_get_defaults(tsdata, pdata); +  	edt_ft5x06_ts_get_parameters(tsdata);  	dev_dbg(&client->dev, @@ -776,23 +1047,24 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,  	error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);  	if (error) {  		dev_err(&client->dev, "Unable to init MT slots.\n"); -		goto err_free_mem; +		return error;  	}  	input_set_drvdata(input, tsdata);  	i2c_set_clientdata(client, tsdata); -	error = request_threaded_irq(client->irq, NULL, edt_ft5x06_ts_isr, -				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT, -				     client->name, tsdata); +	error = devm_request_threaded_irq(&client->dev, client->irq, NULL, +					edt_ft5x06_ts_isr, +					IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +					client->name, tsdata);  	if (error) {  		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); -		goto err_free_mem; +		return error;  	}  	error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group);  	if (error) -		goto err_free_irq; +		return error;  	error = input_register_device(input);  	if (error) @@ -802,44 +1074,23 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,  	device_init_wakeup(&client->dev, 1);  	dev_dbg(&client->dev, -		"EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n", -		pdata->irq_pin, pdata->reset_pin); +		"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", +		client->irq, tsdata->wake_pin, tsdata->reset_pin);  	return 0;  err_remove_attrs:  	sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); -err_free_irq: -	free_irq(client->irq, tsdata); -err_free_mem: -	input_free_device(input); -	kfree(tsdata); - -	if (gpio_is_valid(pdata->irq_pin)) -		gpio_free(pdata->irq_pin); -  	return error;  }  static int edt_ft5x06_ts_remove(struct i2c_client *client)  { -	const struct edt_ft5x06_platform_data *pdata = -						dev_get_platdata(&client->dev);  	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);  	edt_ft5x06_ts_teardown_debugfs(tsdata);  	sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); -	free_irq(client->irq, tsdata); -	input_unregister_device(tsdata->input); - -	if (gpio_is_valid(pdata->irq_pin)) -		gpio_free(pdata->irq_pin); -	if (gpio_is_valid(pdata->reset_pin)) -		gpio_free(pdata->reset_pin); - -	kfree(tsdata); -  	return 0;  } @@ -869,15 +1120,26 @@ static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,  			 edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);  static const struct i2c_device_id edt_ft5x06_ts_id[] = { -	{ "edt-ft5x06", 0 }, -	{ } +	{ "edt-ft5x06", 0, }, +	{ /* sentinel */ }  };  MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); +#ifdef CONFIG_OF +static const struct of_device_id edt_ft5x06_of_match[] = { +	{ .compatible = "edt,edt-ft5206", }, +	{ .compatible = "edt,edt-ft5306", }, +	{ .compatible = "edt,edt-ft5406", }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); +#endif +  static struct i2c_driver edt_ft5x06_ts_driver = {  	.driver = {  		.owner = THIS_MODULE,  		.name = "edt_ft5x06", +		.of_match_table = of_match_ptr(edt_ft5x06_of_match),  		.pm = &edt_ft5x06_ts_pm_ops,  	},  	.id_table = edt_ft5x06_ts_id, diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 1ce3d29ffca..b1884ddd7a8 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -157,7 +157,7 @@ static void eeti_ts_close(struct input_dev *dev)  static int eeti_ts_probe(struct i2c_client *client,  				   const struct i2c_device_id *idp)  { -	struct eeti_ts_platform_data *pdata = client->dev.platform_data; +	struct eeti_ts_platform_data *pdata = dev_get_platdata(&client->dev);  	struct eeti_ts_priv *priv;  	struct input_dev *input;  	unsigned int irq_flags; diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index ef5fcb0945e..c8057847d71 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -18,7 +18,6 @@  */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/i2c.h>  #include <linux/interrupt.h>  #include <linux/input.h> @@ -263,7 +262,7 @@ static int egalax_ts_resume(struct device *dev)  static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume); -static struct of_device_id egalax_ts_dt_ids[] = { +static const struct of_device_id egalax_ts_dt_ids[] = {  	{ .compatible = "eeti,egalax_ts" },  	{ /* sentinel */ }  }; @@ -273,7 +272,7 @@ static struct i2c_driver egalax_ts_driver = {  		.name	= "egalax_ts",  		.owner	= THIS_MODULE,  		.pm	= &egalax_ts_pm_ops, -		.of_match_table	= of_match_ptr(egalax_ts_dt_ids), +		.of_match_table	= egalax_ts_dt_ids,  	},  	.id_table	= egalax_ts_id,  	.probe		= egalax_ts_probe, diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index 957423d1471..8051a4b704e 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -22,7 +22,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #include <linux/ctype.h>  #define DRIVER_DESC	"Elo serial touchscreen driver" diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c index 10794ddbdf5..d0e46a7e183 100644 --- a/drivers/input/touchscreen/fujitsu_ts.c +++ b/drivers/input/touchscreen/fujitsu_ts.c @@ -16,7 +16,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Fujitsu serial touchscreen driver" diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index 41c71766bf1..e2ee6261527 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -32,7 +32,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Gunze AHL-51S touchscreen driver" diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c index 0cc47ea98ac..ecb1e0e0132 100644 --- a/drivers/input/touchscreen/hampshire.c +++ b/drivers/input/touchscreen/hampshire.c @@ -23,7 +23,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Hampshire serial touchscreen driver" diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c index 66500852341..92e2243fb77 100644 --- a/drivers/input/touchscreen/htcpen.c +++ b/drivers/input/touchscreen/htcpen.c @@ -186,8 +186,6 @@ static int htcpen_isa_remove(struct device *dev, unsigned int id)  	release_region(HTCPEN_PORT_INIT, 1);  	release_region(HTCPEN_PORT_IRQ_CLEAR, 1); -	dev_set_drvdata(dev, NULL); -  	return 0;  } diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 1418bdda61b..2a508913981 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -184,7 +184,7 @@ static int ili210x_i2c_probe(struct i2c_client *client,  				       const struct i2c_device_id *id)  {  	struct device *dev = &client->dev; -	const struct ili210x_platform_data *pdata = dev->platform_data; +	const struct ili210x_platform_data *pdata = dev_get_platdata(dev);  	struct ili210x *priv;  	struct input_dev *input;  	struct panel_info panel; diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c index a29c99c3224..adb80b65a25 100644 --- a/drivers/input/touchscreen/inexio.c +++ b/drivers/input/touchscreen/inexio.c @@ -23,7 +23,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"iNexio serial touchscreen driver" diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c index e30d837dae2..c38ca4a7e38 100644 --- a/drivers/input/touchscreen/intel-mid-touch.c +++ b/drivers/input/touchscreen/intel-mid-touch.c @@ -27,7 +27,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/err.h> @@ -37,6 +36,7 @@  #include <linux/irq.h>  #include <linux/delay.h>  #include <asm/intel_scu_ipc.h> +#include <linux/device.h>  /* PMIC Interrupt registers */  #define PMIC_REG_ID1		0x00 /* PMIC ID1 register */ @@ -581,12 +581,17 @@ static int mrstouch_probe(struct platform_device *pdev)  		return -EINVAL;  	} -	tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL); -	input = input_allocate_device(); -	if (!tsdev || !input) { +	tsdev = devm_kzalloc(&pdev->dev, sizeof(struct mrstouch_dev), +			     GFP_KERNEL); +	if (!tsdev) {  		dev_err(&pdev->dev, "unable to allocate memory\n"); -		err = -ENOMEM; -		goto err_free_mem; +		return -ENOMEM; +	} + +	input = devm_input_allocate_device(&pdev->dev); +	if (!input) { +		dev_err(&pdev->dev, "unable to allocate input device\n"); +		return -ENOMEM;  	}  	tsdev->dev = &pdev->dev; @@ -599,7 +604,7 @@ static int mrstouch_probe(struct platform_device *pdev)  	err = mrstouch_adc_init(tsdev);  	if (err) {  		dev_err(&pdev->dev, "ADC initialization failed\n"); -		goto err_free_mem; +		return err;  	}  	input->name = "mrst_touchscreen"; @@ -619,38 +624,20 @@ static int mrstouch_probe(struct platform_device *pdev)  	input_set_abs_params(tsdev->input, ABS_PRESSURE,  			     MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0); -	err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq, -				   IRQF_ONESHOT, "mrstouch", tsdev); +	err = devm_request_threaded_irq(&pdev->dev, tsdev->irq, NULL, +					mrstouch_pendet_irq, IRQF_ONESHOT, +					"mrstouch", tsdev);  	if (err) {  		dev_err(tsdev->dev, "unable to allocate irq\n"); -		goto err_free_mem; +		return err;  	}  	err = input_register_device(tsdev->input);  	if (err) {  		dev_err(tsdev->dev, "unable to register input device\n"); -		goto err_free_irq; +		return err;  	} -	platform_set_drvdata(pdev, tsdev); -	return 0; - -err_free_irq: -	free_irq(tsdev->irq, tsdev); -err_free_mem: -	input_free_device(input); -	kfree(tsdev); -	return err; -} - -static int mrstouch_remove(struct platform_device *pdev) -{ -	struct mrstouch_dev *tsdev = platform_get_drvdata(pdev); - -	free_irq(tsdev->irq, tsdev); -	input_unregister_device(tsdev->input); -	kfree(tsdev); -  	return 0;  } @@ -660,7 +647,6 @@ static struct platform_driver mrstouch_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= mrstouch_probe, -	.remove		= mrstouch_remove,  };  module_platform_driver(mrstouch_driver); diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index e463a79ffec..7324c5c0fb8 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -14,7 +14,6 @@   */  #include <linux/platform_device.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/module.h> diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 9101ee529c9..bb47d3442a3 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -15,7 +15,6 @@   */  #include <linux/platform_device.h> -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/module.h> @@ -385,7 +384,7 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {  #endif  #ifdef CONFIG_OF -static struct of_device_id lpc32xx_tsc_of_match[] = { +static const struct of_device_id lpc32xx_tsc_of_match[] = {  	{ .compatible = "nxp,lpc3220-tsc", },  	{ },  }; diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index 7d2b2136e5a..0786010d7ed 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -25,7 +25,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/irq.h>  #include <linux/interrupt.h> diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index 9f84fcd0873..a68ec142ee9 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -33,7 +33,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/i2c.h>  #include <linux/interrupt.h>  #include <linux/input.h> diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index f9f4e0c56ed..00510a9836b 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -14,7 +14,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/i2c.h>  #include <linux/i2c/mcs.h>  #include <linux/interrupt.h> @@ -162,10 +161,9 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } -static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data) +static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data, +				 const struct mcs_platform_data *platform_data)  { -	const struct mcs_platform_data *platform_data = -		data->platform_data;  	struct i2c_client *client = data->client;  	/* Touch reset & sleep mode */ @@ -188,28 +186,32 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)  }  static int mcs5000_ts_probe(struct i2c_client *client, -		const struct i2c_device_id *id) +			    const struct i2c_device_id *id)  { +	const struct mcs_platform_data *pdata;  	struct mcs5000_ts_data *data;  	struct input_dev *input_dev; -	int ret; +	int error; -	if (!client->dev.platform_data) +	pdata = dev_get_platdata(&client->dev); +	if (!pdata)  		return -EINVAL; -	data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL); -	input_dev = input_allocate_device(); -	if (!data || !input_dev) { +	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); +	if (!data) {  		dev_err(&client->dev, "Failed to allocate memory\n"); -		ret = -ENOMEM; -		goto err_free_mem; +		return -ENOMEM;  	}  	data->client = client; -	data->input_dev = input_dev; -	data->platform_data = client->dev.platform_data; -	input_dev->name = "MELPAS MCS-5000 Touchscreen"; +	input_dev = devm_input_allocate_device(&client->dev); +	if (!input_dev) { +		dev_err(&client->dev, "Failed to allocate input device\n"); +		return -ENOMEM; +	} + +	input_dev->name = "MELFAS MCS-5000 Touchscreen";  	input_dev->id.bustype = BUS_I2C;  	input_dev->dev.parent = &client->dev; @@ -220,44 +222,30 @@ static int mcs5000_ts_probe(struct i2c_client *client,  	input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);  	input_set_drvdata(input_dev, data); +	data->input_dev = input_dev; -	if (data->platform_data->cfg_pin) -		data->platform_data->cfg_pin(); - -	ret = request_threaded_irq(client->irq, NULL, mcs5000_ts_interrupt, -			IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mcs5000_ts", data); +	if (pdata->cfg_pin) +		pdata->cfg_pin(); -	if (ret < 0) { +	error = devm_request_threaded_irq(&client->dev, client->irq, +					  NULL, mcs5000_ts_interrupt, +					  IRQF_TRIGGER_LOW | IRQF_ONESHOT, +					  "mcs5000_ts", data); +	if (error) {  		dev_err(&client->dev, "Failed to register interrupt\n"); -		goto err_free_mem; +		return error;  	} -	ret = input_register_device(data->input_dev); -	if (ret < 0) -		goto err_free_irq; +	error = input_register_device(data->input_dev); +	if (error) { +		dev_err(&client->dev, "Failed to register input device\n"); +		return error; +	} -	mcs5000_ts_phys_init(data); +	mcs5000_ts_phys_init(data, pdata);  	i2c_set_clientdata(client, data);  	return 0; - -err_free_irq: -	free_irq(client->irq, data); -err_free_mem: -	input_free_device(input_dev); -	kfree(data); -	return ret; -} - -static int mcs5000_ts_remove(struct i2c_client *client) -{ -	struct mcs5000_ts_data *data = i2c_get_clientdata(client); - -	free_irq(client->irq, data); -	input_unregister_device(data->input_dev); -	kfree(data); - -	return 0;  }  #ifdef CONFIG_PM @@ -275,14 +263,15 @@ static int mcs5000_ts_resume(struct device *dev)  {  	struct i2c_client *client = to_i2c_client(dev);  	struct mcs5000_ts_data *data = i2c_get_clientdata(client); +	const struct mcs_platform_data *pdata = dev_get_platdata(dev); -	mcs5000_ts_phys_init(data); +	mcs5000_ts_phys_init(data, pdata);  	return 0;  } +#endif  static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume); -#endif  static const struct i2c_device_id mcs5000_ts_id[] = {  	{ "mcs5000_ts", 0 }, @@ -292,12 +281,9 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);  static struct i2c_driver mcs5000_ts_driver = {  	.probe		= mcs5000_ts_probe, -	.remove		= mcs5000_ts_remove,  	.driver = {  		.name = "mcs5000_ts", -#ifdef CONFIG_PM  		.pm   = &mcs5000_ts_pm, -#endif  	},  	.id_table	= mcs5000_ts_id,  }; diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 1443532fe6c..372bbf7658f 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -8,7 +8,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/of.h>  #include <linux/i2c.h> @@ -457,7 +456,7 @@ static int mms114_probe(struct i2c_client *client,  	data->input_dev = input_dev;  	data->pdata = pdata; -	input_dev->name = "MELPAS MMS114 Touchscreen"; +	input_dev->name = "MELFAS MMS114 Touchscreen";  	input_dev->id.bustype = BUS_I2C;  	input_dev->dev.parent = &client->dev;  	input_dev->open = mms114_input_open; @@ -571,7 +570,7 @@ static const struct i2c_device_id mms114_id[] = {  MODULE_DEVICE_TABLE(i2c, mms114_id);  #ifdef CONFIG_OF -static struct of_device_id mms114_dt_match[] = { +static const struct of_device_id mms114_dt_match[] = {  	{ .compatible = "melfas,mms114" },  	{ }  }; diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c index eb66b7c37c2..9b5552a2616 100644 --- a/drivers/input/touchscreen/mtouch.c +++ b/drivers/input/touchscreen/mtouch.c @@ -21,7 +21,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"MicroTouch serial touchscreen driver" diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c new file mode 100644 index 00000000000..f8f9b84230b --- /dev/null +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -0,0 +1,45 @@ +/* + *  Generic DT helper functions for touchscreen devices + * + *  Copyright (c) 2014 Sebastian Reichel <sre@kernel.org> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License version 2 as + *  published by the Free Software Foundation. + * + */ + +#include <linux/of.h> +#include <linux/input.h> +#include <linux/input/touchscreen.h> + +/** + * touchscreen_parse_of_params - parse common touchscreen DT properties + * @dev: device that should be parsed + * + * This function parses common DT properties for touchscreens and setups the + * input device accordingly. The function keeps previously setuped default + * values if no value is specified via DT. + */ +void touchscreen_parse_of_params(struct input_dev *dev) +{ +	struct device_node *np = dev->dev.parent->of_node; +	struct input_absinfo *absinfo; + +	input_alloc_absinfo(dev); +	if (!dev->absinfo) +		return; + +	absinfo = &dev->absinfo[ABS_X]; +	of_property_read_u32(np, "touchscreen-size-x", &absinfo->maximum); +	of_property_read_u32(np, "touchscreen-fuzz-x", &absinfo->fuzz); + +	absinfo = &dev->absinfo[ABS_Y]; +	of_property_read_u32(np, "touchscreen-size-y", &absinfo->maximum); +	of_property_read_u32(np, "touchscreen-fuzz-y", &absinfo->fuzz); + +	absinfo = &dev->absinfo[ABS_PRESSURE]; +	of_property_read_u32(np, "touchscreen-max-pressure", &absinfo->maximum); +	of_property_read_u32(np, "touchscreen-fuzz-pressure", &absinfo->fuzz); +} +EXPORT_SYMBOL(touchscreen_parse_of_params); diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index f22e04dd4e1..cff2376817e 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -11,7 +11,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/fs.h>  #include <linux/string.h>  #include <linux/slab.h> diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index b49f0b83692..417d8737926 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -21,7 +21,6 @@  #include <linux/input.h>  #include <linux/input/mt.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"PenMount serial touchscreen driver" diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 6cc6b36663f..19c6c0fdc94 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -24,12 +24,13 @@  #include <linux/i2c.h>  #include <linux/input.h>  #include <linux/input/pixcir_ts.h> +#include <linux/gpio.h>  struct pixcir_i2c_ts_data {  	struct i2c_client *client;  	struct input_dev *input;  	const struct pixcir_ts_platform_data *chip; -	bool exiting; +	bool running;  };  static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) @@ -87,11 +88,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)  static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)  {  	struct pixcir_i2c_ts_data *tsdata = dev_id; +	const struct pixcir_ts_platform_data *pdata = tsdata->chip; -	while (!tsdata->exiting) { +	while (tsdata->running) {  		pixcir_ts_poscheck(tsdata); -		if (tsdata->chip->attb_read_val()) +		if (gpio_get_value(pdata->gpio_attb))  			break;  		msleep(20); @@ -100,25 +102,221 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)  	return IRQ_HANDLED;  } +static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, +				 enum pixcir_power_mode mode) +{ +	struct device *dev = &ts->client->dev; +	int ret; + +	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE); +	if (ret < 0) { +		dev_err(dev, "%s: can't read reg 0x%x : %d\n", +			__func__, PIXCIR_REG_POWER_MODE, ret); +		return ret; +	} + +	ret &= ~PIXCIR_POWER_MODE_MASK; +	ret |= mode; + +	/* Always AUTO_IDLE */ +	ret |= PIXCIR_POWER_ALLOW_IDLE; + +	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret); +	if (ret < 0) { +		dev_err(dev, "%s: can't write reg 0x%x : %d\n", +			__func__, PIXCIR_REG_POWER_MODE, ret); +		return ret; +	} + +	return 0; +} + +/* + * Set the interrupt mode for the device i.e. ATTB line behaviour + * + * @polarity : 1 for active high, 0 for active low. + */ +static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts, +			       enum pixcir_int_mode mode, bool polarity) +{ +	struct device *dev = &ts->client->dev; +	int ret; + +	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); +	if (ret < 0) { +		dev_err(dev, "%s: can't read reg 0x%x : %d\n", +			__func__, PIXCIR_REG_INT_MODE, ret); +		return ret; +	} + +	ret &= ~PIXCIR_INT_MODE_MASK; +	ret |= mode; + +	if (polarity) +		ret |= PIXCIR_INT_POL_HIGH; +	else +		ret &= ~PIXCIR_INT_POL_HIGH; + +	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); +	if (ret < 0) { +		dev_err(dev, "%s: can't write reg 0x%x : %d\n", +			__func__, PIXCIR_REG_INT_MODE, ret); +		return ret; +	} + +	return 0; +} + +/* + * Enable/disable interrupt generation + */ +static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable) +{ +	struct device *dev = &ts->client->dev; +	int ret; + +	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); +	if (ret < 0) { +		dev_err(dev, "%s: can't read reg 0x%x : %d\n", +			__func__, PIXCIR_REG_INT_MODE, ret); +		return ret; +	} + +	if (enable) +		ret |= PIXCIR_INT_ENABLE; +	else +		ret &= ~PIXCIR_INT_ENABLE; + +	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); +	if (ret < 0) { +		dev_err(dev, "%s: can't write reg 0x%x : %d\n", +			__func__, PIXCIR_REG_INT_MODE, ret); +		return ret; +	} + +	return 0; +} + +static int pixcir_start(struct pixcir_i2c_ts_data *ts) +{ +	struct device *dev = &ts->client->dev; +	int error; + +	/* LEVEL_TOUCH interrupt with active low polarity */ +	error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0); +	if (error) { +		dev_err(dev, "Failed to set interrupt mode: %d\n", error); +		return error; +	} + +	ts->running = true; +	mb();	/* Update status before IRQ can fire */ + +	/* enable interrupt generation */ +	error = pixcir_int_enable(ts, true); +	if (error) { +		dev_err(dev, "Failed to enable interrupt generation: %d\n", +			error); +		return error; +	} + +	return 0; +} + +static int pixcir_stop(struct pixcir_i2c_ts_data *ts) +{ +	int error; + +	/* Disable interrupt generation */ +	error = pixcir_int_enable(ts, false); +	if (error) { +		dev_err(&ts->client->dev, +			"Failed to disable interrupt generation: %d\n", +			error); +		return error; +	} + +	/* Exit ISR if running, no more report parsing */ +	ts->running = false; +	mb();	/* update status before we synchronize irq */ + +	/* Wait till running ISR is complete */ +	synchronize_irq(ts->client->irq); + +	return 0; +} + +static int pixcir_input_open(struct input_dev *dev) +{ +	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + +	return pixcir_start(ts); +} + +static void pixcir_input_close(struct input_dev *dev) +{ +	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + +	pixcir_stop(ts); +} +  #ifdef CONFIG_PM_SLEEP  static int pixcir_i2c_ts_suspend(struct device *dev)  {  	struct i2c_client *client = to_i2c_client(dev); +	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); +	struct input_dev *input = ts->input; +	int ret = 0; + +	mutex_lock(&input->mutex); + +	if (device_may_wakeup(&client->dev)) { +		if (!input->users) { +			ret = pixcir_start(ts); +			if (ret) { +				dev_err(dev, "Failed to start\n"); +				goto unlock; +			} +		} -	if (device_may_wakeup(&client->dev))  		enable_irq_wake(client->irq); +	} else if (input->users) { +		ret = pixcir_stop(ts); +	} -	return 0; +unlock: +	mutex_unlock(&input->mutex); + +	return ret;  }  static int pixcir_i2c_ts_resume(struct device *dev)  {  	struct i2c_client *client = to_i2c_client(dev); +	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); +	struct input_dev *input = ts->input; +	int ret = 0; + +	mutex_lock(&input->mutex); -	if (device_may_wakeup(&client->dev)) +	if (device_may_wakeup(&client->dev)) {  		disable_irq_wake(client->irq); -	return 0; +		if (!input->users) { +			ret = pixcir_stop(ts); +			if (ret) { +				dev_err(dev, "Failed to stop\n"); +				goto unlock; +			} +		} +	} else if (input->users) { +		ret = pixcir_start(ts); +	} + +unlock: +	mutex_unlock(&input->mutex); + +	return ret;  }  #endif @@ -128,7 +326,9 @@ static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,  static int pixcir_i2c_ts_probe(struct i2c_client *client,  					 const struct i2c_device_id *id)  { -	const struct pixcir_ts_platform_data *pdata = client->dev.platform_data; +	const struct pixcir_ts_platform_data *pdata = +			dev_get_platdata(&client->dev); +	struct device *dev = &client->dev;  	struct pixcir_i2c_ts_data *tsdata;  	struct input_dev *input;  	int error; @@ -138,12 +338,19 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,  		return -EINVAL;  	} -	tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL); -	input = input_allocate_device(); -	if (!tsdata || !input) { -		dev_err(&client->dev, "Failed to allocate driver data!\n"); -		error = -ENOMEM; -		goto err_free_mem; +	if (!gpio_is_valid(pdata->gpio_attb)) { +		dev_err(dev, "Invalid gpio_attb in pdata\n"); +		return -EINVAL; +	} + +	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); +	if (!tsdata) +		return -ENOMEM; + +	input = devm_input_allocate_device(dev); +	if (!input) { +		dev_err(dev, "Failed to allocate input device\n"); +		return -ENOMEM;  	}  	tsdata->client = client; @@ -152,6 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,  	input->name = client->name;  	input->id.bustype = BUS_I2C; +	input->open = pixcir_input_open; +	input->close = pixcir_input_close;  	input->dev.parent = &client->dev;  	__set_bit(EV_KEY, input->evbit); @@ -164,44 +373,47 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,  	input_set_drvdata(input, tsdata); -	error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr, -				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT, -				     client->name, tsdata); +	error = devm_gpio_request_one(dev, pdata->gpio_attb, +				      GPIOF_DIR_IN, "pixcir_i2c_attb");  	if (error) { -		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); -		goto err_free_mem; +		dev_err(dev, "Failed to request ATTB gpio\n"); +		return error;  	} +	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, +					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +					  client->name, tsdata); +	if (error) { +		dev_err(dev, "failed to request irq %d\n", client->irq); +		return error; +	} + +	/* Always be in IDLE mode to save power, device supports auto wake */ +	error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); +	if (error) { +		dev_err(dev, "Failed to set IDLE mode\n"); +		return error; +	} + +	/* Stop device till opened */ +	error = pixcir_stop(tsdata); +	if (error) +		return error; +  	error = input_register_device(input);  	if (error) -		goto err_free_irq; +		return error;  	i2c_set_clientdata(client, tsdata);  	device_init_wakeup(&client->dev, 1);  	return 0; - -err_free_irq: -	free_irq(client->irq, tsdata); -err_free_mem: -	input_free_device(input); -	kfree(tsdata); -	return error;  }  static int pixcir_i2c_ts_remove(struct i2c_client *client)  { -	struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client); -  	device_init_wakeup(&client->dev, 0); -	tsdata->exiting = true; -	mb(); -	free_irq(client->irq, tsdata); - -	input_unregister_device(tsdata->input); -	kfree(tsdata); -  	return 0;  } diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index b061af2c837..19cb247dbb8 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -28,7 +28,6 @@  #include <linux/module.h>  #include <linux/gpio.h>  #include <linux/input.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/interrupt.h>  #include <linux/platform_device.h> @@ -251,7 +250,7 @@ static int s3c2410ts_probe(struct platform_device *pdev)  	ts.dev = dev; -	info = pdev->dev.platform_data; +	info = dev_get_platdata(&pdev->dev);  	if (!info) {  		dev_err(dev, "no platform data, cannot attach\n");  		return -EINVAL; @@ -392,7 +391,7 @@ static int s3c2410ts_suspend(struct device *dev)  static int s3c2410ts_resume(struct device *dev)  {  	struct platform_device *pdev = to_platform_device(dev); -	struct s3c2410_ts_mach_info *info = pdev->dev.platform_data; +	struct s3c2410_ts_mach_info *info = dev_get_platdata(&pdev->dev);  	clk_enable(ts.clock);  	enable_irq(ts.irq_tc); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 1740a249637..3c0f57efe7b 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -24,6 +24,7 @@  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/module.h> +#include <linux/of.h>  #include <linux/of_gpio.h>  #include <linux/pm_qos.h>  #include <linux/slab.h> @@ -133,7 +134,8 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)  	} else if (!ts->low_latency_req.dev) {  		/* First contact, request 100 us latency. */  		dev_pm_qos_add_ancestor_request(&ts->client->dev, -						&ts->low_latency_req, 100); +						&ts->low_latency_req, +						DEV_PM_QOS_RESUME_LATENCY, 100);  	}  	/* SYN_REPORT */ @@ -153,7 +155,7 @@ static int st1232_ts_probe(struct i2c_client *client,  					const struct i2c_device_id *id)  {  	struct st1232_ts_data *ts; -	struct st1232_pdata *pdata = client->dev.platform_data; +	struct st1232_pdata *pdata = dev_get_platdata(&client->dev);  	struct input_dev *input_dev;  	int error; diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 59e81b00f24..42ce31afa25 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -15,7 +15,6 @@  #include <linux/module.h>  #include <linux/sched.h>  #include <linux/interrupt.h> -#include <linux/init.h>  #include <linux/device.h>  #include <linux/of.h>  #include <linux/platform_device.h> diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c new file mode 100644 index 00000000000..2ba82602495 --- /dev/null +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -0,0 +1,339 @@ +/* + * Allwinner sunxi resistive touchscreen controller driver + * + * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com> + * + * The hwmon parts are based on work by Corentin LABBE which is: + * Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * The sun4i-ts controller is capable of detecting a second touch, but when a + * second touch is present then the accuracy becomes so bad the reported touch + * location is not useable. + * + * The original android driver contains some complicated heuristics using the + * aprox. distance between the 2 touches to see if the user is making a pinch + * open / close movement, and then reports emulated multi-touch events around + * the last touch coordinate (as the dual-touch coordinates are worthless). + * + * These kinds of heuristics are just asking for trouble (and don't belong + * in the kernel). So this driver offers straight forward, reliable single + * touch functionality only. + */ + +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define TP_CTRL0		0x00 +#define TP_CTRL1		0x04 +#define TP_CTRL2		0x08 +#define TP_CTRL3		0x0c +#define TP_INT_FIFOC		0x10 +#define TP_INT_FIFOS		0x14 +#define TP_TPR			0x18 +#define TP_CDAT			0x1c +#define TEMP_DATA		0x20 +#define TP_DATA			0x24 + +/* TP_CTRL0 bits */ +#define ADC_FIRST_DLY(x)	((x) << 24) /* 8 bits */ +#define ADC_FIRST_DLY_MODE(x)	((x) << 23) +#define ADC_CLK_SEL(x)		((x) << 22) +#define ADC_CLK_DIV(x)		((x) << 20) /* 3 bits */ +#define FS_DIV(x)		((x) << 16) /* 4 bits */ +#define T_ACQ(x)		((x) << 0) /* 16 bits */ + +/* TP_CTRL1 bits */ +#define STYLUS_UP_DEBOUN(x)	((x) << 12) /* 8 bits */ +#define STYLUS_UP_DEBOUN_EN(x)	((x) << 9) +#define TOUCH_PAN_CALI_EN(x)	((x) << 6) +#define TP_DUAL_EN(x)		((x) << 5) +#define TP_MODE_EN(x)		((x) << 4) +#define TP_ADC_SELECT(x)	((x) << 3) +#define ADC_CHAN_SELECT(x)	((x) << 0)  /* 3 bits */ + +/* TP_CTRL2 bits */ +#define TP_SENSITIVE_ADJUST(x)	((x) << 28) /* 4 bits */ +#define TP_MODE_SELECT(x)	((x) << 26) /* 2 bits */ +#define PRE_MEA_EN(x)		((x) << 24) +#define PRE_MEA_THRE_CNT(x)	((x) << 0) /* 24 bits */ + +/* TP_CTRL3 bits */ +#define FILTER_EN(x)		((x) << 2) +#define FILTER_TYPE(x)		((x) << 0)  /* 2 bits */ + +/* TP_INT_FIFOC irq and fifo mask / control bits */ +#define TEMP_IRQ_EN(x)		((x) << 18) +#define OVERRUN_IRQ_EN(x)	((x) << 17) +#define DATA_IRQ_EN(x)		((x) << 16) +#define TP_DATA_XY_CHANGE(x)	((x) << 13) +#define FIFO_TRIG(x)		((x) << 8)  /* 5 bits */ +#define DATA_DRQ_EN(x)		((x) << 7) +#define FIFO_FLUSH(x)		((x) << 4) +#define TP_UP_IRQ_EN(x)		((x) << 1) +#define TP_DOWN_IRQ_EN(x)	((x) << 0) + +/* TP_INT_FIFOS irq and fifo status bits */ +#define TEMP_DATA_PENDING	BIT(18) +#define FIFO_OVERRUN_PENDING	BIT(17) +#define FIFO_DATA_PENDING	BIT(16) +#define TP_IDLE_FLG		BIT(2) +#define TP_UP_PENDING		BIT(1) +#define TP_DOWN_PENDING		BIT(0) + +/* TP_TPR bits */ +#define TEMP_ENABLE(x)		((x) << 16) +#define TEMP_PERIOD(x)		((x) << 0)  /* t = x * 256 * 16 / clkin */ + +struct sun4i_ts_data { +	struct device *dev; +	struct input_dev *input; +	void __iomem *base; +	unsigned int irq; +	bool ignore_fifo_data; +	int temp_data; +}; + +static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val) +{ +	u32 x, y; + +	if (reg_val & FIFO_DATA_PENDING) { +		x = readl(ts->base + TP_DATA); +		y = readl(ts->base + TP_DATA); +		/* The 1st location reported after an up event is unreliable */ +		if (!ts->ignore_fifo_data) { +			input_report_abs(ts->input, ABS_X, x); +			input_report_abs(ts->input, ABS_Y, y); +			/* +			 * The hardware has a separate down status bit, but +			 * that gets set before we get the first location, +			 * resulting in reporting a click on the old location. +			 */ +			input_report_key(ts->input, BTN_TOUCH, 1); +			input_sync(ts->input); +		} else { +			ts->ignore_fifo_data = false; +		} +	} + +	if (reg_val & TP_UP_PENDING) { +		ts->ignore_fifo_data = true; +		input_report_key(ts->input, BTN_TOUCH, 0); +		input_sync(ts->input); +	} +} + +static irqreturn_t sun4i_ts_irq(int irq, void *dev_id) +{ +	struct sun4i_ts_data *ts = dev_id; +	u32 reg_val; + +	reg_val  = readl(ts->base + TP_INT_FIFOS); + +	if (reg_val & TEMP_DATA_PENDING) +		ts->temp_data = readl(ts->base + TEMP_DATA); + +	if (ts->input) +		sun4i_ts_irq_handle_input(ts, reg_val); + +	writel(reg_val, ts->base + TP_INT_FIFOS); + +	return IRQ_HANDLED; +} + +static int sun4i_ts_open(struct input_dev *dev) +{ +	struct sun4i_ts_data *ts = input_get_drvdata(dev); + +	/* Flush, set trig level to 1, enable temp, data and up irqs */ +	writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | +		TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC); + +	return 0; +} + +static void sun4i_ts_close(struct input_dev *dev) +{ +	struct sun4i_ts_data *ts = input_get_drvdata(dev); + +	/* Deactivate all input IRQs */ +	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, +			 char *buf) +{ +	struct sun4i_ts_data *ts = dev_get_drvdata(dev); + +	/* No temp_data until the first irq */ +	if (ts->temp_data == -1) +		return -EAGAIN; + +	return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100); +} + +static ssize_t show_temp_label(struct device *dev, +			      struct device_attribute *devattr, char *buf) +{ +	return sprintf(buf, "SoC temperature\n"); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL); + +static struct attribute *sun4i_ts_attrs[] = { +	&dev_attr_temp1_input.attr, +	&dev_attr_temp1_label.attr, +	NULL +}; +ATTRIBUTE_GROUPS(sun4i_ts); + +static int sun4i_ts_probe(struct platform_device *pdev) +{ +	struct sun4i_ts_data *ts; +	struct device *dev = &pdev->dev; +	struct device_node *np = dev->of_node; +	struct device *hwmon; +	int error; +	bool ts_attached; + +	ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); +	if (!ts) +		return -ENOMEM; + +	ts->dev = dev; +	ts->ignore_fifo_data = true; +	ts->temp_data = -1; + +	ts_attached = of_property_read_bool(np, "allwinner,ts-attached"); +	if (ts_attached) { +		ts->input = devm_input_allocate_device(dev); +		if (!ts->input) +			return -ENOMEM; + +		ts->input->name = pdev->name; +		ts->input->phys = "sun4i_ts/input0"; +		ts->input->open = sun4i_ts_open; +		ts->input->close = sun4i_ts_close; +		ts->input->id.bustype = BUS_HOST; +		ts->input->id.vendor = 0x0001; +		ts->input->id.product = 0x0001; +		ts->input->id.version = 0x0100; +		ts->input->evbit[0] =  BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); +		__set_bit(BTN_TOUCH, ts->input->keybit); +		input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0); +		input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0); +		input_set_drvdata(ts->input, ts); +	} + +	ts->base = devm_ioremap_resource(dev, +			      platform_get_resource(pdev, IORESOURCE_MEM, 0)); +	if (IS_ERR(ts->base)) +		return PTR_ERR(ts->base); + +	ts->irq = platform_get_irq(pdev, 0); +	error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts); +	if (error) +		return error; + +	/* +	 * Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192, +	 * t_acq = clkin / (16 * 64) +	 */ +	writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63), +	       ts->base + TP_CTRL0); + +	/* +	 * sensitive_adjust = 15 : max, which is not all that sensitive, +	 * tp_mode = 0 : only x and y coordinates, as we don't use dual touch +	 */ +	writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0), +	       ts->base + TP_CTRL2); + +	/* Enable median filter, type 1 : 5/3 */ +	writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3); + +	/* Enable temperature measurement, period 1953 (2 seconds) */ +	writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR); + +	/* +	 * Set stylus up debounce to aprox 10 ms, enable debounce, and +	 * finally enable tp mode. +	 */ +	writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), +	       ts->base + TP_CTRL1); + +	hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts", +						       ts, sun4i_ts_groups); +	if (IS_ERR(hwmon)) +		return PTR_ERR(hwmon); + +	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); + +	if (ts_attached) { +		error = input_register_device(ts->input); +		if (error) { +			writel(0, ts->base + TP_INT_FIFOC); +			return error; +		} +	} + +	platform_set_drvdata(pdev, ts); +	return 0; +} + +static int sun4i_ts_remove(struct platform_device *pdev) +{ +	struct sun4i_ts_data *ts = platform_get_drvdata(pdev); + +	/* Explicit unregister to avoid open/close changing the imask later */ +	if (ts->input) +		input_unregister_device(ts->input); + +	/* Deactivate all IRQs */ +	writel(0, ts->base + TP_INT_FIFOC); + +	return 0; +} + +static const struct of_device_id sun4i_ts_of_match[] = { +	{ .compatible = "allwinner,sun4i-a10-ts", }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); + +static struct platform_driver sun4i_ts_driver = { +	.driver = { +		.owner	= THIS_MODULE, +		.name	= "sun4i-ts", +		.of_match_table = of_match_ptr(sun4i_ts_of_match), +	}, +	.probe	= sun4i_ts_probe, +	.remove	= sun4i_ts_remove, +}; + +module_platform_driver(sun4i_ts_driver); + +MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver"); +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c new file mode 100644 index 00000000000..f1cb05148b4 --- /dev/null +++ b/drivers/input/touchscreen/sur40.c @@ -0,0 +1,466 @@ +/* + * Surface2.0/SUR40/PixelSense input driver + * + * Copyright (c) 2013 by Florian 'floe' Echtler <floe@butterbrot.org> + * + * Derived from the USB Skeleton driver 1.1, + * Copyright (c) 2003 Greg Kroah-Hartman (greg@kroah.com) + * + * and from the Apple USB BCM5974 multitouch driver, + * Copyright (c) 2008 Henrik Rydberg (rydberg@euromail.se) + * + * and from the generic hid-multitouch driver, + * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/completion.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/printk.h> +#include <linux/input-polldev.h> +#include <linux/input/mt.h> +#include <linux/usb/input.h> + +/* read 512 bytes from endpoint 0x86 -> get header + blobs */ +struct sur40_header { + +	__le16 type;       /* always 0x0001 */ +	__le16 count;      /* count of blobs (if 0: continue prev. packet) */ + +	__le32 packet_id;  /* unique ID for all packets in one frame */ + +	__le32 timestamp;  /* milliseconds (inc. by 16 or 17 each frame) */ +	__le32 unknown;    /* "epoch?" always 02/03 00 00 00 */ + +} __packed; + +struct sur40_blob { + +	__le16 blob_id; + +	u8 action;         /* 0x02 = enter/exit, 0x03 = update (?) */ +	u8 unknown;        /* always 0x01 or 0x02 (no idea what this is?) */ + +	__le16 bb_pos_x;   /* upper left corner of bounding box */ +	__le16 bb_pos_y; + +	__le16 bb_size_x;  /* size of bounding box */ +	__le16 bb_size_y; + +	__le16 pos_x;      /* finger tip position */ +	__le16 pos_y; + +	__le16 ctr_x;      /* centroid position */ +	__le16 ctr_y; + +	__le16 axis_x;     /* somehow related to major/minor axis, mostly: */ +	__le16 axis_y;     /* axis_x == bb_size_y && axis_y == bb_size_x */ + +	__le32 angle;      /* orientation in radians relative to x axis - +	                      actually an IEEE754 float, don't use in kernel */ + +	__le32 area;       /* size in pixels/pressure (?) */ + +	u8 padding[32]; + +} __packed; + +/* combined header/blob data */ +struct sur40_data { +	struct sur40_header header; +	struct sur40_blob   blobs[]; +} __packed; + + +/* version information */ +#define DRIVER_SHORT   "sur40" +#define DRIVER_AUTHOR  "Florian 'floe' Echtler <floe@butterbrot.org>" +#define DRIVER_DESC    "Surface2.0/SUR40/PixelSense input driver" + +/* vendor and device IDs */ +#define ID_MICROSOFT 0x045e +#define ID_SUR40     0x0775 + +/* sensor resolution */ +#define SENSOR_RES_X 1920 +#define SENSOR_RES_Y 1080 + +/* touch data endpoint */ +#define TOUCH_ENDPOINT 0x86 + +/* polling interval (ms) */ +#define POLL_INTERVAL 10 + +/* maximum number of contacts FIXME: this is a guess? */ +#define MAX_CONTACTS 64 + +/* control commands */ +#define SUR40_GET_VERSION 0xb0 /* 12 bytes string    */ +#define SUR40_UNKNOWN1    0xb3 /*  5 bytes           */ +#define SUR40_UNKNOWN2    0xc1 /* 24 bytes           */ + +#define SUR40_GET_STATE   0xc5 /*  4 bytes state (?) */ +#define SUR40_GET_SENSORS 0xb1 /*  8 bytes sensors   */ + +/* + * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT + * here by mistake which is very likely to have corrupted the firmware EEPROM + * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug. + * Should you ever run into a similar problem, the background story to this + * incident and instructions on how to fix the corrupted EEPROM are available + * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html +*/ + +struct sur40_state { + +	struct usb_device *usbdev; +	struct device *dev; +	struct input_polled_dev *input; + +	struct sur40_data *bulk_in_buffer; +	size_t bulk_in_size; +	u8 bulk_in_epaddr; + +	char phys[64]; +}; + +static int sur40_command(struct sur40_state *dev, +			 u8 command, u16 index, void *buffer, u16 size) +{ +	return usb_control_msg(dev->usbdev, usb_rcvctrlpipe(dev->usbdev, 0), +			       command, +			       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, +			       0x00, index, buffer, size, 1000); +} + +/* Initialization routine, called from sur40_open */ +static int sur40_init(struct sur40_state *dev) +{ +	int result; +	u8 buffer[24]; + +	/* stupidly replay the original MS driver init sequence */ +	result = sur40_command(dev, SUR40_GET_VERSION, 0x00, buffer, 12); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_GET_VERSION, 0x01, buffer, 12); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_GET_VERSION, 0x02, buffer, 12); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_UNKNOWN2,    0x00, buffer, 24); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_UNKNOWN1,    0x00, buffer,  5); +	if (result < 0) +		return result; + +	result = sur40_command(dev, SUR40_GET_VERSION, 0x03, buffer, 12); + +	/* +	 * Discard the result buffer - no known data inside except +	 * some version strings, maybe extract these sometime... +	 */ + +	return result; +} + +/* + * Callback routines from input_polled_dev + */ + +/* Enable the device, polling will now start. */ +static void sur40_open(struct input_polled_dev *polldev) +{ +	struct sur40_state *sur40 = polldev->private; + +	dev_dbg(sur40->dev, "open\n"); +	sur40_init(sur40); +} + +/* Disable device, polling has stopped. */ +static void sur40_close(struct input_polled_dev *polldev) +{ +	struct sur40_state *sur40 = polldev->private; + +	dev_dbg(sur40->dev, "close\n"); +	/* +	 * There is no known way to stop the device, so we simply +	 * stop polling. +	 */ +} + +/* + * This function is called when a whole contact has been processed, + * so that it can assign it to a slot and store the data there. + */ +static void sur40_report_blob(struct sur40_blob *blob, struct input_dev *input) +{ +	int wide, major, minor; + +	int bb_size_x = le16_to_cpu(blob->bb_size_x); +	int bb_size_y = le16_to_cpu(blob->bb_size_y); + +	int pos_x = le16_to_cpu(blob->pos_x); +	int pos_y = le16_to_cpu(blob->pos_y); + +	int ctr_x = le16_to_cpu(blob->ctr_x); +	int ctr_y = le16_to_cpu(blob->ctr_y); + +	int slotnum = input_mt_get_slot_by_key(input, blob->blob_id); +	if (slotnum < 0 || slotnum >= MAX_CONTACTS) +		return; + +	input_mt_slot(input, slotnum); +	input_mt_report_slot_state(input, MT_TOOL_FINGER, 1); +	wide = (bb_size_x > bb_size_y); +	major = max(bb_size_x, bb_size_y); +	minor = min(bb_size_x, bb_size_y); + +	input_report_abs(input, ABS_MT_POSITION_X, pos_x); +	input_report_abs(input, ABS_MT_POSITION_Y, pos_y); +	input_report_abs(input, ABS_MT_TOOL_X, ctr_x); +	input_report_abs(input, ABS_MT_TOOL_Y, ctr_y); + +	/* TODO: use a better orientation measure */ +	input_report_abs(input, ABS_MT_ORIENTATION, wide); +	input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); +	input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); +} + +/* core function: poll for new input data */ +static void sur40_poll(struct input_polled_dev *polldev) +{ + +	struct sur40_state *sur40 = polldev->private; +	struct input_dev *input = polldev->input; +	int result, bulk_read, need_blobs, packet_blobs, i; +	u32 uninitialized_var(packet_id); + +	struct sur40_header *header = &sur40->bulk_in_buffer->header; +	struct sur40_blob *inblob = &sur40->bulk_in_buffer->blobs[0]; + +	dev_dbg(sur40->dev, "poll\n"); + +	need_blobs = -1; + +	do { + +		/* perform a blocking bulk read to get data from the device */ +		result = usb_bulk_msg(sur40->usbdev, +			usb_rcvbulkpipe(sur40->usbdev, sur40->bulk_in_epaddr), +			sur40->bulk_in_buffer, sur40->bulk_in_size, +			&bulk_read, 1000); + +		dev_dbg(sur40->dev, "received %d bytes\n", bulk_read); + +		if (result < 0) { +			dev_err(sur40->dev, "error in usb_bulk_read\n"); +			return; +		} + +		result = bulk_read - sizeof(struct sur40_header); + +		if (result % sizeof(struct sur40_blob) != 0) { +			dev_err(sur40->dev, "transfer size mismatch\n"); +			return; +		} + +		/* first packet? */ +		if (need_blobs == -1) { +			need_blobs = le16_to_cpu(header->count); +			dev_dbg(sur40->dev, "need %d blobs\n", need_blobs); +			packet_id = le32_to_cpu(header->packet_id); +		} + +		/* +		 * Sanity check. when video data is also being retrieved, the +		 * packet ID will usually increase in the middle of a series +		 * instead of at the end. +		 */ +		if (packet_id != header->packet_id) +			dev_warn(sur40->dev, "packet ID mismatch\n"); + +		packet_blobs = result / sizeof(struct sur40_blob); +		dev_dbg(sur40->dev, "received %d blobs\n", packet_blobs); + +		/* packets always contain at least 4 blobs, even if empty */ +		if (packet_blobs > need_blobs) +			packet_blobs = need_blobs; + +		for (i = 0; i < packet_blobs; i++) { +			need_blobs--; +			dev_dbg(sur40->dev, "processing blob\n"); +			sur40_report_blob(&(inblob[i]), input); +		} + +	} while (need_blobs > 0); + +	input_mt_sync_frame(input); +	input_sync(input); +} + +/* Initialize input device parameters. */ +static void sur40_input_setup(struct input_dev *input_dev) +{ +	__set_bit(EV_KEY, input_dev->evbit); +	__set_bit(EV_ABS, input_dev->evbit); + +	input_set_abs_params(input_dev, ABS_MT_POSITION_X, +			     0, SENSOR_RES_X, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, +			     0, SENSOR_RES_Y, 0, 0); + +	input_set_abs_params(input_dev, ABS_MT_TOOL_X, +			     0, SENSOR_RES_X, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_TOOL_Y, +			     0, SENSOR_RES_Y, 0, 0); + +	/* max value unknown, but major/minor axis +	 * can never be larger than screen */ +	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, +			     0, SENSOR_RES_X, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, +			     0, SENSOR_RES_Y, 0, 0); + +	input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); + +	input_mt_init_slots(input_dev, MAX_CONTACTS, +			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); +} + +/* Check candidate USB interface. */ +static int sur40_probe(struct usb_interface *interface, +		       const struct usb_device_id *id) +{ +	struct usb_device *usbdev = interface_to_usbdev(interface); +	struct sur40_state *sur40; +	struct usb_host_interface *iface_desc; +	struct usb_endpoint_descriptor *endpoint; +	struct input_polled_dev *poll_dev; +	int error; + +	/* Check if we really have the right interface. */ +	iface_desc = &interface->altsetting[0]; +	if (iface_desc->desc.bInterfaceClass != 0xFF) +		return -ENODEV; + +	/* Use endpoint #4 (0x86). */ +	endpoint = &iface_desc->endpoint[4].desc; +	if (endpoint->bEndpointAddress != TOUCH_ENDPOINT) +		return -ENODEV; + +	/* Allocate memory for our device state and initialize it. */ +	sur40 = kzalloc(sizeof(struct sur40_state), GFP_KERNEL); +	if (!sur40) +		return -ENOMEM; + +	poll_dev = input_allocate_polled_device(); +	if (!poll_dev) { +		error = -ENOMEM; +		goto err_free_dev; +	} + +	/* Set up polled input device control structure */ +	poll_dev->private = sur40; +	poll_dev->poll_interval = POLL_INTERVAL; +	poll_dev->open = sur40_open; +	poll_dev->poll = sur40_poll; +	poll_dev->close = sur40_close; + +	/* Set up regular input device structure */ +	sur40_input_setup(poll_dev->input); + +	poll_dev->input->name = "Samsung SUR40"; +	usb_to_input_id(usbdev, &poll_dev->input->id); +	usb_make_path(usbdev, sur40->phys, sizeof(sur40->phys)); +	strlcat(sur40->phys, "/input0", sizeof(sur40->phys)); +	poll_dev->input->phys = sur40->phys; +	poll_dev->input->dev.parent = &interface->dev; + +	sur40->usbdev = usbdev; +	sur40->dev = &interface->dev; +	sur40->input = poll_dev; + +	/* use the bulk-in endpoint tested above */ +	sur40->bulk_in_size = usb_endpoint_maxp(endpoint); +	sur40->bulk_in_epaddr = endpoint->bEndpointAddress; +	sur40->bulk_in_buffer = kmalloc(sur40->bulk_in_size, GFP_KERNEL); +	if (!sur40->bulk_in_buffer) { +		dev_err(&interface->dev, "Unable to allocate input buffer."); +		error = -ENOMEM; +		goto err_free_polldev; +	} + +	error = input_register_polled_device(poll_dev); +	if (error) { +		dev_err(&interface->dev, +			"Unable to register polled input device."); +		goto err_free_buffer; +	} + +	/* we can register the device now, as it is ready */ +	usb_set_intfdata(interface, sur40); +	dev_dbg(&interface->dev, "%s is now attached\n", DRIVER_DESC); + +	return 0; + +err_free_buffer: +	kfree(sur40->bulk_in_buffer); +err_free_polldev: +	input_free_polled_device(sur40->input); +err_free_dev: +	kfree(sur40); + +	return error; +} + +/* Unregister device & clean up. */ +static void sur40_disconnect(struct usb_interface *interface) +{ +	struct sur40_state *sur40 = usb_get_intfdata(interface); + +	input_unregister_polled_device(sur40->input); +	input_free_polled_device(sur40->input); +	kfree(sur40->bulk_in_buffer); +	kfree(sur40); + +	usb_set_intfdata(interface, NULL); +	dev_dbg(&interface->dev, "%s is now disconnected\n", DRIVER_DESC); +} + +static const struct usb_device_id sur40_table[] = { +	{ USB_DEVICE(ID_MICROSOFT, ID_SUR40) },  /* Samsung SUR40 */ +	{ }                                      /* terminating null entry */ +}; +MODULE_DEVICE_TABLE(usb, sur40_table); + +/* USB-specific object needed to register this driver with the USB subsystem. */ +static struct usb_driver sur40_driver = { +	.name = DRIVER_SHORT, +	.probe = sur40_probe, +	.disconnect = sur40_disconnect, +	.id_table = sur40_table, +}; + +module_usb_driver(sur40_driver); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index e1c5300cacf..2ce649520fe 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -14,7 +14,6 @@   */ -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/err.h>  #include <linux/module.h> @@ -52,6 +51,7 @@ struct titsc {  	u32			config_inp[4];  	u32			bit_xp, bit_xn, bit_yp, bit_yn;  	u32			inp_xp, inp_xn, inp_yp, inp_yn; +	u32			step_mask;  };  static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) @@ -196,7 +196,8 @@ static void titsc_step_config(struct titsc *ts_dev)  	/* The steps1 … end and bit 0 for TS_Charge */  	stepenable = (1 << (end_step + 2)) - 1; -	am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable); +	ts_dev->step_mask = stepenable; +	am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);  }  static void titsc_read_coordinates(struct titsc *ts_dev, @@ -260,6 +261,10 @@ static irqreturn_t titsc_irq(int irq, void *dev)  	unsigned int fsm;  	status = titsc_readl(ts_dev, REG_IRQSTATUS); +	/* +	 * ADC and touchscreen share the IRQ line. +	 * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only +	 */  	if (status & IRQENB_FIFO0THRES) {  		titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2); @@ -316,7 +321,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)  	if (irqclr) {  		titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); -		am335x_tsc_se_update(ts_dev->mfd_tscadc); +		am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);  		return IRQ_HANDLED;  	}  	return IRQ_NONE; @@ -348,8 +353,18 @@ static int titsc_parse_dt(struct platform_device *pdev,  	if (err < 0)  		return err; -	err = of_property_read_u32(node, "ti,coordiante-readouts", +	/* +	 * Try with the new binding first. If it fails, try again with +	 * bogus, miss-spelled version. +	 */ +	err = of_property_read_u32(node, "ti,coordinate-readouts",  			&ts_dev->coordinate_readouts); +	if (err < 0) { +		dev_warn(&pdev->dev, "please use 'ti,coordinate-readouts' instead\n"); +		err = of_property_read_u32(node, "ti,coordiante-readouts", +				&ts_dev->coordinate_readouts); +	} +  	if (err < 0)  		return err; @@ -389,7 +404,7 @@ static int titsc_probe(struct platform_device *pdev)  	}  	err = request_irq(ts_dev->irq, titsc_irq, -			  0, pdev->dev.driver->name, ts_dev); +			  IRQF_SHARED, pdev->dev.driver->name, ts_dev);  	if (err) {  		dev_err(&pdev->dev, "failed to allocate irq.\n");  		goto err_free_mem; @@ -505,7 +520,7 @@ static struct platform_driver ti_tsc_driver = {  		.name   = "TI-am335x-tsc",  		.owner	= THIS_MODULE,  		.pm	= TITSC_PM_OPS, -		.of_match_table = of_match_ptr(ti_tsc_dt_ids), +		.of_match_table = ti_tsc_dt_ids,  	},  };  module_platform_driver(ti_tsc_driver); diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c deleted file mode 100644 index c47827a26e3..00000000000 --- a/drivers/input/touchscreen/tnetv107x-ts.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Texas Instruments TNETV107X Touchscreen Driver - * - * Copyright (C) 2010 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/ctype.h> -#include <linux/io.h> -#include <linux/clk.h> - -#include <mach/tnetv107x.h> - -#define TSC_PENUP_POLL		(HZ / 5) -#define IDLE_TIMEOUT		100 /* msec */ - -/* - * The first and last samples of a touch interval are usually garbage and need - * to be filtered out with these devices.  The following definitions control - * the number of samples skipped. - */ -#define TSC_HEAD_SKIP		1 -#define TSC_TAIL_SKIP		1 -#define TSC_SKIP		(TSC_HEAD_SKIP + TSC_TAIL_SKIP + 1) -#define TSC_SAMPLES		(TSC_SKIP + 1) - -/* Register Offsets */ -struct tsc_regs { -	u32	rev; -	u32	tscm; -	u32	bwcm; -	u32	swc; -	u32	adcchnl; -	u32	adcdata; -	u32	chval[4]; -}; - -/* TSC Mode Configuration Register (tscm) bits */ -#define WMODE		BIT(0) -#define TSKIND		BIT(1) -#define ZMEASURE_EN	BIT(2) -#define IDLE		BIT(3) -#define TSC_EN		BIT(4) -#define STOP		BIT(5) -#define ONE_SHOT	BIT(6) -#define SINGLE		BIT(7) -#define AVG		BIT(8) -#define AVGNUM(x)	(((x) & 0x03) <<  9) -#define PVSTC(x)	(((x) & 0x07) << 11) -#define PON		BIT(14) -#define PONBG		BIT(15) -#define AFERST		BIT(16) - -/* ADC DATA Capture Register bits */ -#define DATA_VALID	BIT(16) - -/* Register Access Macros */ -#define tsc_read(ts, reg)		__raw_readl(&(ts)->regs->reg) -#define tsc_write(ts, reg, val)		__raw_writel(val, &(ts)->regs->reg); -#define tsc_set_bits(ts, reg, val)	\ -	tsc_write(ts, reg, tsc_read(ts, reg) | (val)) -#define tsc_clr_bits(ts, reg, val)	\ -	tsc_write(ts, reg, tsc_read(ts, reg) & ~(val)) - -struct sample { -	int x, y, p; -}; - -struct tsc_data { -	struct input_dev		*input_dev; -	struct resource			*res; -	struct tsc_regs __iomem		*regs; -	struct timer_list		timer; -	spinlock_t			lock; -	struct clk			*clk; -	struct device			*dev; -	int				sample_count; -	struct sample			samples[TSC_SAMPLES]; -	int				tsc_irq; -}; - -static int tsc_read_sample(struct tsc_data *ts, struct sample* sample) -{ -	int	x, y, z1, z2, t, p = 0; -	u32	val; - -	val = tsc_read(ts, chval[0]); -	if (val & DATA_VALID) -		x = val & 0xffff; -	else -		return -EINVAL; - -	y  = tsc_read(ts, chval[1]) & 0xffff; -	z1 = tsc_read(ts, chval[2]) & 0xffff; -	z2 = tsc_read(ts, chval[3]) & 0xffff; - -	if (z1) { -		t = ((600 * x) * (z2 - z1)); -		p = t / (u32) (z1 << 12); -		if (p < 0) -			p = 0; -	} - -	sample->x  = x; -	sample->y  = y; -	sample->p  = p; - -	return 0; -} - -static void tsc_poll(unsigned long data) -{ -	struct tsc_data *ts = (struct tsc_data *)data; -	unsigned long flags; -	int i, val, x, y, p; - -	spin_lock_irqsave(&ts->lock, flags); - -	if (ts->sample_count >= TSC_SKIP) { -		input_report_abs(ts->input_dev, ABS_PRESSURE, 0); -		input_report_key(ts->input_dev, BTN_TOUCH, 0); -		input_sync(ts->input_dev); -	} else if (ts->sample_count > 0) { -		/* -		 * A touch event lasted less than our skip count.  Salvage and -		 * report anyway. -		 */ -		for (i = 0, val = 0; i < ts->sample_count; i++) -			val += ts->samples[i].x; -		x = val / ts->sample_count; - -		for (i = 0, val = 0; i < ts->sample_count; i++) -			val += ts->samples[i].y; -		y = val / ts->sample_count; - -		for (i = 0, val = 0; i < ts->sample_count; i++) -			val += ts->samples[i].p; -		p = val / ts->sample_count; - -		input_report_abs(ts->input_dev, ABS_X, x); -		input_report_abs(ts->input_dev, ABS_Y, y); -		input_report_abs(ts->input_dev, ABS_PRESSURE, p); -		input_report_key(ts->input_dev, BTN_TOUCH, 1); -		input_sync(ts->input_dev); -	} - -	ts->sample_count = 0; - -	spin_unlock_irqrestore(&ts->lock, flags); -} - -static irqreturn_t tsc_irq(int irq, void *dev_id) -{ -	struct tsc_data *ts = (struct tsc_data *)dev_id; -	struct sample *sample; -	int index; - -	spin_lock(&ts->lock); - -	index = ts->sample_count % TSC_SAMPLES; -	sample = &ts->samples[index]; -	if (tsc_read_sample(ts, sample) < 0) -		goto out; - -	if (++ts->sample_count >= TSC_SKIP) { -		index = (ts->sample_count - TSC_TAIL_SKIP - 1) % TSC_SAMPLES; -		sample = &ts->samples[index]; - -		input_report_abs(ts->input_dev, ABS_X, sample->x); -		input_report_abs(ts->input_dev, ABS_Y, sample->y); -		input_report_abs(ts->input_dev, ABS_PRESSURE, sample->p); -		if (ts->sample_count == TSC_SKIP) -			input_report_key(ts->input_dev, BTN_TOUCH, 1); -		input_sync(ts->input_dev); -	} -	mod_timer(&ts->timer, jiffies + TSC_PENUP_POLL); -out: -	spin_unlock(&ts->lock); -	return IRQ_HANDLED; -} - -static int tsc_start(struct input_dev *dev) -{ -	struct tsc_data *ts = input_get_drvdata(dev); -	unsigned long timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT); -	u32 val; - -	clk_enable(ts->clk); - -	/* Go to idle mode, before any initialization */ -	while (time_after(timeout, jiffies)) { -		if (tsc_read(ts, tscm) & IDLE) -			break; -	} - -	if (time_before(timeout, jiffies)) { -		dev_warn(ts->dev, "timeout waiting for idle\n"); -		clk_disable(ts->clk); -		return -EIO; -	} - -	/* Configure TSC Control register*/ -	val = (PONBG | PON | PVSTC(4) | ONE_SHOT | ZMEASURE_EN); -	tsc_write(ts, tscm, val); - -	/* Bring TSC out of reset: Clear AFE reset bit */ -	val &= ~(AFERST); -	tsc_write(ts, tscm, val); - -	/* Configure all pins for hardware control*/ -	tsc_write(ts, bwcm, 0); - -	/* Finally enable the TSC */ -	tsc_set_bits(ts, tscm, TSC_EN); - -	return 0; -} - -static void tsc_stop(struct input_dev *dev) -{ -	struct tsc_data *ts = input_get_drvdata(dev); - -	tsc_clr_bits(ts, tscm, TSC_EN); -	synchronize_irq(ts->tsc_irq); -	del_timer_sync(&ts->timer); -	clk_disable(ts->clk); -} - -static int tsc_probe(struct platform_device *pdev) -{ -	struct device *dev = &pdev->dev; -	struct tsc_data *ts; -	int error = 0; -	u32 rev = 0; - -	ts = kzalloc(sizeof(struct tsc_data), GFP_KERNEL); -	if (!ts) { -		dev_err(dev, "cannot allocate device info\n"); -		return -ENOMEM; -	} - -	ts->dev = dev; -	spin_lock_init(&ts->lock); -	setup_timer(&ts->timer, tsc_poll, (unsigned long)ts); -	platform_set_drvdata(pdev, ts); - -	ts->tsc_irq = platform_get_irq(pdev, 0); -	if (ts->tsc_irq < 0) { -		dev_err(dev, "cannot determine device interrupt\n"); -		error = -ENODEV; -		goto error_res; -	} - -	ts->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!ts->res) { -		dev_err(dev, "cannot determine register area\n"); -		error = -ENODEV; -		goto error_res; -	} - -	if (!request_mem_region(ts->res->start, resource_size(ts->res), -				pdev->name)) { -		dev_err(dev, "cannot claim register memory\n"); -		ts->res = NULL; -		error = -EINVAL; -		goto error_res; -	} - -	ts->regs = ioremap(ts->res->start, resource_size(ts->res)); -	if (!ts->regs) { -		dev_err(dev, "cannot map register memory\n"); -		error = -ENOMEM; -		goto error_map; -	} - -	ts->clk = clk_get(dev, NULL); -	if (IS_ERR(ts->clk)) { -		dev_err(dev, "cannot claim device clock\n"); -		error = PTR_ERR(ts->clk); -		goto error_clk; -	} - -	error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, IRQF_ONESHOT, -				     dev_name(dev), ts); -	if (error < 0) { -		dev_err(ts->dev, "Could not allocate ts irq\n"); -		goto error_irq; -	} - -	ts->input_dev = input_allocate_device(); -	if (!ts->input_dev) { -		dev_err(dev, "cannot allocate input device\n"); -		error = -ENOMEM; -		goto error_input; -	} -	input_set_drvdata(ts->input_dev, ts); - -	ts->input_dev->name       = pdev->name; -	ts->input_dev->id.bustype = BUS_HOST; -	ts->input_dev->dev.parent = &pdev->dev; -	ts->input_dev->open	  = tsc_start; -	ts->input_dev->close	  = tsc_stop; - -	clk_enable(ts->clk); -	rev = tsc_read(ts, rev); -	ts->input_dev->id.product = ((rev >>  8) & 0x07); -	ts->input_dev->id.version = ((rev >> 16) & 0xfff); -	clk_disable(ts->clk); - -	__set_bit(EV_KEY,    ts->input_dev->evbit); -	__set_bit(EV_ABS,    ts->input_dev->evbit); -	__set_bit(BTN_TOUCH, ts->input_dev->keybit); - -	input_set_abs_params(ts->input_dev, ABS_X, 0, 0xffff, 5, 0); -	input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xffff, 5, 0); -	input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 4095, 128, 0); - -	error = input_register_device(ts->input_dev); -	if (error < 0) { -		dev_err(dev, "failed input device registration\n"); -		goto error_reg; -	} - -	return 0; - -error_reg: -	input_free_device(ts->input_dev); -error_input: -	free_irq(ts->tsc_irq, ts); -error_irq: -	clk_put(ts->clk); -error_clk: -	iounmap(ts->regs); -error_map: -	release_mem_region(ts->res->start, resource_size(ts->res)); -error_res: -	kfree(ts); - -	return error; -} - -static int tsc_remove(struct platform_device *pdev) -{ -	struct tsc_data *ts = platform_get_drvdata(pdev); - -	input_unregister_device(ts->input_dev); -	free_irq(ts->tsc_irq, ts); -	clk_put(ts->clk); -	iounmap(ts->regs); -	release_mem_region(ts->res->start, resource_size(ts->res)); -	kfree(ts); - -	return 0; -} - -static struct platform_driver tsc_driver = { -	.probe		= tsc_probe, -	.remove		= tsc_remove, -	.driver.name	= "tnetv107x-ts", -	.driver.owner	= THIS_MODULE, -}; -module_platform_driver(tsc_driver); - -MODULE_AUTHOR("Cyril Chemparathy"); -MODULE_DESCRIPTION("TNETV107X Touchscreen Driver"); -MODULE_ALIAS("platform:tnetv107x-ts"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c index 5f29e5b8e1c..c27cf8f3d1c 100644 --- a/drivers/input/touchscreen/touchit213.c +++ b/drivers/input/touchscreen/touchit213.c @@ -21,7 +21,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Sahara TouchIT-213 serial touchscreen driver" diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c index 8a2887daf19..4000e520540 100644 --- a/drivers/input/touchscreen/touchright.c +++ b/drivers/input/touchscreen/touchright.c @@ -20,7 +20,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Touchright serial touchscreen driver" diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c index 588cdcb839d..ba90f447df7 100644 --- a/drivers/input/touchscreen/touchwin.c +++ b/drivers/input/touchscreen/touchwin.c @@ -27,7 +27,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Touchwindow serial touchscreen driver" diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 7213e8b07e7..52380b68ebd 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -25,11 +25,15 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/input.h> +#include <linux/input/touchscreen.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/pm.h> +#include <linux/of.h> +#include <linux/of_gpio.h>  #include <linux/spi/spi.h>  #include <linux/spi/tsc2005.h> +#include <linux/regulator/consumer.h>  /*   * The touchscreen interface operates as follows: @@ -100,6 +104,11 @@  					 TSC2005_CFR2_AVG_7)  #define MAX_12BIT			0xfff +#define TSC2005_DEF_X_FUZZ		4 +#define TSC2005_DEF_Y_FUZZ		8 +#define TSC2005_DEF_P_FUZZ		2 +#define TSC2005_DEF_RESISTOR		280 +  #define TSC2005_SPI_MAX_SPEED_HZ	10000000  #define TSC2005_PENUP_TIME_MS		40 @@ -143,6 +152,9 @@ struct tsc2005 {  	bool			pen_down; +	struct regulator	*vio; + +	int			reset_gpio;  	void			(*set_reset)(bool enable);  }; @@ -337,6 +349,14 @@ static void tsc2005_stop_scan(struct tsc2005 *ts)  	tsc2005_cmd(ts, TSC2005_CMD_STOP);  } +static void tsc2005_set_reset(struct tsc2005 *ts, bool enable) +{ +	if (ts->reset_gpio >= 0) +		gpio_set_value(ts->reset_gpio, enable); +	else if (ts->set_reset) +		ts->set_reset(enable); +} +  /* must be called with ts->mutex held */  static void __tsc2005_disable(struct tsc2005 *ts)  { @@ -355,7 +375,7 @@ static void __tsc2005_enable(struct tsc2005 *ts)  {  	tsc2005_start_scan(ts); -	if (ts->esd_timeout && ts->set_reset) { +	if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) {  		ts->last_valid_interrupt = jiffies;  		schedule_delayed_work(&ts->esd_work,  				round_jiffies_relative( @@ -414,9 +434,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev,  	}  	/* hardware reset */ -	ts->set_reset(false); +	tsc2005_set_reset(ts, false);  	usleep_range(100, 500); /* only 10us required */ -	ts->set_reset(true); +	tsc2005_set_reset(ts, true);  	if (!success)  		goto out; @@ -459,7 +479,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj,  	umode_t mode = attr->mode;  	if (attr == &dev_attr_selftest.attr) { -		if (!ts->set_reset) +		if (!ts->set_reset && !ts->reset_gpio)  			mode = 0;  	} @@ -509,9 +529,9 @@ static void tsc2005_esd_work(struct work_struct *work)  	tsc2005_update_pen_state(ts, 0, 0, 0); -	ts->set_reset(false); +	tsc2005_set_reset(ts, false);  	usleep_range(100, 500); /* only 10us required */ -	ts->set_reset(true); +	tsc2005_set_reset(ts, true);  	enable_irq(ts->spi->irq);  	tsc2005_start_scan(ts); @@ -571,30 +591,48 @@ static void tsc2005_setup_spi_xfer(struct tsc2005 *ts)  static int tsc2005_probe(struct spi_device *spi)  { -	const struct tsc2005_platform_data *pdata = spi->dev.platform_data; +	const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev); +	struct device_node *np = spi->dev.of_node; +  	struct tsc2005 *ts;  	struct input_dev *input_dev; -	unsigned int max_x, max_y, max_p; -	unsigned int fudge_x, fudge_y, fudge_p; +	unsigned int max_x = MAX_12BIT; +	unsigned int max_y = MAX_12BIT; +	unsigned int max_p = MAX_12BIT; +	unsigned int fudge_x = TSC2005_DEF_X_FUZZ; +	unsigned int fudge_y = TSC2005_DEF_Y_FUZZ; +	unsigned int fudge_p = TSC2005_DEF_P_FUZZ; +	unsigned int x_plate_ohm = TSC2005_DEF_RESISTOR; +	unsigned int esd_timeout;  	int error; -	if (!pdata) { -		dev_dbg(&spi->dev, "no platform data\n"); +	if (!np && !pdata) { +		dev_err(&spi->dev, "no platform data\n");  		return -ENODEV;  	} -	fudge_x	= pdata->ts_x_fudge	   ? : 4; -	fudge_y	= pdata->ts_y_fudge	   ? : 8; -	fudge_p	= pdata->ts_pressure_fudge ? : 2; -	max_x	= pdata->ts_x_max	   ? : MAX_12BIT; -	max_y	= pdata->ts_y_max	   ? : MAX_12BIT; -	max_p	= pdata->ts_pressure_max   ? : MAX_12BIT; -  	if (spi->irq <= 0) { -		dev_dbg(&spi->dev, "no irq\n"); +		dev_err(&spi->dev, "no irq\n");  		return -ENODEV;  	} +	if (pdata) { +		fudge_x	= pdata->ts_x_fudge; +		fudge_y	= pdata->ts_y_fudge; +		fudge_p	= pdata->ts_pressure_fudge; +		max_x	= pdata->ts_x_max; +		max_y	= pdata->ts_y_max; +		max_p	= pdata->ts_pressure_max; +		x_plate_ohm = pdata->ts_x_plate_ohm; +		esd_timeout = pdata->esd_timeout_ms; +	} else { +		x_plate_ohm = TSC2005_DEF_RESISTOR; +		of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm); +		esd_timeout = 0; +		of_property_read_u32(np, "ti,esd-recovery-timeout-ms", +								&esd_timeout); +	} +  	spi->mode = SPI_MODE_0;  	spi->bits_per_word = 8;  	if (!spi->max_speed_hz) @@ -604,19 +642,48 @@ static int tsc2005_probe(struct spi_device *spi)  	if (error)  		return error; -	ts = kzalloc(sizeof(*ts), GFP_KERNEL); -	input_dev = input_allocate_device(); -	if (!ts || !input_dev) { -		error = -ENOMEM; -		goto err_free_mem; -	} +	ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL); +	if (!ts) +		return -ENOMEM; + +	input_dev = devm_input_allocate_device(&spi->dev); +	if (!input_dev) +		return -ENOMEM;  	ts->spi = spi;  	ts->idev = input_dev; -	ts->x_plate_ohm	= pdata->ts_x_plate_ohm	? : 280; -	ts->esd_timeout	= pdata->esd_timeout_ms; -	ts->set_reset	= pdata->set_reset; +	ts->x_plate_ohm = x_plate_ohm; +	ts->esd_timeout = esd_timeout; + +	if (np) { +		ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); +		if (ts->reset_gpio == -EPROBE_DEFER) +			return ts->reset_gpio; +		if (ts->reset_gpio < 0) { +			dev_err(&spi->dev, "error acquiring reset gpio: %d\n", +				ts->reset_gpio); +			return ts->reset_gpio; +		} + +		error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0, +					      "reset-gpios"); +		if (error) { +			dev_err(&spi->dev, "error requesting reset gpio: %d\n", +				error); +			return error; +		} + +		ts->vio = devm_regulator_get(&spi->dev, "vio"); +		if (IS_ERR(ts->vio)) { +			error = PTR_ERR(ts->vio); +			dev_err(&spi->dev, "vio regulator missing (%d)", error); +			return error; +		} +	} else { +		ts->reset_gpio = -1; +		ts->set_reset = pdata->set_reset; +	}  	mutex_init(&ts->mutex); @@ -641,6 +708,9 @@ static int tsc2005_probe(struct spi_device *spi)  	input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);  	input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); +	if (np) +		touchscreen_parse_of_params(input_dev); +  	input_dev->open = tsc2005_open;  	input_dev->close = tsc2005_close; @@ -649,12 +719,20 @@ static int tsc2005_probe(struct spi_device *spi)  	/* Ensure the touchscreen is off */  	tsc2005_stop_scan(ts); -	error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, -				     IRQF_TRIGGER_RISING | IRQF_ONESHOT, -				     "tsc2005", ts); +	error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, +					  tsc2005_irq_thread, +					  IRQF_TRIGGER_RISING | IRQF_ONESHOT, +					  "tsc2005", ts);  	if (error) {  		dev_err(&spi->dev, "Failed to request irq, err: %d\n", error); -		goto err_free_mem; +		return error; +	} + +	/* enable regulator for DT */ +	if (ts->vio) { +		error = regulator_enable(ts->vio); +		if (error) +			return error;  	}  	spi_set_drvdata(spi, ts); @@ -662,7 +740,7 @@ static int tsc2005_probe(struct spi_device *spi)  	if (error) {  		dev_err(&spi->dev,  			"Failed to create sysfs attributes, err: %d\n", error); -		goto err_clear_drvdata; +		goto disable_regulator;  	}  	error = input_register_device(ts->idev); @@ -677,12 +755,9 @@ static int tsc2005_probe(struct spi_device *spi)  err_remove_sysfs:  	sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); -err_clear_drvdata: -	spi_set_drvdata(spi, NULL); -	free_irq(spi->irq, ts); -err_free_mem: -	input_free_device(input_dev); -	kfree(ts); +disable_regulator: +	if (ts->vio) +		regulator_disable(ts->vio);  	return error;  } @@ -690,13 +765,11 @@ static int tsc2005_remove(struct spi_device *spi)  {  	struct tsc2005 *ts = spi_get_drvdata(spi); -	sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); +	sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); -	free_irq(ts->spi->irq, ts); -	input_unregister_device(ts->idev); -	kfree(ts); +	if (ts->vio) +		regulator_disable(ts->vio); -	spi_set_drvdata(spi, NULL);  	return 0;  } diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 0b67ba476b4..1bf9906b5a3 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -26,6 +26,9 @@  #include <linux/interrupt.h>  #include <linux/i2c.h>  #include <linux/i2c/tsc2007.h> +#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/of_gpio.h>  #define TSC2007_MEASURE_TEMP0		(0x0 << 4)  #define TSC2007_MEASURE_AUX		(0x2 << 4) @@ -72,15 +75,18 @@ struct tsc2007 {  	u16			model;  	u16			x_plate_ohms;  	u16			max_rt; -	unsigned long		poll_delay;  	unsigned long		poll_period; +	int			fuzzx; +	int			fuzzy; +	int			fuzzz; +	unsigned		gpio;  	int			irq;  	wait_queue_head_t	wait;  	bool			stopped; -	int			(*get_pendown_state)(void); +	int			(*get_pendown_state)(struct device *);  	void			(*clear_penirq)(void);  }; @@ -161,7 +167,7 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts)  	if (!ts->get_pendown_state)  		return true; -	return ts->get_pendown_state(); +	return ts->get_pendown_state(&ts->client->dev);  }  static irqreturn_t tsc2007_soft_irq(int irq, void *handle) @@ -178,7 +184,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)  		rt = tsc2007_calculate_pressure(ts, &tc); -		if (rt == 0 && !ts->get_pendown_state) { +		if (!rt && !ts->get_pendown_state) {  			/*  			 * If pressure reported is 0 and we don't have  			 * callback to check pendown state, we have to @@ -228,7 +234,7 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle)  {  	struct tsc2007 *ts = handle; -	if (!ts->get_pendown_state || likely(ts->get_pendown_state())) +	if (tsc2007_is_pen_down(ts))  		return IRQ_WAKE_THREAD;  	if (ts->clear_penirq) @@ -273,49 +279,134 @@ static void tsc2007_close(struct input_dev *input_dev)  	tsc2007_stop(ts);  } -static int tsc2007_probe(struct i2c_client *client, -				   const struct i2c_device_id *id) +#ifdef CONFIG_OF +static int tsc2007_get_pendown_state_gpio(struct device *dev)  { -	struct tsc2007 *ts; -	struct tsc2007_platform_data *pdata = client->dev.platform_data; -	struct input_dev *input_dev; -	int err; +	struct i2c_client *client = to_i2c_client(dev); +	struct tsc2007 *ts = i2c_get_clientdata(client); + +	return !gpio_get_value(ts->gpio); +} + +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ +	struct device_node *np = client->dev.of_node; +	u32 val32; +	u64 val64; -	if (!pdata) { -		dev_err(&client->dev, "platform data is required!\n"); +	if (!np) { +		dev_err(&client->dev, "missing device tree data\n");  		return -EINVAL;  	} -	if (!i2c_check_functionality(client->adapter, -				     I2C_FUNC_SMBUS_READ_WORD_DATA)) -		return -EIO; +	if (!of_property_read_u32(np, "ti,max-rt", &val32)) +		ts->max_rt = val32; +	else +		ts->max_rt = MAX_12BIT; + +	if (!of_property_read_u32(np, "ti,fuzzx", &val32)) +		ts->fuzzx = val32; + +	if (!of_property_read_u32(np, "ti,fuzzy", &val32)) +		ts->fuzzy = val32; + +	if (!of_property_read_u32(np, "ti,fuzzz", &val32)) +		ts->fuzzz = val32; + +	if (!of_property_read_u64(np, "ti,poll-period", &val64)) +		ts->poll_period = val64; +	else +		ts->poll_period = 1; -	ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL); -	input_dev = input_allocate_device(); -	if (!ts || !input_dev) { -		err = -ENOMEM; -		goto err_free_mem; +	if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) { +		ts->x_plate_ohms = val32; +	} else { +		dev_err(&client->dev, "missing ti,x-plate-ohms devicetree property."); +		return -EINVAL;  	} -	ts->client = client; -	ts->irq = client->irq; -	ts->input = input_dev; -	init_waitqueue_head(&ts->wait); +	ts->gpio = of_get_gpio(np, 0); +	if (gpio_is_valid(ts->gpio)) +		ts->get_pendown_state = tsc2007_get_pendown_state_gpio; +	else +		dev_warn(&client->dev, +			 "GPIO not specified in DT (of_get_gpio returned %d)\n", +			 ts->gpio); + +	return 0; +} +#else +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ +	dev_err(&client->dev, "platform data is required!\n"); +	return -EINVAL; +} +#endif +static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts, +			      const struct tsc2007_platform_data *pdata, +			      const struct i2c_device_id *id) +{  	ts->model             = pdata->model;  	ts->x_plate_ohms      = pdata->x_plate_ohms;  	ts->max_rt            = pdata->max_rt ? : MAX_12BIT; -	ts->poll_delay        = pdata->poll_delay ? : 1;  	ts->poll_period       = pdata->poll_period ? : 1;  	ts->get_pendown_state = pdata->get_pendown_state;  	ts->clear_penirq      = pdata->clear_penirq; +	ts->fuzzx             = pdata->fuzzx; +	ts->fuzzy             = pdata->fuzzy; +	ts->fuzzz             = pdata->fuzzz;  	if (pdata->x_plate_ohms == 0) {  		dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); -		err = -EINVAL; -		goto err_free_mem; +		return -EINVAL;  	} +	return 0; +} + +static void tsc2007_call_exit_platform_hw(void *data) +{ +	struct device *dev = data; +	const struct tsc2007_platform_data *pdata = dev_get_platdata(dev); + +	pdata->exit_platform_hw(); +} + +static int tsc2007_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); +	struct tsc2007 *ts; +	struct input_dev *input_dev; +	int err; + +	if (!i2c_check_functionality(client->adapter, +				     I2C_FUNC_SMBUS_READ_WORD_DATA)) +		return -EIO; + +	ts = devm_kzalloc(&client->dev, sizeof(struct tsc2007), GFP_KERNEL); +	if (!ts) +		return -ENOMEM; + +	if (pdata) +		err = tsc2007_probe_pdev(client, ts, pdata, id); +	else +		err = tsc2007_probe_dt(client, ts); +	if (err) +		return err; + +	input_dev = devm_input_allocate_device(&client->dev); +	if (!input_dev) +		return -ENOMEM; + +	i2c_set_clientdata(client, ts); + +	ts->client = client; +	ts->irq = client->irq; +	ts->input = input_dev; +	init_waitqueue_head(&ts->wait); +  	snprintf(ts->phys, sizeof(ts->phys),  		 "%s/input0", dev_name(&client->dev)); @@ -331,53 +422,46 @@ static int tsc2007_probe(struct i2c_client *client,  	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);  	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); -	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0); -	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0); +	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); +	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);  	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, -			pdata->fuzzz, 0); +			     ts->fuzzz, 0); + +	if (pdata) { +		if (pdata->exit_platform_hw) { +			err = devm_add_action(&client->dev, +					      tsc2007_call_exit_platform_hw, +					      &client->dev); +			if (err) { +				dev_err(&client->dev, +					"Failed to register exit_platform_hw action, %d\n", +					err); +				return err; +			} +		} -	if (pdata->init_platform_hw) -		pdata->init_platform_hw(); +		if (pdata->init_platform_hw) +			pdata->init_platform_hw(); +	} -	err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq, -				   IRQF_ONESHOT, client->dev.driver->name, ts); -	if (err < 0) { -		dev_err(&client->dev, "irq %d busy?\n", ts->irq); -		goto err_free_mem; +	err = devm_request_threaded_irq(&client->dev, ts->irq, +					tsc2007_hard_irq, tsc2007_soft_irq, +					IRQF_ONESHOT, +					client->dev.driver->name, ts); +	if (err) { +		dev_err(&client->dev, "Failed to request irq %d: %d\n", +			ts->irq, err); +		return err;  	}  	tsc2007_stop(ts);  	err = input_register_device(input_dev); -	if (err) -		goto err_free_irq; - -	i2c_set_clientdata(client, ts); - -	return 0; - - err_free_irq: -	free_irq(ts->irq, ts); -	if (pdata->exit_platform_hw) -		pdata->exit_platform_hw(); - err_free_mem: -	input_free_device(input_dev); -	kfree(ts); -	return err; -} - -static int tsc2007_remove(struct i2c_client *client) -{ -	struct tsc2007	*ts = i2c_get_clientdata(client); -	struct tsc2007_platform_data *pdata = client->dev.platform_data; - -	free_irq(ts->irq, ts); - -	if (pdata->exit_platform_hw) -		pdata->exit_platform_hw(); - -	input_unregister_device(ts->input); -	kfree(ts); +	if (err) { +		dev_err(&client->dev, +			"Failed to register input device: %d\n", err); +		return err; +	}  	return 0;  } @@ -389,14 +473,22 @@ static const struct i2c_device_id tsc2007_idtable[] = {  MODULE_DEVICE_TABLE(i2c, tsc2007_idtable); +#ifdef CONFIG_OF +static const struct of_device_id tsc2007_of_match[] = { +	{ .compatible = "ti,tsc2007" }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tsc2007_of_match); +#endif +  static struct i2c_driver tsc2007_driver = {  	.driver = {  		.owner	= THIS_MODULE, -		.name	= "tsc2007" +		.name	= "tsc2007", +		.of_match_table = of_match_ptr(tsc2007_of_match),  	},  	.id_table	= tsc2007_idtable,  	.probe		= tsc2007_probe, -	.remove		= tsc2007_remove,  };  module_i2c_driver(tsc2007_driver); diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c index eb96f168fb9..29687872cb9 100644 --- a/drivers/input/touchscreen/tsc40.c +++ b/drivers/input/touchscreen/tsc40.c @@ -11,7 +11,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define PACKET_LENGTH  5  struct tsc_ser { diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 1271f97b407..b46c55cd1bb 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -19,7 +19,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/sched.h>  #include <linux/wait.h> @@ -320,7 +319,7 @@ static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb,  static int ucb1400_ts_probe(struct platform_device *pdev)  { -	struct ucb1400_ts *ucb = pdev->dev.platform_data; +	struct ucb1400_ts *ucb = dev_get_platdata(&pdev->dev);  	int error, x_res, y_res;  	u16 fcsr; @@ -399,7 +398,7 @@ err:  static int ucb1400_ts_remove(struct platform_device *pdev)  { -	struct ucb1400_ts *ucb = pdev->dev.platform_data; +	struct ucb1400_ts *ucb = dev_get_platdata(&pdev->dev);  	free_irq(ucb->irq, ucb);  	input_unregister_device(ucb->ts_idev); @@ -410,7 +409,7 @@ static int ucb1400_ts_remove(struct platform_device *pdev)  #ifdef CONFIG_PM_SLEEP  static int ucb1400_ts_suspend(struct device *dev)  { -	struct ucb1400_ts *ucb = dev->platform_data; +	struct ucb1400_ts *ucb = dev_get_platdata(dev);  	struct input_dev *idev = ucb->ts_idev;  	mutex_lock(&idev->mutex); @@ -424,7 +423,7 @@ static int ucb1400_ts_suspend(struct device *dev)  static int ucb1400_ts_resume(struct device *dev)  { -	struct ucb1400_ts *ucb = dev->platform_data; +	struct ucb1400_ts *ucb = dev_get_platdata(dev);  	struct input_dev *idev = ucb->ts_idev;  	mutex_lock(&idev->mutex); diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 721fdb3597c..a0966331a89 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -51,7 +51,6 @@  #include <linux/slab.h>  #include <linux/input.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/usb.h>  #include <linux/usb/input.h>  #include <linux/hid.h> @@ -106,6 +105,7 @@ struct usbtouch_device_info {  struct usbtouch_usb {  	unsigned char *data;  	dma_addr_t data_dma; +	int data_size;  	unsigned char *buffer;  	int buf_len;  	struct urb *irq; @@ -146,12 +146,10 @@ enum {  #define USB_DEVICE_HID_CLASS(vend, prod) \  	.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \ -		| USB_DEVICE_ID_MATCH_INT_PROTOCOL \  		| USB_DEVICE_ID_MATCH_DEVICE, \  	.idVendor = (vend), \  	.idProduct = (prod), \ -	.bInterfaceClass = USB_INTERFACE_CLASS_HID, \ -	.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE +	.bInterfaceClass = USB_INTERFACE_CLASS_HID  static const struct usb_device_id usbtouch_devices[] = {  #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX @@ -1523,7 +1521,7 @@ static int usbtouch_reset_resume(struct usb_interface *intf)  static void usbtouch_free_buffers(struct usb_device *udev,  				  struct usbtouch_usb *usbtouch)  { -	usb_free_coherent(udev, usbtouch->type->rept_size, +	usb_free_coherent(udev, usbtouch->data_size,  			  usbtouch->data, usbtouch->data_dma);  	kfree(usbtouch->buffer);  } @@ -1568,7 +1566,20 @@ static int usbtouch_probe(struct usb_interface *intf,  	if (!type->process_pkt)  		type->process_pkt = usbtouch_process_pkt; -	usbtouch->data = usb_alloc_coherent(udev, type->rept_size, +	usbtouch->data_size = type->rept_size; +	if (type->get_pkt_len) { +		/* +		 * When dealing with variable-length packets we should +		 * not request more than wMaxPacketSize bytes at once +		 * as we do not know if there is more data coming or +		 * we filled exactly wMaxPacketSize bytes and there is +		 * nothing else. +		 */ +		usbtouch->data_size = min(usbtouch->data_size, +					  usb_endpoint_maxp(endpoint)); +	} + +	usbtouch->data = usb_alloc_coherent(udev, usbtouch->data_size,  					    GFP_KERNEL, &usbtouch->data_dma);  	if (!usbtouch->data)  		goto out_free; @@ -1628,12 +1639,12 @@ static int usbtouch_probe(struct usb_interface *intf,  	if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)  		usb_fill_int_urb(usbtouch->irq, udev,  			 usb_rcvintpipe(udev, endpoint->bEndpointAddress), -			 usbtouch->data, type->rept_size, +			 usbtouch->data, usbtouch->data_size,  			 usbtouch_irq, usbtouch, endpoint->bInterval);  	else  		usb_fill_bulk_urb(usbtouch->irq, udev,  			 usb_rcvbulkpipe(udev, endpoint->bEndpointAddress), -			 usbtouch->data, type->rept_size, +			 usbtouch->data, usbtouch->data_size,  			 usbtouch_irq, usbtouch);  	usbtouch->irq->dev = udev; diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 9a83be6b658..2792ca397dd 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -18,7 +18,6 @@  #include <linux/slab.h>  #include <linux/input/mt.h>  #include <linux/serio.h> -#include <linux/init.h>  #include <linux/ctype.h>  #include <linux/delay.h> diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 6be2eb6a153..1b953a066b2 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -13,7 +13,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/string.h>  #include <linux/pm.h>  #include <linux/input.h> diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 7e45c9f6e6b..d0ef91fc87d 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -584,7 +584,7 @@ static void wm97xx_ts_input_close(struct input_dev *idev)  static int wm97xx_probe(struct device *dev)  {  	struct wm97xx *wm; -	struct wm97xx_pdata *pdata = dev->platform_data; +	struct wm97xx_pdata *pdata = dev_get_platdata(dev);  	int ret = 0, id = 0;  	wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL); diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c new file mode 100644 index 00000000000..feea85b52fa --- /dev/null +++ b/drivers/input/touchscreen/zforce_ts.c @@ -0,0 +1,905 @@ +/* + * Copyright (C) 2012-2013 MundoReader S.L. + * Author: Heiko Stuebner <heiko@sntech.de> + * + * based in parts on Nook zforce driver + * + * Copyright (C) 2010 Barnes & Noble, Inc. + * Author: Pieter Truter<ptruter@intrinsyc.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include <linux/module.h> +#include <linux/hrtimer.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/sysfs.h> +#include <linux/input/mt.h> +#include <linux/platform_data/zforce_ts.h> +#include <linux/of.h> +#include <linux/of_gpio.h> + +#define WAIT_TIMEOUT		msecs_to_jiffies(1000) + +#define FRAME_START		0xee +#define FRAME_MAXSIZE		257 + +/* Offsets of the different parts of the payload the controller sends */ +#define PAYLOAD_HEADER		0 +#define PAYLOAD_LENGTH		1 +#define PAYLOAD_BODY		2 + +/* Response offsets */ +#define RESPONSE_ID		0 +#define RESPONSE_DATA		1 + +/* Commands */ +#define COMMAND_DEACTIVATE	0x00 +#define COMMAND_INITIALIZE	0x01 +#define COMMAND_RESOLUTION	0x02 +#define COMMAND_SETCONFIG	0x03 +#define COMMAND_DATAREQUEST	0x04 +#define COMMAND_SCANFREQ	0x08 +#define COMMAND_STATUS		0X1e + +/* + * Responses the controller sends as a result of + * command requests + */ +#define RESPONSE_DEACTIVATE	0x00 +#define RESPONSE_INITIALIZE	0x01 +#define RESPONSE_RESOLUTION	0x02 +#define RESPONSE_SETCONFIG	0x03 +#define RESPONSE_SCANFREQ	0x08 +#define RESPONSE_STATUS		0X1e + +/* + * Notifications are sent by the touch controller without + * being requested by the driver and include for example + * touch indications + */ +#define NOTIFICATION_TOUCH		0x04 +#define NOTIFICATION_BOOTCOMPLETE	0x07 +#define NOTIFICATION_OVERRUN		0x25 +#define NOTIFICATION_PROXIMITY		0x26 +#define NOTIFICATION_INVALID_COMMAND	0xfe + +#define ZFORCE_REPORT_POINTS		2 +#define ZFORCE_MAX_AREA			0xff + +#define STATE_DOWN			0 +#define STATE_MOVE			1 +#define STATE_UP			2 + +#define SETCONFIG_DUALTOUCH		(1 << 0) + +struct zforce_point { +	int coord_x; +	int coord_y; +	int state; +	int id; +	int area_major; +	int area_minor; +	int orientation; +	int pressure; +	int prblty; +}; + +/* + * @client		the i2c_client + * @input		the input device + * @suspending		in the process of going to suspend (don't emit wakeup + *			events for commands executed to suspend the device) + * @suspended		device suspended + * @access_mutex	serialize i2c-access, to keep multipart reads together + * @command_done	completion to wait for the command result + * @command_mutex	serialize commands sent to the ic + * @command_waiting	the id of the command that is currently waiting + *			for a result + * @command_result	returned result of the command + */ +struct zforce_ts { +	struct i2c_client	*client; +	struct input_dev	*input; +	const struct zforce_ts_platdata *pdata; +	char			phys[32]; + +	bool			suspending; +	bool			suspended; +	bool			boot_complete; + +	/* Firmware version information */ +	u16			version_major; +	u16			version_minor; +	u16			version_build; +	u16			version_rev; + +	struct mutex		access_mutex; + +	struct completion	command_done; +	struct mutex		command_mutex; +	int			command_waiting; +	int			command_result; +}; + +static int zforce_command(struct zforce_ts *ts, u8 cmd) +{ +	struct i2c_client *client = ts->client; +	char buf[3]; +	int ret; + +	dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); + +	buf[0] = FRAME_START; +	buf[1] = 1; /* data size, command only */ +	buf[2] = cmd; + +	mutex_lock(&ts->access_mutex); +	ret = i2c_master_send(client, &buf[0], ARRAY_SIZE(buf)); +	mutex_unlock(&ts->access_mutex); +	if (ret < 0) { +		dev_err(&client->dev, "i2c send data request error: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len) +{ +	struct i2c_client *client = ts->client; +	int ret; + +	ret = mutex_trylock(&ts->command_mutex); +	if (!ret) { +		dev_err(&client->dev, "already waiting for a command\n"); +		return -EBUSY; +	} + +	dev_dbg(&client->dev, "sending %d bytes for command 0x%x\n", +		buf[1], buf[2]); + +	ts->command_waiting = buf[2]; + +	mutex_lock(&ts->access_mutex); +	ret = i2c_master_send(client, buf, len); +	mutex_unlock(&ts->access_mutex); +	if (ret < 0) { +		dev_err(&client->dev, "i2c send data request error: %d\n", ret); +		goto unlock; +	} + +	dev_dbg(&client->dev, "waiting for result for command 0x%x\n", buf[2]); + +	if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) { +		ret = -ETIME; +		goto unlock; +	} + +	ret = ts->command_result; + +unlock: +	mutex_unlock(&ts->command_mutex); +	return ret; +} + +static int zforce_command_wait(struct zforce_ts *ts, u8 cmd) +{ +	struct i2c_client *client = ts->client; +	char buf[3]; +	int ret; + +	dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); + +	buf[0] = FRAME_START; +	buf[1] = 1; /* data size, command only */ +	buf[2] = cmd; + +	ret = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); +	if (ret < 0) { +		dev_err(&client->dev, "i2c send data request error: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static int zforce_resolution(struct zforce_ts *ts, u16 x, u16 y) +{ +	struct i2c_client *client = ts->client; +	char buf[7] = { FRAME_START, 5, COMMAND_RESOLUTION, +			(x & 0xff), ((x >> 8) & 0xff), +			(y & 0xff), ((y >> 8) & 0xff) }; + +	dev_dbg(&client->dev, "set resolution to (%d,%d)\n", x, y); + +	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); +} + +static int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger, +				 u16 stylus) +{ +	struct i2c_client *client = ts->client; +	char buf[9] = { FRAME_START, 7, COMMAND_SCANFREQ, +			(idle & 0xff), ((idle >> 8) & 0xff), +			(finger & 0xff), ((finger >> 8) & 0xff), +			(stylus & 0xff), ((stylus >> 8) & 0xff) }; + +	dev_dbg(&client->dev, +		"set scan frequency to (idle: %d, finger: %d, stylus: %d)\n", +		idle, finger, stylus); + +	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); +} + +static int zforce_setconfig(struct zforce_ts *ts, char b1) +{ +	struct i2c_client *client = ts->client; +	char buf[7] = { FRAME_START, 5, COMMAND_SETCONFIG, +			b1, 0, 0, 0 }; + +	dev_dbg(&client->dev, "set config to (%d)\n", b1); + +	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf)); +} + +static int zforce_start(struct zforce_ts *ts) +{ +	struct i2c_client *client = ts->client; +	const struct zforce_ts_platdata *pdata = ts->pdata; +	int ret; + +	dev_dbg(&client->dev, "starting device\n"); + +	ret = zforce_command_wait(ts, COMMAND_INITIALIZE); +	if (ret) { +		dev_err(&client->dev, "Unable to initialize, %d\n", ret); +		return ret; +	} + +	ret = zforce_resolution(ts, pdata->x_max, pdata->y_max); +	if (ret) { +		dev_err(&client->dev, "Unable to set resolution, %d\n", ret); +		goto error; +	} + +	ret = zforce_scan_frequency(ts, 10, 50, 50); +	if (ret) { +		dev_err(&client->dev, "Unable to set scan frequency, %d\n", +			ret); +		goto error; +	} + +	ret = zforce_setconfig(ts, SETCONFIG_DUALTOUCH); +	if (ret) { +		dev_err(&client->dev, "Unable to set config\n"); +		goto error; +	} + +	/* start sending touch events */ +	ret = zforce_command(ts, COMMAND_DATAREQUEST); +	if (ret) { +		dev_err(&client->dev, "Unable to request data\n"); +		goto error; +	} + +	/* +	 * Per NN, initial cal. take max. of 200msec. +	 * Allow time to complete this calibration +	 */ +	msleep(200); + +	return 0; + +error: +	zforce_command_wait(ts, COMMAND_DEACTIVATE); +	return ret; +} + +static int zforce_stop(struct zforce_ts *ts) +{ +	struct i2c_client *client = ts->client; +	int ret; + +	dev_dbg(&client->dev, "stopping device\n"); + +	/* Deactivates touch sensing and puts the device into sleep. */ +	ret = zforce_command_wait(ts, COMMAND_DEACTIVATE); +	if (ret != 0) { +		dev_err(&client->dev, "could not deactivate device, %d\n", +			ret); +		return ret; +	} + +	return 0; +} + +static int zforce_touch_event(struct zforce_ts *ts, u8 *payload) +{ +	struct i2c_client *client = ts->client; +	const struct zforce_ts_platdata *pdata = ts->pdata; +	struct zforce_point point; +	int count, i, num = 0; + +	count = payload[0]; +	if (count > ZFORCE_REPORT_POINTS) { +		dev_warn(&client->dev, +			 "too many coordinates %d, expected max %d\n", +			 count, ZFORCE_REPORT_POINTS); +		count = ZFORCE_REPORT_POINTS; +	} + +	for (i = 0; i < count; i++) { +		point.coord_x = +			payload[9 * i + 2] << 8 | payload[9 * i + 1]; +		point.coord_y = +			payload[9 * i + 4] << 8 | payload[9 * i + 3]; + +		if (point.coord_x > pdata->x_max || +		    point.coord_y > pdata->y_max) { +			dev_warn(&client->dev, "coordinates (%d,%d) invalid\n", +				point.coord_x, point.coord_y); +			point.coord_x = point.coord_y = 0; +		} + +		point.state = payload[9 * i + 5] & 0x03; +		point.id = (payload[9 * i + 5] & 0xfc) >> 2; + +		/* determine touch major, minor and orientation */ +		point.area_major = max(payload[9 * i + 6], +					  payload[9 * i + 7]); +		point.area_minor = min(payload[9 * i + 6], +					  payload[9 * i + 7]); +		point.orientation = payload[9 * i + 6] > payload[9 * i + 7]; + +		point.pressure = payload[9 * i + 8]; +		point.prblty = payload[9 * i + 9]; + +		dev_dbg(&client->dev, +			"point %d/%d: state %d, id %d, pressure %d, prblty %d, x %d, y %d, amajor %d, aminor %d, ori %d\n", +			i, count, point.state, point.id, +			point.pressure, point.prblty, +			point.coord_x, point.coord_y, +			point.area_major, point.area_minor, +			point.orientation); + +		/* the zforce id starts with "1", so needs to be decreased */ +		input_mt_slot(ts->input, point.id - 1); + +		input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, +						point.state != STATE_UP); + +		if (point.state != STATE_UP) { +			input_report_abs(ts->input, ABS_MT_POSITION_X, +					 point.coord_x); +			input_report_abs(ts->input, ABS_MT_POSITION_Y, +					 point.coord_y); +			input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, +					 point.area_major); +			input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, +					 point.area_minor); +			input_report_abs(ts->input, ABS_MT_ORIENTATION, +					 point.orientation); +			num++; +		} +	} + +	input_mt_sync_frame(ts->input); + +	input_mt_report_finger_count(ts->input, num); + +	input_sync(ts->input); + +	return 0; +} + +static int zforce_read_packet(struct zforce_ts *ts, u8 *buf) +{ +	struct i2c_client *client = ts->client; +	int ret; + +	mutex_lock(&ts->access_mutex); + +	/* read 2 byte message header */ +	ret = i2c_master_recv(client, buf, 2); +	if (ret < 0) { +		dev_err(&client->dev, "error reading header: %d\n", ret); +		goto unlock; +	} + +	if (buf[PAYLOAD_HEADER] != FRAME_START) { +		dev_err(&client->dev, "invalid frame start: %d\n", buf[0]); +		ret = -EIO; +		goto unlock; +	} + +	if (buf[PAYLOAD_LENGTH] == 0) { +		dev_err(&client->dev, "invalid payload length: %d\n", +			buf[PAYLOAD_LENGTH]); +		ret = -EIO; +		goto unlock; +	} + +	/* read the message */ +	ret = i2c_master_recv(client, &buf[PAYLOAD_BODY], buf[PAYLOAD_LENGTH]); +	if (ret < 0) { +		dev_err(&client->dev, "error reading payload: %d\n", ret); +		goto unlock; +	} + +	dev_dbg(&client->dev, "read %d bytes for response command 0x%x\n", +		buf[PAYLOAD_LENGTH], buf[PAYLOAD_BODY]); + +unlock: +	mutex_unlock(&ts->access_mutex); +	return ret; +} + +static void zforce_complete(struct zforce_ts *ts, int cmd, int result) +{ +	struct i2c_client *client = ts->client; + +	if (ts->command_waiting == cmd) { +		dev_dbg(&client->dev, "completing command 0x%x\n", cmd); +		ts->command_result = result; +		complete(&ts->command_done); +	} else { +		dev_dbg(&client->dev, "command %d not for us\n", cmd); +	} +} + +static irqreturn_t zforce_irq(int irq, void *dev_id) +{ +	struct zforce_ts *ts = dev_id; +	struct i2c_client *client = ts->client; + +	if (ts->suspended && device_may_wakeup(&client->dev)) +		pm_wakeup_event(&client->dev, 500); + +	return IRQ_WAKE_THREAD; +} + +static irqreturn_t zforce_irq_thread(int irq, void *dev_id) +{ +	struct zforce_ts *ts = dev_id; +	struct i2c_client *client = ts->client; +	const struct zforce_ts_platdata *pdata = ts->pdata; +	int ret; +	u8 payload_buffer[FRAME_MAXSIZE]; +	u8 *payload; + +	/* +	 * When still suspended, return. +	 * Due to the level-interrupt we will get re-triggered later. +	 */ +	if (ts->suspended) { +		msleep(20); +		return IRQ_HANDLED; +	} + +	dev_dbg(&client->dev, "handling interrupt\n"); + +	/* Don't emit wakeup events from commands run by zforce_suspend */ +	if (!ts->suspending && device_may_wakeup(&client->dev)) +		pm_stay_awake(&client->dev); + +	while (!gpio_get_value(pdata->gpio_int)) { +		ret = zforce_read_packet(ts, payload_buffer); +		if (ret < 0) { +			dev_err(&client->dev, +				"could not read packet, ret: %d\n", ret); +			break; +		} + +		payload =  &payload_buffer[PAYLOAD_BODY]; + +		switch (payload[RESPONSE_ID]) { +		case NOTIFICATION_TOUCH: +			/* +			 * Always report touch-events received while +			 * suspending, when being a wakeup source +			 */ +			if (ts->suspending && device_may_wakeup(&client->dev)) +				pm_wakeup_event(&client->dev, 500); +			zforce_touch_event(ts, &payload[RESPONSE_DATA]); +			break; + +		case NOTIFICATION_BOOTCOMPLETE: +			ts->boot_complete = payload[RESPONSE_DATA]; +			zforce_complete(ts, payload[RESPONSE_ID], 0); +			break; + +		case RESPONSE_INITIALIZE: +		case RESPONSE_DEACTIVATE: +		case RESPONSE_SETCONFIG: +		case RESPONSE_RESOLUTION: +		case RESPONSE_SCANFREQ: +			zforce_complete(ts, payload[RESPONSE_ID], +					payload[RESPONSE_DATA]); +			break; + +		case RESPONSE_STATUS: +			/* +			 * Version Payload Results +			 * [2:major] [2:minor] [2:build] [2:rev] +			 */ +			ts->version_major = (payload[RESPONSE_DATA + 1] << 8) | +						payload[RESPONSE_DATA]; +			ts->version_minor = (payload[RESPONSE_DATA + 3] << 8) | +						payload[RESPONSE_DATA + 2]; +			ts->version_build = (payload[RESPONSE_DATA + 5] << 8) | +						payload[RESPONSE_DATA + 4]; +			ts->version_rev   = (payload[RESPONSE_DATA + 7] << 8) | +						payload[RESPONSE_DATA + 6]; +			dev_dbg(&ts->client->dev, +				"Firmware Version %04x:%04x %04x:%04x\n", +				ts->version_major, ts->version_minor, +				ts->version_build, ts->version_rev); + +			zforce_complete(ts, payload[RESPONSE_ID], 0); +			break; + +		case NOTIFICATION_INVALID_COMMAND: +			dev_err(&ts->client->dev, "invalid command: 0x%x\n", +				payload[RESPONSE_DATA]); +			break; + +		default: +			dev_err(&ts->client->dev, +				"unrecognized response id: 0x%x\n", +				payload[RESPONSE_ID]); +			break; +		} +	} + +	if (!ts->suspending && device_may_wakeup(&client->dev)) +		pm_relax(&client->dev); + +	dev_dbg(&client->dev, "finished interrupt\n"); + +	return IRQ_HANDLED; +} + +static int zforce_input_open(struct input_dev *dev) +{ +	struct zforce_ts *ts = input_get_drvdata(dev); +	int ret; + +	ret = zforce_start(ts); +	if (ret) +		return ret; + +	return 0; +} + +static void zforce_input_close(struct input_dev *dev) +{ +	struct zforce_ts *ts = input_get_drvdata(dev); +	struct i2c_client *client = ts->client; +	int ret; + +	ret = zforce_stop(ts); +	if (ret) +		dev_warn(&client->dev, "stopping zforce failed\n"); + +	return; +} + +#ifdef CONFIG_PM_SLEEP +static int zforce_suspend(struct device *dev) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct zforce_ts *ts = i2c_get_clientdata(client); +	struct input_dev *input = ts->input; +	int ret = 0; + +	mutex_lock(&input->mutex); +	ts->suspending = true; + +	/* +	 * When configured as a wakeup source device should always wake +	 * the system, therefore start device if necessary. +	 */ +	if (device_may_wakeup(&client->dev)) { +		dev_dbg(&client->dev, "suspend while being a wakeup source\n"); + +		/* Need to start device, if not open, to be a wakeup source. */ +		if (!input->users) { +			ret = zforce_start(ts); +			if (ret) +				goto unlock; +		} + +		enable_irq_wake(client->irq); +	} else if (input->users) { +		dev_dbg(&client->dev, +			"suspend without being a wakeup source\n"); + +		ret = zforce_stop(ts); +		if (ret) +			goto unlock; + +		disable_irq(client->irq); +	} + +	ts->suspended = true; + +unlock: +	ts->suspending = false; +	mutex_unlock(&input->mutex); + +	return ret; +} + +static int zforce_resume(struct device *dev) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct zforce_ts *ts = i2c_get_clientdata(client); +	struct input_dev *input = ts->input; +	int ret = 0; + +	mutex_lock(&input->mutex); + +	ts->suspended = false; + +	if (device_may_wakeup(&client->dev)) { +		dev_dbg(&client->dev, "resume from being a wakeup source\n"); + +		disable_irq_wake(client->irq); + +		/* need to stop device if it was not open on suspend */ +		if (!input->users) { +			ret = zforce_stop(ts); +			if (ret) +				goto unlock; +		} +	} else if (input->users) { +		dev_dbg(&client->dev, "resume without being a wakeup source\n"); + +		enable_irq(client->irq); + +		ret = zforce_start(ts); +		if (ret < 0) +			goto unlock; +	} + +unlock: +	mutex_unlock(&input->mutex); + +	return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume); + +static void zforce_reset(void *data) +{ +	struct zforce_ts *ts = data; + +	gpio_set_value(ts->pdata->gpio_rst, 0); +} + +static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev) +{ +	struct zforce_ts_platdata *pdata; +	struct device_node *np = dev->of_node; + +	if (!np) +		return ERR_PTR(-ENOENT); + +	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) { +		dev_err(dev, "failed to allocate platform data\n"); +		return ERR_PTR(-ENOMEM); +	} + +	pdata->gpio_int = of_get_gpio(np, 0); +	if (!gpio_is_valid(pdata->gpio_int)) { +		dev_err(dev, "failed to get interrupt gpio\n"); +		return ERR_PTR(-EINVAL); +	} + +	pdata->gpio_rst = of_get_gpio(np, 1); +	if (!gpio_is_valid(pdata->gpio_rst)) { +		dev_err(dev, "failed to get reset gpio\n"); +		return ERR_PTR(-EINVAL); +	} + +	if (of_property_read_u32(np, "x-size", &pdata->x_max)) { +		dev_err(dev, "failed to get x-size property\n"); +		return ERR_PTR(-EINVAL); +	} + +	if (of_property_read_u32(np, "y-size", &pdata->y_max)) { +		dev_err(dev, "failed to get y-size property\n"); +		return ERR_PTR(-EINVAL); +	} + +	return pdata; +} + +static int zforce_probe(struct i2c_client *client, +			const struct i2c_device_id *id) +{ +	const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev); +	struct zforce_ts *ts; +	struct input_dev *input_dev; +	int ret; + +	if (!pdata) { +		pdata = zforce_parse_dt(&client->dev); +		if (IS_ERR(pdata)) +			return PTR_ERR(pdata); +	} + +	ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL); +	if (!ts) +		return -ENOMEM; + +	ret = devm_gpio_request_one(&client->dev, pdata->gpio_int, GPIOF_IN, +				    "zforce_ts_int"); +	if (ret) { +		dev_err(&client->dev, "request of gpio %d failed, %d\n", +			pdata->gpio_int, ret); +		return ret; +	} + +	ret = devm_gpio_request_one(&client->dev, pdata->gpio_rst, +				    GPIOF_OUT_INIT_LOW, "zforce_ts_rst"); +	if (ret) { +		dev_err(&client->dev, "request of gpio %d failed, %d\n", +			pdata->gpio_rst, ret); +		return ret; +	} + +	ret = devm_add_action(&client->dev, zforce_reset, ts); +	if (ret) { +		dev_err(&client->dev, "failed to register reset action, %d\n", +			ret); +		return ret; +	} + +	snprintf(ts->phys, sizeof(ts->phys), +		 "%s/input0", dev_name(&client->dev)); + +	input_dev = devm_input_allocate_device(&client->dev); +	if (!input_dev) { +		dev_err(&client->dev, "could not allocate input device\n"); +		return -ENOMEM; +	} + +	mutex_init(&ts->access_mutex); +	mutex_init(&ts->command_mutex); + +	ts->pdata = pdata; +	ts->client = client; +	ts->input = input_dev; + +	input_dev->name = "Neonode zForce touchscreen"; +	input_dev->phys = ts->phys; +	input_dev->id.bustype = BUS_I2C; + +	input_dev->open = zforce_input_open; +	input_dev->close = zforce_input_close; + +	__set_bit(EV_KEY, input_dev->evbit); +	__set_bit(EV_SYN, input_dev->evbit); +	__set_bit(EV_ABS, input_dev->evbit); + +	/* For multi touch */ +	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, +			     pdata->x_max, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, +			     pdata->y_max, 0, 0); + +	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, +			     ZFORCE_MAX_AREA, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, +			     ZFORCE_MAX_AREA, 0, 0); +	input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); +	input_mt_init_slots(input_dev, ZFORCE_REPORT_POINTS, INPUT_MT_DIRECT); + +	input_set_drvdata(ts->input, ts); + +	init_completion(&ts->command_done); + +	/* +	 * The zforce pulls the interrupt low when it has data ready. +	 * After it is triggered the isr thread runs until all the available +	 * packets have been read and the interrupt is high again. +	 * Therefore we can trigger the interrupt anytime it is low and do +	 * not need to limit it to the interrupt edge. +	 */ +	ret = devm_request_threaded_irq(&client->dev, client->irq, +					zforce_irq, zforce_irq_thread, +					IRQF_TRIGGER_LOW | IRQF_ONESHOT, +					input_dev->name, ts); +	if (ret) { +		dev_err(&client->dev, "irq %d request failed\n", client->irq); +		return ret; +	} + +	i2c_set_clientdata(client, ts); + +	/* let the controller boot */ +	gpio_set_value(pdata->gpio_rst, 1); + +	ts->command_waiting = NOTIFICATION_BOOTCOMPLETE; +	if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) +		dev_warn(&client->dev, "bootcomplete timed out\n"); + +	/* need to start device to get version information */ +	ret = zforce_command_wait(ts, COMMAND_INITIALIZE); +	if (ret) { +		dev_err(&client->dev, "unable to initialize, %d\n", ret); +		return ret; +	} + +	/* this gets the firmware version among other information */ +	ret = zforce_command_wait(ts, COMMAND_STATUS); +	if (ret < 0) { +		dev_err(&client->dev, "couldn't get status, %d\n", ret); +		zforce_stop(ts); +		return ret; +	} + +	/* stop device and put it into sleep until it is opened */ +	ret = zforce_stop(ts); +	if (ret < 0) +		return ret; + +	device_set_wakeup_capable(&client->dev, true); + +	ret = input_register_device(input_dev); +	if (ret) { +		dev_err(&client->dev, "could not register input device, %d\n", +			ret); +		return ret; +	} + +	return 0; +} + +static struct i2c_device_id zforce_idtable[] = { +	{ "zforce-ts", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, zforce_idtable); + +#ifdef CONFIG_OF +static const struct of_device_id zforce_dt_idtable[] = { +	{ .compatible = "neonode,zforce" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, zforce_dt_idtable); +#endif + +static struct i2c_driver zforce_driver = { +	.driver = { +		.owner	= THIS_MODULE, +		.name	= "zforce-ts", +		.pm	= &zforce_pm_ops, +		.of_match_table	= of_match_ptr(zforce_dt_idtable), +	}, +	.probe		= zforce_probe, +	.id_table	= zforce_idtable, +}; + +module_i2c_driver(zforce_driver); + +MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); +MODULE_DESCRIPTION("zForce TouchScreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c index bf0869a7a78..e2ccd683de6 100644 --- a/drivers/input/touchscreen/zylonite-wm97xx.c +++ b/drivers/input/touchscreen/zylonite-wm97xx.c @@ -20,7 +20,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/gpio.h>  #include <linux/irq.h>  | 
