diff options
author | Eric Miao <eric.y.miao@gmail.com> | 2008-09-10 12:06:15 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-09-10 12:13:28 -0400 |
commit | 4d5975e5016a9025814b92981de21eaf9203caa6 (patch) | |
tree | d1bc92acac3db21a5e92795ed7802f3776acb0bd /drivers | |
parent | 0d46ed1c747edfe6476961d4d9f732ceb7a29074 (diff) |
Input: ads7846 - introduce .gpio_pendown to get pendown state
The GPIO connected to ADS7846 nPENIRQ signal is usually used to get
the pendown state as well. Introduce a .gpio_pendown, and use this
to decide the pendown state if .get_pendown_state is NULL.
Signed-off-by: Eric Miao <eric.miao@marvell.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 68 |
1 files changed, 54 insertions, 14 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index efbbbe48621a..6020a7dcce33 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/input.h> | 24 | #include <linux/input.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/gpio.h> | ||
27 | #include <linux/spi/spi.h> | 28 | #include <linux/spi/spi.h> |
28 | #include <linux/spi/ads7846.h> | 29 | #include <linux/spi/ads7846.h> |
29 | #include <asm/irq.h> | 30 | #include <asm/irq.h> |
@@ -116,6 +117,7 @@ struct ads7846 { | |||
116 | void *filter_data; | 117 | void *filter_data; |
117 | void (*filter_cleanup)(void *data); | 118 | void (*filter_cleanup)(void *data); |
118 | int (*get_pendown_state)(void); | 119 | int (*get_pendown_state)(void); |
120 | int gpio_pendown; | ||
119 | }; | 121 | }; |
120 | 122 | ||
121 | /* leave chip selected when we're done, for quicker re-select? */ | 123 | /* leave chip selected when we're done, for quicker re-select? */ |
@@ -492,6 +494,14 @@ static struct attribute_group ads784x_attr_group = { | |||
492 | 494 | ||
493 | /*--------------------------------------------------------------------------*/ | 495 | /*--------------------------------------------------------------------------*/ |
494 | 496 | ||
497 | static int get_pendown_state(struct ads7846 *ts) | ||
498 | { | ||
499 | if (ts->get_pendown_state) | ||
500 | return ts->get_pendown_state(); | ||
501 | |||
502 | return !gpio_get_value(ts->gpio_pendown); | ||
503 | } | ||
504 | |||
495 | /* | 505 | /* |
496 | * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, | 506 | * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, |
497 | * to retrieve touchscreen status. | 507 | * to retrieve touchscreen status. |
@@ -551,7 +561,7 @@ static void ads7846_rx(void *ads) | |||
551 | */ | 561 | */ |
552 | if (ts->penirq_recheck_delay_usecs) { | 562 | if (ts->penirq_recheck_delay_usecs) { |
553 | udelay(ts->penirq_recheck_delay_usecs); | 563 | udelay(ts->penirq_recheck_delay_usecs); |
554 | if (!ts->get_pendown_state()) | 564 | if (!get_pendown_state(ts)) |
555 | Rt = 0; | 565 | Rt = 0; |
556 | } | 566 | } |
557 | 567 | ||
@@ -678,7 +688,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) | |||
678 | 688 | ||
679 | spin_lock_irq(&ts->lock); | 689 | spin_lock_irq(&ts->lock); |
680 | 690 | ||
681 | if (unlikely(!ts->get_pendown_state() || | 691 | if (unlikely(!get_pendown_state(ts) || |
682 | device_suspended(&ts->spi->dev))) { | 692 | device_suspended(&ts->spi->dev))) { |
683 | if (ts->pendown) { | 693 | if (ts->pendown) { |
684 | struct input_dev *input = ts->input; | 694 | struct input_dev *input = ts->input; |
@@ -717,7 +727,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) | |||
717 | unsigned long flags; | 727 | unsigned long flags; |
718 | 728 | ||
719 | spin_lock_irqsave(&ts->lock, flags); | 729 | spin_lock_irqsave(&ts->lock, flags); |
720 | if (likely(ts->get_pendown_state())) { | 730 | if (likely(get_pendown_state(ts))) { |
721 | if (!ts->irq_disabled) { | 731 | if (!ts->irq_disabled) { |
722 | /* The ARM do_simple_IRQ() dispatcher doesn't act | 732 | /* The ARM do_simple_IRQ() dispatcher doesn't act |
723 | * like the other dispatchers: it will report IRQs | 733 | * like the other dispatchers: it will report IRQs |
@@ -807,6 +817,36 @@ static int ads7846_resume(struct spi_device *spi) | |||
807 | return 0; | 817 | return 0; |
808 | } | 818 | } |
809 | 819 | ||
820 | static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts) | ||
821 | { | ||
822 | struct ads7846_platform_data *pdata = spi->dev.platform_data; | ||
823 | int err; | ||
824 | |||
825 | /* REVISIT when the irq can be triggered active-low, or if for some | ||
826 | * reason the touchscreen isn't hooked up, we don't need to access | ||
827 | * the pendown state. | ||
828 | */ | ||
829 | if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) { | ||
830 | dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); | ||
831 | return -EINVAL; | ||
832 | } | ||
833 | |||
834 | if (pdata->get_pendown_state) { | ||
835 | ts->get_pendown_state = pdata->get_pendown_state; | ||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | err = gpio_request(pdata->gpio_pendown, "ads7846_pendown"); | ||
840 | if (err) { | ||
841 | dev_err(&spi->dev, "failed to request pendown GPIO%d\n", | ||
842 | pdata->gpio_pendown); | ||
843 | return err; | ||
844 | } | ||
845 | |||
846 | ts->gpio_pendown = pdata->gpio_pendown; | ||
847 | return 0; | ||
848 | } | ||
849 | |||
810 | static int __devinit ads7846_probe(struct spi_device *spi) | 850 | static int __devinit ads7846_probe(struct spi_device *spi) |
811 | { | 851 | { |
812 | struct ads7846 *ts; | 852 | struct ads7846 *ts; |
@@ -834,15 +874,6 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
834 | return -EINVAL; | 874 | return -EINVAL; |
835 | } | 875 | } |
836 | 876 | ||
837 | /* REVISIT when the irq can be triggered active-low, or if for some | ||
838 | * reason the touchscreen isn't hooked up, we don't need to access | ||
839 | * the pendown state. | ||
840 | */ | ||
841 | if (pdata->get_pendown_state == NULL) { | ||
842 | dev_dbg(&spi->dev, "no get_pendown_state function?\n"); | ||
843 | return -EINVAL; | ||
844 | } | ||
845 | |||
846 | /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except | 877 | /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except |
847 | * that even if the hardware can do that, the SPI controller driver | 878 | * that even if the hardware can do that, the SPI controller driver |
848 | * may not. So we stick to very-portable 8 bit words, both RX and TX. | 879 | * may not. So we stick to very-portable 8 bit words, both RX and TX. |
@@ -894,7 +925,10 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
894 | ts->filter_data = ts; | 925 | ts->filter_data = ts; |
895 | } else | 926 | } else |
896 | ts->filter = ads7846_no_filter; | 927 | ts->filter = ads7846_no_filter; |
897 | ts->get_pendown_state = pdata->get_pendown_state; | 928 | |
929 | err = setup_pendown(spi, ts); | ||
930 | if (err) | ||
931 | goto err_cleanup_filter; | ||
898 | 932 | ||
899 | if (pdata->penirq_recheck_delay_usecs) | 933 | if (pdata->penirq_recheck_delay_usecs) |
900 | ts->penirq_recheck_delay_usecs = | 934 | ts->penirq_recheck_delay_usecs = |
@@ -1086,7 +1120,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1086 | spi->dev.driver->name, ts)) { | 1120 | spi->dev.driver->name, ts)) { |
1087 | dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); | 1121 | dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); |
1088 | err = -EBUSY; | 1122 | err = -EBUSY; |
1089 | goto err_cleanup_filter; | 1123 | goto err_free_gpio; |
1090 | } | 1124 | } |
1091 | 1125 | ||
1092 | err = ads784x_hwmon_register(spi, ts); | 1126 | err = ads784x_hwmon_register(spi, ts); |
@@ -1117,6 +1151,9 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1117 | ads784x_hwmon_unregister(spi, ts); | 1151 | ads784x_hwmon_unregister(spi, ts); |
1118 | err_free_irq: | 1152 | err_free_irq: |
1119 | free_irq(spi->irq, ts); | 1153 | free_irq(spi->irq, ts); |
1154 | err_free_gpio: | ||
1155 | if (ts->gpio_pendown != -1) | ||
1156 | gpio_free(ts->gpio_pendown); | ||
1120 | err_cleanup_filter: | 1157 | err_cleanup_filter: |
1121 | if (ts->filter_cleanup) | 1158 | if (ts->filter_cleanup) |
1122 | ts->filter_cleanup(ts->filter_data); | 1159 | ts->filter_cleanup(ts->filter_data); |
@@ -1141,6 +1178,9 @@ static int __devexit ads7846_remove(struct spi_device *spi) | |||
1141 | /* suspend left the IRQ disabled */ | 1178 | /* suspend left the IRQ disabled */ |
1142 | enable_irq(ts->spi->irq); | 1179 | enable_irq(ts->spi->irq); |
1143 | 1180 | ||
1181 | if (ts->gpio_pendown != -1) | ||
1182 | gpio_free(ts->gpio_pendown); | ||
1183 | |||
1144 | if (ts->filter_cleanup) | 1184 | if (ts->filter_cleanup) |
1145 | ts->filter_cleanup(ts->filter_data); | 1185 | ts->filter_cleanup(ts->filter_data); |
1146 | 1186 | ||