Skip to content

Commit

Permalink
Input: ads7846 - introduce .gpio_pendown to get pendown state
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Miao authored and Dmitry Torokhov committed Sep 10, 2008
1 parent 0d46ed1 commit 4d5975e
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 14 deletions.
68 changes: 54 additions & 14 deletions drivers/input/touchscreen/ads7846.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <asm/irq.h>
Expand Down Expand Up @@ -116,6 +117,7 @@ struct ads7846 {
void *filter_data;
void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void);
int gpio_pendown;
};

/* leave chip selected when we're done, for quicker re-select? */
Expand Down Expand Up @@ -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,
* to retrieve touchscreen status.
Expand Down Expand Up @@ -551,7 +561,7 @@ static void ads7846_rx(void *ads)
*/
if (ts->penirq_recheck_delay_usecs) {
udelay(ts->penirq_recheck_delay_usecs);
if (!ts->get_pendown_state())
if (!get_pendown_state(ts))
Rt = 0;
}

Expand Down Expand Up @@ -678,7 +688,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)

spin_lock_irq(&ts->lock);

if (unlikely(!ts->get_pendown_state() ||
if (unlikely(!get_pendown_state(ts) ||
device_suspended(&ts->spi->dev))) {
if (ts->pendown) {
struct input_dev *input = ts->input;
Expand Down Expand Up @@ -717,7 +727,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
unsigned long flags;

spin_lock_irqsave(&ts->lock, flags);
if (likely(ts->get_pendown_state())) {
if (likely(get_pendown_state(ts))) {
if (!ts->irq_disabled) {
/* The ARM do_simple_IRQ() dispatcher doesn't act
* like the other dispatchers: it will report IRQs
Expand Down Expand Up @@ -807,6 +817,36 @@ static int ads7846_resume(struct spi_device *spi)
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)
{
struct ads7846 *ts;
Expand Down Expand Up @@ -834,15 +874,6 @@ static int __devinit ads7846_probe(struct spi_device *spi)
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
* 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.
Expand Down Expand Up @@ -894,7 +925,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->filter_data = ts;
} else
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)
ts->penirq_recheck_delay_usecs =
Expand Down Expand Up @@ -1086,7 +1120,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY;
goto err_cleanup_filter;
goto err_free_gpio;
}

err = ads784x_hwmon_register(spi, ts);
Expand Down Expand Up @@ -1117,6 +1151,9 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ads784x_hwmon_unregister(spi, ts);
err_free_irq:
free_irq(spi->irq, ts);
err_free_gpio:
if (ts->gpio_pendown != -1)
gpio_free(ts->gpio_pendown);
err_cleanup_filter:
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);
Expand All @@ -1141,6 +1178,9 @@ static int __devexit ads7846_remove(struct spi_device *spi)
/* suspend left the IRQ disabled */
enable_irq(ts->spi->irq);

if (ts->gpio_pendown != -1)
gpio_free(ts->gpio_pendown);

if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);

Expand Down
3 changes: 3 additions & 0 deletions include/linux/spi/ads7846.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ struct ads7846_platform_data {
u16 debounce_tol; /* tolerance used for filtering */
u16 debounce_rep; /* additional consecutive good readings
* 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 (*filter_init) (struct ads7846_platform_data *pdata,
void **filter_data);
Expand Down

0 comments on commit 4d5975e

Please sign in to comment.