From bd6a6bb4328fb608ca941de2fd45f19cc395f910 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 30 Oct 2014 15:59:38 +0200 Subject: [PATCH 1/4] i2c: core: Map OF IRQ at probe time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 2fd36c55264926e268deb50f6de5f43fa5e490f7 upstream. I2C clients instantiated from OF get their IRQ mapped at device registration time. This leads to the IRQ being silently ignored if the related irqchip hasn't been proved yet. Fix this by moving IRQ mapping at probe time using of_get_irq(). The function operates as irq_of_parse_and_map() but additionally returns -EPROBE_DEFER if the irqchip isn't available, allowing us to defer I2C client probing. Signed-off-by: Laurent Pinchart Signed-off-by: Wolfram Sang [Benoît: Backport to 3.14] Signed-off-by: Benoît Thébaudeau --- drivers/i2c/i2c-core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 5fb80b8962a2a..ebf8e52f07787 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -250,6 +250,15 @@ static int i2c_device_probe(struct device *dev) if (!client) return 0; + if (!client->irq && dev->of_node) { + int irq = of_irq_get(dev->of_node, 0); + + if (irq < 0) + return irq; + + client->irq = irq; + } + driver = to_i2c_driver(dev->driver); if (!driver->probe || !driver->id_table) return -ENODEV; @@ -1021,7 +1030,6 @@ static void of_i2c_register_devices(struct i2c_adapter *adap) continue; } - info.irq = irq_of_parse_and_map(node, 0); info.of_node = of_node_get(node); info.archdata = &dev_ad; @@ -1035,7 +1043,6 @@ static void of_i2c_register_devices(struct i2c_adapter *adap) dev_err(&adap->dev, "of_i2c: Failure registering %s\n", node->full_name); of_node_put(node); - irq_dispose_mapping(info.irq); continue; } } From a6e80cb7cb4cdb5adff635ac1cd1c37adb39b460 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 17 Nov 2014 12:43:00 +0100 Subject: [PATCH 2/4] i2c: core: Fix probing of i2c slaves without interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 6f34be7400c68d3f761ceca405edabb94ccfcd03 upstream. Since commit 2fd36c55264926e2 ("i2c: core: Map OF IRQ at probe time"), i2c slaves without interrupts (e.g. da9210 and at24 on r8a7791/koelsch) fail to probe: at24: probe of 2-0050 failed with error -22 da9210: probe of 6-0068 failed with error -22 This happens because the call to of_irq_get() in i2c_device_probe() returns -EINVAL. If a device node does not have an "interrupts" property, of_irq_parse_one() fails. Unlike irq_of_parse_and_map(), of_irq_get() does not ignore errors from of_irq_parse_one(), but forwards them. Make i2c_device_probe() ignore all errors but -EPROBE_DEFER to fix this, just like platform_get_irq() and platform_get_irq_byname() already do. Fixes: 2fd36c55264926e2 ("i2c: core: Map OF IRQ at probe time") Signed-off-by: Geert Uytterhoeven Tested-by: Fabio Estevam Signed-off-by: Wolfram Sang [Benoît: Backport to 3.14] Signed-off-by: Benoît Thébaudeau --- drivers/i2c/i2c-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index ebf8e52f07787..36e478e53edbd 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -253,8 +253,10 @@ static int i2c_device_probe(struct device *dev) if (!client->irq && dev->of_node) { int irq = of_irq_get(dev->of_node, 0); - if (irq < 0) + if (irq == -EPROBE_DEFER) return irq; + if (irq < 0) + irq = 0; client->irq = irq; } From fcad64a9b8e6ed0e50517746139c1c5318f763bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Fri, 10 Nov 2017 15:17:51 +0100 Subject: [PATCH 3/4] gpio: pca953x: Add support for Amlogic GPIO IRQs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amlogic's GPIO driver handles interrupts in a non-standard way. Therefore, all the drivers needing Amlogic GPIO IRQs have to be modified in order to support them. Here, the pca953x GPIO expander driver is modified to make it possible to have its IRQ output wired to an Amlogic GPIO. The DTS files needing this have to define the "irq-gpios" property as the Amlogic GPIO to which the expander IRQ output is wired, e.g.: &pinmux { gpio_expander0_pins: gpio-expander0-pins { amlogic,setmask=<6 0x00000000>; amlogic,clrmask=<6 0x00000000>; amlogic,pins = "GPIOH_5"; amlogic,pullupen = <1>; amlogic,pullup = <1>; amlogic,enable-output = <0>; }; }; &i2c_b { gpio_expander0: gpio-expander@20 { compatible = "nxp,pca9555"; reg = <0x20>; irq-gpios = <&gpio GPIOH_5 GPIO_ACTIVE_LOW>; interrupt-parent = <&gic>; interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&gpio_expander0_pins>; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; }; }; Signed-off-by: Benoît Thébaudeau --- drivers/gpio/gpio-pca953x.c | 59 ++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 019b23b955a28..cb02189f542f7 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,7 @@ struct pca953x_chip { struct mutex i2c_lock; #ifdef CONFIG_GPIO_PCA953X_IRQ + int irq_gpio; struct mutex irq_lock; u8 irq_mask[MAX_BANK]; u8 irq_stat[MAX_BANK]; @@ -578,22 +580,51 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (!chip->domain) return -ENODEV; + if (gpio_is_valid(chip->irq_gpio)) { + ret = gpio_request_one(chip->irq_gpio, GPIOF_IN, + dev_name(&client->dev)); + if (ret) { + dev_err(&client->dev, + "unable to request GPIO %d\n", + chip->irq_gpio); + return ret; + } + + ret = gpio_for_irq(chip->irq_gpio, + AML_GPIO_IRQ(client->irq, + FILTER_NUM0, GPIO_IRQ_LOW)); + if (ret) { + dev_err(&client->dev, + "unable to set GPIO for IRQ %d\n", + client->irq); + goto exit_free_irq_gpio; + } + } + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, pca953x_irq_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + (gpio_is_valid(chip->irq_gpio) ? + IRQF_TRIGGER_HIGH : + IRQF_TRIGGER_FALLING) | IRQF_ONESHOT, dev_name(&client->dev), chip); if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); - return ret; + goto exit_free_irq_gpio; } chip->gpio_chip.to_irq = pca953x_gpio_to_irq; } return 0; + +exit_free_irq_gpio: + if (gpio_is_valid(chip->irq_gpio)) + gpio_free(chip->irq_gpio); + + return ret; } #else /* CONFIG_GPIO_PCA953X_IRQ */ @@ -710,6 +741,7 @@ static int pca953x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pca953x_platform_data *pdata; + struct device_node *node; struct pca953x_chip *chip; int irq_base = 0; int ret; @@ -721,6 +753,9 @@ static int pca953x_probe(struct i2c_client *client, return -ENOMEM; pdata = dev_get_platdata(&client->dev); +#ifdef CONFIG_GPIO_PCA953X_IRQ + chip->irq_gpio = -1; +#endif if (pdata) { irq_base = pdata->irq_base; chip->gpio_start = pdata->gpio_base; @@ -729,9 +764,15 @@ static int pca953x_probe(struct i2c_client *client, } else { pca953x_get_alt_pdata(client, &chip->gpio_start, &invert); #ifdef CONFIG_OF_GPIO + node = client->dev.of_node; /* If I2C node has no interrupts property, disable GPIO interrupts */ - if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL) + if (of_find_property(node, "interrupts", NULL) == NULL) irq_base = -1; +#ifdef CONFIG_GPIO_PCA953X_IRQ + else if (client->irq) + chip->irq_gpio = of_get_named_gpio_flags(node, + "irq-gpios", 0, NULL); +#endif #endif } @@ -758,8 +799,13 @@ static int pca953x_probe(struct i2c_client *client, return ret; ret = gpiochip_add(&chip->gpio_chip); - if (ret) + if (ret) { +#ifdef CONFIG_GPIO_PCA953X_IRQ + if (gpio_is_valid(chip->irq_gpio)) + gpio_free(chip->irq_gpio); +#endif return ret; + } if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -795,6 +841,11 @@ static int pca953x_remove(struct i2c_client *client) return ret; } +#ifdef CONFIG_GPIO_PCA953X_IRQ + if (gpio_is_valid(chip->irq_gpio)) + gpio_free(chip->irq_gpio); +#endif + return 0; } From 84f8d8af63d35b195d1d69185e266ea89f23906e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Fri, 10 Nov 2017 16:22:38 +0100 Subject: [PATCH 4/4] input: rotary-encoder: Add support for Amlogic GPIO IRQs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amlogic's GPIO driver handles interrupts in a non-standard way. Therefore, all the drivers needing Amlogic GPIO IRQs have to be modified in order to support them. Here, the rotary encoder driver is modified to make it possible to have its outputs wired to Amlogic GPIOs. The DTS files needing this have to define the "interrupts" property as the list of the interrupts of the Amlogic GPIOs to which the encoder outputs are wired, e.g.: / { rotary-encoder0 { compatible = "rotary-encoder"; gpios = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>, <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>; interrupts = , , , ; linux,axis = <7>; /* REL_DIAL */ rotary-encoder,relative-axis; pinctrl-names = "default"; pinctrl-0 = <&rotary_encoder0_pins>; }; }; &pinmux { rotary_encoder0_pins: rotary-encoder0-pins { amlogic,setmask=; amlogic,clrmask=; amlogic,pins = "GPIOAO_6", "GPIOAO_3"; amlogic,pullupen = <0>; amlogic,enable-output = <0>; }; }; Signed-off-by: Benoît Thébaudeau --- .../bindings/input/rotary-encoder.txt | 3 + drivers/input/misc/rotary_encoder.c | 117 ++++++++++++++---- include/linux/rotary_encoder.h | 1 + 3 files changed, 98 insertions(+), 23 deletions(-) diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt index 331549593ed5e..92ab2fe181e6d 100644 --- a/Documentation/devicetree/bindings/input/rotary-encoder.txt +++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt @@ -3,6 +3,9 @@ Rotary encoder DT bindings Required properties: - gpios: a spec for two GPIOs to be used +Properties required if Amlogic GPIOs are used: +- interrupts: a list of 4 specifiers for the interrupts to be used + Optional properties: - linux,axis: the input subsystem axis to map to this rotary encoder. Defaults to 0 (ABS_X / REL_X) diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 99b9e42aa7482..bae0853aa51ce 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -21,10 +21,12 @@ #include #include #include +#include #include #include #include #include +#include #include #define DRV_NAME "rotary-encoder" @@ -156,6 +158,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 i; if (!of_id || !np) return NULL; @@ -174,6 +177,15 @@ 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; + for (i = 0; i < ARRAY_SIZE(pdata->irqs); i++) { + pdata->irqs[i] = irq_of_parse_and_map(np, i); + if (!pdata->irqs[i]) { + while (i) + pdata->irqs[--i] = 0; + break; + } + } + pdata->relative_axis = !!of_get_property(np, "rotary-encoder,relative-axis", NULL); pdata->rollover = !!of_get_property(np, @@ -198,7 +210,7 @@ static int rotary_encoder_probe(struct platform_device *pdev) struct rotary_encoder *encoder; struct input_dev *input; irq_handler_t handler; - int err; + int i, err; if (!pdata) { pdata = rotary_encoder_parse_dt(dev); @@ -247,9 +259,6 @@ static int rotary_encoder_probe(struct platform_device *pdev) goto exit_free_gpio_a; } - 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) { handler = &rotary_encoder_half_period_irq; @@ -258,36 +267,92 @@ static int rotary_encoder_probe(struct platform_device *pdev) handler = &rotary_encoder_irq; } - err = request_irq(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; - } + if (pdata->irqs[0]) { + err = gpio_for_irq(pdata->gpio_a, AML_GPIO_IRQ(pdata->irqs[0], + FILTER_NUM0, GPIO_IRQ_RISING)); + if (err) { + dev_err(dev, "unable to set GPIO for IRQ %d\n", + pdata->irqs[0]); + goto exit_free_gpio_b; + } - err = request_irq(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; + err = gpio_for_irq(pdata->gpio_a, AML_GPIO_IRQ(pdata->irqs[1], + FILTER_NUM0, GPIO_IRQ_FALLING)); + if (err) { + dev_err(dev, "unable to set GPIO for IRQ %d\n", + pdata->irqs[1]); + goto exit_free_gpio_b; + } + + err = gpio_for_irq(pdata->gpio_b, AML_GPIO_IRQ(pdata->irqs[2], + FILTER_NUM0, GPIO_IRQ_RISING)); + if (err) { + dev_err(dev, "unable to set GPIO for IRQ %d\n", + pdata->irqs[2]); + goto exit_free_gpio_b; + } + + err = gpio_for_irq(pdata->gpio_b, AML_GPIO_IRQ(pdata->irqs[3], + FILTER_NUM0, GPIO_IRQ_FALLING)); + if (err) { + dev_err(dev, "unable to set GPIO for IRQ %d\n", + pdata->irqs[3]); + goto exit_free_gpio_b; + } + + for (i = 0; i < ARRAY_SIZE(pdata->irqs); i++) { + err = request_irq(pdata->irqs[i], handler, + IRQF_TRIGGER_RISING, DRV_NAME, encoder); + if (err) { + dev_err(dev, "unable to request IRQ %d\n", + pdata->irqs[i]); + goto exit_free_rem_irqs; + } + } + } else { + encoder->irq_a = gpio_to_irq(pdata->gpio_a); + encoder->irq_b = gpio_to_irq(pdata->gpio_b); + + err = request_irq(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; + } + + err = request_irq(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; + } } err = input_register_device(input); if (err) { dev_err(dev, "failed to register input device\n"); - goto exit_free_irq_b; + goto exit_free_irqs; } platform_set_drvdata(pdev, encoder); return 0; -exit_free_irq_b: - free_irq(encoder->irq_b, encoder); +exit_free_irqs: + if (pdata->irqs[0]) { + i = ARRAY_SIZE(pdata->irqs); +exit_free_rem_irqs: + while (i) + free_irq(pdata->irqs[--i], encoder); + } else { + free_irq(encoder->irq_b, encoder); exit_free_irq_a: - free_irq(encoder->irq_a, encoder); + free_irq(encoder->irq_a, encoder); + } exit_free_gpio_b: gpio_free(pdata->gpio_b); exit_free_gpio_a: @@ -305,9 +370,15 @@ 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; + int i; - free_irq(encoder->irq_a, encoder); - free_irq(encoder->irq_b, encoder); + if (pdata->irqs[0]) { + for (i = 0; i < ARRAY_SIZE(pdata->irqs); i++) + free_irq(pdata->irqs[i], encoder); + } else { + free_irq(encoder->irq_a, encoder); + free_irq(encoder->irq_b, encoder); + } gpio_free(pdata->gpio_a); gpio_free(pdata->gpio_b); diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h index 3f594dce57165..d6c9d3573aa48 100644 --- a/include/linux/rotary_encoder.h +++ b/include/linux/rotary_encoder.h @@ -8,6 +8,7 @@ struct rotary_encoder_platform_data { unsigned int gpio_b; unsigned int inverted_a; unsigned int inverted_b; + unsigned int irqs[4]; bool relative_axis; bool rollover; bool half_period;