summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2016-01-17 07:46:24 +0300
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2016-03-02 20:30:06 +0300
commitdee520e368f54e1bc0e387bfda7ef4e0676e248b (patch)
tree10f1ed503f37b5a058241b5169b56a4dd0828162 /drivers/input
parentd9202af2ffa083f096684fd5f4b530aebbc07439 (diff)
downloadlinux-dee520e368f54e1bc0e387bfda7ef4e0676e248b.tar.xz
Input: rotary_encoder - use threaded irqs
Convert to use threaded IRQs to support GPIOs that can sleep. Protect the irq handler with mutex as it can be triggered from two different irq lines accessing the same state. This allows using GPIO expanders behind I2C or SPI bus. Signed-off-by: Timo Teräs <timo.teras@iki.fi> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/misc/rotary_encoder.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index ebbadf3f0579..aeeaaea69610 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -33,6 +33,7 @@
struct rotary_encoder {
struct input_dev *input;
const struct rotary_encoder_platform_data *pdata;
+ struct mutex access_mutex;
unsigned int axis;
unsigned int pos;
@@ -48,8 +49,8 @@ struct rotary_encoder {
static int rotary_encoder_get_state(const struct rotary_encoder_platform_data *pdata)
{
- int a = !!gpio_get_value(pdata->gpio_a);
- int b = !!gpio_get_value(pdata->gpio_b);
+ int a = !!gpio_get_value_cansleep(pdata->gpio_a);
+ int b = !!gpio_get_value_cansleep(pdata->gpio_b);
a ^= pdata->inverted_a;
b ^= pdata->inverted_b;
@@ -94,6 +95,8 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
struct rotary_encoder *encoder = dev_id;
int state;
+ mutex_lock(&encoder->access_mutex);
+
state = rotary_encoder_get_state(encoder->pdata);
switch (state) {
@@ -115,6 +118,8 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
break;
}
+ mutex_unlock(&encoder->access_mutex);
+
return IRQ_HANDLED;
}
@@ -123,6 +128,8 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
struct rotary_encoder *encoder = dev_id;
int state;
+ mutex_lock(&encoder->access_mutex);
+
state = rotary_encoder_get_state(encoder->pdata);
switch (state) {
@@ -140,6 +147,8 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
break;
}
+ mutex_unlock(&encoder->access_mutex);
+
return IRQ_HANDLED;
}
@@ -149,6 +158,8 @@ static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
unsigned char sum;
int state;
+ mutex_lock(&encoder->access_mutex);
+
state = rotary_encoder_get_state(encoder->pdata);
/*
@@ -189,6 +200,8 @@ static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
out:
encoder->last_stable = state;
+ mutex_unlock(&encoder->access_mutex);
+
return IRQ_HANDLED;
}
@@ -285,6 +298,8 @@ static int rotary_encoder_probe(struct platform_device *pdev)
if (!input)
return -ENOMEM;
+ mutex_init(&encoder->access_mutex);
+
encoder->input = input;
encoder->pdata = pdata;
@@ -337,17 +352,19 @@ static int rotary_encoder_probe(struct platform_device *pdev)
return -EINVAL;
}
- err = devm_request_irq(dev, encoder->irq_a, handler,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- DRV_NAME, encoder);
+ err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
return err;
}
- err = devm_request_irq(dev, encoder->irq_b, handler,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- DRV_NAME, encoder);
+ err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
return err;