diff options
author | Sebastian Reichel <sre@kernel.org> | 2014-05-29 02:57:29 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-05-29 03:06:00 -0400 |
commit | a38cfebb56898633687ab337fd53710e63a0aedd (patch) | |
tree | 1b44393603fc1ae1469e1698238044bd5973dda4 | |
parent | b98abe52fa8e2a3797d3cc2db3d0e109f4549c03 (diff) |
Input: tsc2005 - add DT support
This adds DT support to the tsc2005 touchscreen driver. It also adds
regulator support to the driver if booted via DT.
Reviewed-by: Pavel Machek <pavel@ucw.cz>
Acked-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt | 42 | ||||
-rw-r--r-- | drivers/input/touchscreen/tsc2005.c | 124 |
2 files changed, 146 insertions, 20 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt b/Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt new file mode 100644 index 000000000000..4b641c7bf1c2 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt | |||
@@ -0,0 +1,42 @@ | |||
1 | * Texas Instruments tsc2005 touchscreen controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : "ti,tsc2005" | ||
5 | - reg : SPI device address | ||
6 | - spi-max-frequency : Maximal SPI speed | ||
7 | - interrupts : IRQ specifier | ||
8 | - reset-gpios : GPIO specifier | ||
9 | - vio-supply : Regulator specifier | ||
10 | |||
11 | Optional properties: | ||
12 | - ti,x-plate-ohms : integer, resistance of the touchscreen's X plates | ||
13 | in ohm (defaults to 280) | ||
14 | - ti,esd-recovery-timeout-ms : integer, if the touchscreen does not respond after | ||
15 | the configured time (in milli seconds), the driver | ||
16 | will reset it. This is disabled by default. | ||
17 | - properties defined in touchscreen.txt | ||
18 | |||
19 | Example: | ||
20 | |||
21 | &mcspi1 { | ||
22 | tsc2005@0 { | ||
23 | compatible = "ti,tsc2005"; | ||
24 | spi-max-frequency = <6000000>; | ||
25 | reg = <0>; | ||
26 | |||
27 | vio-supply = <&vio>; | ||
28 | |||
29 | reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; /* 104 */ | ||
30 | interrupts-extended = <&gpio4 4 IRQ_TYPE_EDGE_RISING>; /* 100 */ | ||
31 | |||
32 | touchscreen-fuzz-x = <4>; | ||
33 | touchscreen-fuzz-y = <7>; | ||
34 | touchscreen-fuzz-pressure = <2>; | ||
35 | touchscreen-max-x = <4096>; | ||
36 | touchscreen-max-y = <4096>; | ||
37 | touchscreen-max-pressure = <2048>; | ||
38 | |||
39 | ti,x-plate-ohms = <280>; | ||
40 | ti,esd-recovery-timeout-ms = <8000>; | ||
41 | }; | ||
42 | } | ||
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index d981e49368ad..52380b68ebdf 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c | |||
@@ -25,11 +25,15 @@ | |||
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/input.h> | 27 | #include <linux/input.h> |
28 | #include <linux/input/touchscreen.h> | ||
28 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
29 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
30 | #include <linux/pm.h> | 31 | #include <linux/pm.h> |
32 | #include <linux/of.h> | ||
33 | #include <linux/of_gpio.h> | ||
31 | #include <linux/spi/spi.h> | 34 | #include <linux/spi/spi.h> |
32 | #include <linux/spi/tsc2005.h> | 35 | #include <linux/spi/tsc2005.h> |
36 | #include <linux/regulator/consumer.h> | ||
33 | 37 | ||
34 | /* | 38 | /* |
35 | * The touchscreen interface operates as follows: | 39 | * The touchscreen interface operates as follows: |
@@ -100,6 +104,11 @@ | |||
100 | TSC2005_CFR2_AVG_7) | 104 | TSC2005_CFR2_AVG_7) |
101 | 105 | ||
102 | #define MAX_12BIT 0xfff | 106 | #define MAX_12BIT 0xfff |
107 | #define TSC2005_DEF_X_FUZZ 4 | ||
108 | #define TSC2005_DEF_Y_FUZZ 8 | ||
109 | #define TSC2005_DEF_P_FUZZ 2 | ||
110 | #define TSC2005_DEF_RESISTOR 280 | ||
111 | |||
103 | #define TSC2005_SPI_MAX_SPEED_HZ 10000000 | 112 | #define TSC2005_SPI_MAX_SPEED_HZ 10000000 |
104 | #define TSC2005_PENUP_TIME_MS 40 | 113 | #define TSC2005_PENUP_TIME_MS 40 |
105 | 114 | ||
@@ -143,6 +152,9 @@ struct tsc2005 { | |||
143 | 152 | ||
144 | bool pen_down; | 153 | bool pen_down; |
145 | 154 | ||
155 | struct regulator *vio; | ||
156 | |||
157 | int reset_gpio; | ||
146 | void (*set_reset)(bool enable); | 158 | void (*set_reset)(bool enable); |
147 | }; | 159 | }; |
148 | 160 | ||
@@ -337,6 +349,14 @@ static void tsc2005_stop_scan(struct tsc2005 *ts) | |||
337 | tsc2005_cmd(ts, TSC2005_CMD_STOP); | 349 | tsc2005_cmd(ts, TSC2005_CMD_STOP); |
338 | } | 350 | } |
339 | 351 | ||
352 | static void tsc2005_set_reset(struct tsc2005 *ts, bool enable) | ||
353 | { | ||
354 | if (ts->reset_gpio >= 0) | ||
355 | gpio_set_value(ts->reset_gpio, enable); | ||
356 | else if (ts->set_reset) | ||
357 | ts->set_reset(enable); | ||
358 | } | ||
359 | |||
340 | /* must be called with ts->mutex held */ | 360 | /* must be called with ts->mutex held */ |
341 | static void __tsc2005_disable(struct tsc2005 *ts) | 361 | static void __tsc2005_disable(struct tsc2005 *ts) |
342 | { | 362 | { |
@@ -355,7 +375,7 @@ static void __tsc2005_enable(struct tsc2005 *ts) | |||
355 | { | 375 | { |
356 | tsc2005_start_scan(ts); | 376 | tsc2005_start_scan(ts); |
357 | 377 | ||
358 | if (ts->esd_timeout && ts->set_reset) { | 378 | if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) { |
359 | ts->last_valid_interrupt = jiffies; | 379 | ts->last_valid_interrupt = jiffies; |
360 | schedule_delayed_work(&ts->esd_work, | 380 | schedule_delayed_work(&ts->esd_work, |
361 | round_jiffies_relative( | 381 | round_jiffies_relative( |
@@ -414,9 +434,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev, | |||
414 | } | 434 | } |
415 | 435 | ||
416 | /* hardware reset */ | 436 | /* hardware reset */ |
417 | ts->set_reset(false); | 437 | tsc2005_set_reset(ts, false); |
418 | usleep_range(100, 500); /* only 10us required */ | 438 | usleep_range(100, 500); /* only 10us required */ |
419 | ts->set_reset(true); | 439 | tsc2005_set_reset(ts, true); |
420 | 440 | ||
421 | if (!success) | 441 | if (!success) |
422 | goto out; | 442 | goto out; |
@@ -459,7 +479,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj, | |||
459 | umode_t mode = attr->mode; | 479 | umode_t mode = attr->mode; |
460 | 480 | ||
461 | if (attr == &dev_attr_selftest.attr) { | 481 | if (attr == &dev_attr_selftest.attr) { |
462 | if (!ts->set_reset) | 482 | if (!ts->set_reset && !ts->reset_gpio) |
463 | mode = 0; | 483 | mode = 0; |
464 | } | 484 | } |
465 | 485 | ||
@@ -509,9 +529,9 @@ static void tsc2005_esd_work(struct work_struct *work) | |||
509 | 529 | ||
510 | tsc2005_update_pen_state(ts, 0, 0, 0); | 530 | tsc2005_update_pen_state(ts, 0, 0, 0); |
511 | 531 | ||
512 | ts->set_reset(false); | 532 | tsc2005_set_reset(ts, false); |
513 | usleep_range(100, 500); /* only 10us required */ | 533 | usleep_range(100, 500); /* only 10us required */ |
514 | ts->set_reset(true); | 534 | tsc2005_set_reset(ts, true); |
515 | 535 | ||
516 | enable_irq(ts->spi->irq); | 536 | enable_irq(ts->spi->irq); |
517 | tsc2005_start_scan(ts); | 537 | tsc2005_start_scan(ts); |
@@ -572,29 +592,47 @@ static void tsc2005_setup_spi_xfer(struct tsc2005 *ts) | |||
572 | static int tsc2005_probe(struct spi_device *spi) | 592 | static int tsc2005_probe(struct spi_device *spi) |
573 | { | 593 | { |
574 | const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev); | 594 | const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev); |
595 | struct device_node *np = spi->dev.of_node; | ||
596 | |||
575 | struct tsc2005 *ts; | 597 | struct tsc2005 *ts; |
576 | struct input_dev *input_dev; | 598 | struct input_dev *input_dev; |
577 | unsigned int max_x, max_y, max_p; | 599 | unsigned int max_x = MAX_12BIT; |
578 | unsigned int fudge_x, fudge_y, fudge_p; | 600 | unsigned int max_y = MAX_12BIT; |
601 | unsigned int max_p = MAX_12BIT; | ||
602 | unsigned int fudge_x = TSC2005_DEF_X_FUZZ; | ||
603 | unsigned int fudge_y = TSC2005_DEF_Y_FUZZ; | ||
604 | unsigned int fudge_p = TSC2005_DEF_P_FUZZ; | ||
605 | unsigned int x_plate_ohm = TSC2005_DEF_RESISTOR; | ||
606 | unsigned int esd_timeout; | ||
579 | int error; | 607 | int error; |
580 | 608 | ||
581 | if (!pdata) { | 609 | if (!np && !pdata) { |
582 | dev_err(&spi->dev, "no platform data\n"); | 610 | dev_err(&spi->dev, "no platform data\n"); |
583 | return -ENODEV; | 611 | return -ENODEV; |
584 | } | 612 | } |
585 | 613 | ||
586 | fudge_x = pdata->ts_x_fudge ? : 4; | ||
587 | fudge_y = pdata->ts_y_fudge ? : 8; | ||
588 | fudge_p = pdata->ts_pressure_fudge ? : 2; | ||
589 | max_x = pdata->ts_x_max ? : MAX_12BIT; | ||
590 | max_y = pdata->ts_y_max ? : MAX_12BIT; | ||
591 | max_p = pdata->ts_pressure_max ? : MAX_12BIT; | ||
592 | |||
593 | if (spi->irq <= 0) { | 614 | if (spi->irq <= 0) { |
594 | dev_err(&spi->dev, "no irq\n"); | 615 | dev_err(&spi->dev, "no irq\n"); |
595 | return -ENODEV; | 616 | return -ENODEV; |
596 | } | 617 | } |
597 | 618 | ||
619 | if (pdata) { | ||
620 | fudge_x = pdata->ts_x_fudge; | ||
621 | fudge_y = pdata->ts_y_fudge; | ||
622 | fudge_p = pdata->ts_pressure_fudge; | ||
623 | max_x = pdata->ts_x_max; | ||
624 | max_y = pdata->ts_y_max; | ||
625 | max_p = pdata->ts_pressure_max; | ||
626 | x_plate_ohm = pdata->ts_x_plate_ohm; | ||
627 | esd_timeout = pdata->esd_timeout_ms; | ||
628 | } else { | ||
629 | x_plate_ohm = TSC2005_DEF_RESISTOR; | ||
630 | of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm); | ||
631 | esd_timeout = 0; | ||
632 | of_property_read_u32(np, "ti,esd-recovery-timeout-ms", | ||
633 | &esd_timeout); | ||
634 | } | ||
635 | |||
598 | spi->mode = SPI_MODE_0; | 636 | spi->mode = SPI_MODE_0; |
599 | spi->bits_per_word = 8; | 637 | spi->bits_per_word = 8; |
600 | if (!spi->max_speed_hz) | 638 | if (!spi->max_speed_hz) |
@@ -615,9 +653,37 @@ static int tsc2005_probe(struct spi_device *spi) | |||
615 | ts->spi = spi; | 653 | ts->spi = spi; |
616 | ts->idev = input_dev; | 654 | ts->idev = input_dev; |
617 | 655 | ||
618 | ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280; | 656 | ts->x_plate_ohm = x_plate_ohm; |
619 | ts->esd_timeout = pdata->esd_timeout_ms; | 657 | ts->esd_timeout = esd_timeout; |
620 | ts->set_reset = pdata->set_reset; | 658 | |
659 | if (np) { | ||
660 | ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); | ||
661 | if (ts->reset_gpio == -EPROBE_DEFER) | ||
662 | return ts->reset_gpio; | ||
663 | if (ts->reset_gpio < 0) { | ||
664 | dev_err(&spi->dev, "error acquiring reset gpio: %d\n", | ||
665 | ts->reset_gpio); | ||
666 | return ts->reset_gpio; | ||
667 | } | ||
668 | |||
669 | error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0, | ||
670 | "reset-gpios"); | ||
671 | if (error) { | ||
672 | dev_err(&spi->dev, "error requesting reset gpio: %d\n", | ||
673 | error); | ||
674 | return error; | ||
675 | } | ||
676 | |||
677 | ts->vio = devm_regulator_get(&spi->dev, "vio"); | ||
678 | if (IS_ERR(ts->vio)) { | ||
679 | error = PTR_ERR(ts->vio); | ||
680 | dev_err(&spi->dev, "vio regulator missing (%d)", error); | ||
681 | return error; | ||
682 | } | ||
683 | } else { | ||
684 | ts->reset_gpio = -1; | ||
685 | ts->set_reset = pdata->set_reset; | ||
686 | } | ||
621 | 687 | ||
622 | mutex_init(&ts->mutex); | 688 | mutex_init(&ts->mutex); |
623 | 689 | ||
@@ -642,6 +708,9 @@ static int tsc2005_probe(struct spi_device *spi) | |||
642 | input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); | 708 | input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); |
643 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); | 709 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); |
644 | 710 | ||
711 | if (np) | ||
712 | touchscreen_parse_of_params(input_dev); | ||
713 | |||
645 | input_dev->open = tsc2005_open; | 714 | input_dev->open = tsc2005_open; |
646 | input_dev->close = tsc2005_close; | 715 | input_dev->close = tsc2005_close; |
647 | 716 | ||
@@ -659,12 +728,19 @@ static int tsc2005_probe(struct spi_device *spi) | |||
659 | return error; | 728 | return error; |
660 | } | 729 | } |
661 | 730 | ||
731 | /* enable regulator for DT */ | ||
732 | if (ts->vio) { | ||
733 | error = regulator_enable(ts->vio); | ||
734 | if (error) | ||
735 | return error; | ||
736 | } | ||
737 | |||
662 | spi_set_drvdata(spi, ts); | 738 | spi_set_drvdata(spi, ts); |
663 | error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group); | 739 | error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group); |
664 | if (error) { | 740 | if (error) { |
665 | dev_err(&spi->dev, | 741 | dev_err(&spi->dev, |
666 | "Failed to create sysfs attributes, err: %d\n", error); | 742 | "Failed to create sysfs attributes, err: %d\n", error); |
667 | return error; | 743 | goto disable_regulator; |
668 | } | 744 | } |
669 | 745 | ||
670 | error = input_register_device(ts->idev); | 746 | error = input_register_device(ts->idev); |
@@ -679,13 +755,21 @@ static int tsc2005_probe(struct spi_device *spi) | |||
679 | 755 | ||
680 | err_remove_sysfs: | 756 | err_remove_sysfs: |
681 | sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); | 757 | sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); |
758 | disable_regulator: | ||
759 | if (ts->vio) | ||
760 | regulator_disable(ts->vio); | ||
682 | return error; | 761 | return error; |
683 | } | 762 | } |
684 | 763 | ||
685 | static int tsc2005_remove(struct spi_device *spi) | 764 | static int tsc2005_remove(struct spi_device *spi) |
686 | { | 765 | { |
766 | struct tsc2005 *ts = spi_get_drvdata(spi); | ||
767 | |||
687 | sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); | 768 | sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); |
688 | 769 | ||
770 | if (ts->vio) | ||
771 | regulator_disable(ts->vio); | ||
772 | |||
689 | return 0; | 773 | return 0; |
690 | } | 774 | } |
691 | 775 | ||