aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/input/touchscreen/Kconfig9
-rw-r--r--drivers/input/touchscreen/ads7846.c306
2 files changed, 224 insertions, 91 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 29ca0ab0acb..4bec8422821 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -12,13 +12,18 @@ menuconfig INPUT_TOUCHSCREEN
12if INPUT_TOUCHSCREEN 12if INPUT_TOUCHSCREEN
13 13
14config TOUCHSCREEN_ADS7846 14config TOUCHSCREEN_ADS7846
15 tristate "ADS 7846 based touchscreens" 15 tristate "ADS 7846/7843 based touchscreens"
16 depends on SPI_MASTER 16 depends on SPI_MASTER
17 depends on HWMON = n || HWMON
17 help 18 help
18 Say Y here if you have a touchscreen interface using the 19 Say Y here if you have a touchscreen interface using the
19 ADS7846 controller, and your board-specific initialization 20 ADS7846 or ADS7843 controller, and your board-specific setup
20 code includes that in its table of SPI devices. 21 code includes that in its table of SPI devices.
21 22
23 If HWMON is selected, and the driver is told the reference voltage
24 on your board, you will also get hwmon interfaces for the voltage
25 (and on ads7846, temperature) sensors of this chip.
26
22 If unsure, say N (but it's safe to say "Y"). 27 If unsure, say N (but it's safe to say "Y").
23 28
24 To compile this driver as a module, choose M here: the 29 To compile this driver as a module, choose M here: the
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index b18c63a3f2a..cd251efda41 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 */