mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
Input: ads7846 - extend the driver for ads7845 controller support
ADS7845 is a controller for 5-wire touch screens and somewhat different from 7846. It requires three serial communications to accomplish one complete conversion. Unlike 7846 it doesn't allow Z1-/Z2- position measurement. The patch extends the ads7846 driver to also support ads7845. The packet struct is extended to contain needed command and conversion buffers. ads7846_rx() and ads7846_rx_val() now differentiate between 7845 and 7846 case. ads7846_probe() is modified to setup ads7845 specific command and conversion messages and to switch ads7845 into power-down mode, since this is needed to be prepared to respond to pendown interrupts. Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
parent
0f622bf465
commit
3eac5c7e44
1 changed files with 135 additions and 37 deletions
|
@ -68,6 +68,8 @@ struct ts_event {
|
|||
u16 y;
|
||||
u16 z1, z2;
|
||||
int ignore;
|
||||
u8 x_buf[3];
|
||||
u8 y_buf[3];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -79,6 +81,8 @@ struct ads7846_packet {
|
|||
u8 read_x, read_y, read_z1, read_z2, pwrdown;
|
||||
u16 dummy; /* for the pwrdown read */
|
||||
struct ts_event tc;
|
||||
/* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
|
||||
u8 read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
|
||||
};
|
||||
|
||||
struct ads7846 {
|
||||
|
@ -207,6 +211,14 @@ struct ser_req {
|
|||
struct spi_transfer xfer[6];
|
||||
};
|
||||
|
||||
struct ads7845_ser_req {
|
||||
u8 command[3];
|
||||
u8 pwrdown[3];
|
||||
u8 sample[3];
|
||||
struct spi_message msg;
|
||||
struct spi_transfer xfer[2];
|
||||
};
|
||||
|
||||
static void ads7846_enable(struct ads7846 *ts);
|
||||
static void ads7846_disable(struct ads7846 *ts);
|
||||
|
||||
|
@ -287,6 +299,41 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
|
|||
return status;
|
||||
}
|
||||
|
||||
static int ads7845_read12_ser(struct device *dev, unsigned command)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct ads7846 *ts = dev_get_drvdata(dev);
|
||||
struct ads7845_ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
|
||||
int status;
|
||||
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
spi_message_init(&req->msg);
|
||||
|
||||
req->command[0] = (u8) command;
|
||||
req->xfer[0].tx_buf = req->command;
|
||||
req->xfer[0].rx_buf = req->sample;
|
||||
req->xfer[0].len = 3;
|
||||
spi_message_add_tail(&req->xfer[0], &req->msg);
|
||||
|
||||
ts->irq_disabled = 1;
|
||||
disable_irq(spi->irq);
|
||||
status = spi_sync(spi, &req->msg);
|
||||
ts->irq_disabled = 0;
|
||||
enable_irq(spi->irq);
|
||||
|
||||
if (status == 0) {
|
||||
/* BE12 value, then padding */
|
||||
status = be16_to_cpu(*((u16 *)&req->sample[1]));
|
||||
status = status >> 3;
|
||||
status &= 0x0fff;
|
||||
}
|
||||
|
||||
kfree(req);
|
||||
return status;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
|
||||
|
||||
#define SHOW(name, var, adjust) static ssize_t \
|
||||
|
@ -540,10 +587,17 @@ static void ads7846_rx(void *ads)
|
|||
/* ads7846_rx_val() did in-place conversion (including byteswap) from
|
||||
* on-the-wire format as part of debouncing to get stable readings.
|
||||
*/
|
||||
if (ts->model == 7845) {
|
||||
x = *(u16 *)packet->tc.x_buf;
|
||||
y = *(u16 *)packet->tc.y_buf;
|
||||
z1 = 0;
|
||||
z2 = 0;
|
||||
} else {
|
||||
x = packet->tc.x;
|
||||
y = packet->tc.y;
|
||||
z1 = packet->tc.z1;
|
||||
z2 = packet->tc.z2;
|
||||
}
|
||||
|
||||
/* range filtering */
|
||||
if (x == MAX_12BIT)
|
||||
|
@ -551,6 +605,12 @@ static void ads7846_rx(void *ads)
|
|||
|
||||
if (ts->model == 7843) {
|
||||
Rt = ts->pressure_max / 2;
|
||||
} else if (ts->model == 7845) {
|
||||
if (get_pendown_state(ts))
|
||||
Rt = ts->pressure_max / 2;
|
||||
else
|
||||
Rt = 0;
|
||||
dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
|
||||
} else if (likely(x && z1)) {
|
||||
/* compute touch pressure resistance using equation #2 */
|
||||
Rt = z2;
|
||||
|
@ -671,10 +731,14 @@ static void ads7846_rx_val(void *ads)
|
|||
m = &ts->msg[ts->msg_idx];
|
||||
t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
|
||||
|
||||
/* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
|
||||
* built from two 8 bit values written msb-first.
|
||||
if (ts->model == 7845) {
|
||||
val = be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
|
||||
} else {
|
||||
/* adjust: on-wire is a must-ignore bit, a BE12 value, then
|
||||
* padding; built from two 8 bit values written msb-first.
|
||||
*/
|
||||
val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
|
||||
}
|
||||
|
||||
action = ts->filter(ts->filter_data, ts->msg_idx, &val);
|
||||
switch (action) {
|
||||
|
@ -1009,6 +1073,15 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||
|
||||
spi_message_init(m);
|
||||
|
||||
if (ts->model == 7845) {
|
||||
packet->read_y_cmd[0] = READ_Y(vref);
|
||||
packet->read_y_cmd[1] = 0;
|
||||
packet->read_y_cmd[2] = 0;
|
||||
x->tx_buf = &packet->read_y_cmd[0];
|
||||
x->rx_buf = &packet->tc.y_buf[0];
|
||||
x->len = 3;
|
||||
spi_message_add_tail(x, m);
|
||||
} else {
|
||||
/* y- still on; turn on only y+ (and ADC) */
|
||||
packet->read_y = READ_Y(vref);
|
||||
x->tx_buf = &packet->read_y;
|
||||
|
@ -1019,6 +1092,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||
x->rx_buf = &packet->tc.y;
|
||||
x->len = 2;
|
||||
spi_message_add_tail(x, m);
|
||||
}
|
||||
|
||||
/* the first sample after switching drivers can be low quality;
|
||||
* optionally discard it, using a second one after the signals
|
||||
|
@ -1044,6 +1118,16 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||
m++;
|
||||
spi_message_init(m);
|
||||
|
||||
if (ts->model == 7845) {
|
||||
x++;
|
||||
packet->read_x_cmd[0] = READ_X(vref);
|
||||
packet->read_x_cmd[1] = 0;
|
||||
packet->read_x_cmd[2] = 0;
|
||||
x->tx_buf = &packet->read_x_cmd[0];
|
||||
x->rx_buf = &packet->tc.x_buf[0];
|
||||
x->len = 3;
|
||||
spi_message_add_tail(x, m);
|
||||
} else {
|
||||
/* turn y- off, x+ on, then leave in lowpower */
|
||||
x++;
|
||||
packet->read_x = READ_X(vref);
|
||||
|
@ -1055,6 +1139,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||
x->rx_buf = &packet->tc.x;
|
||||
x->len = 2;
|
||||
spi_message_add_tail(x, m);
|
||||
}
|
||||
|
||||
/* ... maybe discard first sample ... */
|
||||
if (pdata->settle_delay_usecs) {
|
||||
|
@ -1145,6 +1230,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||
m++;
|
||||
spi_message_init(m);
|
||||
|
||||
if (ts->model == 7845) {
|
||||
x++;
|
||||
packet->pwrdown_cmd[0] = PWRDOWN;
|
||||
packet->pwrdown_cmd[1] = 0;
|
||||
packet->pwrdown_cmd[2] = 0;
|
||||
x->tx_buf = &packet->pwrdown_cmd[0];
|
||||
x->len = 3;
|
||||
} else {
|
||||
x++;
|
||||
packet->pwrdown = PWRDOWN;
|
||||
x->tx_buf = &packet->pwrdown;
|
||||
|
@ -1154,6 +1247,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||
x++;
|
||||
x->rx_buf = &packet->dummy;
|
||||
x->len = 2;
|
||||
}
|
||||
|
||||
CS_CHANGE(*x);
|
||||
spi_message_add_tail(x, m);
|
||||
|
||||
|
@ -1202,6 +1297,9 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||
/* take a first sample, leaving nPENIRQ active and vREF off; avoid
|
||||
* the touchscreen, in case it's not connected.
|
||||
*/
|
||||
if (ts->model == 7845)
|
||||
ads7845_read12_ser(&spi->dev, PWRDOWN);
|
||||
else
|
||||
(void) ads7846_read12_ser(&spi->dev,
|
||||
READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
|
||||
|
||||
|
|
Loading…
Reference in a new issue