diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-14 05:05:13 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-14 05:05:13 +0400 |
commit | 18fb38e2f58ff7a66e30cbb71af81425edf1c9a1 (patch) | |
tree | 8ff2cc5b0d1a11c87a0e2576d6fe863b87faf69a /drivers/input/touchscreen | |
parent | be9c6d9169705504296bdb42ffec8f406691d99f (diff) | |
parent | 88ce3c3ca3df754e8a2a63b01c38bd1667fcae70 (diff) | |
download | linux-18fb38e2f58ff7a66e30cbb71af81425edf1c9a1.tar.xz |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull second round of input updates from Dmitry Torokhov:
"An update to Elantech driver to support hardware v7, fix to the new
cyttsp4 driver to use proper addressing, ads7846 device tree support
and nspire-keypad got a small cleanup."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
Input: nspire-keypad - replace magic offset with define
Input: elantech - fix for newer hardware versions (v7)
Input: cyttsp4 - use 16bit address for I2C/SPI communication
Input: ads7846 - add device tree bindings
Input: ads7846 - make sure we do not change platform data
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 123 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp4_core.h | 12 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp4_spi.c | 20 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp_core.h | 8 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp_i2c_common.c | 30 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp_spi.c | 6 |
6 files changed, 152 insertions, 47 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 84ccf140c1bb..ea195360747e 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -27,6 +27,9 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/pm.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> #include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> @@ -961,9 +964,9 @@ static int ads7846_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); static int ads7846_setup_pendown(struct spi_device *spi, - struct ads7846 *ts) + struct ads7846 *ts, + const struct ads7846_platform_data *pdata) { - struct ads7846_platform_data *pdata = spi->dev.platform_data; int err; /* @@ -1003,7 +1006,7 @@ static int ads7846_setup_pendown(struct spi_device *spi, * use formula #2 for pressure, not #3. */ static void ads7846_setup_spi_msg(struct ads7846 *ts, - const struct ads7846_platform_data *pdata) + const struct ads7846_platform_data *pdata) { struct spi_message *m = &ts->msg[0]; struct spi_transfer *x = ts->xfer; @@ -1201,33 +1204,107 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, spi_message_add_tail(x, m); } +#ifdef CONFIG_OF +static const struct of_device_id ads7846_dt_ids[] = { + { .compatible = "ti,tsc2046", .data = (void *) 7846 }, + { .compatible = "ti,ads7843", .data = (void *) 7843 }, + { .compatible = "ti,ads7845", .data = (void *) 7845 }, + { .compatible = "ti,ads7846", .data = (void *) 7846 }, + { .compatible = "ti,ads7873", .data = (void *) 7873 }, + { } +}; +MODULE_DEVICE_TABLE(of, ads7846_dt_ids); + +static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) +{ + struct ads7846_platform_data *pdata; + struct device_node *node = dev->of_node; + const struct of_device_id *match; + + if (!node) { + dev_err(dev, "Device does not have associated DT data\n"); + return ERR_PTR(-EINVAL); + } + + match = of_match_device(ads7846_dt_ids, dev); + if (!match) { + dev_err(dev, "Unknown device model\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->model = (unsigned long)match->data; + + of_property_read_u16(node, "ti,vref-delay-usecs", + &pdata->vref_delay_usecs); + of_property_read_u16(node, "ti,vref-mv", &pdata->vref_mv); + pdata->keep_vref_on = of_property_read_bool(node, "ti,keep-vref-on"); + + pdata->swap_xy = of_property_read_bool(node, "ti,swap-xy"); + + of_property_read_u16(node, "ti,settle-delay-usec", + &pdata->settle_delay_usecs); + of_property_read_u16(node, "ti,penirq-recheck-delay-usecs", + &pdata->penirq_recheck_delay_usecs); + + of_property_read_u16(node, "ti,x-plate-ohms", &pdata->x_plate_ohms); + of_property_read_u16(node, "ti,y-plate-ohms", &pdata->y_plate_ohms); + + of_property_read_u16(node, "ti,x-min", &pdata->x_min); + of_property_read_u16(node, "ti,y-min", &pdata->y_min); + of_property_read_u16(node, "ti,x-max", &pdata->x_max); + of_property_read_u16(node, "ti,y-max", &pdata->y_max); + + of_property_read_u16(node, "ti,pressure-min", &pdata->pressure_min); + of_property_read_u16(node, "ti,pressure-max", &pdata->pressure_max); + + of_property_read_u16(node, "ti,debounce-max", &pdata->debounce_max); + of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol); + of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep); + + of_property_read_u32(node, "ti,pendown-gpio-debounce", + &pdata->gpio_pendown_debounce); + + pdata->wakeup = of_property_read_bool(node, "linux,wakeup"); + + pdata->gpio_pendown = of_get_named_gpio(dev->of_node, "pendown-gpio", 0); + + return pdata; +} +#else +static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) +{ + dev_err(dev, "no platform data defined\n"); + return ERR_PTR(-EINVAL); +} +#endif + static int ads7846_probe(struct spi_device *spi) { + const struct ads7846_platform_data *pdata; struct ads7846 *ts; struct ads7846_packet *packet; struct input_dev *input_dev; - struct ads7846_platform_data *pdata = spi->dev.platform_data; unsigned long irq_flags; int err; if (!spi->irq) { dev_dbg(&spi->dev, "no IRQ?\n"); - return -ENODEV; - } - - if (!pdata) { - dev_dbg(&spi->dev, "no platform data?\n"); - return -ENODEV; + return -EINVAL; } /* don't exceed max specified sample rate */ if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) { - dev_dbg(&spi->dev, "f(sample) %d KHz?\n", + dev_err(&spi->dev, "f(sample) %d KHz?\n", (spi->max_speed_hz/SAMPLE_BITS)/1000); return -EINVAL; } - /* We'd set TX word size 8 bits and RX word size to 13 bits ... except + /* + * We'd set TX word size 8 bits and RX word size to 13 bits ... except * that even if the hardware can do that, the SPI controller driver * may not. So we stick to very-portable 8 bit words, both RX and TX. */ @@ -1250,17 +1327,25 @@ static int ads7846_probe(struct spi_device *spi) ts->packet = packet; ts->spi = spi; ts->input = input_dev; - ts->vref_mv = pdata->vref_mv; - ts->swap_xy = pdata->swap_xy; mutex_init(&ts->lock); init_waitqueue_head(&ts->wait); + pdata = dev_get_platdata(&spi->dev); + if (!pdata) { + pdata = ads7846_probe_dt(&spi->dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } + ts->model = pdata->model ? : 7846; ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; ts->pressure_max = pdata->pressure_max ? : ~0; + ts->vref_mv = pdata->vref_mv; + ts->swap_xy = pdata->swap_xy; + if (pdata->filter != NULL) { if (pdata->filter_init != NULL) { err = pdata->filter_init(pdata, &ts->filter_data); @@ -1281,7 +1366,7 @@ static int ads7846_probe(struct spi_device *spi) ts->filter = ads7846_no_filter; } - err = ads7846_setup_pendown(spi, ts); + err = ads7846_setup_pendown(spi, ts, pdata); if (err) goto err_cleanup_filter; @@ -1370,6 +1455,13 @@ static int ads7846_probe(struct spi_device *spi) device_init_wakeup(&spi->dev, pdata->wakeup); + /* + * If device does not carry platform data we must have allocated it + * when parsing DT data. + */ + if (!dev_get_platdata(&spi->dev)) + devm_kfree(&spi->dev, (void *)pdata); + return 0; err_remove_attr_group: @@ -1437,6 +1529,7 @@ static struct spi_driver ads7846_driver = { .name = "ads7846", .owner = THIS_MODULE, .pm = &ads7846_pm, + .of_match_table = of_match_ptr(ads7846_dt_ids), }, .probe = ads7846_probe, .remove = ads7846_remove, diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h index 86a254354136..8e0d4d490b20 100644 --- a/drivers/input/touchscreen/cyttsp4_core.h +++ b/drivers/input/touchscreen/cyttsp4_core.h @@ -369,9 +369,9 @@ struct cyttsp4 { struct cyttsp4_bus_ops { u16 bustype; - int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, + int (*write)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length, const void *values); - int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, + int (*read)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length, void *values); }; @@ -448,13 +448,13 @@ enum cyttsp4_event_id { /* y-axis, 0:origin is on top side of panel, 1: bottom */ #define CY_PCFG_ORIGIN_Y_MASK 0x80 -static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u8 addr, int size, +static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u16 addr, int size, void *buf) { return ts->bus_ops->read(ts->dev, ts->xfer_buf, addr, size, buf); } -static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u8 addr, int size, +static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u16 addr, int size, const void *buf) { return ts->bus_ops->write(ts->dev, ts->xfer_buf, addr, size, buf); @@ -463,9 +463,9 @@ static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u8 addr, int size, extern struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops, struct device *dev, u16 irq, size_t xfer_buf_size); extern int cyttsp4_remove(struct cyttsp4 *ts); -int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr, +int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr, u8 length, const void *values); -int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr, +int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr, u8 length, void *values); extern const struct dev_pm_ops cyttsp4_pm_ops; diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c index f8f891bead34..a71e1141d638 100644 --- a/drivers/input/touchscreen/cyttsp4_spi.c +++ b/drivers/input/touchscreen/cyttsp4_spi.c @@ -44,7 +44,7 @@ #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, - u8 op, u8 reg, u8 *buf, int length) + u8 op, u16 reg, u8 *buf, int length) { struct spi_device *spi = to_spi_device(dev); struct spi_message msg; @@ -63,14 +63,12 @@ static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE); memset(rd_buf, 0, CY_SPI_CMD_BYTES); - if (reg > 255) - wr_buf[0] = op + CY_SPI_A8_BIT; - else - wr_buf[0] = op; - if (op == CY_SPI_WR_OP) - wr_buf[1] = reg % 256; - if (op == CY_SPI_WR_OP && length > 0) - memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length); + wr_buf[0] = op + (((reg >> 8) & 0x1) ? CY_SPI_A8_BIT : 0); + if (op == CY_SPI_WR_OP) { + wr_buf[1] = reg & 0xFF; + if (length > 0) + memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length); + } memset(xfer, 0, sizeof(xfer)); spi_message_init(&msg); @@ -130,7 +128,7 @@ static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, } static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf, - u8 addr, u8 length, void *data) + u16 addr, u8 length, void *data) { int rc; @@ -143,7 +141,7 @@ static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf, } static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf, - u8 addr, u8 length, const void *data) + u16 addr, u8 length, const void *data) { return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data, length); diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h index 0cf564a79fb5..07074110a902 100644 --- a/drivers/input/touchscreen/cyttsp_core.h +++ b/drivers/input/touchscreen/cyttsp_core.h @@ -112,9 +112,9 @@ struct cyttsp; struct cyttsp_bus_ops { u16 bustype; - int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, + int (*write)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length, const void *values); - int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, + int (*read)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length, void *values); }; @@ -145,9 +145,9 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, struct device *dev, int irq, size_t xfer_buf_size); void cyttsp_remove(struct cyttsp *ts); -int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr, +int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr, u8 length, const void *values); -int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr, +int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr, u8 length, void *values); extern const struct dev_pm_ops cyttsp_pm_ops; diff --git a/drivers/input/touchscreen/cyttsp_i2c_common.c b/drivers/input/touchscreen/cyttsp_i2c_common.c index 07c553fbcef2..1d7b6f154168 100644 --- a/drivers/input/touchscreen/cyttsp_i2c_common.c +++ b/drivers/input/touchscreen/cyttsp_i2c_common.c @@ -32,18 +32,20 @@ #include <linux/types.h> int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, - u8 addr, u8 length, void *values) + u16 addr, u8 length, void *values) { struct i2c_client *client = to_i2c_client(dev); + u8 client_addr = client->addr | ((addr >> 8) & 0x1); + u8 addr_lo = addr & 0xFF; struct i2c_msg msgs[] = { { - .addr = client->addr, + .addr = client_addr, .flags = 0, .len = 1, - .buf = &addr, + .buf = &addr_lo, }, { - .addr = client->addr, + .addr = client_addr, .flags = I2C_M_RD, .len = length, .buf = values, @@ -60,17 +62,29 @@ int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, EXPORT_SYMBOL_GPL(cyttsp_i2c_read_block_data); int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, - u8 addr, u8 length, const void *values) + u16 addr, u8 length, const void *values) { struct i2c_client *client = to_i2c_client(dev); + u8 client_addr = client->addr | ((addr >> 8) & 0x1); + u8 addr_lo = addr & 0xFF; + struct i2c_msg msgs[] = { + { + .addr = client_addr, + .flags = 0, + .len = length + 1, + .buf = xfer_buf, + }, + }; int retval; - xfer_buf[0] = addr; + xfer_buf[0] = addr_lo; memcpy(&xfer_buf[1], values, length); - retval = i2c_master_send(client, xfer_buf, length + 1); + retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (retval < 0) + return retval; - return retval < 0 ? retval : 0; + return retval != ARRAY_SIZE(msgs) ? -EIO : 0; } EXPORT_SYMBOL_GPL(cyttsp_i2c_write_block_data); diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c index 1df625337b84..4728bcb1916c 100644 --- a/drivers/input/touchscreen/cyttsp_spi.c +++ b/drivers/input/touchscreen/cyttsp_spi.c @@ -41,7 +41,7 @@ #define CY_SPI_BITS_PER_WORD 8 static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, - u8 op, u8 reg, u8 *buf, int length) + u8 op, u16 reg, u8 *buf, int length) { struct spi_device *spi = to_spi_device(dev); struct spi_message msg; @@ -126,14 +126,14 @@ static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, } static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf, - u8 addr, u8 length, void *data) + u16 addr, u8 length, void *data) { return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data, length); } static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf, - u8 addr, u8 length, const void *data) + u16 addr, u8 length, const void *data) { return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data, length); |