diff options
Diffstat (limited to 'recipes-kernel/linux/linux-handheld-4.0/locomo/0009-gpio-locomo-implement-per-pin-irq-handling.patch')
-rw-r--r-- | recipes-kernel/linux/linux-handheld-4.0/locomo/0009-gpio-locomo-implement-per-pin-irq-handling.patch | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0009-gpio-locomo-implement-per-pin-irq-handling.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0009-gpio-locomo-implement-per-pin-irq-handling.patch new file mode 100644 index 0000000..7d07659 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0009-gpio-locomo-implement-per-pin-irq-handling.patch @@ -0,0 +1,204 @@ +From ec2485ae9fd5238d1def04e6377d213285ab3315 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 04:27:27 +0400 +Subject: [PATCH 09/20] gpio: locomo: implement per-pin irq handling + +LoCoMo has a possibility to generate per-GPIO edge irqs. Support for +that was there in old locomo driver, got 'cleaned up' during old driver +IRQ cascading cleanup and is now reimplemented. It is expected that +SL-5500 (collie) will use locomo gpio irqs for mmc detection irq. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/gpio/Kconfig | 1 + + drivers/gpio/gpio-locomo.c | 120 ++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 120 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index 9b1c2e6..b6ebcb6 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -507,6 +507,7 @@ config GPIO_TB10X + config GPIO_LOCOMO + bool "Sharp LoCoMo GPIO support" + depends on MFD_LOCOMO ++ select GPIOLIB_IRQCHIP + help + Select this to support GPIO pins on Sharp LoCoMo Grid Array found + in Sharp Zaurus collie and poodle models. +diff --git a/drivers/gpio/gpio-locomo.c b/drivers/gpio/gpio-locomo.c +index dd9a1ca..d8e5880 100644 +--- a/drivers/gpio/gpio-locomo.c ++++ b/drivers/gpio/gpio-locomo.c +@@ -16,13 +16,15 @@ + #include <linux/slab.h> + #include <linux/bitops.h> + #include <linux/err.h> +-#include <linux/gpio.h> ++#include <linux/gpio/driver.h> + #include <linux/io.h> ++#include <linux/irq.h> + #include <linux/regmap.h> + #include <linux/mfd/locomo.h> + + struct locomo_gpio { + struct regmap *regmap; ++ int irq; + + struct gpio_chip gpio; + +@@ -79,6 +81,99 @@ static int locomo_gpio_direction_output(struct gpio_chip *chip, + return 0; + } + ++static void ++locomo_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ struct gpio_chip *chip = irq_get_handler_data(irq); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ struct irq_chip *irqchip = irq_desc_get_chip(desc); ++ unsigned int gir; ++ unsigned int gpd; ++ unsigned int req; ++ ++ chained_irq_enter(irqchip, desc); ++ ++ while (1) { ++ regmap_read(lg->regmap, LOCOMO_GIR, &gir); ++ regmap_read(lg->regmap, LOCOMO_GPD, &gpd); ++ req = gir & gpd; ++ ++ if (!req) ++ break; ++ ++ generic_handle_irq(irq_find_mapping(lg->gpio.irqdomain, ++ ffs(req) - 1)); ++ } ++ ++ chained_irq_exit(irqchip, desc); ++} ++ ++static void locomo_gpio_ack_irq(struct irq_data *d) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(d); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ unsigned int mask = BIT(d->hwirq); ++ ++ regmap_update_bits(lg->regmap, LOCOMO_GWE, mask, mask); ++ regmap_update_bits(lg->regmap, LOCOMO_GIS, mask, 0); ++ regmap_update_bits(lg->regmap, LOCOMO_GWE, mask, 0); ++} ++ ++static void locomo_gpio_mask_irq(struct irq_data *d) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(d); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ unsigned int mask = BIT(d->hwirq); ++ ++ regmap_update_bits(lg->regmap, LOCOMO_GIE, mask, 0); ++} ++ ++static void locomo_gpio_unmask_irq(struct irq_data *d) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(d); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ unsigned int mask = BIT(d->hwirq); ++ ++ regmap_update_bits(lg->regmap, LOCOMO_GIE, mask, mask); ++} ++ ++static int locomo_gpio_type_irq(struct irq_data *d, unsigned int type) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(d); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ unsigned int mask; ++ ++ mask = BIT(d->hwirq); ++ ++ if (type == IRQ_TYPE_PROBE) { ++ if ((lg->rising_edge | lg->falling_edge) & mask) ++ return 0; ++ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; ++ } ++ ++ if (type & IRQ_TYPE_EDGE_RISING) ++ lg->rising_edge |= mask; ++ else ++ lg->rising_edge &= ~mask; ++ if (type & IRQ_TYPE_EDGE_FALLING) ++ lg->falling_edge |= mask; ++ else ++ lg->falling_edge &= ~mask; ++ ++ regmap_write(lg->regmap, LOCOMO_GRIE, lg->rising_edge); ++ regmap_write(lg->regmap, LOCOMO_GFIE, lg->falling_edge); ++ ++ return 0; ++} ++ ++static struct irq_chip locomo_gpio_irq_chip = { ++ .name = "LOCOMO-g", ++ .irq_ack = locomo_gpio_ack_irq, ++ .irq_mask = locomo_gpio_mask_irq, ++ .irq_unmask = locomo_gpio_unmask_irq, ++ .irq_set_type = locomo_gpio_type_irq, ++}; ++ + #ifdef CONFIG_PM_SLEEP + static int locomo_gpio_suspend(struct device *dev) + { +@@ -119,6 +214,10 @@ static int locomo_gpio_probe(struct platform_device *pdev) + if (!lg) + return -ENOMEM; + ++ lg->irq = platform_get_irq(pdev, 0); ++ if (lg->irq < 0) ++ return -ENXIO; ++ + lg->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!lg->regmap) + return -EINVAL; +@@ -130,6 +229,7 @@ static int locomo_gpio_probe(struct platform_device *pdev) + regmap_write(lg->regmap, LOCOMO_GPD, 0x00); + regmap_write(lg->regmap, LOCOMO_GIE, 0x00); + ++ lg->gpio.dev = &pdev->dev; + lg->gpio.base = pdata ? pdata->gpio_base : -1; + lg->gpio.label = "locomo-gpio"; + lg->gpio.ngpio = 16; +@@ -142,7 +242,22 @@ static int locomo_gpio_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ ret = gpiochip_irqchip_add(&lg->gpio, &locomo_gpio_irq_chip, 0, ++ handle_level_irq, IRQ_TYPE_NONE); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to add irq chip\n"); ++ goto err_rm_gpiochip; ++ } ++ ++ gpiochip_set_chained_irqchip(&lg->gpio, &locomo_gpio_irq_chip, lg->irq, ++ locomo_gpio_irq_handler); ++ + return 0; ++ ++err_rm_gpiochip: ++ gpiochip_remove(&lg->gpio); ++ ++ return ret; + } + + static int locomo_gpio_remove(struct platform_device *pdev) +@@ -151,6 +266,9 @@ static int locomo_gpio_remove(struct platform_device *pdev) + + gpiochip_remove(&lg->gpio); + ++ irq_set_chained_handler(lg->irq, NULL); ++ irq_set_handler_data(lg->irq, NULL); ++ + return 0; + } + +-- +1.9.1 + |