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>
This commit is contained in:
Eric Miao 2008-09-10 12:06:15 -04:00 committed by Dmitry Torokhov
parent 0d46ed1c74
commit 4d5975e501
2 changed files with 57 additions and 14 deletions

View file

@ -24,6 +24,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/ads7846.h> #include <linux/spi/ads7846.h>
#include <asm/irq.h> #include <asm/irq.h>
@ -116,6 +117,7 @@ struct ads7846 {
void *filter_data; void *filter_data;
void (*filter_cleanup)(void *data); void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void); int (*get_pendown_state)(void);
int gpio_pendown;
}; };
/* leave chip selected when we're done, for quicker re-select? */ /* leave chip selected when we're done, for quicker re-select? */
@ -492,6 +494,14 @@ static struct attribute_group ads784x_attr_group = {
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
static int get_pendown_state(struct ads7846 *ts)
{
if (ts->get_pendown_state)
return ts->get_pendown_state();
return !gpio_get_value(ts->gpio_pendown);
}
/* /*
* PENIRQ only kicks the timer. The timer only reissues the SPI transfer, * PENIRQ only kicks the timer. The timer only reissues the SPI transfer,
* to retrieve touchscreen status. * to retrieve touchscreen status.
@ -551,7 +561,7 @@ static void ads7846_rx(void *ads)
*/ */
if (ts->penirq_recheck_delay_usecs) { if (ts->penirq_recheck_delay_usecs) {
udelay(ts->penirq_recheck_delay_usecs); udelay(ts->penirq_recheck_delay_usecs);
if (!ts->get_pendown_state()) if (!get_pendown_state(ts))
Rt = 0; Rt = 0;
} }
@ -678,7 +688,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
spin_lock_irq(&ts->lock); spin_lock_irq(&ts->lock);
if (unlikely(!ts->get_pendown_state() || if (unlikely(!get_pendown_state(ts) ||
device_suspended(&ts->spi->dev))) { device_suspended(&ts->spi->dev))) {
if (ts->pendown) { if (ts->pendown) {
struct input_dev *input = ts->input; struct input_dev *input = ts->input;
@ -717,7 +727,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ts->lock, flags); spin_lock_irqsave(&ts->lock, flags);
if (likely(ts->get_pendown_state())) { if (likely(get_pendown_state(ts))) {
if (!ts->irq_disabled) { if (!ts->irq_disabled) {
/* The ARM do_simple_IRQ() dispatcher doesn't act /* The ARM do_simple_IRQ() dispatcher doesn't act
* like the other dispatchers: it will report IRQs * like the other dispatchers: it will report IRQs
@ -807,6 +817,36 @@ static int ads7846_resume(struct spi_device *spi)
return 0; return 0;
} }
static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
{
struct ads7846_platform_data *pdata = spi->dev.platform_data;
int err;
/* REVISIT when the irq can be triggered active-low, or if for some
* reason the touchscreen isn't hooked up, we don't need to access
* the pendown state.
*/
if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) {
dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
return -EINVAL;
}
if (pdata->get_pendown_state) {
ts->get_pendown_state = pdata->get_pendown_state;
return 0;
}
err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
if (err) {
dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
pdata->gpio_pendown);
return err;
}
ts->gpio_pendown = pdata->gpio_pendown;
return 0;
}
static int __devinit ads7846_probe(struct spi_device *spi) static int __devinit ads7846_probe(struct spi_device *spi)
{ {
struct ads7846 *ts; struct ads7846 *ts;
@ -834,15 +874,6 @@ static int __devinit ads7846_probe(struct spi_device *spi)
return -EINVAL; return -EINVAL;
} }
/* REVISIT when the irq can be triggered active-low, or if for some
* reason the touchscreen isn't hooked up, we don't need to access
* the pendown state.
*/
if (pdata->get_pendown_state == NULL) {
dev_dbg(&spi->dev, "no get_pendown_state function?\n");
return -EINVAL;
}
/* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
* that even if the hardware can do that, the SPI controller driver * that even if the hardware can do that, the SPI controller driver
* may not. So we stick to very-portable 8 bit words, both RX and TX. * 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)
ts->filter_data = ts; ts->filter_data = ts;
} else } else
ts->filter = ads7846_no_filter; ts->filter = ads7846_no_filter;
ts->get_pendown_state = pdata->get_pendown_state;
err = setup_pendown(spi, ts);
if (err)
goto err_cleanup_filter;
if (pdata->penirq_recheck_delay_usecs) if (pdata->penirq_recheck_delay_usecs)
ts->penirq_recheck_delay_usecs = ts->penirq_recheck_delay_usecs =
@ -1086,7 +1120,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi->dev.driver->name, ts)) { spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY; err = -EBUSY;
goto err_cleanup_filter; goto err_free_gpio;
} }
err = ads784x_hwmon_register(spi, ts); err = ads784x_hwmon_register(spi, ts);
@ -1117,6 +1151,9 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ads784x_hwmon_unregister(spi, ts); ads784x_hwmon_unregister(spi, ts);
err_free_irq: err_free_irq:
free_irq(spi->irq, ts); free_irq(spi->irq, ts);
err_free_gpio:
if (ts->gpio_pendown != -1)
gpio_free(ts->gpio_pendown);
err_cleanup_filter: err_cleanup_filter:
if (ts->filter_cleanup) if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data); ts->filter_cleanup(ts->filter_data);
@ -1141,6 +1178,9 @@ static int __devexit ads7846_remove(struct spi_device *spi)
/* suspend left the IRQ disabled */ /* suspend left the IRQ disabled */
enable_irq(ts->spi->irq); enable_irq(ts->spi->irq);
if (ts->gpio_pendown != -1)
gpio_free(ts->gpio_pendown);
if (ts->filter_cleanup) if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data); ts->filter_cleanup(ts->filter_data);

View file

@ -43,6 +43,9 @@ struct ads7846_platform_data {
u16 debounce_tol; /* tolerance used for filtering */ u16 debounce_tol; /* tolerance used for filtering */
u16 debounce_rep; /* additional consecutive good readings u16 debounce_rep; /* additional consecutive good readings
* required after the first two */ * required after the first two */
int gpio_pendown; /* the GPIO used to decide the pendown
* state if get_pendown_state == NULL
*/
int (*get_pendown_state)(void); int (*get_pendown_state)(void);
int (*filter_init) (struct ads7846_platform_data *pdata, int (*filter_init) (struct ads7846_platform_data *pdata,
void **filter_data); void **filter_data);