diff options
author | Timo Teräs <timo.teras@iki.fi> | 2016-02-12 06:43:04 +0000 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2016-02-12 06:43:04 +0000 |
commit | e58b060fb95244ba28880441a379ae69cc2b92c4 (patch) | |
tree | a95494fc6e802458254b7e6a917b55c1a778bd4c /main/linux-rpi/rotary-encoder-fix.patch | |
parent | f27f4c412ff313a05dfaeb7a63414df879248893 (diff) | |
download | aports-e58b060fb95244ba28880441a379ae69cc2b92c4.tar.bz2 aports-e58b060fb95244ba28880441a379ae69cc2b92c4.tar.xz |
main/linux-rpi: upgrade to 4.1.17
Diffstat (limited to 'main/linux-rpi/rotary-encoder-fix.patch')
-rw-r--r-- | main/linux-rpi/rotary-encoder-fix.patch | 721 |
1 files changed, 680 insertions, 41 deletions
diff --git a/main/linux-rpi/rotary-encoder-fix.patch b/main/linux-rpi/rotary-encoder-fix.patch index 0d9c6ba59f..3d599f3d0b 100644 --- a/main/linux-rpi/rotary-encoder-fix.patch +++ b/main/linux-rpi/rotary-encoder-fix.patch @@ -1,62 +1,701 @@ -From e2b19ed7b2284e808dfca3e9207ad52c09e11104 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> -Date: Wed, 23 Dec 2015 16:37:00 +0200 -Subject: [PATCH] Input: rotary-encoder: use request_any_context_irq and - gpio_get_value_cansleep -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This allows to use GPIO expanders behind I2C or SPI bus. - -Signed-off-by: Timo Teräs <timo.teras@iki.fi> ---- - drivers/input/misc/rotary_encoder.c | 20 ++++++++++---------- - 1 file changed, 10 insertions(+), 10 deletions(-) +commit 47ec6e5a5f57f96d7d382e2d9f8dc5a5bdb45259 +Author: Sylvain Rochet <sylvain.rochet@finsecur.com> +Date: Tue Oct 13 23:24:36 2015 -0700 + Input: rotary_encoder - add wake up support + + This patch adds wake up support to GPIO rotary encoders. + + Signed-off-by: Sylvain Rochet <sylvain.rochet@finsecur.com> + Reviewed-by: Johan Hovold <johan@kernel.org> + Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> + +diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt +index 3315495..891ddba 100644 +--- a/Documentation/devicetree/bindings/input/rotary-encoder.txt ++++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt +@@ -15,6 +15,7 @@ Optional properties: + - rotary-encoder,rollover: Automatic rollove when the rotary value becomes + greater than the specified steps or smaller than 0. For absolute axis only. + - rotary-encoder,half-period: Makes the driver work on half-period mode. ++- wakeup-source: Boolean, rotary encoder can wake up the system. + + See Documentation/input/rotary-encoder.txt for more information. + +diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt +index 5737e35..bddbee1 100644 +--- a/Documentation/input/rotary-encoder.txt ++++ b/Documentation/input/rotary-encoder.txt +@@ -109,6 +109,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = { + .inverted_a = 0, + .inverted_b = 0, + .half_period = false, ++ .wakeup_source = false, + }; + + static struct platform_device rotary_encoder_device = { diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c -index 8aee719..8bedd7b 100644 +index f27f81e..d166554 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c -@@ -48,8 +48,8 @@ struct rotary_encoder { +@@ -26,6 +26,7 @@ + #include <linux/of.h> + #include <linux/of_platform.h> + #include <linux/of_gpio.h> ++#include <linux/pm.h> - 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); + #define DRV_NAME "rotary-encoder" - a ^= pdata->inverted_a; - b ^= pdata->inverted_b; -@@ -335,18 +335,18 @@ static int rotary_encoder_probe(struct platform_device *pdev) - goto exit_free_gpio_b; +@@ -180,6 +181,8 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic + "rotary-encoder,rollover", NULL); + pdata->half_period = !!of_get_property(np, + "rotary-encoder,half-period", NULL); ++ pdata->wakeup_source = !!of_get_property(np, ++ "wakeup-source", NULL); + + return pdata; + } +@@ -280,6 +283,8 @@ static int rotary_encoder_probe(struct platform_device *pdev) + goto exit_free_irq_b; + } + ++ device_init_wakeup(&pdev->dev, pdata->wakeup_source); ++ + platform_set_drvdata(pdev, encoder); + + return 0; +@@ -306,6 +311,8 @@ static int rotary_encoder_remove(struct platform_device *pdev) + struct rotary_encoder *encoder = platform_get_drvdata(pdev); + const struct rotary_encoder_platform_data *pdata = encoder->pdata; + ++ device_init_wakeup(&pdev->dev, false); ++ + free_irq(encoder->irq_a, encoder); + free_irq(encoder->irq_b, encoder); + gpio_free(pdata->gpio_a); +@@ -320,11 +327,41 @@ static int rotary_encoder_remove(struct platform_device *pdev) + return 0; + } + ++#ifdef CONFIG_PM_SLEEP ++static int rotary_encoder_suspend(struct device *dev) ++{ ++ struct rotary_encoder *encoder = dev_get_drvdata(dev); ++ ++ if (device_may_wakeup(dev)) { ++ enable_irq_wake(encoder->irq_a); ++ enable_irq_wake(encoder->irq_b); ++ } ++ ++ return 0; ++} ++ ++static int rotary_encoder_resume(struct device *dev) ++{ ++ struct rotary_encoder *encoder = dev_get_drvdata(dev); ++ ++ if (device_may_wakeup(dev)) { ++ disable_irq_wake(encoder->irq_a); ++ disable_irq_wake(encoder->irq_b); ++ } ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops, ++ rotary_encoder_suspend, rotary_encoder_resume); ++ + static struct platform_driver rotary_encoder_driver = { + .probe = rotary_encoder_probe, + .remove = rotary_encoder_remove, + .driver = { + .name = DRV_NAME, ++ .pm = &rotary_encoder_pm_ops, + .of_match_table = of_match_ptr(rotary_encoder_of_match), + } + }; +diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h +index 3f594dc..b33f2d2 100644 +--- a/include/linux/rotary_encoder.h ++++ b/include/linux/rotary_encoder.h +@@ -11,6 +11,7 @@ struct rotary_encoder_platform_data { + bool relative_axis; + bool rollover; + bool half_period; ++ bool wakeup_source; + }; + + #endif /* __ROTARY_ENCODER_H__ */ + +commit 648b15cb79e90d80f7b53d0184bdb14132a03754 +Author: Ben Gamari <bgamari.foss@gmail.com> +Date: Tue Oct 13 23:37:28 2015 -0700 + + Input: rotary-encoder - use of_property_read_bool + + This commit makes uses of_property_read_bool() to read + boolean properties. This is just cosmetic cleanup. + + Signed-off-by: Ben Gamari <bgamari.foss@gmail.com> + Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> + +diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c +index d166554..962f9e8 100644 +--- a/drivers/input/misc/rotary_encoder.c ++++ b/drivers/input/misc/rotary_encoder.c +@@ -175,14 +175,12 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic + pdata->gpio_b = of_get_gpio_flags(np, 1, &flags); + pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW; + +- pdata->relative_axis = !!of_get_property(np, +- "rotary-encoder,relative-axis", NULL); +- pdata->rollover = !!of_get_property(np, +- "rotary-encoder,rollover", NULL); +- pdata->half_period = !!of_get_property(np, +- "rotary-encoder,half-period", NULL); +- pdata->wakeup_source = !!of_get_property(np, +- "wakeup-source", NULL); ++ pdata->relative_axis = ++ of_property_read_bool(np, "rotary-encoder,relative-axis"); ++ pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover"); ++ pdata->half_period = ++ of_property_read_bool(np, "rotary-encoder,half-period"); ++ pdata->wakeup_source = of_property_read_bool(np, "wakeup-source"); + + return pdata; + } + +commit 3a341a4c30d427fd05617087db1564a595f65093 +Author: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> +Date: Tue Oct 13 23:39:50 2015 -0700 + + Input: rotary-encoder - add support for quarter-period mode + + Some encoders have both outputs low in stable states, others also have + a stable state with both outputs high (half-period mode) and some have + a stable state in all steps (quarter-period mode). The driver used to + support the former states and with this change it can also support the + later. + + This commit also deprecates the 'half-period' property and introduces + a new property 'steps-per-period'. This property specifies the + number of steps (stable states) produced by the rotary encoder + for each GPIO period. + + Signed-off-by: Guido Martínez <guido@vanguardiasur.com.ar> + Signed-off-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> + Acked-by: Rob Herring <robh@kernel.org> + Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> + +diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt +index 891ddba..de99cbb 100644 +--- a/Documentation/devicetree/bindings/input/rotary-encoder.txt ++++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt +@@ -14,9 +14,18 @@ Optional properties: + device, hence no steps need to be passed. + - rotary-encoder,rollover: Automatic rollove when the rotary value becomes + greater than the specified steps or smaller than 0. For absolute axis only. +-- rotary-encoder,half-period: Makes the driver work on half-period mode. ++- rotary-encoder,steps-per-period: Number of steps (stable states) per period. ++ The values have the following meaning: ++ 1: Full-period mode (default) ++ 2: Half-period mode ++ 4: Quarter-period mode + - wakeup-source: Boolean, rotary encoder can wake up the system. + ++Deprecated properties: ++- rotary-encoder,half-period: Makes the driver work on half-period mode. ++ This property is deprecated. Instead, a 'steps-per-period ' value should ++ be used, such as "rotary-encoder,steps-per-period = <2>". ++ + See Documentation/input/rotary-encoder.txt for more information. + + Example: +diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt +index bddbee1..46a74f0 100644 +--- a/Documentation/input/rotary-encoder.txt ++++ b/Documentation/input/rotary-encoder.txt +@@ -9,8 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees + and by triggering on falling and rising edges, the turn direction can + be determined. + +-Some encoders have both outputs low in stable states, whereas others also have +-a stable state with both outputs high (half-period mode). ++Some encoders have both outputs low in stable states, others also have ++a stable state with both outputs high (half-period mode) and some have ++a stable state in all steps (quarter-period mode). + + The phase diagram of these two outputs look like this: + +@@ -32,6 +33,9 @@ The phase diagram of these two outputs look like this: + |<-->| + one step (half-period mode) + ++ |<>| ++ one step (quarter-period mode) ++ + For more information, please see + https://en.wikipedia.org/wiki/Rotary_encoder + +diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c +index 962f9e8..8aee719 100644 +--- a/drivers/input/misc/rotary_encoder.c ++++ b/drivers/input/misc/rotary_encoder.c +@@ -143,6 +143,55 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) ++{ ++ struct rotary_encoder *encoder = dev_id; ++ unsigned char sum; ++ int state; ++ ++ state = rotary_encoder_get_state(encoder->pdata); ++ ++ /* ++ * We encode the previous and the current state using a byte. ++ * The previous state in the MSB nibble, the current state in the LSB ++ * nibble. Then use a table to decide the direction of the turn. ++ */ ++ sum = (encoder->last_stable << 4) + state; ++ switch (sum) { ++ case 0x31: ++ case 0x10: ++ case 0x02: ++ case 0x23: ++ encoder->dir = 0; /* clockwise */ ++ break; ++ ++ case 0x13: ++ case 0x01: ++ case 0x20: ++ case 0x32: ++ encoder->dir = 1; /* counter-clockwise */ ++ break; ++ ++ default: ++ /* ++ * Ignore all other values. This covers the case when the ++ * state didn't change (a spurious interrupt) and the ++ * cases where the state changed by two steps, making it ++ * impossible to tell the direction. ++ * ++ * In either case, don't report any event and save the ++ * state for later. ++ */ ++ goto out; ++ } ++ ++ rotary_encoder_report_event(encoder); ++ ++out: ++ encoder->last_stable = state; ++ return IRQ_HANDLED; ++} ++ + #ifdef CONFIG_OF + static const struct of_device_id rotary_encoder_of_match[] = { + { .compatible = "rotary-encoder", }, +@@ -157,6 +206,7 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic + struct device_node *np = dev->of_node; + struct rotary_encoder_platform_data *pdata; + enum of_gpio_flags flags; ++ int error; + + if (!of_id || !np) + return NULL; +@@ -178,8 +228,23 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic + pdata->relative_axis = + of_property_read_bool(np, "rotary-encoder,relative-axis"); + pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover"); +- pdata->half_period = +- of_property_read_bool(np, "rotary-encoder,half-period"); ++ ++ error = of_property_read_u32(np, "rotary-encoder,steps-per-period", ++ &pdata->steps_per_period); ++ if (error) { ++ /* ++ * The 'half-period' property has been deprecated, you must use ++ * 'steps-per-period' and set an appropriate value, but we still ++ * need to parse it to maintain compatibility. ++ */ ++ if (of_property_read_bool(np, "rotary-encoder,half-period")) { ++ pdata->steps_per_period = 2; ++ } else { ++ /* Fallback to one step per period behavior */ ++ pdata->steps_per_period = 1; ++ } ++ } ++ + pdata->wakeup_source = of_property_read_bool(np, "wakeup-source"); + + return pdata; +@@ -251,12 +316,23 @@ static int rotary_encoder_probe(struct platform_device *pdev) + encoder->irq_a = gpio_to_irq(pdata->gpio_a); + encoder->irq_b = gpio_to_irq(pdata->gpio_b); + +- /* request the IRQs */ +- if (pdata->half_period) { ++ switch (pdata->steps_per_period) { ++ case 4: ++ handler = &rotary_encoder_quarter_period_irq; ++ encoder->last_stable = rotary_encoder_get_state(pdata); ++ break; ++ case 2: + handler = &rotary_encoder_half_period_irq; + encoder->last_stable = rotary_encoder_get_state(pdata); +- } else { ++ break; ++ case 1: + handler = &rotary_encoder_irq; ++ break; ++ default: ++ dev_err(dev, "'%d' is not a valid steps-per-period value\n", ++ pdata->steps_per_period); ++ err = -EINVAL; ++ goto exit_free_gpio_b; + } + + err = request_irq(encoder->irq_a, handler, +diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h +index b33f2d2..fe3dc64 100644 +--- a/include/linux/rotary_encoder.h ++++ b/include/linux/rotary_encoder.h +@@ -8,9 +8,9 @@ struct rotary_encoder_platform_data { + unsigned int gpio_b; + unsigned int inverted_a; + unsigned int inverted_b; ++ unsigned int steps_per_period; + bool relative_axis; + bool rollover; +- bool half_period; + bool wakeup_source; + }; + + +commit 0f940be407b87ca629fa2f3085f613483a075b16 +Author: Timo Teräs <timo.teras@iki.fi> +Date: Fri Jan 15 15:24:14 2016 +0200 + + Input: rotary_encoder - convert to devm-* api + + Use managed resource API for simplifying error paths. + + Signed-off-by: Timo Teräs <timo.teras@iki.fi> + +diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c +index 8aee719..0f23d32 100644 +--- a/drivers/input/misc/rotary_encoder.c ++++ b/drivers/input/misc/rotary_encoder.c +@@ -211,8 +211,8 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic + if (!of_id || !np) + return NULL; + +- pdata = kzalloc(sizeof(struct rotary_encoder_platform_data), +- GFP_KERNEL); ++ pdata = devm_kzalloc(dev, sizeof(struct rotary_encoder_platform_data), ++ GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + +@@ -277,12 +277,10 @@ static int rotary_encoder_probe(struct platform_device *pdev) + } + } + +- encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL); +- input = input_allocate_device(); +- if (!encoder || !input) { +- err = -ENOMEM; +- goto exit_free_mem; +- } ++ encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL); ++ input = devm_input_allocate_device(dev); ++ if (!encoder || !input) ++ return -ENOMEM; + + encoder->input = input; + encoder->pdata = pdata; +@@ -301,16 +299,16 @@ static int rotary_encoder_probe(struct platform_device *pdev) + } + + /* request the GPIOs */ +- err = gpio_request_one(pdata->gpio_a, GPIOF_IN, dev_name(dev)); ++ err = devm_gpio_request_one(dev, pdata->gpio_a, GPIOF_IN, dev_name(dev)); + if (err) { + dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a); +- goto exit_free_mem; ++ return err; + } + +- err = gpio_request_one(pdata->gpio_b, GPIOF_IN, dev_name(dev)); ++ err = devm_gpio_request_one(dev, pdata->gpio_b, GPIOF_IN, dev_name(dev)); + if (err) { + dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_b); +- goto exit_free_gpio_a; ++ return err; + } + + encoder->irq_a = gpio_to_irq(pdata->gpio_a); +@@ -331,30 +329,29 @@ static int rotary_encoder_probe(struct platform_device *pdev) + default: + dev_err(dev, "'%d' is not a valid steps-per-period value\n", + pdata->steps_per_period); +- err = -EINVAL; +- goto exit_free_gpio_b; ++ return-EINVAL; } - err = request_irq(encoder->irq_a, handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRV_NAME, encoder); -- if (err) { -+ err = request_any_context_irq(encoder->irq_a, handler, -+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -+ DRV_NAME, encoder); -+ if (err < 0) { ++ err = devm_request_irq(dev, encoder->irq_a, handler, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, ++ DRV_NAME, encoder); + if (err) { dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); - goto exit_free_gpio_b; +- goto exit_free_gpio_b; ++ return err; } - err = request_irq(encoder->irq_b, handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRV_NAME, encoder); -- if (err) { -+ err = request_any_context_irq(encoder->irq_b, handler, -+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -+ DRV_NAME, encoder); -+ if (err < 0) { ++ err = devm_request_irq(dev, encoder->irq_b, handler, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, ++ DRV_NAME, encoder); + if (err) { dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); - goto exit_free_irq_a; +- goto exit_free_irq_a; ++ return err; + } + + err = input_register_device(input); + if (err) { + dev_err(dev, "failed to register input device\n"); +- goto exit_free_irq_b; ++ return err; } --- -2.6.4 + + device_init_wakeup(&pdev->dev, pdata->wakeup_source); +@@ -362,42 +359,12 @@ static int rotary_encoder_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, encoder); + + return 0; +- +-exit_free_irq_b: +- free_irq(encoder->irq_b, encoder); +-exit_free_irq_a: +- free_irq(encoder->irq_a, encoder); +-exit_free_gpio_b: +- gpio_free(pdata->gpio_b); +-exit_free_gpio_a: +- gpio_free(pdata->gpio_a); +-exit_free_mem: +- input_free_device(input); +- kfree(encoder); +- if (!dev_get_platdata(&pdev->dev)) +- kfree(pdata); +- +- return err; + } + + static int rotary_encoder_remove(struct platform_device *pdev) + { +- struct rotary_encoder *encoder = platform_get_drvdata(pdev); +- const struct rotary_encoder_platform_data *pdata = encoder->pdata; +- + device_init_wakeup(&pdev->dev, false); + +- free_irq(encoder->irq_a, encoder); +- free_irq(encoder->irq_b, encoder); +- gpio_free(pdata->gpio_a); +- gpio_free(pdata->gpio_b); +- +- input_unregister_device(encoder->input); +- kfree(encoder); +- +- if (!dev_get_platdata(&pdev->dev)) +- kfree(pdata); +- + return 0; + } + + +commit 3467a8dafd27e2c6c1545028ea4e4a78701031df +Author: Timo Teräs <timo.teras@iki.fi> +Date: Fri Jan 15 15:37:00 2016 +0200 + + Input: rotary_encoder - fix device tree error handling + + of_get_gpio_flags() can fail, so pass through the error code + properly. Most important use case is when it returns EPROBE_DEFER + so that the probe gets called again later. + + Signed-off-by: Timo Teräs <timo.teras@iki.fi> +diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c +index 0f23d32..156f40f 100644 +--- a/drivers/input/misc/rotary_encoder.c ++++ b/drivers/input/misc/rotary_encoder.c +@@ -206,7 +206,7 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic + struct device_node *np = dev->of_node; + struct rotary_encoder_platform_data *pdata; + enum of_gpio_flags flags; +- int error; ++ int ret; + + if (!of_id || !np) + return NULL; +@@ -219,19 +219,25 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic + of_property_read_u32(np, "rotary-encoder,steps", &pdata->steps); + of_property_read_u32(np, "linux,axis", &pdata->axis); + +- pdata->gpio_a = of_get_gpio_flags(np, 0, &flags); ++ ret = of_get_gpio_flags(np, 0, &flags); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ pdata->gpio_a = ret; + pdata->inverted_a = flags & OF_GPIO_ACTIVE_LOW; + +- pdata->gpio_b = of_get_gpio_flags(np, 1, &flags); ++ ret = of_get_gpio_flags(np, 1, &flags); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ pdata->gpio_b = ret; + pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW; + + pdata->relative_axis = + of_property_read_bool(np, "rotary-encoder,relative-axis"); + pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover"); + +- error = of_property_read_u32(np, "rotary-encoder,steps-per-period", +- &pdata->steps_per_period); +- if (error) { ++ ret = of_property_read_u32(np, "rotary-encoder,steps-per-period", ++ &pdata->steps_per_period); ++ if (ret) { + /* + * The 'half-period' property has been deprecated, you must use + * 'steps-per-period' and set an appropriate value, but we still +commit 85bec2ad5ac7ee79b3f1d264947a5b4dc4c5ef6e (HEAD -> master) +Author: Timo Teräs <timo.teras@iki.fi> +Date: Fri Jan 15 15:55:48 2016 +0200 + + 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> + +diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c +index 156f40f..a2d47ce 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,7 @@ 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) { +@@ -114,6 +116,7 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) + encoder->armed = true; + break; + } ++ mutex_unlock(&encoder->access_mutex); + + return IRQ_HANDLED; + } +@@ -123,6 +126,7 @@ 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) { +@@ -139,6 +143,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) + encoder->dir = (encoder->last_stable + state) & 0x01; + break; + } ++ mutex_unlock(&encoder->access_mutex); + + return IRQ_HANDLED; + } +@@ -149,6 +154,7 @@ 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 +195,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; + } + +@@ -288,6 +296,8 @@ static int rotary_encoder_probe(struct platform_device *pdev) + if (!encoder || !input) + return -ENOMEM; + ++ mutex_init(&encoder->access_mutex); ++ + encoder->input = input; + encoder->pdata = pdata; + +@@ -338,17 +348,17 @@ 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, ++ 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, ++ DRV_NAME, encoder); + if (err) { + dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); + return err; |