aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r--drivers/input/touchscreen/Kconfig28
-rw-r--r--drivers/input/touchscreen/Makefile3
-rw-r--r--drivers/input/touchscreen/ad7879-i2c.c67
-rw-r--r--drivers/input/touchscreen/ad7879-spi.c131
-rw-r--r--drivers/input/touchscreen/ad7879.c152
-rw-r--r--drivers/input/touchscreen/ad7879.h14
-rw-r--r--drivers/input/touchscreen/ads7846.c2
-rw-r--r--drivers/input/touchscreen/ar1021_i2c.c30
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c1
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c2
-rw-r--r--drivers/input/touchscreen/eeti_ts.c226
-rw-r--r--drivers/input/touchscreen/imx6ul_tsc.c15
-rw-r--r--drivers/input/touchscreen/lpc32xx_ts.c13
-rw-r--r--drivers/input/touchscreen/max11801_ts.c7
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c11
-rw-r--r--drivers/input/touchscreen/mk712.c4
-rw-r--r--drivers/input/touchscreen/mxs-lradc-ts.c714
-rw-r--r--drivers/input/touchscreen/silead.c13
-rw-r--r--drivers/input/touchscreen/sur40.c2
-rw-r--r--drivers/input/touchscreen/tps6507x-ts.c33
-rw-r--r--drivers/input/touchscreen/tsc2007.h101
-rw-r--r--drivers/input/touchscreen/tsc2007_core.c (renamed from drivers/input/touchscreen/tsc2007.c)102
-rw-r--r--drivers/input/touchscreen/tsc2007_iio.c140
23 files changed, 1298 insertions, 513 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 033599777651..cf26ca49ae6d 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -73,6 +73,7 @@ config TOUCHSCREEN_AD7879
config TOUCHSCREEN_AD7879_I2C
tristate "support I2C bus connection"
depends on TOUCHSCREEN_AD7879 && I2C
+ select REGMAP_I2C
help
Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
@@ -82,6 +83,7 @@ config TOUCHSCREEN_AD7879_I2C
config TOUCHSCREEN_AD7879_SPI
tristate "support SPI bus connection"
depends on TOUCHSCREEN_AD7879 && SPI_MASTER
+ select REGMAP_SPI
help
Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
@@ -91,11 +93,11 @@ config TOUCHSCREEN_AD7879_SPI
module will be called ad7879-spi.
config TOUCHSCREEN_AR1021_I2C
- tristate "Microchip AR1021 i2c touchscreen"
+ tristate "Microchip AR1020/1021 i2c touchscreen"
depends on I2C && OF
help
- Say Y here if you have the Microchip AR1021 touchscreen controller
- chip in your system.
+ Say Y here if you have the Microchip AR1020 or AR1021 touchscreen
+ controller chip in your system.
If unsure, say N.
@@ -829,6 +831,16 @@ config TOUCHSCREEN_USB_COMPOSITE
To compile this driver as a module, choose M here: the
module will be called usbtouchscreen.
+config TOUCHSCREEN_MXS_LRADC
+ tristate "Freescale i.MX23/i.MX28 LRADC touchscreen"
+ depends on MFD_MXS_LRADC
+ help
+ Say Y here if you have a touchscreen connected to the low-resolution
+ analog-to-digital converter (LRADC) on an i.MX23 or i.MX28 processor.
+
+ To compile this driver as a module, choose M here: the module will be
+ called mxs-lradc-ts.
+
config TOUCHSCREEN_MX25
tristate "Freescale i.MX25 touchscreen input driver"
depends on MFD_MX25_TSADC
@@ -1023,6 +1035,16 @@ config TOUCHSCREEN_TSC2007
To compile this driver as a module, choose M here: the
module will be called tsc2007.
+config TOUCHSCREEN_TSC2007_IIO
+ bool "IIO interface for external ADC input and temperature"
+ depends on TOUCHSCREEN_TSC2007
+ depends on IIO=y || IIO=TOUCHSCREEN_TSC2007
+ help
+ Saying Y here adds an iio interface to the tsc2007 which
+ provides values for the AUX input (used for e.g. battery
+ or ambient light monitoring), temperature and raw input
+ values.
+
config TOUCHSCREEN_W90X900
tristate "W90P910 touchscreen driver"
depends on ARCH_W90X900
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index b622e5344137..18e476948e44 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o
obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o
obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
@@ -79,6 +80,8 @@ obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o
obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o
obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
+tsc2007-y := tsc2007_core.o
+tsc2007-$(CONFIG_TOUCHSCREEN_TSC2007_IIO) += tsc2007_iio.o
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
index 58f72e0246ab..49b902b10c5f 100644
--- a/drivers/input/touchscreen/ad7879-i2c.c
+++ b/drivers/input/touchscreen/ad7879-i2c.c
@@ -12,53 +12,22 @@
#include <linux/types.h>
#include <linux/of.h>
#include <linux/pm.h>
+#include <linux/regmap.h>
#include "ad7879.h"
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
-/* All registers are word-sized.
- * AD7879 uses a high-byte first convention.
- */
-static int ad7879_i2c_read(struct device *dev, u8 reg)
-{
- struct i2c_client *client = to_i2c_client(dev);
-
- return i2c_smbus_read_word_swapped(client, reg);
-}
-
-static int ad7879_i2c_multi_read(struct device *dev,
- u8 first_reg, u8 count, u16 *buf)
-{
- struct i2c_client *client = to_i2c_client(dev);
- u8 idx;
-
- i2c_smbus_read_i2c_block_data(client, first_reg, count * 2, (u8 *)buf);
-
- for (idx = 0; idx < count; ++idx)
- buf[idx] = swab16(buf[idx]);
-
- return 0;
-}
-
-static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val)
-{
- struct i2c_client *client = to_i2c_client(dev);
-
- return i2c_smbus_write_word_swapped(client, reg, val);
-}
-
-static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
- .bustype = BUS_I2C,
- .read = ad7879_i2c_read,
- .multi_read = ad7879_i2c_multi_read,
- .write = ad7879_i2c_write,
+static const struct regmap_config ad7879_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = 15,
};
static int ad7879_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct ad7879 *ts;
+ struct regmap *regmap;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) {
@@ -66,23 +35,12 @@ static int ad7879_i2c_probe(struct i2c_client *client,
return -EIO;
}
- ts = ad7879_probe(&client->dev, AD7879_DEVID, client->irq,
- &ad7879_i2c_bus_ops);
- if (IS_ERR(ts))
- return PTR_ERR(ts);
-
- i2c_set_clientdata(client, ts);
-
- return 0;
-}
-
-static int ad7879_i2c_remove(struct i2c_client *client)
-{
- struct ad7879 *ts = i2c_get_clientdata(client);
-
- ad7879_remove(ts);
+ regmap = devm_regmap_init_i2c(client, &ad7879_i2c_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- return 0;
+ return ad7879_probe(&client->dev, regmap, client->irq,
+ BUS_I2C, AD7879_DEVID);
}
static const struct i2c_device_id ad7879_id[] = {
@@ -107,12 +65,11 @@ static struct i2c_driver ad7879_i2c_driver = {
.of_match_table = of_match_ptr(ad7879_i2c_dt_ids),
},
.probe = ad7879_i2c_probe,
- .remove = ad7879_i2c_remove,
.id_table = ad7879_id,
};
module_i2c_driver(ad7879_i2c_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c
index d42b6b9af191..3457a5626d75 100644
--- a/drivers/input/touchscreen/ad7879-spi.c
+++ b/drivers/input/touchscreen/ad7879-spi.c
@@ -11,110 +11,28 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/regmap.h>
#include "ad7879.h"
#define AD7879_DEVID 0x7A /* AD7879/AD7889 */
#define MAX_SPI_FREQ_HZ 5000000
-#define AD7879_CMD_MAGIC 0xE000
-#define AD7879_CMD_READ (1 << 10)
-#define AD7879_CMD(reg) (AD7879_CMD_MAGIC | ((reg) & 0xF))
-#define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
-#define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ)
-/*
- * ad7879_read/write are only used for initial setup and for sysfs controls.
- * The main traffic is done in ad7879_collect().
- */
-
-static int ad7879_spi_xfer(struct spi_device *spi,
- u16 cmd, u8 count, u16 *tx_buf, u16 *rx_buf)
-{
- struct spi_message msg;
- struct spi_transfer *xfers;
- void *spi_data;
- u16 *command;
- u16 *_rx_buf = _rx_buf; /* shut gcc up */
- u8 idx;
- int ret;
-
- xfers = spi_data = kzalloc(sizeof(*xfers) * (count + 2), GFP_KERNEL);
- if (!spi_data)
- return -ENOMEM;
-
- spi_message_init(&msg);
-
- command = spi_data;
- command[0] = cmd;
- if (count == 1) {
- /* ad7879_spi_{read,write} gave us buf on stack */
- command[1] = *tx_buf;
- tx_buf = &command[1];
- _rx_buf = rx_buf;
- rx_buf = &command[2];
- }
-
- ++xfers;
- xfers[0].tx_buf = command;
- xfers[0].len = 2;
- spi_message_add_tail(&xfers[0], &msg);
- ++xfers;
-
- for (idx = 0; idx < count; ++idx) {
- if (rx_buf)
- xfers[idx].rx_buf = &rx_buf[idx];
- if (tx_buf)
- xfers[idx].tx_buf = &tx_buf[idx];
- xfers[idx].len = 2;
- spi_message_add_tail(&xfers[idx], &msg);
- }
-
- ret = spi_sync(spi, &msg);
-
- if (count == 1)
- _rx_buf[0] = command[2];
-
- kfree(spi_data);
-
- return ret;
-}
-
-static int ad7879_spi_multi_read(struct device *dev,
- u8 first_reg, u8 count, u16 *buf)
-{
- struct spi_device *spi = to_spi_device(dev);
+#define AD7879_CMD_MAGIC 0xE0
+#define AD7879_CMD_READ BIT(2)
- return ad7879_spi_xfer(spi, AD7879_READCMD(first_reg), count, NULL, buf);
-}
-
-static int ad7879_spi_read(struct device *dev, u8 reg)
-{
- struct spi_device *spi = to_spi_device(dev);
- u16 ret, dummy;
-
- return ad7879_spi_xfer(spi, AD7879_READCMD(reg), 1, &dummy, &ret) ? : ret;
-}
-
-static int ad7879_spi_write(struct device *dev, u8 reg, u16 val)
-{
- struct spi_device *spi = to_spi_device(dev);
- u16 dummy;
-
- return ad7879_spi_xfer(spi, AD7879_WRITECMD(reg), 1, &val, &dummy);
-}
-
-static const struct ad7879_bus_ops ad7879_spi_bus_ops = {
- .bustype = BUS_SPI,
- .read = ad7879_spi_read,
- .multi_read = ad7879_spi_multi_read,
- .write = ad7879_spi_write,
+static const struct regmap_config ad7879_spi_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .max_register = 15,
+ .read_flag_mask = AD7879_CMD_MAGIC | AD7879_CMD_READ,
+ .write_flag_mask = AD7879_CMD_MAGIC,
};
static int ad7879_spi_probe(struct spi_device *spi)
{
- struct ad7879 *ts;
- int err;
+ struct regmap *regmap;
/* don't exceed max specified SPI CLK frequency */
if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
@@ -122,29 +40,11 @@ static int ad7879_spi_probe(struct spi_device *spi)
return -EINVAL;
}
- spi->bits_per_word = 16;
- err = spi_setup(spi);
- if (err) {
- dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n");
- return err;
- }
-
- ts = ad7879_probe(&spi->dev, AD7879_DEVID, spi->irq, &ad7879_spi_bus_ops);
- if (IS_ERR(ts))
- return PTR_ERR(ts);
-
- spi_set_drvdata(spi, ts);
-
- return 0;
-}
-
-static int ad7879_spi_remove(struct spi_device *spi)
-{
- struct ad7879 *ts = spi_get_drvdata(spi);
-
- ad7879_remove(ts);
+ regmap = devm_regmap_init_spi(spi, &ad7879_spi_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- return 0;
+ return ad7879_probe(&spi->dev, regmap, spi->irq, BUS_SPI, AD7879_DEVID);
}
#ifdef CONFIG_OF
@@ -162,12 +62,11 @@ static struct spi_driver ad7879_spi_driver = {
.of_match_table = of_match_ptr(ad7879_spi_dt_ids),
},
.probe = ad7879_spi_probe,
- .remove = ad7879_spi_remove,
};
module_spi_driver(ad7879_spi_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ad7879");
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index e16a44667da7..196028c45210 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -26,9 +26,9 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/spi/spi.h>
-#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/input/touchscreen.h>
@@ -106,8 +106,7 @@ enum {
#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50)
struct ad7879 {
- const struct ad7879_bus_ops *bops;
-
+ struct regmap *regmap;
struct device *dev;
struct input_dev *input;
struct timer_list timer;
@@ -137,17 +136,32 @@ struct ad7879 {
static int ad7879_read(struct ad7879 *ts, u8 reg)
{
- return ts->bops->read(ts->dev, reg);
-}
+ unsigned int val;
+ int error;
-static int ad7879_multi_read(struct ad7879 *ts, u8 first_reg, u8 count, u16 *buf)
-{
- return ts->bops->multi_read(ts->dev, first_reg, count, buf);
+ error = regmap_read(ts->regmap, reg, &val);
+ if (error) {
+ dev_err(ts->dev, "failed to read register %#02x: %d\n",
+ reg, error);
+ return error;
+ }
+
+ return val;
}
static int ad7879_write(struct ad7879 *ts, u8 reg, u16 val)
{
- return ts->bops->write(ts->dev, reg, val);
+ int error;
+
+ error = regmap_write(ts->regmap, reg, val);
+ if (error) {
+ dev_err(ts->dev,
+ "failed to write %#04x to register %#02x: %d\n",
+ val, reg, error);
+ return error;
+ }
+
+ return 0;
}
static int ad7879_report(struct ad7879 *ts)
@@ -234,7 +248,8 @@ static irqreturn_t ad7879_irq(int irq, void *handle)
{
struct ad7879 *ts = handle;
- ad7879_multi_read(ts, AD7879_REG_XPLUS, AD7879_NR_SENSE, ts->conversion_data);
+ regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS,
+ ts->conversion_data, AD7879_NR_SENSE);
if (!ad7879_report(ts))
mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
@@ -440,23 +455,34 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip,
static int ad7879_gpio_add(struct ad7879 *ts,
const struct ad7879_platform_data *pdata)
{
+ bool gpio_export;
+ int gpio_base;
int ret = 0;
+ if (pdata) {
+ gpio_export = pdata->gpio_export;
+ gpio_base = pdata->gpio_base;
+ } else {
+ gpio_export = device_property_read_bool(ts->dev,
+ "gpio-controller");
+ gpio_base = -1;
+ }
+
mutex_init(&ts->mutex);
- if (pdata->gpio_export) {
+ if (gpio_export) {
ts->gc.direction_input = ad7879_gpio_direction_input;
ts->gc.direction_output = ad7879_gpio_direction_output;
ts->gc.get = ad7879_gpio_get_value;
ts->gc.set = ad7879_gpio_set_value;
ts->gc.can_sleep = 1;
- ts->gc.base = pdata->gpio_base;
+ ts->gc.base = gpio_base;
ts->gc.ngpio = 1;
ts->gc.label = "AD7879-GPIO";
ts->gc.owner = THIS_MODULE;
ts->gc.parent = ts->dev;
- ret = gpiochip_add_data(&ts->gc, ts);
+ ret = devm_gpiochip_add_data(ts->dev, &ts->gc, ts);
if (ret)
dev_err(ts->dev, "failed to register gpio %d\n",
ts->gc.base);
@@ -464,25 +490,12 @@ static int ad7879_gpio_add(struct ad7879 *ts,
return ret;
}
-
-static void ad7879_gpio_remove(struct ad7879 *ts)
-{
- const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev);
-
- if (pdata && pdata->gpio_export)
- gpiochip_remove(&ts->gc);
-
-}
#else
-static inline int ad7879_gpio_add(struct ad7879 *ts,
- const struct ad7879_platform_data *pdata)
+static int ad7879_gpio_add(struct ad7879 *ts,
+ const struct ad7879_platform_data *pdata)
{
return 0;
}
-
-static inline void ad7879_gpio_remove(struct ad7879 *ts)
-{
-}
#endif
static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts)
@@ -511,8 +524,15 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts)
return 0;
}
-struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
- const struct ad7879_bus_ops *bops)
+static void ad7879_cleanup_sysfs(void *_ts)
+{
+ struct ad7879 *ts = _ts;
+
+ sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
+}
+
+int ad7879_probe(struct device *dev, struct regmap *regmap,
+ int irq, u16 bustype, u8 devid)
{
struct ad7879_platform_data *pdata = dev_get_platdata(dev);
struct ad7879 *ts;
@@ -520,14 +540,14 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
int err;
u16 revid;
- if (!irq) {
+ if (irq <= 0) {
dev_err(dev, "No IRQ specified\n");
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
if (pdata) {
/* Platform data use swapped axis (backward compatibility) */
@@ -540,23 +560,22 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
ts->averaging = pdata->averaging;
ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
ts->median = pdata->median;
- } else if (dev->of_node) {
- ad7879_parse_dt(dev, ts);
} else {
- dev_err(dev, "No platform data\n");
- return ERR_PTR(-EINVAL);
+ err = ad7879_parse_dt(dev, ts);
+ if (err)
+ return err;
}
input_dev = devm_input_allocate_device(dev);
if (!input_dev) {
dev_err(dev, "Failed to allocate input device\n");
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
}
- ts->bops = bops;
ts->dev = dev;
ts->input = input_dev;
ts->irq = irq;
+ ts->regmap = regmap;
setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
@@ -564,20 +583,14 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
input_dev->name = "AD7879 Touchscreen";
input_dev->phys = ts->phys;
input_dev->dev.parent = dev;
- input_dev->id.bustype = bops->bustype;
+ input_dev->id.bustype = bustype;
input_dev->open = ad7879_open;
input_dev->close = ad7879_close;
input_set_drvdata(input_dev, ts);
- __set_bit(EV_ABS, input_dev->evbit);
- __set_bit(ABS_X, input_dev->absbit);
- __set_bit(ABS_Y, input_dev->absbit);
- __set_bit(ABS_PRESSURE, input_dev->absbit);
-
- __set_bit(EV_KEY, input_dev->evbit);
- __set_bit(BTN_TOUCH, input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
if (pdata) {
input_set_abs_params(input_dev, ABS_X,
@@ -595,17 +608,18 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
} else {
input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
+ input_set_capability(input_dev, EV_ABS, ABS_PRESSURE);
touchscreen_parse_properties(input_dev, false, NULL);
if (!input_abs_get_max(input_dev, ABS_PRESSURE)) {
dev_err(dev, "Touchscreen pressure is not specified\n");
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
}
err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET);
if (err < 0) {
dev_err(dev, "Failed to write %s\n", input_dev->name);
- return ERR_PTR(err);
+ return err;
}
revid = ad7879_read(ts, AD7879_REG_REVID);
@@ -614,7 +628,7 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
if (input_dev->id.product != devid) {
dev_err(dev, "Failed to probe %s (%x vs %x)\n",
input_dev->name, devid, revid);
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
}
ts->cmd_crtl3 = AD7879_YPLUS_BIT |
@@ -639,43 +653,33 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
dev_name(dev), ts);
if (err) {
dev_err(dev, "Failed to request IRQ: %d\n", err);
- return ERR_PTR(err);
+ return err;
}
__ad7879_disable(ts);
err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
if (err)
- goto err_out;
+ return err;
- if (pdata) {
- err = ad7879_gpio_add(ts, pdata);
- if (err)
- goto err_remove_attr;
- }
+ err = devm_add_action_or_reset(dev, ad7879_cleanup_sysfs, ts);
+ if (err)
+ return err;
+
+ err = ad7879_gpio_add(ts, pdata);
+ if (err)
+ return err;
err = input_register_device(input_dev);
if (err)
- goto err_remove_gpio;
+ return err;
- return ts;
+ dev_set_drvdata(dev, ts);
-err_remove_gpio:
- ad7879_gpio_remove(ts);
-err_remove_attr:
- sysfs_remove_group(&dev->kobj, &ad7879_attr_group);
-err_out:
- return ERR_PTR(err);
+ return 0;
}
EXPORT_SYMBOL(ad7879_probe);
-void ad7879_remove(struct ad7879 *ts)
-{
- ad7879_gpio_remove(ts);
- sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
-}
-EXPORT_SYMBOL(ad7879_remove);
-
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h
index 6fd13c48d373..7e43066a4b68 100644
--- a/drivers/input/touchscreen/ad7879.h
+++ b/drivers/input/touchscreen/ad7879.h
@@ -11,20 +11,12 @@
#include <linux/types.h>
-struct ad7879;
struct device;
-
-struct ad7879_bus_ops {
- u16 bustype;
- int (*read)(struct device *dev, u8 reg);
- int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf);
- int (*write)(struct device *dev, u8 reg, u16 val);
-};
+struct regmap;
extern const struct dev_pm_ops ad7879_pm_ops;
-struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq,
- const struct ad7879_bus_ops *bops);
-void ad7879_remove(struct ad7879 *);
+int ad7879_probe(struct device *dev, struct regmap *regmap,
+ int irq, u16 bustype, u8 devid);
#endif
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index f5793e3d945f..735a0be1ad95 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -871,7 +871,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
msecs_to_jiffies(TS_POLL_PERIOD));
}
- if (ts->pendown) {
+ if (ts->pendown && !ts->stopped) {
struct input_dev *input = ts->input;
input_report_key(input, BTN_TOUCH, 0);
diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c
index 6562b17117f7..f9dcbd63e598 100644
--- a/drivers/input/touchscreen/ar1021_i2c.c
+++ b/drivers/input/touchscreen/ar1021_i2c.c
@@ -1,11 +1,12 @@
/*
- * Microchip AR1021 driver for I2C
+ * Microchip AR1020 and AR1021 driver for I2C
*
* Author: Christian Gmeiner <christian.gmeiner@gmail.com>
*
* License: GPLv2 as published by the FSF.
*/
+#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/of.h>
@@ -18,6 +19,10 @@
#define AR1021_MAX_X 4095
#define AR1021_MAX_Y 4095
+#define AR1021_CMD 0x55
+
+#define AR1021_CMD_ENABLE_TOUCH 0x12
+
struct ar1021_i2c {
struct i2c_client *client;
struct input_dev *input;
@@ -33,12 +38,12 @@ static irqreturn_t ar1021_i2c_irq(int irq, void *dev_id)
int retval;
retval = i2c_master_recv(ar1021->client,
- ar1021->data, sizeof(ar1021->data));
+ ar1021->data, sizeof(ar1021->data));
if (retval != sizeof(ar1021->data))
goto out;
/* sync bit set ? */
- if ((data[0] & 0x80) == 0)
+ if (!(data[0] & BIT(7)))
goto out;
button = data[0] & BIT(0);
@@ -56,8 +61,19 @@ out:
static int ar1021_i2c_open(struct input_dev *dev)
{
+ static const u8 cmd_enable_touch[] = {
+ AR1021_CMD,
+ 0x01, /* number of bytes after this */
+ AR1021_CMD_ENABLE_TOUCH
+ };
struct ar1021_i2c *ar1021 = input_get_drvdata(dev);
struct i2c_client *client = ar1021->client;
+ int error;
+
+ error = i2c_master_send(ar1021->client, cmd_enable_touch,
+ sizeof(cmd_enable_touch));
+ if (error < 0)
+ return error;
enable_irq(client->irq);
@@ -73,7 +89,7 @@ static void ar1021_i2c_close(struct input_dev *dev)
}
static int ar1021_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct ar1021_i2c *ar1021;
struct input_dev *input;
@@ -109,7 +125,7 @@ static int ar1021_i2c_probe(struct i2c_client *client,
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, ar1021_i2c_irq,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ IRQF_ONESHOT,
"ar1021_i2c", ar1021);
if (error) {
dev_err(&client->dev,
@@ -151,7 +167,7 @@ static int __maybe_unused ar1021_i2c_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume);
static const struct i2c_device_id ar1021_i2c_id[] = {
- { "MICROCHIP_AR1021_I2C", 0 },
+ { "ar1021", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id);
@@ -175,5 +191,5 @@ static struct i2c_driver ar1021_i2c_driver = {
module_i2c_driver(ar1021_i2c_driver);
MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
-MODULE_DESCRIPTION("Microchip AR1021 I2C Driver");
+MODULE_DESCRIPTION("Microchip AR1020 and AR1021 I2C Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2302aef2b2d4..dd042a9b0aaa 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -350,6 +350,7 @@ static bool mxt_object_readable(unsigned int type)
case MXT_TOUCH_KEYARRAY_T15:
case MXT_TOUCH_PROXIMITY_T23:
case MXT_TOUCH_PROXKEY_T52:
+ case MXT_TOUCH_MULTITOUCHSCREEN_T100:
case MXT_PROCI_GRIPFACE_T20:
case MXT_PROCG_NOISE_T22:
case MXT_PROCI_ONETOUCH_T24:
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 8cf8d8d5d4ef..f872817e81e4 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -471,7 +471,7 @@ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
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);
+ M09_REGISTER_THRESHOLD, 0, 80);
static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
NO_REGISTER, 3, 14);
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 16023867b9da..2facad75eb6d 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -31,9 +31,9 @@
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/timer.h>
-#include <linux/gpio.h>
-#include <linux/input/eeti_ts.h>
+#include <linux/gpio/consumer.h>
#include <linux/slab.h>
+#include <asm/unaligned.h>
static bool flip_x;
module_param(flip_x, bool, 0644);
@@ -43,54 +43,31 @@ static bool flip_y;
module_param(flip_y, bool, 0644);
MODULE_PARM_DESC(flip_y, "flip y coordinate");
-struct eeti_ts_priv {
+struct eeti_ts {
struct i2c_client *client;
struct input_dev *input;
- struct work_struct work;
- struct mutex mutex;
- int irq_gpio, irq, irq_active_high;
+ struct gpio_desc *attn_gpio;
+ bool running;
};
#define EETI_TS_BITDEPTH (11)
#define EETI_MAXVAL ((1 << (EETI_TS_BITDEPTH + 1)) - 1)
-#define REPORT_BIT_PRESSED (1 << 0)
-#define REPORT_BIT_AD0 (1 << 1)
-#define REPORT_BIT_AD1 (1 << 2)
-#define REPORT_BIT_HAS_PRESSURE (1 << 6)
+#define REPORT_BIT_PRESSED BIT(0)
+#define REPORT_BIT_AD0 BIT(1)
+#define REPORT_BIT_AD1 BIT(2)
+#define REPORT_BIT_HAS_PRESSURE BIT(6)
#define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH)
-static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
+static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf)
{
- return gpio_get_value(priv->irq_gpio) == priv->irq_active_high;
-}
-
-static void eeti_ts_read(struct work_struct *work)
-{
- char buf[6];
- unsigned int x, y, res, pressed, to = 100;
- struct eeti_ts_priv *priv =
- container_of(work, struct eeti_ts_priv, work);
+ unsigned int res;
+ u16 x, y;
- mutex_lock(&priv->mutex);
-
- while (eeti_ts_irq_active(priv) && --to)
- i2c_master_recv(priv->client, buf, sizeof(buf));
-
- if (!to) {
- dev_err(&priv->client->dev,
- "unable to clear IRQ - line stuck?\n");
- goto out;
- }
-
- /* drop non-report packets */
- if (!(buf[0] & 0x80))
- goto out;
-
- pressed = buf[0] & REPORT_BIT_PRESSED;
res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1));
- x = buf[2] | (buf[1] << 8);
- y = buf[4] | (buf[3] << 8);
+
+ x = get_unaligned_be16(&buf[1]);
+ y = get_unaligned_be16(&buf[3]);
/* fix the range to 11 bits */
x >>= res - EETI_TS_BITDEPTH;
@@ -103,65 +80,78 @@ static void eeti_ts_read(struct work_struct *work)
y = EETI_MAXVAL - y;
if (buf[0] & REPORT_BIT_HAS_PRESSURE)
- input_report_abs(priv->input, ABS_PRESSURE, buf[5]);
+ input_report_abs(eeti->input, ABS_PRESSURE, buf[5]);
- input_report_abs(priv->input, ABS_X, x);
- input_report_abs(priv->input, ABS_Y, y);
- input_report_key(priv->input, BTN_TOUCH, !!pressed);
- input_sync(priv->input);
-
-out:
- mutex_unlock(&priv->mutex);
+ input_report_abs(eeti->input, ABS_X, x);
+ input_report_abs(eeti->input, ABS_Y, y);
+ input_report_key(eeti->input, BTN_TOUCH, buf[0] & REPORT_BIT_PRESSED);
+ input_sync(eeti->input);
}
static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
{
- struct eeti_ts_priv *priv = dev_id;
+ struct eeti_ts *eeti = dev_id;
+ int len;
+ int error;
+ char buf[6];
- /* postpone I2C transactions as we are atomic */
- schedule_work(&priv->work);
+ do {
+ len = i2c_master_recv(eeti->client, buf, sizeof(buf));
+ if (len != sizeof(buf)) {
+ error = len < 0 ? len : -EIO;
+ dev_err(&eeti->client->dev,
+ "failed to read touchscreen data: %d\n",
+ error);
+ break;
+ }
+
+ if (buf[0] & 0x80) {
+ /* Motion packet */
+ eeti_ts_report_event(eeti, buf);
+ }
+ } while (eeti->running &&
+ eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio));
return IRQ_HANDLED;
}
-static void eeti_ts_start(struct eeti_ts_priv *priv)
+static void eeti_ts_start(struct eeti_ts *eeti)
{
- enable_irq(priv->irq);
-
- /* Read the events once to arm the IRQ */
- eeti_ts_read(&priv->work);
+ eeti->running = true;
+ wmb();
+ enable_irq(eeti->client->irq);
}
-static void eeti_ts_stop(struct eeti_ts_priv *priv)
+static void eeti_ts_stop(struct eeti_ts *eeti)
{
- disable_irq(priv->irq);
- cancel_work_sync(&priv->work);
+ eeti->running = false;
+ wmb();
+ disable_irq(eeti->client->irq);
}
static int eeti_ts_open(struct input_dev *dev)
{
- struct eeti_ts_priv *priv = input_get_drvdata(dev);
+ struct eeti_ts *eeti = input_get_drvdata(dev);
- eeti_ts_start(priv);
+ eeti_ts_start(eeti);
return 0;
}
static void eeti_ts_close(struct input_dev *dev)
{
- struct eeti_ts_priv *priv = input_get_drvdata(dev);
+ struct eeti_ts *eeti = input_get_drvdata(dev);
- eeti_ts_stop(priv);
+ eeti_ts_stop(eeti);
}
static int eeti_ts_probe(struct i2c_client *client,
- const struct i2c_device_id *idp)
+ const struct i2c_device_id *idp)
{
- struct eeti_ts_platform_data *pdata = dev_get_platdata(&client->dev);
- struct eeti_ts_priv *priv;
+ struct device *dev = &client->dev;
+ struct eeti_ts *eeti;
struct input_dev *input;
- unsigned int irq_flags;
- int err = -ENOMEM;
+ int error;
/*
* In contrast to what's described in the datasheet, there seems
@@ -170,21 +160,19 @@ static int eeti_ts_probe(struct i2c_client *client,
* for interrupts to occur.
*/
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(&client->dev, "failed to allocate driver data\n");
+ eeti = devm_kzalloc(dev, sizeof(*eeti), GFP_KERNEL);
+ if (!eeti) {
+ dev_err(dev, "failed to allocate driver data\n");
return -ENOMEM;
}
- mutex_init(&priv->mutex);
- input = input_allocate_device();
+ input = devm_input_allocate_device(dev);
if (!input) {
- dev_err(&client->dev, "Failed to allocate input device.\n");
- goto err1;
+ dev_err(dev, "Failed to allocate input device.\n");
+ return -ENOMEM;
}
- input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_capability(input, EV_KEY, BTN_TOUCH);
input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0);
input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0);
@@ -192,71 +180,38 @@ static int eeti_ts_probe(struct i2c_client *client,
input->name = client->name;
input->id.bustype = BUS_I2C;
- input->dev.parent = &client->dev;
input->open = eeti_ts_open;
input->close = eeti_ts_close;
- priv->client = client;
- priv->input = input;
- priv->irq_gpio = pdata->irq_gpio;
- priv->irq = gpio_to_irq(pdata->irq_gpio);
-
- err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name);
- if (err < 0)
- goto err1;
-
- priv->irq_active_high = pdata->irq_active_high;
-
- irq_flags = priv->irq_active_high ?
- IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
+ eeti->client = client;
+ eeti->input = input;
- INIT_WORK(&priv->work, eeti_ts_read);
- i2c_set_clientdata(client, priv);
- input_set_drvdata(input, priv);
+ eeti->attn_gpio = devm_gpiod_get_optional(dev, "attn", GPIOD_IN);
+ if (IS_ERR(eeti->attn_gpio))
+ return PTR_ERR(eeti->attn_gpio);
- err = input_register_device(input);
- if (err)
- goto err2;
+ i2c_set_clientdata(client, eeti);
+ input_set_drvdata(input, eeti);
- err = request_irq(priv->irq, eeti_ts_isr, irq_flags,
- client->name, priv);
- if (err) {
- dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
- goto err3;
+ error = devm_request_threaded_irq(dev, client->irq,
+ NULL, eeti_ts_isr,
+ IRQF_ONESHOT,
+ client->name, eeti);
+ if (error) {
+ dev_err(dev, "Unable to request touchscreen IRQ: %d\n",
+ error);
+ return error;
}
/*
* Disable the device for now. It will be enabled once the
* input device is opened.
*/
- eeti_ts_stop(priv);
-
- return 0;
-
-err3:
- input_unregister_device(input);
- input = NULL; /* so we dont try to free it below */
-err2:
- gpio_free(pdata->irq_gpio);
-err1:
- input_free_device(input);
- kfree(priv);
- return err;
-}
-
-static int eeti_ts_remove(struct i2c_client *client)
-{
- struct eeti_ts_priv *priv = i2c_get_clientdata(client);
-
- free_irq(priv->irq, priv);
- /*
- * eeti_ts_stop() leaves IRQ disabled. We need to re-enable it
- * so that device still works if we reload the driver.
- */
- enable_irq(priv->irq);
+ eeti_ts_stop(eeti);
- input_unregister_device(priv->input);
- kfree(priv);
+ error = input_register_device(input);
+ if (error)
+ return error;
return 0;
}
@@ -264,18 +219,18 @@ static int eeti_ts_remove(struct i2c_client *client)
static int __maybe_unused eeti_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
- struct eeti_ts_priv *priv = i2c_get_clientdata(client);
- struct input_dev *input_dev = priv->input;
+ struct eeti_ts *eeti = i2c_get_clientdata(client);
+ struct input_dev *input_dev = eeti->input;
mutex_lock(&input_dev->mutex);
if (input_dev->users)
- eeti_ts_stop(priv);
+ eeti_ts_stop(eeti);
mutex_unlock(&input_dev->mutex);
if (device_may_wakeup(&client->dev))
- enable_irq_wake(priv->irq);
+ enable_irq_wake(client->irq);
return 0;
}
@@ -283,16 +238,16 @@ static int __maybe_unused eeti_ts_suspend(struct device *dev)
static int __maybe_unused eeti_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
- struct eeti_ts_priv *priv = i2c_get_clientdata(client);
- struct input_dev *input_dev = priv->input;
+ struct eeti_ts *eeti = i2c_get_clientdata(client);
+ struct input_dev *input_dev = eeti->input;
if (device_may_wakeup(&client->dev))
- disable_irq_wake(priv->irq);
+ disable_irq_wake(client->irq);
mutex_lock(&input_dev->mutex);
if (input_dev->users)
- eeti_ts_start(priv);
+ eeti_ts_start(eeti);
mutex_unlock(&input_dev->mutex);
@@ -313,7 +268,6 @@ static struct i2c_driver eeti_ts_driver = {
.pm = &eeti_ts_pm,
},
.probe = eeti_ts_probe,
- .remove = eeti_ts_remove,
.id_table = eeti_ts_id,
};
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index 7098e0a47019..ee82a975bfd2 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -337,11 +337,20 @@ static int imx6ul_tsc_open(struct input_dev *input_dev)
dev_err(tsc->dev,
"Could not prepare or enable the tsc clock: %d\n",
err);
- clk_disable_unprepare(tsc->adc_clk);
- return err;
+ goto disable_adc_clk;
}
- return imx6ul_tsc_init(tsc);
+ err = imx6ul_tsc_init(tsc);
+ if (err)
+ goto disable_tsc_clk;
+
+ return 0;
+
+disable_tsc_clk:
+ clk_disable_unprepare(tsc->tsc_clk);
+disable_adc_clk:
+ clk_disable_unprepare(tsc->adc_clk);
+ return err;
}
static void imx6ul_tsc_close(struct input_dev *input_dev)
diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c
index e0baa7de4102..4eb31ec10b18 100644
--- a/drivers/input/touchscreen/lpc32xx_ts.c
+++ b/drivers/input/touchscreen/lpc32xx_ts.c
@@ -142,11 +142,14 @@ static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)
clk_disable_unprepare(tsc->clk);
}
-static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
+static int lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
{
u32 tmp;
+ int err;
- clk_prepare_enable(tsc->clk);
+ err = clk_prepare_enable(tsc->clk);
+ if (err)
+ return err;
tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;
@@ -184,15 +187,15 @@ static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
/* Enable automatic ts event capture */
tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN);
+
+ return 0;
}
static int lpc32xx_ts_open(struct input_dev *dev)
{
struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
- lpc32xx_setup_tsc(tsc);
-
- return 0;
+ return lpc32xx_setup_tsc(tsc);
}
static void lpc32xx_ts_close(struct input_dev *dev)
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
index a595ae5284e3..72ca3efb5781 100644
--- a/drivers/input/touchscreen/max11801_ts.c
+++ b/drivers/input/touchscreen/max11801_ts.c
@@ -224,9 +224,16 @@ static const struct i2c_device_id max11801_ts_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
+static const struct of_device_id max11801_ts_dt_ids[] = {
+ { .compatible = "maxim,max11801" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, max11801_ts_dt_ids);
+
static struct i2c_driver max11801_ts_driver = {
.driver = {
.name = "max11801_ts",
+ .of_match_table = max11801_ts_dt_ids,
},
.id_table = max11801_ts_id,
.probe = max11801_ts_probe,
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index 703d7f983d0a..05108c2fea93 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -253,10 +253,21 @@ static int mip4_get_fw_version(struct mip4_ts *ts)
*/
static int mip4_query_device(struct mip4_ts *ts)
{
+ union i2c_smbus_data dummy;
int error;
u8 cmd[2];
u8 buf[14];
+ /*
+ * Make sure there is something at this address as we do not
+ * consider subsequent failures as fatal.
+ */
+ if (i2c_smbus_xfer(ts->client->adapter, ts->client->addr,
+ 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) {
+ dev_err(&ts->client->dev, "nothing at this address\n");
+ return -ENXIO;
+ }
+
/* Product name */
cmd[0] = MIP4_R0_INFO;
cmd[1] = MIP4_R1_INFO_PRODUCT_NAME;
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index 36e57deacd03..bd5352824f77 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -50,11 +50,11 @@ MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
MODULE_LICENSE("GPL");
static unsigned int mk712_io = 0x260; /* Also 0x200, 0x208, 0x300 */
-module_param_named(io, mk712_io, uint, 0);
+module_param_hw_named(io, mk712_io, uint, ioport, 0);
MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
static unsigned int mk712_irq = 10; /* Also 12, 14, 15 */
-module_param_named(irq, mk712_irq, uint, 0);
+module_param_hw_named(irq, mk712_irq, uint, irq, 0);
MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
/* eight 8-bit registers */
diff --git a/drivers/input/touchscreen/mxs-lradc-ts.c b/drivers/input/touchscreen/mxs-lradc-ts.c
new file mode 100644
index 000000000000..58c016cd6809
--- /dev/null
+++ b/drivers/input/touchscreen/mxs-lradc-ts.c
@@ -0,0 +1,714 @@
+/*
+ * Freescale MXS LRADC touchscreen driver
+ *
+ * Copyright (c) 2012 DENX Software Engineering, GmbH.
+ * Copyright (c) 2017 Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
+ *
+ * Authors:
+ * Marek Vasut <marex@denx.de>
+ * Ksenija Stanojevic <ksenija.stanojevic@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.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mxs-lradc.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+const char *mxs_lradc_ts_irq_names[] = {
+ "mxs-lradc-touchscreen",
+ "mxs-lradc-channel6",
+ "mxs-lradc-channel7",
+};
+
+/*
+ * Touchscreen handling
+ */
+enum mxs_lradc_ts_plate {
+ LRADC_TOUCH = 0,
+ LRADC_SAMPLE_X,
+ LRADC_SAMPLE_Y,
+ LRADC_SAMPLE_PRESSURE,
+ LRADC_SAMPLE_VALID,
+};
+
+struct mxs_lradc_ts {
+ struct mxs_lradc *lradc;
+ struct device *dev;
+
+ void __iomem *base;
+ /*
+ * When the touchscreen is enabled, we give it two private virtual
+ * channels: #6 and #7. This means that only 6 virtual channels (instead
+ * of 8) will be available for buffered capture.
+ */
+#define TOUCHSCREEN_VCHANNEL1 7
+#define TOUCHSCREEN_VCHANNEL2 6
+
+ struct input_dev *ts_input;
+
+ enum mxs_lradc_ts_plate cur_plate; /* state machine */
+ bool ts_valid;
+ unsigned int ts_x_pos;
+ unsigned int ts_y_pos;
+ unsigned int ts_pressure;
+
+ /* handle touchscreen's physical behaviour */
+ /* samples per coordinate */
+ unsigned int over_sample_cnt;
+ /* time clocks between samples */
+ unsigned int over_sample_delay;
+ /* time in clocks to wait after the plates where switched */
+ unsigned int settling_delay;
+ spinlock_t lock;
+};
+
+struct state_info {
+ u32 mask;
+ u32 bit;
+ u32 x_plate;
+ u32 y_plate;
+ u32 pressure;
+};
+
+static struct state_info info[] = {
+ {LRADC_CTRL0_MX23_PLATE_MASK, LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE,
+ LRADC_CTRL0_MX23_XP | LRADC_CTRL0_MX23_XM,
+ LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_YM,
+ LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_XM},
+ {LRADC_CTRL0_MX28_PLATE_MASK, LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE,
+ LRADC_CTRL0_MX28_XPPSW | LRADC_CTRL0_MX28_XNNSW,
+ LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_YNNSW,
+ LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_XNNSW}
+};
+
+static bool mxs_lradc_check_touch_event(struct mxs_lradc_ts *ts)
+{
+ return !!(readl(ts->base + LRADC_STATUS) &
+ LRADC_STATUS_TOUCH_DETECT_RAW);
+}
+
+static void mxs_lradc_map_ts_channel(struct mxs_lradc_ts *ts, unsigned int vch,
+ unsigned int ch)
+{
+ writel(LRADC_CTRL4_LRADCSELECT_MASK(vch),
+ ts->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR);
+ writel(LRADC_CTRL4_LRADCSELECT(vch, ch),
+ ts->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET);
+}
+
+static void mxs_lradc_setup_ts_channel(struct mxs_lradc_ts *ts, unsigned int ch)
+{
+ /*
+ * prepare for oversampling conversion
+ *
+ * from the datasheet:
+ * "The ACCUMULATE bit in the appropriate channel register
+ * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0;
+ * otherwise, the IRQs will not fire."
+ */
+ writel(LRADC_CH_ACCUMULATE |
+ LRADC_CH_NUM_SAMPLES(ts->over_sample_cnt - 1),
+ ts->base + LRADC_CH(ch));
+
+ /* from the datasheet:
+ * "Software must clear this register in preparation for a
+ * multi-cycle accumulation.
+ */
+ writel(LRADC_CH_VALUE_MASK,
+ ts->base + LRADC_CH(ch) + STMP_OFFSET_REG_CLR);
+
+ /*
+ * prepare the delay/loop unit according to the oversampling count
+ *
+ * from the datasheet:
+ * "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1,
+ * HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise,
+ * the LRADC will not trigger the delay group."
+ */
+ writel(LRADC_DELAY_TRIGGER(1 << ch) | LRADC_DELAY_TRIGGER_DELAYS(0) |
+ LRADC_DELAY_LOOP(ts->over_sample_cnt - 1) |
+ LRADC_DELAY_DELAY(ts->over_sample_delay - 1),
+ ts->base + LRADC_DELAY(3));
+
+ writel(LRADC_CTRL1_LRADC_IRQ(ch),
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+ /*
+ * after changing the touchscreen plates setting
+ * the signals need some initial time to settle. Start the
+ * SoC's delay unit and start the conversion later
+ * and automatically.
+ */
+ writel(LRADC_DELAY_TRIGGER(0) | LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) |
+ LRADC_DELAY_KICK | LRADC_DELAY_DELAY(ts->settling_delay),
+ ts->base + LRADC_DELAY(2));
+}
+
+/*
+ * Pressure detection is special:
+ * We want to do both required measurements for the pressure detection in
+ * one turn. Use the hardware features to chain both conversions and let the
+ * hardware report one interrupt if both conversions are done
+ */
+static void mxs_lradc_setup_ts_pressure(struct mxs_lradc_ts *ts,
+ unsigned int ch1, unsigned int ch2)
+{
+ u32 reg;
+
+ /*
+ * prepare for oversampling conversion
+ *
+ * from the datasheet:
+ * "The ACCUMULATE bit in the appropriate channel register
+ * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0;
+ * otherwise, the IRQs will not fire."
+ */
+ reg = LRADC_CH_ACCUMULATE |
+ LRADC_CH_NUM_SAMPLES(ts->over_sample_cnt - 1);
+ writel(reg, ts->base + LRADC_CH(ch1));
+ writel(reg, ts->base + LRADC_CH(ch2));
+
+ /* from the datasheet:
+ * "Software must clear this register in preparation for a
+ * multi-cycle accumulation.
+ */
+ writel(LRADC_CH_VALUE_MASK,
+ ts->base + LRADC_CH(ch1) + STMP_OFFSET_REG_CLR);
+ writel(LRADC_CH_VALUE_MASK,
+ ts->base + LRADC_CH(ch2) + STMP_OFFSET_REG_CLR);
+
+ /* prepare the delay/loop unit according to the oversampling count */
+ writel(LRADC_DELAY_TRIGGER(1 << ch1) | LRADC_DELAY_TRIGGER(1 << ch2) |
+ LRADC_DELAY_TRIGGER_DELAYS(0) |
+ LRADC_DELAY_LOOP(ts->over_sample_cnt - 1) |
+ LRADC_DELAY_DELAY(ts->over_sample_delay - 1),
+ ts->base + LRADC_DELAY(3));
+
+ writel(LRADC_CTRL1_LRADC_IRQ(ch2),
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+ /*
+ * after changing the touchscreen plates setting
+ * the signals need some initial time to settle. Start the
+ * SoC's delay unit and start the conversion later
+ * and automatically.
+ */
+ writel(LRADC_DELAY_TRIGGER(0) | LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) |
+ LRADC_DELAY_KICK | LRADC_DELAY_DELAY(ts->settling_delay),
+ ts->base + LRADC_DELAY(2));
+}
+
+static unsigned int mxs_lradc_ts_read_raw_channel(struct mxs_lradc_ts *ts,
+ unsigned int channel)
+{
+ u32 reg;
+ unsigned int num_samples, val;
+
+ reg = readl(ts->base + LRADC_CH(channel));
+ if (reg & LRADC_CH_ACCUMULATE)
+ num_samples = ts->over_sample_cnt;
+ else
+ num_samples = 1;
+
+ val = (reg & LRADC_CH_VALUE_MASK) >> LRADC_CH_VALUE_OFFSET;
+ return val / num_samples;
+}
+
+static unsigned int mxs_lradc_read_ts_pressure(struct mxs_lradc_ts *ts,
+ unsigned int ch1, unsigned int ch2)
+{
+ u32 reg, mask;
+ unsigned int pressure, m1, m2;
+
+ mask = LRADC_CTRL1_LRADC_IRQ(ch1) | LRADC_CTRL1_LRADC_IRQ(ch2);
+ reg = readl(ts->base + LRADC_CTRL1) & mask;
+
+ while (reg != mask) {
+ reg = readl(ts->base + LRADC_CTRL1) & mask;
+ dev_dbg(ts->dev, "One channel is still busy: %X\n", reg);
+ }
+
+ m1 = mxs_lradc_ts_read_raw_channel(ts, ch1);
+ m2 = mxs_lradc_ts_read_raw_channel(ts, ch2);
+
+ if (m2 == 0) {
+ dev_warn(ts->dev, "Cannot calculate pressure\n");
+ return 1 << (LRADC_RESOLUTION - 1);
+ }
+
+ /* simply scale the value from 0 ... max ADC resolution */
+ pressure = m1;
+ pressure *= (1 << LRADC_RESOLUTION);
+ pressure /= m2;
+
+ dev_dbg(ts->dev, "Pressure = %u\n", pressure);
+ return pressure;
+}
+
+#define TS_CH_XP 2
+#define TS_CH_YP 3
+#define TS_CH_XM 4
+#define TS_CH_YM 5
+
+/*
+ * YP(open)--+-------------+
+ * | |--+
+ * | | |
+ * YM(-)--+-------------+ |
+ * +--------------+
+ * | |
+ * XP(weak+) XM(open)
+ *
+ * "weak+" means 200k Ohm VDDIO
+ * (-) means GND
+ */
+static void mxs_lradc_setup_touch_detection(struct mxs_lradc_ts *ts)
+{
+ struct mxs_lradc *lradc = ts->lradc;
+
+ /*
+ * In order to detect a touch event the 'touch detect enable' bit
+ * enables:
+ * - a weak pullup to the X+ connector
+ * - a strong ground at the Y- connector
+ */
+ writel(info[lradc->soc].mask,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+ writel(info[lradc->soc].bit,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+}
+
+/*
+ * YP(meas)--+-------------+
+ * | |--+
+ * | | |
+ * YM(open)--+-------------+ |
+ * +--------------+
+ * | |
+ * XP(+) XM(-)
+ *
+ * (+) means here 1.85 V
+ * (-) means here GND
+ */
+static void mxs_lradc_prepare_x_pos(struct mxs_lradc_ts *ts)
+{
+ struct mxs_lradc *lradc = ts->lradc;
+
+ writel(info[lradc->soc].mask,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+ writel(info[lradc->soc].x_plate,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+ ts->cur_plate = LRADC_SAMPLE_X;
+ mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL1, TS_CH_YP);
+ mxs_lradc_setup_ts_channel(ts, TOUCHSCREEN_VCHANNEL1);
+}
+
+/*
+ * YP(+)--+-------------+
+ * | |--+
+ * | | |
+ * YM(-)--+-------------+ |
+ * +--------------+
+ * | |
+ * XP(open) XM(meas)
+ *
+ * (+) means here 1.85 V
+ * (-) means here GND
+ */
+static void mxs_lradc_prepare_y_pos(struct mxs_lradc_ts *ts)
+{
+ struct mxs_lradc *lradc = ts->lradc;
+
+ writel(info[lradc->soc].mask,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+ writel(info[lradc->soc].y_plate,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+ ts->cur_plate = LRADC_SAMPLE_Y;
+ mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL1, TS_CH_XM);
+ mxs_lradc_setup_ts_channel(ts, TOUCHSCREEN_VCHANNEL1);
+}
+
+/*
+ * YP(+)--+-------------+
+ * | |--+
+ * | | |
+ * YM(meas)--+-------------+ |
+ * +--------------+
+ * | |
+ * XP(meas) XM(-)
+ *
+ * (+) means here 1.85 V
+ * (-) means here GND
+ */
+static void mxs_lradc_prepare_pressure(struct mxs_lradc_ts *ts)
+{
+ struct mxs_lradc *lradc = ts->lradc;
+
+ writel(info[lradc->soc].mask,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+ writel(info[lradc->soc].pressure,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+ ts->cur_plate = LRADC_SAMPLE_PRESSURE;
+ mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL1, TS_CH_YM);
+ mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL2, TS_CH_XP);
+ mxs_lradc_setup_ts_pressure(ts, TOUCHSCREEN_VCHANNEL2,
+ TOUCHSCREEN_VCHANNEL1);
+}
+
+static void mxs_lradc_enable_touch_detection(struct mxs_lradc_ts *ts)
+{
+ mxs_lradc_setup_touch_detection(ts);
+
+ ts->cur_plate = LRADC_TOUCH;
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ | LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+}
+
+static void mxs_lradc_start_touch_event(struct mxs_lradc_ts *ts)
+{
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+ writel(LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1),
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+ /*
+ * start with the Y-pos, because it uses nearly the same plate
+ * settings like the touch detection
+ */
+ mxs_lradc_prepare_y_pos(ts);
+}
+
+static void mxs_lradc_report_ts_event(struct mxs_lradc_ts *ts)
+{
+ input_report_abs(ts->ts_input, ABS_X, ts->ts_x_pos);
+ input_report_abs(ts->ts_input, ABS_Y, ts->ts_y_pos);
+ input_report_abs(ts->ts_input, ABS_PRESSURE, ts->ts_pressure);
+ input_report_key(ts->ts_input, BTN_TOUCH, 1);
+ input_sync(ts->ts_input);
+}
+
+static void mxs_lradc_complete_touch_event(struct mxs_lradc_ts *ts)
+{
+ mxs_lradc_setup_touch_detection(ts);
+ ts->cur_plate = LRADC_SAMPLE_VALID;
+ /*
+ * start a dummy conversion to burn time to settle the signals
+ * note: we are not interested in the conversion's value
+ */
+ writel(0, ts->base + LRADC_CH(TOUCHSCREEN_VCHANNEL1));
+ writel(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2),
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+ writel(LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) |
+ LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10),
+ ts->base + LRADC_DELAY(2));
+}
+
+/*
+ * in order to avoid false measurements, report only samples where
+ * the surface is still touched after the position measurement
+ */
+static void mxs_lradc_finish_touch_event(struct mxs_lradc_ts *ts, bool valid)
+{
+ /* if it is still touched, report the sample */
+ if (valid && mxs_lradc_check_touch_event(ts)) {
+ ts->ts_valid = true;
+ mxs_lradc_report_ts_event(ts);
+ }
+
+ /* if it is even still touched, continue with the next measurement */
+ if (mxs_lradc_check_touch_event(ts)) {
+ mxs_lradc_prepare_y_pos(ts);
+ return;
+ }
+
+ if (ts->ts_valid) {
+ /* signal the release */
+ ts->ts_valid = false;
+ input_report_key(ts->ts_input, BTN_TOUCH, 0);
+ input_sync(ts->ts_input);
+ }
+
+ /* if it is released, wait for the next touch via IRQ */
+ ts->cur_plate = LRADC_TOUCH;
+ writel(0, ts->base + LRADC_DELAY(2));
+ writel(0, ts->base + LRADC_DELAY(3));
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ |
+ LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1),
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+}
+
+/* touchscreen's state machine */
+static void mxs_lradc_handle_touch(struct mxs_lradc_ts *ts)
+{
+ switch (ts->cur_plate) {
+ case LRADC_TOUCH:
+ if (mxs_lradc_check_touch_event(ts))
+ mxs_lradc_start_touch_event(ts);
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ,
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+ return;
+
+ case LRADC_SAMPLE_Y:
+ ts->ts_y_pos =
+ mxs_lradc_ts_read_raw_channel(ts, TOUCHSCREEN_VCHANNEL1);
+ mxs_lradc_prepare_x_pos(ts);
+ return;
+
+ case LRADC_SAMPLE_X:
+ ts->ts_x_pos =
+ mxs_lradc_ts_read_raw_channel(ts, TOUCHSCREEN_VCHANNEL1);
+ mxs_lradc_prepare_pressure(ts);
+ return;
+
+ case LRADC_SAMPLE_PRESSURE:
+ ts->ts_pressure =
+ mxs_lradc_read_ts_pressure(ts,
+ TOUCHSCREEN_VCHANNEL2,
+ TOUCHSCREEN_VCHANNEL1);
+ mxs_lradc_complete_touch_event(ts);
+ return;
+
+ case LRADC_SAMPLE_VALID:
+ mxs_lradc_finish_touch_event(ts, 1);
+ break;
+ }
+}
+
+/* IRQ Handling */
+static irqreturn_t mxs_lradc_ts_handle_irq(int irq, void *data)
+{
+ struct mxs_lradc_ts *ts = data;
+ struct mxs_lradc *lradc = ts->lradc;
+ unsigned long reg = readl(ts->base + LRADC_CTRL1);
+ u32 clr_irq = mxs_lradc_irq_mask(lradc);
+ const u32 ts_irq_mask =
+ LRADC_CTRL1_TOUCH_DETECT_IRQ |
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2);
+ unsigned long flags;
+
+ if (!(reg & mxs_lradc_irq_mask(lradc)))
+ return IRQ_NONE;
+
+ if (reg & ts_irq_mask) {
+ spin_lock_irqsave(&ts->lock, flags);
+ mxs_lradc_handle_touch(ts);
+ spin_unlock_irqrestore(&ts->lock, flags);
+ /* Make sure we don't clear the next conversion's interrupt. */
+ clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2));
+ writel(reg & clr_irq,
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mxs_lradc_ts_open(struct input_dev *dev)
+{
+ struct mxs_lradc_ts *ts = input_get_drvdata(dev);
+
+ /* Enable the touch-detect circuitry. */
+ mxs_lradc_enable_touch_detection(ts);
+
+ return 0;
+}
+
+static void mxs_lradc_ts_stop(struct mxs_lradc_ts *ts)
+{
+ int i;
+ struct mxs_lradc *lradc = ts->lradc;
+
+ /* stop all interrupts from firing */
+ writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN |
+ LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+ LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2),
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+ /* Power-down touchscreen touch-detect circuitry. */
+ writel(info[lradc->soc].mask,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+ writel(lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+ ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+ for (i = 1; i < LRADC_MAX_DELAY_CHANS; i++)
+ writel(0, ts->base + LRADC_DELAY(i));
+}
+
+static void mxs_lradc_ts_close(struct input_dev *dev)
+{
+ struct mxs_lradc_ts *ts = input_get_drvdata(dev);
+
+ mxs_lradc_ts_stop(ts);
+}
+
+static void mxs_lradc_ts_hw_init(struct mxs_lradc_ts *ts)
+{
+ struct mxs_lradc *lradc = ts->lradc;
+
+ /* Configure the touchscreen type */
+ if (lradc->soc == IMX28_LRADC) {
+ writel(LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+ if (lradc->touchscreen_wire == MXS_LRADC_TOUCHSCREEN_5WIRE)
+ writel(LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
+ ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+ }
+}
+
+static int mxs_lradc_ts_register(struct mxs_lradc_ts *ts)
+{
+ struct input_dev *input = ts->ts_input;
+ struct device *dev = ts->dev;
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
+
+ input->name = "mxs-lradc-ts";
+ input->id.bustype = BUS_HOST;
+ input->open = mxs_lradc_ts_open;
+ input->close = mxs_lradc_ts_close;
+
+ __set_bit(INPUT_PROP_DIRECT, input->propbit);
+ input_set_capability(input, EV_KEY, BTN_TOUCH);
+ input_set_abs_params(input, ABS_X, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
+ input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_SINGLE_SAMPLE_MASK,
+ 0, 0);
+
+ ts->ts_input = input;
+ input_set_drvdata(input, ts);
+
+ return input_register_device(input);
+}
+
+static int mxs_lradc_ts_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->parent->of_node;
+ struct mxs_lradc *lradc = dev_get_drvdata(dev->parent);
+ struct mxs_lradc_ts *ts;
+ struct resource *iores;
+ int ret, irq, virq, i;
+ u32 ts_wires = 0, adapt;
+
+ ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ts);
+
+ ts->lradc = lradc;
+ ts->dev = dev;
+ spin_lock_init(&ts->lock);
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ts->base = devm_ioremap(dev, iores->start, resource_size(iores));
+ if (IS_ERR(ts->base))
+ return PTR_ERR(ts->base);
+
+ ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires",
+ &ts_wires);
+ if (ret)
+ return ret;
+
+ if (of_property_read_u32(node, "fsl,ave-ctrl", &adapt)) {
+ ts->over_sample_cnt = 4;
+ } else {
+ if (adapt >= 1 && adapt <= 32) {
+ ts->over_sample_cnt = adapt;
+ } else {
+ dev_err(ts->dev, "Invalid sample count (%u)\n",
+ adapt);
+ return -EINVAL;
+ }
+ }
+
+ if (of_property_read_u32(node, "fsl,ave-delay", &adapt)) {
+ ts->over_sample_delay = 2;
+ } else {
+ if (adapt >= 2 && adapt <= LRADC_DELAY_DELAY_MASK + 1) {
+ ts->over_sample_delay = adapt;
+ } else {
+ dev_err(ts->dev, "Invalid sample delay (%u)\n",
+ adapt);
+ return -EINVAL;
+ }
+ }
+
+ if (of_property_read_u32(node, "fsl,settling", &adapt)) {
+ ts->settling_delay = 10;
+ } else {
+ if (adapt >= 1 && adapt <= LRADC_DELAY_DELAY_MASK) {
+ ts->settling_delay = adapt;
+ } else {
+ dev_err(ts->dev, "Invalid settling delay (%u)\n",
+ adapt);
+ return -EINVAL;
+ }
+ }
+
+ ret = stmp_reset_block(ts->base);
+ if (ret)
+ return ret;
+
+ mxs_lradc_ts_hw_init(ts);
+
+ for (i = 0; i < 3; i++) {
+ irq = platform_get_irq_byname(pdev, mxs_lradc_ts_irq_names[i]);
+ if (irq < 0)
+ return irq;
+
+ virq = irq_of_parse_and_map(node, irq);
+
+ mxs_lradc_ts_stop(ts);
+
+ ret = devm_request_irq(dev, virq,
+ mxs_lradc_ts_handle_irq,
+ 0, mxs_lradc_ts_irq_names[i], ts);
+ if (ret)
+ return ret;
+ }
+
+ return mxs_lradc_ts_register(ts);
+}
+
+static struct platform_driver mxs_lradc_ts_driver = {
+ .driver = {
+ .name = "mxs-lradc-ts",
+ },
+ .probe = mxs_lradc_ts_probe,
+};
+module_platform_driver(mxs_lradc_ts_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Freescale MXS LRADC touchscreen driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxs-lradc-ts");
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index 404830a4a366..813dd68a5c82 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -580,12 +580,25 @@ static const struct acpi_device_id silead_ts_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match);
#endif
+#ifdef CONFIG_OF
+static const struct of_device_id silead_ts_of_match[] = {
+ { .compatible = "silead,gsl1680" },
+ { .compatible = "silead,gsl1688" },
+ { .compatible = "silead,gsl3670" },
+ { .compatible = "silead,gsl3675" },
+ { .compatible = "silead,gsl3692" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, silead_ts_of_match);
+#endif
+
static struct i2c_driver silead_ts_driver = {
.probe = silead_ts_probe,
.id_table = silead_ts_id,
.driver = {
.name = SILEAD_TS_NAME,
.acpi_match_table = ACPI_PTR(silead_ts_acpi_match),
+ .of_match_table = of_match_ptr(silead_ts_of_match),
.pm = &silead_ts_pm,
},
};
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 4c0eecae065c..128e5bd74720 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -369,7 +369,7 @@ static void sur40_poll(struct input_polled_dev *polldev)
* packet ID will usually increase in the middle of a series
* instead of at the end.
*/
- if (packet_id != header->packet_id)
+ if (packet_id != le32_to_cpu(header->packet_id))
dev_dbg(sur40->dev, "packet ID mismatch\n");
packet_blobs = result / sizeof(struct sur40_blob);
diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c
index a340bfccdfb6..75170a7439b1 100644
--- a/drivers/input/touchscreen/tps6507x-ts.c
+++ b/drivers/input/touchscreen/tps6507x-ts.c
@@ -226,7 +226,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
*/
init_data = tps_board->tps6507x_ts_init_data;
- tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL);
+ tsc = devm_kzalloc(&pdev->dev, sizeof(struct tps6507x_ts), GFP_KERNEL);
if (!tsc) {
dev_err(tps6507x_dev->dev, "failed to allocate driver data\n");
return -ENOMEM;
@@ -240,11 +240,10 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
snprintf(tsc->phys, sizeof(tsc->phys),
"%s/input0", dev_name(tsc->dev));
- poll_dev = input_allocate_polled_device();
+ poll_dev = devm_input_allocate_polled_device(&pdev->dev);
if (!poll_dev) {
dev_err(tsc->dev, "Failed to allocate polled input device.\n");
- error = -ENOMEM;
- goto err_free_mem;
+ return -ENOMEM;
}
tsc->poll_dev = poll_dev;
@@ -274,32 +273,11 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
error = tps6507x_adc_standby(tsc);
if (error)
- goto err_free_polled_dev;
+ return error;
error = input_register_polled_device(poll_dev);
if (error)
- goto err_free_polled_dev;
-
- platform_set_drvdata(pdev, tsc);
-
- return 0;
-
-err_free_polled_dev:
- input_free_polled_device(poll_dev);
-err_free_mem:
- kfree(tsc);
- return error;
-}
-
-static int tps6507x_ts_remove(struct platform_device *pdev)
-{
- struct tps6507x_ts *tsc = platform_get_drvdata(pdev);
- struct input_polled_dev *poll_dev = tsc->poll_dev;
-
- input_unregister_polled_device(poll_dev);
- input_free_polled_device(poll_dev);
-
- kfree(tsc);
+ return error;
return 0;
}
@@ -309,7 +287,6 @@ static struct platform_driver tps6507x_ts_driver = {
.name = "tps6507x-ts",
},
.probe = tps6507x_ts_probe,
- .remove = tps6507x_ts_remove,
};
module_platform_driver(tps6507x_ts_driver);
diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h
new file mode 100644
index 000000000000..30fdf5b04a6b
--- /dev/null
+++ b/drivers/input/touchscreen/tsc2007.h
@@ -0,0 +1,101 @@
+
+/*
+ * Copyright (c) 2008 MtekVision Co., Ltd.
+ * Kwangwoo Lee <kwlee@mtekvision.com>
+ *
+ * Using code from:
+ * - ads7846.c
+ * Copyright (c) 2005 David Brownell
+ * Copyright (c) 2006 Nokia Corporation
+ * - corgi_ts.c
+ * Copyright (C) 2004-2005 Richard Purdie
+ * - omap_ts.[hc], ads7846.h, ts_osk.c
+ * Copyright (C) 2002 MontaVista Software
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2005 Dirk Behme
+ *
+ * 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.
+ */
+
+#ifndef _TSC2007_H
+#define _TSC2007_H
+
+#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
+#define TSC2007_MEASURE_AUX (0x2 << 4)
+#define TSC2007_MEASURE_TEMP1 (0x4 << 4)
+#define TSC2007_ACTIVATE_XN (0x8 << 4)
+#define TSC2007_ACTIVATE_YN (0x9 << 4)
+#define TSC2007_ACTIVATE_YP_XN (0xa << 4)
+#define TSC2007_SETUP (0xb << 4)
+#define TSC2007_MEASURE_X (0xc << 4)
+#define TSC2007_MEASURE_Y (0xd << 4)
+#define TSC2007_MEASURE_Z1 (0xe << 4)
+#define TSC2007_MEASURE_Z2 (0xf << 4)
+
+#define TSC2007_POWER_OFF_IRQ_EN (0x0 << 2)
+#define TSC2007_ADC_ON_IRQ_DIS0 (0x1 << 2)
+#define TSC2007_ADC_OFF_IRQ_EN (0x2 << 2)
+#define TSC2007_ADC_ON_IRQ_DIS1 (0x3 << 2)
+
+#define TSC2007_12BIT (0x0 << 1)
+#define TSC2007_8BIT (0x1 << 1)
+
+#define MAX_12BIT ((1 << 12) - 1)
+
+#define ADC_ON_12BIT (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)
+
+#define READ_Y (ADC_ON_12BIT | TSC2007_MEASURE_Y)
+#define READ_Z1 (ADC_ON_12BIT | TSC2007_MEASURE_Z1)
+#define READ_Z2 (ADC_ON_12BIT | TSC2007_MEASURE_Z2)
+#define READ_X (ADC_ON_12BIT | TSC2007_MEASURE_X)
+#define PWRDOWN (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)
+
+struct ts_event {
+ u16 x;
+ u16 y;
+ u16 z1, z2;
+};
+
+struct tsc2007 {
+ struct input_dev *input;
+ char phys[32];
+
+ struct i2c_client *client;
+
+ u16 model;
+ u16 x_plate_ohms;
+ u16 max_rt;
+ unsigned long poll_period; /* in jiffies */
+ int fuzzx;
+ int fuzzy;
+ int fuzzz;
+
+ unsigned int gpio;
+ int irq;
+
+ wait_queue_head_t wait;
+ bool stopped;
+
+ int (*get_pendown_state)(struct device *);
+ void (*clear_penirq)(void);
+
+ struct mutex mlock;
+};
+
+int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd);
+u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc);
+bool tsc2007_is_pen_down(struct tsc2007 *ts);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007_IIO)
+/* defined in tsc2007_iio.c */
+int tsc2007_iio_configure(struct tsc2007 *ts);
+#else
+static inline int tsc2007_iio_configure(struct tsc2007 *ts)
+{
+ return 0;
+}
+#endif /* CONFIG_TOUCHSCREEN_TSC2007_IIO */
+
+#endif /* _TSC2007_H */
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007_core.c
index 5d0cd51c6f41..fc7384936011 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007_core.c
@@ -27,70 +27,10 @@
#include <linux/i2c.h>
#include <linux/i2c/tsc2007.h>
#include <linux/of_device.h>
-#include <linux/of.h>
#include <linux/of_gpio.h>
+#include "tsc2007.h"
-#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
-#define TSC2007_MEASURE_AUX (0x2 << 4)
-#define TSC2007_MEASURE_TEMP1 (0x4 << 4)
-#define TSC2007_ACTIVATE_XN (0x8 << 4)
-#define TSC2007_ACTIVATE_YN (0x9 << 4)
-#define TSC2007_ACTIVATE_YP_XN (0xa << 4)
-#define TSC2007_SETUP (0xb << 4)
-#define TSC2007_MEASURE_X (0xc << 4)
-#define TSC2007_MEASURE_Y (0xd << 4)
-#define TSC2007_MEASURE_Z1 (0xe << 4)
-#define TSC2007_MEASURE_Z2 (0xf << 4)
-
-#define TSC2007_POWER_OFF_IRQ_EN (0x0 << 2)
-#define TSC2007_ADC_ON_IRQ_DIS0 (0x1 << 2)
-#define TSC2007_ADC_OFF_IRQ_EN (0x2 << 2)
-#define TSC2007_ADC_ON_IRQ_DIS1 (0x3 << 2)
-
-#define TSC2007_12BIT (0x0 << 1)
-#define TSC2007_8BIT (0x1 << 1)
-
-#define MAX_12BIT ((1 << 12) - 1)
-
-#define ADC_ON_12BIT (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)
-
-#define READ_Y (ADC_ON_12BIT | TSC2007_MEASURE_Y)
-#define READ_Z1 (ADC_ON_12BIT | TSC2007_MEASURE_Z1)
-#define READ_Z2 (ADC_ON_12BIT | TSC2007_MEASURE_Z2)
-#define READ_X (ADC_ON_12BIT | TSC2007_MEASURE_X)
-#define PWRDOWN (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)
-
-struct ts_event {
- u16 x;
- u16 y;
- u16 z1, z2;
-};
-
-struct tsc2007 {
- struct input_dev *input;
- char phys[32];
-
- struct i2c_client *client;
-
- u16 model;
- u16 x_plate_ohms;
- u16 max_rt;
- unsigned long poll_period; /* in jiffies */
- int fuzzx;
- int fuzzy;
- int fuzzz;
-
- unsigned gpio;
- int irq;
-
- wait_queue_head_t wait;
- bool stopped;
-
- int (*get_pendown_state)(struct device *);
- void (*clear_penirq)(void);
-};
-
-static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
+int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
{
s32 data;
u16 val;
@@ -128,7 +68,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
tsc2007_xfer(tsc, PWRDOWN);
}
-static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
+u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc)
{
u32 rt = 0;
@@ -137,7 +77,7 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
tc->x = 0;
if (likely(tc->x && tc->z1)) {
- /* compute touch pressure resistance using equation #1 */
+ /* compute touch resistance using equation #1 */
rt = tc->z2 - tc->z1;
rt *= tc->x;
rt *= tsc->x_plate_ohms;
@@ -148,7 +88,7 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
return rt;
}
-static bool tsc2007_is_pen_down(struct tsc2007 *ts)
+bool tsc2007_is_pen_down(struct tsc2007 *ts)
{
/*
* NOTE: We can't rely on the pressure to determine the pen down
@@ -180,9 +120,12 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
while (!ts->stopped && tsc2007_is_pen_down(ts)) {
/* pen is down, continue with the measurement */
+
+ mutex_lock(&ts->mlock);
tsc2007_read_values(ts, &tc);
+ mutex_unlock(&ts->mlock);
- rt = tsc2007_calculate_pressure(ts, &tc);
+ rt = tsc2007_calculate_resistance(ts, &tc);
if (!rt && !ts->get_pendown_state) {
/*
@@ -195,9 +138,11 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
if (rt <= ts->max_rt) {
dev_dbg(&ts->client->dev,
- "DOWN point(%4d,%4d), pressure (%4u)\n",
+ "DOWN point(%4d,%4d), resistance (%4u)\n",
tc.x, tc.y, rt);
+ rt = ts->max_rt - rt;
+
input_report_key(input, BTN_TOUCH, 1);
input_report_abs(input, ABS_X, tc.x);
input_report_abs(input, ABS_Y, tc.y);
@@ -375,7 +320,8 @@ static void tsc2007_call_exit_platform_hw(void *data)
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);
+ const struct tsc2007_platform_data *pdata =
+ dev_get_platdata(&client->dev);
struct tsc2007 *ts;
struct input_dev *input_dev;
int err;
@@ -404,7 +350,9 @@ static int tsc2007_probe(struct i2c_client *client,
ts->client = client;
ts->irq = client->irq;
ts->input = input_dev;
+
init_waitqueue_head(&ts->wait);
+ mutex_init(&ts->mlock);
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
@@ -418,8 +366,7 @@ static int tsc2007_probe(struct i2c_client *client,
input_set_drvdata(input_dev, ts);
- 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_capability(input_dev, EV_KEY, BTN_TOUCH);
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);
@@ -455,6 +402,14 @@ static int tsc2007_probe(struct i2c_client *client,
tsc2007_stop(ts);
+ /* power down the chip (TSC2007_SETUP does not ACK on I2C) */
+ err = tsc2007_xfer(ts, PWRDOWN);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Failed to setup chip: %d\n", err);
+ return err; /* chip does not respond */
+ }
+
err = input_register_device(input_dev);
if (err) {
dev_err(&client->dev,
@@ -462,6 +417,13 @@ static int tsc2007_probe(struct i2c_client *client,
return err;
}
+ err = tsc2007_iio_configure(ts);
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to register with IIO: %d\n", err);
+ return err;
+ }
+
return 0;
}
diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c
new file mode 100644
index 000000000000..27b25a9fce83
--- /dev/null
+++ b/drivers/input/touchscreen/tsc2007_iio.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016 Golden Delicious Comp. GmbH&Co. KG
+ * Nikolaus Schaller <hns@goldelico.com>
+ *
+ * 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/i2c.h>
+#include <linux/iio/iio.h>
+#include "tsc2007.h"
+
+struct tsc2007_iio {
+ struct tsc2007 *ts;
+};
+
+#define TSC2007_CHAN_IIO(_chan, _name, _type, _chan_info) \
+{ \
+ .datasheet_name = _name, \
+ .type = _type, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(_chan_info), \
+ .indexed = 1, \
+ .channel = _chan, \
+}
+
+static const struct iio_chan_spec tsc2007_iio_channel[] = {
+ TSC2007_CHAN_IIO(0, "x", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+ TSC2007_CHAN_IIO(1, "y", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+ TSC2007_CHAN_IIO(2, "z1", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+ TSC2007_CHAN_IIO(3, "z2", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+ TSC2007_CHAN_IIO(4, "adc", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+ TSC2007_CHAN_IIO(5, "rt", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), /* Ohms? */
+ TSC2007_CHAN_IIO(6, "pen", IIO_PRESSURE, IIO_CHAN_INFO_RAW),
+ TSC2007_CHAN_IIO(7, "temp0", IIO_TEMP, IIO_CHAN_INFO_RAW),
+ TSC2007_CHAN_IIO(8, "temp1", IIO_TEMP, IIO_CHAN_INFO_RAW),
+};
+
+static int tsc2007_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct tsc2007_iio *iio = iio_priv(indio_dev);
+ struct tsc2007 *tsc = iio->ts;
+ int adc_chan = chan->channel;
+ int ret = 0;
+
+ if (adc_chan >= ARRAY_SIZE(tsc2007_iio_channel))
+ return -EINVAL;
+
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ mutex_lock(&tsc->mlock);
+
+ switch (chan->channel) {
+ case 0:
+ *val = tsc2007_xfer(tsc, READ_X);
+ break;
+ case 1:
+ *val = tsc2007_xfer(tsc, READ_Y);
+ break;
+ case 2:
+ *val = tsc2007_xfer(tsc, READ_Z1);
+ break;
+ case 3:
+ *val = tsc2007_xfer(tsc, READ_Z2);
+ break;
+ case 4:
+ *val = tsc2007_xfer(tsc, (ADC_ON_12BIT | TSC2007_MEASURE_AUX));
+ break;
+ case 5: {
+ struct ts_event tc;
+
+ tc.x = tsc2007_xfer(tsc, READ_X);
+ tc.z1 = tsc2007_xfer(tsc, READ_Z1);
+ tc.z2 = tsc2007_xfer(tsc, READ_Z2);
+ *val = tsc2007_calculate_resistance(tsc, &tc);
+ break;
+ }
+ case 6:
+ *val = tsc2007_is_pen_down(tsc);
+ break;
+ case 7:
+ *val = tsc2007_xfer(tsc,
+ (ADC_ON_12BIT | TSC2007_MEASURE_TEMP0));
+ break;
+ case 8:
+ *val = tsc2007_xfer(tsc,
+ (ADC_ON_12BIT | TSC2007_MEASURE_TEMP1));
+ break;
+ }
+
+ /* Prepare for next touch reading - power down ADC, enable PENIRQ */
+ tsc2007_xfer(tsc, PWRDOWN);
+
+ mutex_unlock(&tsc->mlock);
+
+ ret = IIO_VAL_INT;
+
+ return ret;
+}
+
+static const struct iio_info tsc2007_iio_info = {
+ .read_raw = tsc2007_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+int tsc2007_iio_configure(struct tsc2007 *ts)
+{
+ struct iio_dev *indio_dev;
+ struct tsc2007_iio *iio;
+ int error;
+
+ indio_dev = devm_iio_device_alloc(&ts->client->dev, sizeof(*iio));
+ if (!indio_dev) {
+ dev_err(&ts->client->dev, "iio_device_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ iio = iio_priv(indio_dev);
+ iio->ts = ts;
+
+ indio_dev->name = "tsc2007";
+ indio_dev->dev.parent = &ts->client->dev;
+ indio_dev->info = &tsc2007_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = tsc2007_iio_channel;
+ indio_dev->num_channels = ARRAY_SIZE(tsc2007_iio_channel);
+
+ error = devm_iio_device_register(&ts->client->dev, indio_dev);
+ if (error) {
+ dev_err(&ts->client->dev,
+ "iio_device_register() failed: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}