summaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2013-09-07 12:53:35 +1000
committerHerbert Xu <herbert@gondor.apana.org.au>2013-09-07 12:53:35 +1000
commiteeca9fad52fc4bfdf42c38bfcf383e932eb3e9d6 (patch)
treecc51c880459d41c0e8d7576405bef4c987bc7aa0 /drivers/input/touchscreen
parentff6f83fc9d44db09997937c3475d525a6866fbb4 (diff)
parentb48a97be8e6c2afdba2f3b61fd88c3c7743fbd73 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
Merge upstream tree in order to reinstate crct10dif.
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r--drivers/input/touchscreen/ads7846.c123
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.h12
-rw-r--r--drivers/input/touchscreen/cyttsp4_spi.c20
-rw-r--r--drivers/input/touchscreen/cyttsp_core.h8
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c_common.c30
-rw-r--r--drivers/input/touchscreen/cyttsp_spi.c6
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c288
7 files changed, 355 insertions, 132 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 84ccf140c1b..ea195360747 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 86a25435413..8e0d4d490b2 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 f8f891bead3..a71e1141d63 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 0cf564a79fb..07074110a90 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 07c553fbcef..1d7b6f15416 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 1df625337b8..4728bcb1916 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);
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 50fb1293874..e1c5300cacf 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -24,8 +24,9 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/input/ti_am335x_tsc.h>
#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/mfd/ti_am335x_tscadc.h>
@@ -33,6 +34,13 @@
#define SEQ_SETTLE 275
#define MAX_12BIT ((1 << 12) - 1)
+static const int config_pins[] = {
+ STEPCONFIG_XPP,
+ STEPCONFIG_XNN,
+ STEPCONFIG_YPP,
+ STEPCONFIG_YNN,
+};
+
struct titsc {
struct input_dev *input;
struct ti_tscadc_dev *mfd_tscadc;
@@ -40,7 +48,10 @@ struct titsc {
unsigned int wires;
unsigned int x_plate_resistance;
bool pen_down;
- int steps_to_configure;
+ int coordinate_readouts;
+ u32 config_inp[4];
+ u32 bit_xp, bit_xn, bit_yp, bit_yn;
+ u32 inp_xp, inp_xn, inp_yp, inp_yn;
};
static unsigned int titsc_readl(struct titsc *ts, unsigned int reg)
@@ -54,92 +65,153 @@ static void titsc_writel(struct titsc *tsc, unsigned int reg,
writel(val, tsc->mfd_tscadc->tscadc_base + reg);
}
+static int titsc_config_wires(struct titsc *ts_dev)
+{
+ u32 analog_line[4];
+ u32 wire_order[4];
+ int i, bit_cfg;
+
+ for (i = 0; i < 4; i++) {
+ /*
+ * Get the order in which TSC wires are attached
+ * w.r.t. each of the analog input lines on the EVM.
+ */
+ analog_line[i] = (ts_dev->config_inp[i] & 0xF0) >> 4;
+ wire_order[i] = ts_dev->config_inp[i] & 0x0F;
+ if (WARN_ON(analog_line[i] > 7))
+ return -EINVAL;
+ if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins)))
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 4; i++) {
+ int an_line;
+ int wi_order;
+
+ an_line = analog_line[i];
+ wi_order = wire_order[i];
+ bit_cfg = config_pins[wi_order];
+ if (bit_cfg == 0)
+ return -EINVAL;
+ switch (wi_order) {
+ case 0:
+ ts_dev->bit_xp = bit_cfg;
+ ts_dev->inp_xp = an_line;
+ break;
+
+ case 1:
+ ts_dev->bit_xn = bit_cfg;
+ ts_dev->inp_xn = an_line;
+ break;
+
+ case 2:
+ ts_dev->bit_yp = bit_cfg;
+ ts_dev->inp_yp = an_line;
+ break;
+ case 3:
+ ts_dev->bit_yn = bit_cfg;
+ ts_dev->inp_yn = an_line;
+ break;
+ }
+ }
+ return 0;
+}
+
static void titsc_step_config(struct titsc *ts_dev)
{
unsigned int config;
- int i, total_steps;
-
- /* Configure the Step registers */
- total_steps = 2 * ts_dev->steps_to_configure;
+ int i;
+ int end_step;
+ u32 stepenable;
config = STEPCONFIG_MODE_HWSYNC |
- STEPCONFIG_AVG_16 | STEPCONFIG_XPP;
+ STEPCONFIG_AVG_16 | ts_dev->bit_xp;
switch (ts_dev->wires) {
case 4:
- config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN;
+ config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
break;
case 5:
- config |= STEPCONFIG_YNN |
- STEPCONFIG_INP_AN4 | STEPCONFIG_XNN |
- STEPCONFIG_YPP;
+ config |= ts_dev->bit_yn |
+ STEPCONFIG_INP_AN4 | ts_dev->bit_xn |
+ ts_dev->bit_yp;
break;
case 8:
- config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN;
+ config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
break;
}
- for (i = 1; i <= ts_dev->steps_to_configure; i++) {
+ /* 1 … coordinate_readouts is for X */
+ end_step = ts_dev->coordinate_readouts;
+ for (i = 0; i < end_step; i++) {
titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
}
config = 0;
config = STEPCONFIG_MODE_HWSYNC |
- STEPCONFIG_AVG_16 | STEPCONFIG_YNN |
- STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1;
+ STEPCONFIG_AVG_16 | ts_dev->bit_yn |
+ STEPCONFIG_INM_ADCREFM;
switch (ts_dev->wires) {
case 4:
- config |= STEPCONFIG_YPP;
+ config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
break;
case 5:
- config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 |
- STEPCONFIG_XNP | STEPCONFIG_YPN;
+ config |= ts_dev->bit_xp | STEPCONFIG_INP_AN4 |
+ ts_dev->bit_xn | ts_dev->bit_yp;
break;
case 8:
- config |= STEPCONFIG_YPP;
+ config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
break;
}
- for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) {
+ /* coordinate_readouts … coordinate_readouts * 2 is for Y */
+ end_step = ts_dev->coordinate_readouts * 2;
+ for (i = ts_dev->coordinate_readouts; i < end_step; i++) {
titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
}
- config = 0;
/* Charge step configuration */
- config = STEPCONFIG_XPP | STEPCONFIG_YNN |
+ config = ts_dev->bit_xp | ts_dev->bit_yn |
STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR |
- STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1;
+ STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp);
titsc_writel(ts_dev, REG_CHARGECONFIG, config);
titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY);
- config = 0;
- /* Configure to calculate pressure */
+ /* coordinate_readouts * 2 … coordinate_readouts * 2 + 2 is for Z */
config = STEPCONFIG_MODE_HWSYNC |
- STEPCONFIG_AVG_16 | STEPCONFIG_YPP |
- STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM;
- titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config);
- titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1),
+ STEPCONFIG_AVG_16 | ts_dev->bit_yp |
+ ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM |
+ STEPCONFIG_INP(ts_dev->inp_xp);
+ titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
+ titsc_writel(ts_dev, REG_STEPDELAY(end_step),
STEPCONFIG_OPENDLY);
- config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1;
- titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config);
- titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2),
+ end_step++;
+ config |= STEPCONFIG_INP(ts_dev->inp_yn);
+ titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
+ titsc_writel(ts_dev, REG_STEPDELAY(end_step),
STEPCONFIG_OPENDLY);
- titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC);
+ /* The steps1 … end and bit 0 for TS_Charge */
+ stepenable = (1 << (end_step + 2)) - 1;
+ am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable);
}
static void titsc_read_coordinates(struct titsc *ts_dev,
- unsigned int *x, unsigned int *y)
+ u32 *x, u32 *y, u32 *z1, u32 *z2)
{
unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
unsigned int prev_val_x = ~0, prev_val_y = ~0;
unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
unsigned int read, diff;
unsigned int i, channel;
+ unsigned int creads = ts_dev->coordinate_readouts;
+ *z1 = *z2 = 0;
+ if (fifocount % (creads * 2 + 2))
+ fifocount -= fifocount % (creads * 2 + 2);
/*
* Delta filter is used to remove large variations in sampled
* values from ADC. The filter tries to predict where the next
@@ -148,32 +220,32 @@ static void titsc_read_coordinates(struct titsc *ts_dev,
* algorithm compares the difference with that of a present value,
* if true the value is reported to the sub system.
*/
- for (i = 0; i < fifocount - 1; i++) {
+ for (i = 0; i < fifocount; i++) {
read = titsc_readl(ts_dev, REG_FIFO0);
- channel = read & 0xf0000;
- channel = channel >> 0x10;
- if ((channel >= 0) && (channel < ts_dev->steps_to_configure)) {
- read &= 0xfff;
+
+ channel = (read & 0xf0000) >> 16;
+ read &= 0xfff;
+ if (channel < creads) {
diff = abs(read - prev_val_x);
if (diff < prev_diff_x) {
prev_diff_x = diff;
*x = read;
}
prev_val_x = read;
- }
- read = titsc_readl(ts_dev, REG_FIFO1);
- channel = read & 0xf0000;
- channel = channel >> 0x10;
- if ((channel >= ts_dev->steps_to_configure) &&
- (channel < (2 * ts_dev->steps_to_configure - 1))) {
- read &= 0xfff;
+ } else if (channel < creads * 2) {
diff = abs(read - prev_val_y);
if (diff < prev_diff_y) {
prev_diff_y = diff;
*y = read;
}
prev_val_y = read;
+
+ } else if (channel < creads * 2 + 1) {
+ *z1 = read;
+
+ } else if (channel < creads * 2 + 2) {
+ *z2 = read;
}
}
}
@@ -186,23 +258,11 @@ static irqreturn_t titsc_irq(int irq, void *dev)
unsigned int x = 0, y = 0;
unsigned int z1, z2, z;
unsigned int fsm;
- unsigned int fifo1count, fifo0count;
- int i;
status = titsc_readl(ts_dev, REG_IRQSTATUS);
if (status & IRQENB_FIFO0THRES) {
- titsc_read_coordinates(ts_dev, &x, &y);
- z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff;
- z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff;
-
- fifo1count = titsc_readl(ts_dev, REG_FIFO1CNT);
- for (i = 0; i < fifo1count; i++)
- titsc_readl(ts_dev, REG_FIFO1);
-
- fifo0count = titsc_readl(ts_dev, REG_FIFO0CNT);
- for (i = 0; i < fifo0count; i++)
- titsc_readl(ts_dev, REG_FIFO0);
+ titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
/*
@@ -210,10 +270,10 @@ static irqreturn_t titsc_irq(int irq, void *dev)
* Resistance(touch) = x plate resistance *
* x postion/4096 * ((z2 / z1) - 1)
*/
- z = z2 - z1;
+ z = z1 - z2;
z *= x;
z *= ts_dev->x_plate_resistance;
- z /= z1;
+ z /= z2;
z = (z + 2047) >> 12;
if (z <= MAX_12BIT) {
@@ -248,10 +308,53 @@ static irqreturn_t titsc_irq(int irq, void *dev)
irqclr |= IRQENB_PENUP;
}
- titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+ if (status & IRQENB_HW_PEN) {
+
+ titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00);
+ titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
+ }
- titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC);
- return IRQ_HANDLED;
+ if (irqclr) {
+ titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+ am335x_tsc_se_update(ts_dev->mfd_tscadc);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int titsc_parse_dt(struct platform_device *pdev,
+ struct titsc *ts_dev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ int err;
+
+ if (!node)
+ return -EINVAL;
+
+ err = of_property_read_u32(node, "ti,wires", &ts_dev->wires);
+ if (err < 0)
+ return err;
+ switch (ts_dev->wires) {
+ case 4:
+ case 5:
+ case 8:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = of_property_read_u32(node, "ti,x-plate-resistance",
+ &ts_dev->x_plate_resistance);
+ if (err < 0)
+ return err;
+
+ err = of_property_read_u32(node, "ti,coordiante-readouts",
+ &ts_dev->coordinate_readouts);
+ if (err < 0)
+ return err;
+
+ return of_property_read_u32_array(node, "ti,wire-config",
+ ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp));
}
/*
@@ -262,17 +365,9 @@ static int titsc_probe(struct platform_device *pdev)
{
struct titsc *ts_dev;
struct input_dev *input_dev;
- struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data;
- struct mfd_tscadc_board *pdata;
+ struct ti_tscadc_dev *tscadc_dev = ti_tscadc_dev_get(pdev);
int err;
- pdata = tscadc_dev->dev->platform_data;
-
- if (!pdata) {
- dev_err(&pdev->dev, "Could not find platform data\n");
- return -EINVAL;
- }
-
/* Allocate memory for device */
ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL);
input_dev = input_allocate_device();
@@ -286,9 +381,12 @@ static int titsc_probe(struct platform_device *pdev)
ts_dev->mfd_tscadc = tscadc_dev;
ts_dev->input = input_dev;
ts_dev->irq = tscadc_dev->irq;
- ts_dev->wires = pdata->tsc_init->wires;
- ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance;
- ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure;
+
+ err = titsc_parse_dt(pdev, ts_dev);
+ if (err) {
+ dev_err(&pdev->dev, "Could not find valid DT data.\n");
+ goto err_free_mem;
+ }
err = request_irq(ts_dev->irq, titsc_irq,
0, pdev->dev.driver->name, ts_dev);
@@ -298,8 +396,14 @@ static int titsc_probe(struct platform_device *pdev)
}
titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES);
+ err = titsc_config_wires(ts_dev);
+ if (err) {
+ dev_err(&pdev->dev, "wrong i/p wire configuration\n");
+ goto err_free_irq;
+ }
titsc_step_config(ts_dev);
- titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure);
+ titsc_writel(ts_dev, REG_FIFO0THR,
+ ts_dev->coordinate_readouts * 2 + 2 - 1);
input_dev->name = "ti-tsc";
input_dev->dev.parent = &pdev->dev;
@@ -329,11 +433,16 @@ err_free_mem:
static int titsc_remove(struct platform_device *pdev)
{
- struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data;
- struct titsc *ts_dev = tscadc_dev->tsc;
+ struct titsc *ts_dev = platform_get_drvdata(pdev);
+ u32 steps;
free_irq(ts_dev->irq, ts_dev);
+ /* total steps followed by the enable mask */
+ steps = 2 * ts_dev->coordinate_readouts + 2;
+ steps = (1 << steps) - 1;
+ am335x_tsc_se_clr(ts_dev->mfd_tscadc, steps);
+
input_unregister_device(ts_dev->input);
kfree(ts_dev);
@@ -343,10 +452,11 @@ static int titsc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int titsc_suspend(struct device *dev)
{
- struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
- struct titsc *ts_dev = tscadc_dev->tsc;
+ struct titsc *ts_dev = dev_get_drvdata(dev);
+ struct ti_tscadc_dev *tscadc_dev;
unsigned int idle;
+ tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
if (device_may_wakeup(tscadc_dev->dev)) {
idle = titsc_readl(ts_dev, REG_IRQENABLE);
titsc_writel(ts_dev, REG_IRQENABLE,
@@ -358,9 +468,10 @@ static int titsc_suspend(struct device *dev)
static int titsc_resume(struct device *dev)
{
- struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
- struct titsc *ts_dev = tscadc_dev->tsc;
+ struct titsc *ts_dev = dev_get_drvdata(dev);
+ struct ti_tscadc_dev *tscadc_dev;
+ tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
if (device_may_wakeup(tscadc_dev->dev)) {
titsc_writel(ts_dev, REG_IRQWAKEUP,
0x00);
@@ -368,7 +479,7 @@ static int titsc_resume(struct device *dev)
}
titsc_step_config(ts_dev);
titsc_writel(ts_dev, REG_FIFO0THR,
- ts_dev->steps_to_configure);
+ ts_dev->coordinate_readouts * 2 + 2 - 1);
return 0;
}
@@ -381,13 +492,20 @@ static const struct dev_pm_ops titsc_pm_ops = {
#define TITSC_PM_OPS NULL
#endif
+static const struct of_device_id ti_tsc_dt_ids[] = {
+ { .compatible = "ti,am3359-tsc", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids);
+
static struct platform_driver ti_tsc_driver = {
.probe = titsc_probe,
.remove = titsc_remove,
.driver = {
- .name = "tsc",
+ .name = "TI-am335x-tsc",
.owner = THIS_MODULE,
.pm = TITSC_PM_OPS,
+ .of_match_table = of_match_ptr(ti_tsc_dt_ids),
},
};
module_platform_driver(ti_tsc_driver);