aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/ads7846.c
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2007-01-18 00:45:48 -0500
committerDmitry Torokhov <dtor@insightbb.com>2007-01-18 00:45:48 -0500
commit2c8dc071517ec2843869024dc82be2e246f41064 (patch)
tree793c90a34b40d9f2a60eb108387b1077ec9e8861 /drivers/input/touchscreen/ads7846.c
parent15e3589e59c35ed33823dda3d38ad171222b83b4 (diff)
Input: ads7846 - be more compatible with the hwmon framework
- Hook up to hwmon * show sensor attributes only if hwmon is present * ... and the board's reference voltage is known * otherwise be just a touchscreen - Report voltages per hwmon convention * measure in millivolts * voltages are named in[0-8]_input (ugh) * for 7846 chips, properly range-adjust vBATT/in1_input Battery measurements help during recharge monitoring. On OSK/Mistral, the measured voltage agreed with a multimeter to several decimal places. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/touchscreen/ads7846.c')
-rw-r--r--drivers/input/touchscreen/ads7846.c306
1 files changed, 217 insertions, 89 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index b18c63a3f2ab..cd251efda410 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -17,8 +17,9 @@
17 * it under the terms of the GNU General Public License version 2 as 17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation. 18 * published by the Free Software Foundation.
19 */ 19 */
20#include <linux/device.h> 20#include <linux/hwmon.h>
21#include <linux/init.h> 21#include <linux/init.h>
22#include <linux/err.h>
22#include <linux/delay.h> 23#include <linux/delay.h>
23#include <linux/input.h> 24#include <linux/input.h>
24#include <linux/interrupt.h> 25#include <linux/interrupt.h>
@@ -69,7 +70,7 @@ struct ts_event {
69 u16 x; 70 u16 x;
70 u16 y; 71 u16 y;
71 u16 z1, z2; 72 u16 z1, z2;
72 int ignore; 73 int ignore;
73}; 74};
74 75
75struct ads7846 { 76struct ads7846 {
@@ -77,7 +78,12 @@ struct ads7846 {
77 char phys[32]; 78 char phys[32];
78 79
79 struct spi_device *spi; 80 struct spi_device *spi;
81
82#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
80 struct attribute_group *attr_group; 83 struct attribute_group *attr_group;
84 struct class_device *hwmon;
85#endif
86
81 u16 model; 87 u16 model;
82 u16 vref_delay_usecs; 88 u16 vref_delay_usecs;
83 u16 x_plate_ohms; 89 u16 x_plate_ohms;
@@ -170,7 +176,12 @@ struct ads7846 {
170 176
171/* 177/*
172 * Non-touchscreen sensors only use single-ended conversions. 178 * Non-touchscreen sensors only use single-ended conversions.
179 * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
180 * ads7846 lets that pin be unconnected, to use internal vREF.
173 */ 181 */
182static unsigned vREF_mV;
183module_param(vREF_mV, uint, 0);
184MODULE_PARM_DESC(vREF_mV, "external vREF voltage, in milliVolts");
174 185
175struct ser_req { 186struct ser_req {
176 u8 ref_on; 187 u8 ref_on;
@@ -198,50 +209,55 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
198 struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL); 209 struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
199 int status; 210 int status;
200 int sample; 211 int sample;
201 int i; 212 int use_internal;
202 213
203 if (!req) 214 if (!req)
204 return -ENOMEM; 215 return -ENOMEM;
205 216
206 spi_message_init(&req->msg); 217 spi_message_init(&req->msg);
207 218
208 /* activate reference, so it has time to settle; */ 219 /* FIXME boards with ads7846 might use external vref instead ... */
209 req->ref_on = REF_ON; 220 use_internal = (ts->model == 7846);
210 req->xfer[0].tx_buf = &req->ref_on; 221
211 req->xfer[0].len = 1; 222 /* maybe turn on internal vREF, and let it settle */
212 req->xfer[1].rx_buf = &req->scratch; 223 if (use_internal) {
213 req->xfer[1].len = 2; 224 req->ref_on = REF_ON;
214 225 req->xfer[0].tx_buf = &req->ref_on;
215 /* 226 req->xfer[0].len = 1;
216 * for external VREF, 0 usec (and assume it's always on); 227 spi_message_add_tail(&req->xfer[0], &req->msg);
217 * for 1uF, use 800 usec; 228
218 * no cap, 100 usec. 229 req->xfer[1].rx_buf = &req->scratch;
219 */ 230 req->xfer[1].len = 2;
220 req->xfer[1].delay_usecs = ts->vref_delay_usecs; 231
232 /* for 1uF, settle for 800 usec; no cap, 100 usec. */
233 req->xfer[1].delay_usecs = ts->vref_delay_usecs;
234 spi_message_add_tail(&req->xfer[1], &req->msg);
235 }
221 236
222 /* take sample */ 237 /* take sample */
223 req->command = (u8) command; 238 req->command = (u8) command;
224 req->xfer[2].tx_buf = &req->command; 239 req->xfer[2].tx_buf = &req->command;
225 req->xfer[2].len = 1; 240 req->xfer[2].len = 1;
241 spi_message_add_tail(&req->xfer[2], &req->msg);
242
226 req->xfer[3].rx_buf = &req->sample; 243 req->xfer[3].rx_buf = &req->sample;
227 req->xfer[3].len = 2; 244 req->xfer[3].len = 2;
245 spi_message_add_tail(&req->xfer[3], &req->msg);
228 246
229 /* REVISIT: take a few more samples, and compare ... */ 247 /* REVISIT: take a few more samples, and compare ... */
230 248
231 /* turn off reference */ 249 /* maybe off internal vREF */
232 req->ref_off = REF_OFF; 250 if (use_internal) {
233 req->xfer[4].tx_buf = &req->ref_off; 251 req->ref_off = REF_OFF;
234 req->xfer[4].len = 1; 252 req->xfer[4].tx_buf = &req->ref_off;
235 req->xfer[5].rx_buf = &req->scratch; 253 req->xfer[4].len = 1;
236 req->xfer[5].len = 2; 254 spi_message_add_tail(&req->xfer[4], &req->msg);
237 255
238 CS_CHANGE(req->xfer[5]); 256 req->xfer[5].rx_buf = &req->scratch;
239 257 req->xfer[5].len = 2;
240 /* group all the transfers together, so we can't interfere with 258 CS_CHANGE(req->xfer[5]);
241 * reading touchscreen state; disable penirq while sampling 259 spi_message_add_tail(&req->xfer[5], &req->msg);
242 */ 260 }
243 for (i = 0; i < 6; i++)
244 spi_message_add_tail(&req->xfer[i], &req->msg);
245 261
246 ts->irq_disabled = 1; 262 ts->irq_disabled = 1;
247 disable_irq(spi->irq); 263 disable_irq(spi->irq);
@@ -261,25 +277,173 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
261 return status ? status : sample; 277 return status ? status : sample;
262} 278}
263 279
264#define SHOW(name) static ssize_t \ 280#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
281
282#define SHOW(name, var, adjust) static ssize_t \
265name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \ 283name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
266{ \ 284{ \
285 struct ads7846 *ts = dev_get_drvdata(dev); \
267 ssize_t v = ads7846_read12_ser(dev, \ 286 ssize_t v = ads7846_read12_ser(dev, \
268 READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \ 287 READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
269 if (v < 0) \ 288 if (v < 0) \
270 return v; \ 289 return v; \
271 return sprintf(buf, "%u\n", (unsigned) v); \ 290 return sprintf(buf, "%u\n", adjust(ts, v)); \
272} \ 291} \
273static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL); 292static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
274 293
275SHOW(temp0) 294
276SHOW(temp1) 295/* Sysfs conventions report temperatures in millidegrees Celcius.
277SHOW(vaux) 296 * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high
278SHOW(vbatt) 297 * accuracy scheme without calibration data. For now we won't try either;
298 * userspace sees raw sensor values, and must scale/calibrate appropriately.
299 */
300static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
301{
302 return v;
303}
304
305SHOW(temp0, temp0, null_adjust) /* temp1_input */
306SHOW(temp1, temp1, null_adjust) /* temp2_input */
307
308
309/* sysfs conventions report voltages in millivolts. We can convert voltages
310 * if we know vREF. userspace may need to scale vAUX to match the board's
311 * external resistors; we assume that vBATT only uses the internal ones.
312 */
313static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
314{
315 unsigned retval = v;
316
317 /* external resistors may scale vAUX into 0..vREF */
318 retval *= vREF_mV;
319 retval = retval >> 12;
320 return retval;
321}
322
323static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
324{
325 unsigned retval = vaux_adjust(ts, v);
326
327 /* ads7846 has a resistor ladder to scale this signal down */
328 if (ts->model == 7846)
329 retval *= 4;
330 return retval;
331}
332
333SHOW(in0_input, vaux, vaux_adjust)
334SHOW(in1_input, vbatt, vbatt_adjust)
335
336
337static struct attribute *ads7846_attributes[] = {
338 &dev_attr_temp0.attr,
339 &dev_attr_temp1.attr,
340 &dev_attr_in0_input.attr,
341 &dev_attr_in1_input.attr,
342 NULL,
343};
344
345static struct attribute_group ads7846_attr_group = {
346 .attrs = ads7846_attributes,
347};
348
349static struct attribute *ads7843_attributes[] = {
350 &dev_attr_in0_input.attr,
351 &dev_attr_in1_input.attr,
352 NULL,
353};
354
355static struct attribute_group ads7843_attr_group = {
356 .attrs = ads7843_attributes,
357};
358
359static struct attribute *ads7845_attributes[] = {
360 &dev_attr_in0_input.attr,
361 NULL,
362};
363
364static struct attribute_group ads7845_attr_group = {
365 .attrs = ads7845_attributes,
366};
367
368static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
369{
370 struct class_device *hwmon;
371 int err;
372
373 /* hwmon sensors need a reference voltage */
374 switch (ts->model) {
375 case 7846:
376 if (!vREF_mV) {
377 dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
378 vREF_mV = 2500;
379 }
380 break;
381 case 7845:
382 case 7843:
383 if (!vREF_mV) {
384 dev_warn(&spi->dev,
385 "external vREF for ADS%d not specified\n",
386 ts->model);
387 return 0;
388 }
389 break;
390 }
391
392 /* different chips have different sensor groups */
393 switch (ts->model) {
394 case 7846:
395 ts->attr_group = &ads7846_attr_group;
396 break;
397 case 7845:
398 ts->attr_group = &ads7845_attr_group;
399 break;
400 case 7843:
401 ts->attr_group = &ads7843_attr_group;
402 break;
403 default:
404 dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model);
405 return 0;
406 }
407
408 err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
409 if (err)
410 return err;
411
412 hwmon = hwmon_device_register(&spi->dev);
413 if (IS_ERR(hwmon)) {
414 sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
415 return PTR_ERR(hwmon);
416 }
417
418 ts->hwmon = hwmon;
419 return 0;
420}
421
422static void ads784x_hwmon_unregister(struct spi_device *spi,
423 struct ads7846 *ts)
424{
425 if (ts->hwmon) {
426 sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
427 hwmon_device_unregister(ts->hwmon);
428 }
429}
430
431#else
432static inline int ads784x_hwmon_register(struct spi_device *spi,
433 struct ads7846 *ts)
434{
435 return 0;
436}
437
438static inline void ads784x_hwmon_unregister(struct spi_device *spi,
439 struct ads7846 *ts)
440{
441}
442#endif
279 443
280static int is_pen_down(struct device *dev) 444static int is_pen_down(struct device *dev)
281{ 445{
282 struct ads7846 *ts = dev_get_drvdata(dev); 446 struct ads7846 *ts = dev_get_drvdata(dev);
283 447
284 return ts->pendown; 448 return ts->pendown;
285} 449}
@@ -323,46 +487,14 @@ static ssize_t ads7846_disable_store(struct device *dev,
323 487
324static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); 488static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
325 489
326static struct attribute *ads7846_attributes[] = { 490static struct attribute *ads784x_attributes[] = {
327 &dev_attr_temp0.attr,
328 &dev_attr_temp1.attr,
329 &dev_attr_vbatt.attr,
330 &dev_attr_vaux.attr,
331 &dev_attr_pen_down.attr,
332 &dev_attr_disable.attr,
333 NULL,
334};
335
336static struct attribute_group ads7846_attr_group = {
337 .attrs = ads7846_attributes,
338};
339
340/*
341 * ads7843/7845 don't have temperature sensors, and
342 * use the other sensors a bit differently too
343 */
344
345static struct attribute *ads7843_attributes[] = {
346 &dev_attr_vbatt.attr,
347 &dev_attr_vaux.attr,
348 &dev_attr_pen_down.attr, 491 &dev_attr_pen_down.attr,
349 &dev_attr_disable.attr, 492 &dev_attr_disable.attr,
350 NULL, 493 NULL,
351}; 494};
352 495
353static struct attribute_group ads7843_attr_group = { 496static struct attribute_group ads784x_attr_group = {
354 .attrs = ads7843_attributes, 497 .attrs = ads784x_attributes,
355};
356
357static struct attribute *ads7845_attributes[] = {
358 &dev_attr_vaux.attr,
359 &dev_attr_pen_down.attr,
360 &dev_attr_disable.attr,
361 NULL,
362};
363
364static struct attribute_group ads7845_attr_group = {
365 .attrs = ads7845_attributes,
366}; 498};
367 499
368/*--------------------------------------------------------------------------*/ 500/*--------------------------------------------------------------------------*/
@@ -886,28 +1018,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
886 goto err_cleanup_filter; 1018 goto err_cleanup_filter;
887 } 1019 }
888 1020
1021 err = ads784x_hwmon_register(spi, ts);
1022 if (err)
1023 goto err_free_irq;
1024
889 dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq); 1025 dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
890 1026
891 /* take a first sample, leaving nPENIRQ active; avoid 1027 /* take a first sample, leaving nPENIRQ active and vREF off; avoid
892 * the touchscreen, in case it's not connected. 1028 * the touchscreen, in case it's not connected.
893 */ 1029 */
894 (void) ads7846_read12_ser(&spi->dev, 1030 (void) ads7846_read12_ser(&spi->dev,
895 READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON); 1031 READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
896 1032
897 switch (ts->model) { 1033 err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
898 case 7846:
899 ts->attr_group = &ads7846_attr_group;
900 break;
901 case 7845:
902 ts->attr_group = &ads7845_attr_group;
903 break;
904 default:
905 ts->attr_group = &ads7843_attr_group;
906 break;
907 }
908 err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
909 if (err) 1034 if (err)
910 goto err_free_irq; 1035 goto err_remove_hwmon;
911 1036
912 err = input_register_device(input_dev); 1037 err = input_register_device(input_dev);
913 if (err) 1038 if (err)
@@ -916,7 +1041,9 @@ static int __devinit ads7846_probe(struct spi_device *spi)
916 return 0; 1041 return 0;
917 1042
918 err_remove_attr_group: 1043 err_remove_attr_group:
919 sysfs_remove_group(&spi->dev.kobj, ts->attr_group); 1044 sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
1045 err_remove_hwmon:
1046 ads784x_hwmon_unregister(spi, ts);
920 err_free_irq: 1047 err_free_irq:
921 free_irq(spi->irq, ts); 1048 free_irq(spi->irq, ts);
922 err_cleanup_filter: 1049 err_cleanup_filter:
@@ -932,11 +1059,12 @@ static int __devexit ads7846_remove(struct spi_device *spi)
932{ 1059{
933 struct ads7846 *ts = dev_get_drvdata(&spi->dev); 1060 struct ads7846 *ts = dev_get_drvdata(&spi->dev);
934 1061
1062 ads784x_hwmon_unregister(spi, ts);
935 input_unregister_device(ts->input); 1063 input_unregister_device(ts->input);
936 1064
937 ads7846_suspend(spi, PMSG_SUSPEND); 1065 ads7846_suspend(spi, PMSG_SUSPEND);
938 1066
939 sysfs_remove_group(&spi->dev.kobj, ts->attr_group); 1067 sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
940 1068
941 free_irq(ts->spi->irq, ts); 1069 free_irq(ts->spi->irq, ts);
942 /* suspend left the IRQ disabled */ 1070 /* suspend left the IRQ disabled */