diff options
| -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 | ||
