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) |
