Commit b534422b authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: ad7877 - switch to using threaded IRQ

Instead of using asynchronous SPI API and then spinning waiting for SPI
transfer to complete when disabling the device, let's use threaded IRQ
model and spi_sync().
Acked-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Tested-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 2fd18aba
...@@ -191,13 +191,12 @@ struct ad7877 { ...@@ -191,13 +191,12 @@ struct ad7877 {
struct spi_message msg; struct spi_message msg;
struct mutex mutex; struct mutex mutex;
unsigned disabled:1; /* P: mutex */ bool disabled; /* P: mutex */
unsigned gpio3:1; /* P: mutex */ bool gpio3; /* P: mutex */
unsigned gpio4:1; /* P: mutex */ bool gpio4; /* P: mutex */
spinlock_t lock; spinlock_t lock;
struct timer_list timer; /* P: lock */ struct timer_list timer; /* P: lock */
unsigned pending:1; /* P: lock */
/* /*
* DMA (thus cache coherency maintenance) requires the * DMA (thus cache coherency maintenance) requires the
...@@ -333,7 +332,7 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command) ...@@ -333,7 +332,7 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
return status ? : sample; return status ? : sample;
} }
static int ad7877_rx(struct ad7877 *ts) static int ad7877_process_data(struct ad7877 *ts)
{ {
struct input_dev *input_dev = ts->input; struct input_dev *input_dev = ts->input;
unsigned Rt; unsigned Rt;
...@@ -374,6 +373,7 @@ static int ad7877_rx(struct ad7877 *ts) ...@@ -374,6 +373,7 @@ static int ad7877_rx(struct ad7877 *ts)
input_report_abs(input_dev, ABS_Y, y); input_report_abs(input_dev, ABS_Y, y);
input_report_abs(input_dev, ABS_PRESSURE, Rt); input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev); input_sync(input_dev);
return 0; return 0;
} }
...@@ -392,64 +392,49 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts) ...@@ -392,64 +392,49 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
static void ad7877_timer(unsigned long handle) static void ad7877_timer(unsigned long handle)
{ {
struct ad7877 *ts = (void *)handle; struct ad7877 *ts = (void *)handle;
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
ad7877_ts_event_release(ts); ad7877_ts_event_release(ts);
spin_unlock_irqrestore(&ts->lock, flags);
} }
static irqreturn_t ad7877_irq(int irq, void *handle) static irqreturn_t ad7877_irq(int irq, void *handle)
{ {
struct ad7877 *ts = handle; struct ad7877 *ts = handle;
unsigned long flags; unsigned long flags;
int status; int error;
/* error = spi_sync(ts->spi, &ts->msg);
* The repeated conversion sequencer controlled by TMR kicked off if (error) {
* too fast. We ignore the last and process the sample sequence dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
* currently in the queue. It can't be older than 9.4ms, and we goto out;
* need to avoid that ts->msg doesn't get issued twice while in work. }
*/
spin_lock_irqsave(&ts->lock, flags); spin_lock_irqsave(&ts->lock, flags);
if (!ts->pending) { error = ad7877_process_data(ts);
ts->pending = 1; if (!error)
mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
status = spi_async(ts->spi, &ts->msg);
if (status)
dev_err(&ts->spi->dev, "spi_sync --> %d\n", status);
}
spin_unlock_irqrestore(&ts->lock, flags); spin_unlock_irqrestore(&ts->lock, flags);
out:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void ad7877_callback(void *_ts)
{
struct ad7877 *ts = _ts;
spin_lock_irq(&ts->lock);
if (!ad7877_rx(ts))
mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
ts->pending = 0;
spin_unlock_irq(&ts->lock);
}
static void ad7877_disable(struct ad7877 *ts) static void ad7877_disable(struct ad7877 *ts)
{ {
mutex_lock(&ts->mutex); mutex_lock(&ts->mutex);
if (!ts->disabled) { if (!ts->disabled) {
ts->disabled = 1; ts->disabled = true;
disable_irq(ts->spi->irq); disable_irq(ts->spi->irq);
/* Wait for spi_async callback */
while (ts->pending)
msleep(1);
if (del_timer_sync(&ts->timer)) if (del_timer_sync(&ts->timer))
ad7877_ts_event_release(ts); ad7877_ts_event_release(ts);
} }
/* we know the chip's in lowpower mode since we always /*
* We know the chip's in lowpower mode since we always
* leave it that way after every request * leave it that way after every request
*/ */
...@@ -461,7 +446,7 @@ static void ad7877_enable(struct ad7877 *ts) ...@@ -461,7 +446,7 @@ static void ad7877_enable(struct ad7877 *ts)
mutex_lock(&ts->mutex); mutex_lock(&ts->mutex);
if (ts->disabled) { if (ts->disabled) {
ts->disabled = 0; ts->disabled = false;
enable_irq(ts->spi->irq); enable_irq(ts->spi->irq);
} }
...@@ -672,7 +657,6 @@ static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts) ...@@ -672,7 +657,6 @@ static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
spi_message_init(m); spi_message_init(m);
m->complete = ad7877_callback;
m->context = ts; m->context = ts;
ts->xfer[0].tx_buf = &ts->cmd_crtl1; ts->xfer[0].tx_buf = &ts->cmd_crtl1;
...@@ -795,7 +779,8 @@ static int __devinit ad7877_probe(struct spi_device *spi) ...@@ -795,7 +779,8 @@ static int __devinit ad7877_probe(struct spi_device *spi)
/* Request AD7877 /DAV GPIO interrupt */ /* Request AD7877 /DAV GPIO interrupt */
err = request_irq(spi->irq, ad7877_irq, IRQF_TRIGGER_FALLING, err = request_threaded_irq(spi->irq, NULL, ad7877_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
spi->dev.driver->name, ts); spi->dev.driver->name, ts);
if (err) { if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment