diff options
author | Eric Miao <eric.y.miao@gmail.com> | 2008-09-10 12:06:15 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-09-17 12:33:37 -0400 |
commit | 6ae19b04ab41a4db0f0c48ec0b78950f6b028823 (patch) | |
tree | 9a9c38bc7be0741b19abbb345f5bd001bfc0ab97 | |
parent | adee14b2e1557d0a8559f29681732d05a89dfc35 (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>
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 68 | ||||
-rw-r--r-- | include/linux/spi/ads7846.h | 3 |
2 files changed, 57 insertions, 14 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ce6f48c695f5..8583c766d565 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? */ |
@@ -491,6 +493,14 @@ static struct attribute_group ads784x_attr_group = { | |||
491 | 493 | ||
492 | /*--------------------------------------------------------------------------*/ | 494 | /*--------------------------------------------------------------------------*/ |
493 | 495 | ||
496 | static int get_pendown_state(struct ads7846 *ts) | ||
497 | { | ||
498 | if (ts->get_pendown_state) | ||
499 | return ts->get_pendown_state(); | ||
500 | |||
501 | return !gpio_get_value(ts->gpio_pendown); | ||
502 | } | ||
503 | |||
494 | /* | 504 | /* |
495 | * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, | 505 | * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, |
496 | * to retrieve touchscreen status. | 506 | * to retrieve touchscreen status. |
@@ -550,7 +560,7 @@ static void ads7846_rx(void *ads) | |||
550 | */ | 560 | */ |
551 | if (ts->penirq_recheck_delay_usecs) { | 561 | if (ts->penirq_recheck_delay_usecs) { |
552 | udelay(ts->penirq_recheck_delay_usecs); | 562 | udelay(ts->penirq_recheck_delay_usecs); |
553 | if (!ts->get_pendown_state()) | 563 | if (!get_pendown_state(ts)) |
554 | Rt = 0; | 564 | Rt = 0; |
555 | } | 565 | } |
556 | 566 | ||
@@ -677,7 +687,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) | |||
677 | 687 | ||
678 | spin_lock_irq(&ts->lock); | 688 | spin_lock_irq(&ts->lock); |
679 | 689 | ||
680 | if (unlikely(!ts->get_pendown_state() || | 690 | if (unlikely(!get_pendown_state(ts) || |
681 | device_suspended(&ts->spi->dev))) { | 691 | device_suspended(&ts->spi->dev))) { |
682 | if (ts->pendown) { | 692 | if (ts->pendown) { |
683 | struct input_dev *input = ts->input; | 693 | struct input_dev *input = ts->input; |
@@ -716,7 +726,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) | |||
716 | unsigned long flags; | 726 | unsigned long flags; |
717 | 727 | ||
718 | spin_lock_irqsave(&ts->lock, flags); | 728 | spin_lock_irqsave(&ts->lock, flags); |
719 | if (likely(ts->get_pendown_state())) { | 729 | if (likely(get_pendown_state(ts))) { |
720 | if (!ts->irq_disabled) { | 730 | if (!ts->irq_disabled) { |
721 | /* The ARM do_simple_IRQ() dispatcher doesn't act | 731 | /* The ARM do_simple_IRQ() dispatcher doesn't act |
722 | * like the other dispatchers: it will report IRQs | 732 | * like the other dispatchers: it will report IRQs |
@@ -806,6 +816,36 @@ static int ads7846_resume(struct spi_device *spi) | |||
806 | return 0; | 816 | return 0; |
807 | } | 817 | } |
808 | 818 | ||
819 | static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts) | ||
820 | { | ||
821 | struct ads7846_platform_data *pdata = spi->dev.platform_data; | ||
822 | int err; | ||
823 | |||
824 | /* REVISIT when the irq can be triggered active-low, or if for some | ||
825 | * reason the touchscreen isn't hooked up, we don't need to access | ||
826 | * the pendown state. | ||
827 | */ | ||
828 | if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) { | ||
829 | dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); | ||
830 | return -EINVAL; | ||
831 | } | ||
832 | |||
833 | if (pdata->get_pendown_state) { | ||
834 | ts->get_pendown_state = pdata->get_pendown_state; | ||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | err = gpio_request(pdata->gpio_pendown, "ads7846_pendown"); | ||
839 | if (err) { | ||
840 | dev_err(&spi->dev, "failed to request pendown GPIO%d\n", | ||
841 | pdata->gpio_pendown); | ||
842 | return err; | ||
843 | } | ||
844 | |||
845 | ts->gpio_pendown = pdata->gpio_pendown; | ||
846 | return 0; | ||
847 | } | ||
848 | |||
809 | static int __devinit ads7846_probe(struct spi_device *spi) | 849 | static int __devinit ads7846_probe(struct spi_device *spi) |
810 | { | 850 | { |
811 | struct ads7846 *ts; | 851 | struct ads7846 *ts; |
@@ -833,15 +873,6 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
833 | return -EINVAL; | 873 | return -EINVAL; |
834 | } | 874 | } |
835 | 875 | ||
836 | /* REVISIT when the irq can be triggered active-low, or if for some | ||
837 | * reason the touchscreen isn't hooked up, we don't need to access | ||
838 | * the pendown state. | ||
839 | */ | ||
840 | if (pdata->get_pendown_state == NULL) { | ||
841 | dev_dbg(&spi->dev, "no get_pendown_state function?\n"); | ||
842 | return -EINVAL; | ||
843 | } | ||
844 | |||
845 | /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except | 876 | /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except |
846 | * that even if the hardware can do that, the SPI controller driver | 877 | * that even if the hardware can do that, the SPI controller driver |
847 | * may not. So we stick to very-portable 8 bit words, both RX and TX. | 878 | * may not. So we stick to very-portable 8 bit words, both RX and TX. |
@@ -893,7 +924,10 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
893 | ts->filter_data = ts; | 924 | ts->filter_data = ts; |
894 | } else | 925 | } else |
895 | ts->filter = ads7846_no_filter; | 926 | ts->filter = ads7846_no_filter; |
896 | ts->get_pendown_state = pdata->get_pendown_state; | 927 | |
928 | err = setup_pendown(spi, ts); | ||
929 | if (err) | ||
930 | goto err_cleanup_filter; | ||
897 | 931 | ||
898 | if (pdata->penirq_recheck_delay_usecs) | 932 | if (pdata->penirq_recheck_delay_usecs) |
899 | ts->penirq_recheck_delay_usecs = | 933 | ts->penirq_recheck_delay_usecs = |
@@ -1085,7 +1119,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1085 | spi->dev.driver->name, ts)) { | 1119 | spi->dev.driver->name, ts)) { |
1086 | dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); | 1120 | dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); |
1087 | err = -EBUSY; | 1121 | err = -EBUSY; |
1088 | goto err_cleanup_filter; | 1122 | goto err_free_gpio; |
1089 | } | 1123 | } |
1090 | 1124 | ||
1091 | err = ads784x_hwmon_register(spi, ts); | 1125 | err = ads784x_hwmon_register(spi, ts); |
@@ -1116,6 +1150,9 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1116 | ads784x_hwmon_unregister(spi, ts); | 1150 | ads784x_hwmon_unregister(spi, ts); |
1117 | err_free_irq: | 1151 | err_free_irq: |
1118 | free_irq(spi->irq, ts); | 1152 | free_irq(spi->irq, ts); |
1153 | err_free_gpio: | ||
1154 | if (ts->gpio_pendown != -1) | ||
1155 | gpio_free(ts->gpio_pendown); | ||
1119 | err_cleanup_filter: | 1156 | err_cleanup_filter: |
1120 | if (ts->filter_cleanup) | 1157 | if (ts->filter_cleanup) |
1121 | ts->filter_cleanup(ts->filter_data); | 1158 | ts->filter_cleanup(ts->filter_data); |
@@ -1140,6 +1177,9 @@ static int __devexit ads7846_remove(struct spi_device *spi) | |||
1140 | /* suspend left the IRQ disabled */ | 1177 | /* suspend left the IRQ disabled */ |
1141 | enable_irq(ts->spi->irq); | 1178 | enable_irq(ts->spi->irq); |
1142 | 1179 | ||
1180 | if (ts->gpio_pendown != -1) | ||
1181 | gpio_free(ts->gpio_pendown); | ||
1182 | |||
1143 | if (ts->filter_cleanup) | 1183 | if (ts->filter_cleanup) |
1144 | ts->filter_cleanup(ts->filter_data); | 1184 | ts->filter_cleanup(ts->filter_data); |
1145 | 1185 | ||
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h index daf744017a31..05eab2f11e63 100644 --- a/include/linux/spi/ads7846.h +++ b/include/linux/spi/ads7846.h | |||
@@ -43,6 +43,9 @@ struct ads7846_platform_data { | |||
43 | u16 debounce_tol; /* tolerance used for filtering */ | 43 | u16 debounce_tol; /* tolerance used for filtering */ |
44 | u16 debounce_rep; /* additional consecutive good readings | 44 | u16 debounce_rep; /* additional consecutive good readings |
45 | * required after the first two */ | 45 | * required after the first two */ |
46 | int gpio_pendown; /* the GPIO used to decide the pendown | ||
47 | * state if get_pendown_state == NULL | ||
48 | */ | ||
46 | int (*get_pendown_state)(void); | 49 | int (*get_pendown_state)(void); |
47 | int (*filter_init) (struct ads7846_platform_data *pdata, | 50 | int (*filter_init) (struct ads7846_platform_data *pdata, |
48 | void **filter_data); | 51 | void **filter_data); |