Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input subsystem updates from Dmitry Torokhov: - a big update from Mauro converting input documentation to ReST format - Synaptics PS/2 is now aware of SMBus companion devices, which means that we can now use native RMI4 protocol to handle touchpads, instead of relying on legacy PS/2 mode. - we removed support from BMA180 accelerometer from input devices as it is now handled properly by IIO - update to TSC2007 to corretcly report pressure - other miscellaneous driver fixes. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (152 commits) Input: ar1021_i2c - use BIT to check for a bit Input: twl4030-pwrbutton - use input_set_capability() helper Input: twl4030-pwrbutton - use correct device for irq request Input: ar1021_i2c - enable touch mode during open Input: add uinput documentation dt-bindings: input: add bindings document for ar1021_i2c driver dt-bindings: input: rotary-encoder: fix typo Input: xen-kbdfront - add module parameter for setting resolution ARM: pxa/raumfeld: fix compile error in rotary controller resources Input: xpad - do not suggest writing to Dominic Input: xpad - don't use literal blocks inside footnotes Input: xpad - note that usb/devices is now at /sys/kernel/debug/ Input: docs - freshen up introduction Input: docs - split input docs into kernel- and user-facing Input: docs - note that MT-A protocol is obsolete Input: docs - update joystick documentation a bit Input: docs - remove disclaimer/GPL notice Input: fix "Game console" heading level in joystick documentation Input: rotary-encoder - remove references to platform data from docs Input: move documentation for Amiga CD32 ...
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -1033,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
|
||||
|
@@ -80,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
|
||||
|
@@ -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);
|
||||
regmap = devm_regmap_init_i2c(client, &ad7879_i2c_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
|
@@ -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().
|
||||
*/
|
||||
#define AD7879_CMD_MAGIC 0xE0
|
||||
#define AD7879_CMD_READ BIT(2)
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
regmap = devm_regmap_init_spi(spi, &ad7879_spi_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
|
@@ -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");
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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");
|
||||
|
@@ -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;
|
||||
}
|
||||
unsigned int res;
|
||||
u16 x, y;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
eeti->client = client;
|
||||
eeti->input = input;
|
||||
|
||||
err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name);
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
eeti->attn_gpio = devm_gpiod_get_optional(dev, "attn", GPIOD_IN);
|
||||
if (IS_ERR(eeti->attn_gpio))
|
||||
return PTR_ERR(eeti->attn_gpio);
|
||||
|
||||
priv->irq_active_high = pdata->irq_active_high;
|
||||
i2c_set_clientdata(client, eeti);
|
||||
input_set_drvdata(input, eeti);
|
||||
|
||||
irq_flags = priv->irq_active_high ?
|
||||
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
|
||||
|
||||
INIT_WORK(&priv->work, eeti_ts_read);
|
||||
i2c_set_clientdata(client, priv);
|
||||
input_set_drvdata(input, priv);
|
||||
|
||||
err = input_register_device(input);
|
||||
if (err)
|
||||
goto err2;
|
||||
|
||||
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);
|
||||
eeti_ts_stop(eeti);
|
||||
|
||||
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);
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
},
|
||||
};
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
101
drivers/input/touchscreen/tsc2007.h
Normal file
101
drivers/input/touchscreen/tsc2007.h
Normal file
@@ -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 */
|
@@ -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 */
|
||||
tsc2007_read_values(ts, &tc);
|
||||
|
||||
rt = tsc2007_calculate_pressure(ts, &tc);
|
||||
mutex_lock(&ts->mlock);
|
||||
tsc2007_read_values(ts, &tc);
|
||||
mutex_unlock(&ts->mlock);
|
||||
|
||||
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;
|
||||
}
|
||||
|
140
drivers/input/touchscreen/tsc2007_iio.c
Normal file
140
drivers/input/touchscreen/tsc2007_iio.c
Normal file
@@ -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;
|
||||
}
|
Reference in New Issue
Block a user