diff options
Diffstat (limited to 'drivers/input/touchscreen/ads7846.c')
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 162 |
1 files changed, 109 insertions, 53 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ce6f48c695f5..b9b7fc6ff1eb 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -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> @@ -68,6 +69,17 @@ struct ts_event { int ignore; }; +/* + * We allocate this separately to avoid cache line sharing issues when + * driver is used with DMA-based SPI controllers (like atmel_spi) on + * systems where main memory is not DMA-coherent (most non-x86 boards). + */ +struct ads7846_packet { + u8 read_x, read_y, read_z1, read_z2, pwrdown; + u16 dummy; /* for the pwrdown read */ + struct ts_event tc; +}; + struct ads7846 { struct input_dev *input; char phys[32]; @@ -85,9 +97,7 @@ struct ads7846 { u16 x_plate_ohms; u16 pressure_max; - u8 read_x, read_y, read_z1, read_z2, pwrdown; - u16 dummy; /* for the pwrdown read */ - struct ts_event tc; + struct ads7846_packet *packet; struct spi_transfer xfer[18]; struct spi_message msg[5]; @@ -116,6 +126,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? */ @@ -461,10 +472,11 @@ static ssize_t ads7846_disable_store(struct device *dev, const char *buf, size_t count) { struct ads7846 *ts = dev_get_drvdata(dev); - char *endp; - int i; + long i; + + if (strict_strtoul(buf, 10, &i)) + return -EINVAL; - i = simple_strtoul(buf, &endp, 10); spin_lock_irq(&ts->lock); if (i) @@ -491,6 +503,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. @@ -502,16 +522,17 @@ static struct attribute_group ads784x_attr_group = { static void ads7846_rx(void *ads) { struct ads7846 *ts = ads; + struct ads7846_packet *packet = ts->packet; unsigned Rt; u16 x, y, z1, z2; /* ads7846_rx_val() did in-place conversion (including byteswap) from * on-the-wire format as part of debouncing to get stable readings. */ - x = ts->tc.x; - y = ts->tc.y; - z1 = ts->tc.z1; - z2 = ts->tc.z2; + x = packet->tc.x; + y = packet->tc.y; + z1 = packet->tc.z1; + z2 = packet->tc.z2; /* range filtering */ if (x == MAX_12BIT) @@ -535,10 +556,10 @@ static void ads7846_rx(void *ads) * the maximum. Don't report it to user space, repeat at least * once more the measurement */ - if (ts->tc.ignore || Rt > ts->pressure_max) { + if (packet->tc.ignore || Rt > ts->pressure_max) { #ifdef VERBOSE pr_debug("%s: ignored %d pressure %d\n", - ts->spi->dev.bus_id, ts->tc.ignore, Rt); + ts->spi->dev.bus_id, packet->tc.ignore, Rt); #endif hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_MODE_REL); @@ -550,7 +571,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; } @@ -631,6 +652,7 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val) static void ads7846_rx_val(void *ads) { struct ads7846 *ts = ads; + struct ads7846_packet *packet = ts->packet; struct spi_message *m; struct spi_transfer *t; int val; @@ -650,7 +672,7 @@ static void ads7846_rx_val(void *ads) case ADS7846_FILTER_REPEAT: break; case ADS7846_FILTER_IGNORE: - ts->tc.ignore = 1; + packet->tc.ignore = 1; /* Last message will contain ads7846_rx() as the * completion function. */ @@ -658,7 +680,7 @@ static void ads7846_rx_val(void *ads) break; case ADS7846_FILTER_OK: *(u16 *)t->rx_buf = val; - ts->tc.ignore = 0; + packet->tc.ignore = 0; m = &ts->msg[++ts->msg_idx]; break; default: @@ -677,7 +699,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; @@ -716,7 +738,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 @@ -763,7 +785,6 @@ static void ads7846_disable(struct ads7846 *ts) /* we know the chip's in lowpower mode since we always * leave it that way after every request */ - } /* Must be called with ts->lock held */ @@ -806,9 +827,40 @@ 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; + struct ads7846_packet *packet; struct input_dev *input_dev; struct ads7846_platform_data *pdata = spi->dev.platform_data; struct spi_message *m; @@ -833,15 +885,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. @@ -853,14 +896,16 @@ static int __devinit ads7846_probe(struct spi_device *spi) return err; ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL); + packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL); input_dev = input_allocate_device(); - if (!ts || !input_dev) { + if (!ts || !packet || !input_dev) { err = -ENOMEM; goto err_free_mem; } dev_set_drvdata(&spi->dev, ts); + ts->packet = packet; ts->spi = spi; ts->input = input_dev; ts->vref_mv = pdata->vref_mv; @@ -893,7 +938,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 = @@ -929,13 +977,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) spi_message_init(m); /* y- still on; turn on only y+ (and ADC) */ - ts->read_y = READ_Y(vref); - x->tx_buf = &ts->read_y; + packet->read_y = READ_Y(vref); + x->tx_buf = &packet->read_y; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->tc.y; + x->rx_buf = &packet->tc.y; x->len = 2; spi_message_add_tail(x, m); @@ -947,12 +995,12 @@ static int __devinit ads7846_probe(struct spi_device *spi) x->delay_usecs = pdata->settle_delay_usecs; x++; - x->tx_buf = &ts->read_y; + x->tx_buf = &packet->read_y; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->tc.y; + x->rx_buf = &packet->tc.y; x->len = 2; spi_message_add_tail(x, m); } @@ -965,13 +1013,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) /* turn y- off, x+ on, then leave in lowpower */ x++; - ts->read_x = READ_X(vref); - x->tx_buf = &ts->read_x; + packet->read_x = READ_X(vref); + x->tx_buf = &packet->read_x; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->tc.x; + x->rx_buf = &packet->tc.x; x->len = 2; spi_message_add_tail(x, m); @@ -980,12 +1028,12 @@ static int __devinit ads7846_probe(struct spi_device *spi) x->delay_usecs = pdata->settle_delay_usecs; x++; - x->tx_buf = &ts->read_x; + x->tx_buf = &packet->read_x; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->tc.x; + x->rx_buf = &packet->tc.x; x->len = 2; spi_message_add_tail(x, m); } @@ -999,13 +1047,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) spi_message_init(m); x++; - ts->read_z1 = READ_Z1(vref); - x->tx_buf = &ts->read_z1; + packet->read_z1 = READ_Z1(vref); + x->tx_buf = &packet->read_z1; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->tc.z1; + x->rx_buf = &packet->tc.z1; x->len = 2; spi_message_add_tail(x, m); @@ -1014,12 +1062,12 @@ static int __devinit ads7846_probe(struct spi_device *spi) x->delay_usecs = pdata->settle_delay_usecs; x++; - x->tx_buf = &ts->read_z1; + x->tx_buf = &packet->read_z1; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->tc.z1; + x->rx_buf = &packet->tc.z1; x->len = 2; spi_message_add_tail(x, m); } @@ -1031,13 +1079,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) spi_message_init(m); x++; - ts->read_z2 = READ_Z2(vref); - x->tx_buf = &ts->read_z2; + packet->read_z2 = READ_Z2(vref); + x->tx_buf = &packet->read_z2; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->tc.z2; + x->rx_buf = &packet->tc.z2; x->len = 2; spi_message_add_tail(x, m); @@ -1046,12 +1094,12 @@ static int __devinit ads7846_probe(struct spi_device *spi) x->delay_usecs = pdata->settle_delay_usecs; x++; - x->tx_buf = &ts->read_z2; + x->tx_buf = &packet->read_z2; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->tc.z2; + x->rx_buf = &packet->tc.z2; x->len = 2; spi_message_add_tail(x, m); } @@ -1065,13 +1113,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) spi_message_init(m); x++; - ts->pwrdown = PWRDOWN; - x->tx_buf = &ts->pwrdown; + packet->pwrdown = PWRDOWN; + x->tx_buf = &packet->pwrdown; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->dummy; + x->rx_buf = &packet->dummy; x->len = 2; CS_CHANGE(*x); spi_message_add_tail(x, m); @@ -1085,7 +1133,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); @@ -1116,11 +1164,15 @@ 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); err_free_mem: input_free_device(input_dev); + kfree(packet); kfree(ts); return err; } @@ -1140,9 +1192,13 @@ 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); + kfree(ts->packet); kfree(ts); dev_dbg(&spi->dev, "unregistered touchscreen\n"); |