diff options
author | Anatolij Gustschin <agust@denx.de> | 2010-07-01 12:01:56 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-07-03 16:13:22 -0400 |
commit | 3eac5c7e44f35eb07f0ecb28ce60f15b2dda1932 (patch) | |
tree | a943d0d07ef4c6178fcbdbca68290ee48b930cb1 /drivers/input/touchscreen | |
parent | 0f622bf465e78c390e13c5f4a14d0b3f8fb7c7e5 (diff) |
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>
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 172 |
1 files changed, 135 insertions, 37 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index a3771607ead5..16031933a8f6 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c | |||
@@ -68,6 +68,8 @@ struct ts_event { | |||
68 | u16 y; | 68 | u16 y; |
69 | u16 z1, z2; | 69 | u16 z1, z2; |
70 | int ignore; | 70 | int ignore; |
71 | u8 x_buf[3]; | ||
72 | u8 y_buf[3]; | ||
71 | }; | 73 | }; |
72 | 74 | ||
73 | /* | 75 | /* |
@@ -79,6 +81,8 @@ struct ads7846_packet { | |||
79 | u8 read_x, read_y, read_z1, read_z2, pwrdown; | 81 | u8 read_x, read_y, read_z1, read_z2, pwrdown; |
80 | u16 dummy; /* for the pwrdown read */ | 82 | u16 dummy; /* for the pwrdown read */ |
81 | struct ts_event tc; | 83 | struct ts_event tc; |
84 | /* for ads7845 with mpc5121 psc spi we use 3-byte buffers */ | ||
85 | u8 read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3]; | ||
82 | }; | 86 | }; |
83 | 87 | ||
84 | struct ads7846 { | 88 | struct ads7846 { |
@@ -207,6 +211,14 @@ struct ser_req { | |||
207 | struct spi_transfer xfer[6]; | 211 | struct spi_transfer xfer[6]; |
208 | }; | 212 | }; |
209 | 213 | ||
214 | struct ads7845_ser_req { | ||
215 | u8 command[3]; | ||
216 | u8 pwrdown[3]; | ||
217 | u8 sample[3]; | ||
218 | struct spi_message msg; | ||
219 | struct spi_transfer xfer[2]; | ||
220 | }; | ||
221 | |||
210 | static void ads7846_enable(struct ads7846 *ts); | 222 | static void ads7846_enable(struct ads7846 *ts); |
211 | static void ads7846_disable(struct ads7846 *ts); | 223 | static void ads7846_disable(struct ads7846 *ts); |
212 | 224 | ||
@@ -287,6 +299,41 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) | |||
287 | return status; | 299 | return status; |
288 | } | 300 | } |
289 | 301 | ||
302 | static int ads7845_read12_ser(struct device *dev, unsigned command) | ||
303 | { | ||
304 | struct spi_device *spi = to_spi_device(dev); | ||
305 | struct ads7846 *ts = dev_get_drvdata(dev); | ||
306 | struct ads7845_ser_req *req = kzalloc(sizeof *req, GFP_KERNEL); | ||
307 | int status; | ||
308 | |||
309 | if (!req) | ||
310 | return -ENOMEM; | ||
311 | |||
312 | spi_message_init(&req->msg); | ||
313 | |||
314 | req->command[0] = (u8) command; | ||
315 | req->xfer[0].tx_buf = req->command; | ||
316 | req->xfer[0].rx_buf = req->sample; | ||
317 | req->xfer[0].len = 3; | ||
318 | spi_message_add_tail(&req->xfer[0], &req->msg); | ||
319 | |||
320 | ts->irq_disabled = 1; | ||
321 | disable_irq(spi->irq); | ||
322 | status = spi_sync(spi, &req->msg); | ||
323 | ts->irq_disabled = 0; | ||
324 | enable_irq(spi->irq); | ||
325 | |||
326 | if (status == 0) { | ||
327 | /* BE12 value, then padding */ | ||
328 | status = be16_to_cpu(*((u16 *)&req->sample[1])); | ||
329 | status = status >> 3; | ||
330 | status &= 0x0fff; | ||
331 | } | ||
332 | |||
333 | kfree(req); | ||
334 | return status; | ||
335 | } | ||
336 | |||
290 | #if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) | 337 | #if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) |
291 | 338 | ||
292 | #define SHOW(name, var, adjust) static ssize_t \ | 339 | #define SHOW(name, var, adjust) static ssize_t \ |
@@ -540,10 +587,17 @@ static void ads7846_rx(void *ads) | |||
540 | /* ads7846_rx_val() did in-place conversion (including byteswap) from | 587 | /* ads7846_rx_val() did in-place conversion (including byteswap) from |
541 | * on-the-wire format as part of debouncing to get stable readings. | 588 | * on-the-wire format as part of debouncing to get stable readings. |
542 | */ | 589 | */ |
543 | x = packet->tc.x; | 590 | if (ts->model == 7845) { |
544 | y = packet->tc.y; | 591 | x = *(u16 *)packet->tc.x_buf; |
545 | z1 = packet->tc.z1; | 592 | y = *(u16 *)packet->tc.y_buf; |
546 | z2 = packet->tc.z2; | 593 | z1 = 0; |
594 | z2 = 0; | ||
595 | } else { | ||
596 | x = packet->tc.x; | ||
597 | y = packet->tc.y; | ||
598 | z1 = packet->tc.z1; | ||
599 | z2 = packet->tc.z2; | ||
600 | } | ||
547 | 601 | ||
548 | /* range filtering */ | 602 | /* range filtering */ |
549 | if (x == MAX_12BIT) | 603 | if (x == MAX_12BIT) |
@@ -551,6 +605,12 @@ static void ads7846_rx(void *ads) | |||
551 | 605 | ||
552 | if (ts->model == 7843) { | 606 | if (ts->model == 7843) { |
553 | Rt = ts->pressure_max / 2; | 607 | Rt = ts->pressure_max / 2; |
608 | } else if (ts->model == 7845) { | ||
609 | if (get_pendown_state(ts)) | ||
610 | Rt = ts->pressure_max / 2; | ||
611 | else | ||
612 | Rt = 0; | ||
613 | dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt); | ||
554 | } else if (likely(x && z1)) { | 614 | } else if (likely(x && z1)) { |
555 | /* compute touch pressure resistance using equation #2 */ | 615 | /* compute touch pressure resistance using equation #2 */ |
556 | Rt = z2; | 616 | Rt = z2; |
@@ -671,10 +731,14 @@ static void ads7846_rx_val(void *ads) | |||
671 | m = &ts->msg[ts->msg_idx]; | 731 | m = &ts->msg[ts->msg_idx]; |
672 | t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); | 732 | t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); |
673 | 733 | ||
674 | /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; | 734 | if (ts->model == 7845) { |
675 | * built from two 8 bit values written msb-first. | 735 | val = be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3; |
676 | */ | 736 | } else { |
677 | val = be16_to_cpup((__be16 *)t->rx_buf) >> 3; | 737 | /* adjust: on-wire is a must-ignore bit, a BE12 value, then |
738 | * padding; built from two 8 bit values written msb-first. | ||
739 | */ | ||
740 | val = be16_to_cpup((__be16 *)t->rx_buf) >> 3; | ||
741 | } | ||
678 | 742 | ||
679 | action = ts->filter(ts->filter_data, ts->msg_idx, &val); | 743 | action = ts->filter(ts->filter_data, ts->msg_idx, &val); |
680 | switch (action) { | 744 | switch (action) { |
@@ -1009,16 +1073,26 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1009 | 1073 | ||
1010 | spi_message_init(m); | 1074 | spi_message_init(m); |
1011 | 1075 | ||
1012 | /* y- still on; turn on only y+ (and ADC) */ | 1076 | if (ts->model == 7845) { |
1013 | packet->read_y = READ_Y(vref); | 1077 | packet->read_y_cmd[0] = READ_Y(vref); |
1014 | x->tx_buf = &packet->read_y; | 1078 | packet->read_y_cmd[1] = 0; |
1015 | x->len = 1; | 1079 | packet->read_y_cmd[2] = 0; |
1016 | spi_message_add_tail(x, m); | 1080 | x->tx_buf = &packet->read_y_cmd[0]; |
1081 | x->rx_buf = &packet->tc.y_buf[0]; | ||
1082 | x->len = 3; | ||
1083 | spi_message_add_tail(x, m); | ||
1084 | } else { | ||
1085 | /* y- still on; turn on only y+ (and ADC) */ | ||
1086 | packet->read_y = READ_Y(vref); | ||
1087 | x->tx_buf = &packet->read_y; | ||
1088 | x->len = 1; | ||
1089 | spi_message_add_tail(x, m); | ||
1017 | 1090 | ||
1018 | x++; | 1091 | x++; |
1019 | x->rx_buf = &packet->tc.y; | 1092 | x->rx_buf = &packet->tc.y; |
1020 | x->len = 2; | 1093 | x->len = 2; |
1021 | spi_message_add_tail(x, m); | 1094 | spi_message_add_tail(x, m); |
1095 | } | ||
1022 | 1096 | ||
1023 | /* the first sample after switching drivers can be low quality; | 1097 | /* the first sample after switching drivers can be low quality; |
1024 | * optionally discard it, using a second one after the signals | 1098 | * optionally discard it, using a second one after the signals |
@@ -1044,17 +1118,28 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1044 | m++; | 1118 | m++; |
1045 | spi_message_init(m); | 1119 | spi_message_init(m); |
1046 | 1120 | ||
1047 | /* turn y- off, x+ on, then leave in lowpower */ | 1121 | if (ts->model == 7845) { |
1048 | x++; | 1122 | x++; |
1049 | packet->read_x = READ_X(vref); | 1123 | packet->read_x_cmd[0] = READ_X(vref); |
1050 | x->tx_buf = &packet->read_x; | 1124 | packet->read_x_cmd[1] = 0; |
1051 | x->len = 1; | 1125 | packet->read_x_cmd[2] = 0; |
1052 | spi_message_add_tail(x, m); | 1126 | x->tx_buf = &packet->read_x_cmd[0]; |
1127 | x->rx_buf = &packet->tc.x_buf[0]; | ||
1128 | x->len = 3; | ||
1129 | spi_message_add_tail(x, m); | ||
1130 | } else { | ||
1131 | /* turn y- off, x+ on, then leave in lowpower */ | ||
1132 | x++; | ||
1133 | packet->read_x = READ_X(vref); | ||
1134 | x->tx_buf = &packet->read_x; | ||
1135 | x->len = 1; | ||
1136 | spi_message_add_tail(x, m); | ||
1053 | 1137 | ||
1054 | x++; | 1138 | x++; |
1055 | x->rx_buf = &packet->tc.x; | 1139 | x->rx_buf = &packet->tc.x; |
1056 | x->len = 2; | 1140 | x->len = 2; |
1057 | spi_message_add_tail(x, m); | 1141 | spi_message_add_tail(x, m); |
1142 | } | ||
1058 | 1143 | ||
1059 | /* ... maybe discard first sample ... */ | 1144 | /* ... maybe discard first sample ... */ |
1060 | if (pdata->settle_delay_usecs) { | 1145 | if (pdata->settle_delay_usecs) { |
@@ -1145,15 +1230,25 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1145 | m++; | 1230 | m++; |
1146 | spi_message_init(m); | 1231 | spi_message_init(m); |
1147 | 1232 | ||
1148 | x++; | 1233 | if (ts->model == 7845) { |
1149 | packet->pwrdown = PWRDOWN; | 1234 | x++; |
1150 | x->tx_buf = &packet->pwrdown; | 1235 | packet->pwrdown_cmd[0] = PWRDOWN; |
1151 | x->len = 1; | 1236 | packet->pwrdown_cmd[1] = 0; |
1152 | spi_message_add_tail(x, m); | 1237 | packet->pwrdown_cmd[2] = 0; |
1238 | x->tx_buf = &packet->pwrdown_cmd[0]; | ||
1239 | x->len = 3; | ||
1240 | } else { | ||
1241 | x++; | ||
1242 | packet->pwrdown = PWRDOWN; | ||
1243 | x->tx_buf = &packet->pwrdown; | ||
1244 | x->len = 1; | ||
1245 | spi_message_add_tail(x, m); | ||
1246 | |||
1247 | x++; | ||
1248 | x->rx_buf = &packet->dummy; | ||
1249 | x->len = 2; | ||
1250 | } | ||
1153 | 1251 | ||
1154 | x++; | ||
1155 | x->rx_buf = &packet->dummy; | ||
1156 | x->len = 2; | ||
1157 | CS_CHANGE(*x); | 1252 | CS_CHANGE(*x); |
1158 | spi_message_add_tail(x, m); | 1253 | spi_message_add_tail(x, m); |
1159 | 1254 | ||
@@ -1202,8 +1297,11 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1202 | /* take a first sample, leaving nPENIRQ active and vREF off; avoid | 1297 | /* take a first sample, leaving nPENIRQ active and vREF off; avoid |
1203 | * the touchscreen, in case it's not connected. | 1298 | * the touchscreen, in case it's not connected. |
1204 | */ | 1299 | */ |
1205 | (void) ads7846_read12_ser(&spi->dev, | 1300 | if (ts->model == 7845) |
1206 | READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON); | 1301 | ads7845_read12_ser(&spi->dev, PWRDOWN); |
1302 | else | ||
1303 | (void) ads7846_read12_ser(&spi->dev, | ||
1304 | READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON); | ||
1207 | 1305 | ||
1208 | err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group); | 1306 | err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group); |
1209 | if (err) | 1307 | if (err) |