From 165b6c2f33860e13d20cd7ac5993ea3acfb5ea34 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 15 Feb 2013 14:54:48 -0700 Subject: gpio/tegra: assume CONFIG_OF Tegra only supports, and always enables, device tree. Remove all ifdefs and runtime checks for DT support from the driver. Signed-off-by: Stephen Warren Signed-off-by: Grant Likely --- drivers/gpio/gpio-tegra.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 414ad912232..a78a81fbc2b 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -398,10 +398,11 @@ static int tegra_gpio_probe(struct platform_device *pdev) int j; match = of_match_device(tegra_gpio_of_match, &pdev->dev); - if (match) - config = (struct tegra_gpio_soc_config *)match->data; - else - config = &tegra20_gpio_config; + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + config = (struct tegra_gpio_soc_config *)match->data; tegra_gpio_bank_stride = config->bank_stride; tegra_gpio_upper_offset = config->upper_offset; @@ -462,9 +463,7 @@ static int tegra_gpio_probe(struct platform_device *pdev) } } -#ifdef CONFIG_OF_GPIO tegra_gpio_chip.of_node = pdev->dev.of_node; -#endif gpiochip_add(&tegra_gpio_chip); -- cgit v1.2.3 From ede4d7a5b9835510fd1f724367f68d2fa4128453 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 1 Mar 2013 11:22:47 -0600 Subject: gpio/omap: convert gpio irq domain to linear mapping Currently the OMAP GPIO driver uses a legacy mapping for the GPIO IRQ domain. This is not necessary because we do not need to assign a specific interrupt number to the GPIO IRQ domain. Therefore, convert the OMAP GPIO driver to use a linear mapping instead. Please note that this also allows to simplify the logic in the OMAP gpio_irq_handler() routine, by using irq_find_mapping() to obtain the virtual irq number from the GPIO bank and bank index. Reported-by: Linus Walleij Signed-off-by: Jon Hunter Reviewed-by: Felipe Balbi Acked-by: Santosh Shilimkar Acked-by: Kevin Hilman Tested-by: Javier Martinez Canillas Signed-off-by: Grant Likely --- drivers/gpio/gpio-omap.c | 72 +++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 159f5c57eb4..c3598d143aa 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -53,7 +53,6 @@ struct gpio_bank { struct list_head node; void __iomem *base; u16 irq; - int irq_base; struct irq_domain *domain; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; @@ -89,7 +88,14 @@ struct gpio_bank { static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) { - return gpio_irq - bank->irq_base + bank->chip.base; + return bank->chip.base + gpio_irq; +} + +static int omap_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); + + return irq_find_mapping(bank->domain, offset); } static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) @@ -427,7 +433,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) #endif if (!gpio) - gpio = irq_to_gpio(bank, d->irq); + gpio = irq_to_gpio(bank, d->hwirq); if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; @@ -580,7 +586,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) static int gpio_wake_enable(struct irq_data *d, unsigned int enable) { struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); return _set_gpio_wakeup(bank, gpio, enable); } @@ -680,7 +686,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { void __iomem *isr_reg = NULL; u32 isr; - unsigned int gpio_irq, gpio_index; + unsigned int i; struct gpio_bank *bank; int unmasked = 0; struct irq_chip *chip = irq_desc_get_chip(desc); @@ -721,15 +727,10 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (!isr) break; - gpio_irq = bank->irq_base; - for (; isr != 0; isr >>= 1, gpio_irq++) { - int gpio = irq_to_gpio(bank, gpio_irq); - + for (i = 0; isr != 0; isr >>= 1, i++) { if (!(isr & 1)) continue; - gpio_index = GPIO_INDEX(bank, gpio); - /* * Some chips can't respond to both rising and falling * at the same time. If this irq was requested with @@ -737,10 +738,10 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) * to respond to the IRQ for the opposite direction. * This will be indicated in the bank toggle_mask. */ - if (bank->toggle_mask & (1 << gpio_index)) - _toggle_gpio_edge_triggering(bank, gpio_index); + if (bank->toggle_mask & (1 << i)) + _toggle_gpio_edge_triggering(bank, i); - generic_handle_irq(gpio_irq); + generic_handle_irq(irq_find_mapping(bank->domain, i)); } } /* if bank has any level sensitive GPIO pin interrupt @@ -756,7 +757,7 @@ exit: static void gpio_irq_shutdown(struct irq_data *d) { struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); @@ -767,7 +768,7 @@ static void gpio_irq_shutdown(struct irq_data *d) static void gpio_ack_irq(struct irq_data *d) { struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); _clear_gpio_irqstatus(bank, gpio); } @@ -775,7 +776,7 @@ static void gpio_ack_irq(struct irq_data *d) static void gpio_mask_irq(struct irq_data *d) { struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); @@ -787,7 +788,7 @@ static void gpio_mask_irq(struct irq_data *d) static void gpio_unmask_irq(struct irq_data *d) { struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned int irq_mask = GPIO_BIT(bank, gpio); u32 trigger = irqd_get_trigger_type(d); unsigned long flags; @@ -953,14 +954,6 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) spin_unlock_irqrestore(&bank->lock, flags); } -static int gpio_2irq(struct gpio_chip *chip, unsigned offset) -{ - struct gpio_bank *bank; - - bank = container_of(chip, struct gpio_bank, chip); - return bank->irq_base + offset; -} - /*---------------------------------------------------------------------*/ static void __init omap_gpio_show_rev(struct gpio_bank *bank) @@ -1057,7 +1050,7 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) bank->chip.direction_output = gpio_output; bank->chip.set_debounce = gpio_debounce; bank->chip.set = gpio_set; - bank->chip.to_irq = gpio_2irq; + bank->chip.to_irq = omap_gpio_to_irq; if (bank->is_mpuio) { bank->chip.label = "mpuio"; if (bank->regs->wkup_en) @@ -1072,15 +1065,16 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) gpiochip_add(&bank->chip); - for (j = bank->irq_base; j < bank->irq_base + bank->width; j++) { - irq_set_lockdep_class(j, &gpio_lock_class); - irq_set_chip_data(j, bank); + for (j = 0; j < bank->width; j++) { + int irq = irq_create_mapping(bank->domain, j); + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_data(irq, bank); if (bank->is_mpuio) { - omap_mpuio_alloc_gc(bank, j, bank->width); + omap_mpuio_alloc_gc(bank, irq, bank->width); } else { - irq_set_chip(j, &gpio_irq_chip); - irq_set_handler(j, handle_simple_irq); - set_irq_flags(j, IRQF_VALID); + irq_set_chip_and_handler(irq, &gpio_irq_chip, + handle_simple_irq); + set_irq_flags(irq, IRQF_VALID); } } irq_set_chained_handler(bank->irq, gpio_irq_handler); @@ -1130,14 +1124,10 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->chip.of_node = of_node_get(node); #endif - bank->irq_base = irq_alloc_descs(-1, 0, bank->width, 0); - if (bank->irq_base < 0) { - dev_err(dev, "Couldn't allocate IRQ numbers\n"); + bank->domain = irq_domain_add_linear(node, bank->width, + &irq_domain_simple_ops, NULL); + if (!bank->domain) return -ENODEV; - } - - bank->domain = irq_domain_add_legacy(node, bank->width, bank->irq_base, - 0, &irq_domain_simple_ops, NULL); if (bank->regs->set_dataout && bank->regs->clr_dataout) bank->set_dataout = _set_gpio_dataout_reg; -- cgit v1.2.3 From 8d4c277e185c31359cf70573d8b0351fb7dd0dfe Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 1 Mar 2013 11:22:48 -0600 Subject: gpio/omap: warn if bank is not enabled on setting irq type For OMAP devices, if a gpio is being used as an interrupt source but has not been requested by calling gpio_request(), a call to request_irq() may cause the kernel hang because the gpio bank may be disabled and hence the register access will fail. To prevent such hangs, test for this case and warn if this is detected. Signed-off-by: Jon Hunter Reviewed-by: Felipe Balbi Acked-by: Santosh Shilimkar Acked-by: Kevin Hilman Tested-by: Javier Martinez Canillas Signed-off-by: Grant Likely --- drivers/gpio/gpio-omap.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index c3598d143aa..0d30c7acf0c 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -427,6 +427,9 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) int retval; unsigned long flags; + if (WARN_ON(!bank->mod_usage)) + return -EINVAL; + #ifdef CONFIG_ARCH_OMAP1 if (d->irq > IH_MPUIO_BASE) gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE); -- cgit v1.2.3 From 753c5983ddd38022a680a36f5d66b23b185c9b62 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 26 Feb 2013 22:26:23 +0900 Subject: gpio/em: Add Device Tree support Update the Emma Mobile GPIO driver to add DT support. The patch simply adds a two-cell xlate function and updates the probe code to allow configuration via DT using the "ngpios" property plus OF id in the same style as gpio-mvebu.c. The code is also adjusted to use postcore_initcall() to force early setup. Signed-off-by: Magnus Damm Signed-off-by: Grant Likely --- drivers/gpio/gpio-em.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index deca78f9931..d0536973585 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -231,10 +231,12 @@ static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, static struct irq_domain_ops em_gio_irq_domain_ops = { .map = em_gio_irq_domain_map, + .xlate = irq_domain_xlate_twocell, }; static int em_gio_probe(struct platform_device *pdev) { + struct gpio_em_config pdata_dt; struct gpio_em_config *pdata = pdev->dev.platform_data; struct em_gio_priv *p; struct resource *io[2], *irq[2]; @@ -259,8 +261,8 @@ static int em_gio_probe(struct platform_device *pdev) irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) { - dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n"); + if (!io[0] || !io[1] || !irq[0] || !irq[1]) { + dev_err(&pdev->dev, "missing IRQ or IOMEM\n"); ret = -EINVAL; goto err1; } @@ -279,6 +281,25 @@ static int em_gio_probe(struct platform_device *pdev) goto err2; } + if (!pdata) { + memset(&pdata_dt, 0, sizeof(pdata_dt)); + pdata = &pdata_dt; + + if (of_property_read_u32(pdev->dev.of_node, "ngpios", + &pdata->number_of_pins)) { + dev_err(&pdev->dev, "Missing ngpios OF property\n"); + ret = -EINVAL; + goto err3; + } + + ret = of_alias_get_id(pdev->dev.of_node, "gpio"); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't get OF id\n"); + goto err3; + } + pdata->gpio_base = ret * 32; /* 32 GPIOs per instance */ + } + gpio_chip = &p->gpio_chip; gpio_chip->direction_input = em_gio_direction_input; gpio_chip->get = em_gio_get; @@ -366,15 +387,33 @@ static int em_gio_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id em_gio_dt_ids[] = { + { .compatible = "renesas,em-gio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, em_gio_dt_ids); + static struct platform_driver em_gio_device_driver = { .probe = em_gio_probe, .remove = em_gio_remove, .driver = { .name = "em_gio", + .of_match_table = em_gio_dt_ids, + .owner = THIS_MODULE, } }; -module_platform_driver(em_gio_device_driver); +static int __init em_gio_init(void) +{ + return platform_driver_register(&em_gio_device_driver); +} +postcore_initcall(em_gio_init); + +static void __exit em_gio_exit(void) +{ + platform_driver_unregister(&em_gio_device_driver); +} +module_exit(em_gio_exit); MODULE_AUTHOR("Magnus Damm"); MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver"); -- cgit v1.2.3 From 25f27db48e9d741cf3494f36e287d3c34a0fdba3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 5 Mar 2013 21:22:38 +0100 Subject: gpio-ich: Check for pin availability at request time Stop checking for pin availability in direction and get functions. These functions can be called repeatedly, so checking every time is bad for performance. Now that requesting GPIO pins is no longer optional, checking for availability at pin request time is enough. Signed-off-by: Jean Delvare Cc: Peter Tyser Cc: Grant Likely Cc: Linus Walleij Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ich.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index f9dbd503fc4..31682178c59 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -135,9 +135,6 @@ static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { - if (!ichx_gpio_check_available(gpio, nr)) - return -ENXIO; - /* * Try setting pin as an input and verify it worked since many pins * are output-only. @@ -151,9 +148,6 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, int val) { - if (!ichx_gpio_check_available(gpio, nr)) - return -ENXIO; - /* Set GPIO output value. */ ichx_write_bit(GPIO_LVL, nr, val, 0); @@ -169,9 +163,6 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr) { - if (!ichx_gpio_check_available(chip, nr)) - return -ENXIO; - return ichx_read_bit(GPIO_LVL, nr); } @@ -180,9 +171,6 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr) unsigned long flags; u32 data; - if (!ichx_gpio_check_available(chip, nr)) - return -ENXIO; - /* * GPI 0 - 15 need to be read from the power management registers on * a ICH6/3100 bridge. @@ -207,6 +195,9 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr) static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr) { + if (!ichx_gpio_check_available(chip, nr)) + return -ENXIO; + /* * Note we assume the BIOS properly set a bridge's USE value. Some * chips (eg Intel 3100) have bogus USE values though, so first see if -- cgit v1.2.3 From 5c97d146f20bb6a82a621009c0c6f368e40a905f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 5 Mar 2013 20:21:56 +0800 Subject: gpio: viperboard: Remove duplicate code to set gpio->gpiob_val Set it once is enough, and it's done in vprbrd_gpiob_set() which is called by vprbrd_gpiob_direction_output(). Signed-off-by: Axel Lin Tested-by: Lars Poeschel Acked-by: Lars Poeschel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-viperboard.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index 59d72391de2..095ab14cea4 100644 --- a/drivers/gpio/gpio-viperboard.c +++ b/drivers/gpio/gpio-viperboard.c @@ -380,10 +380,6 @@ static int vprbrd_gpiob_direction_output(struct gpio_chip *chip, struct vprbrd *vb = gpio->vb; gpio->gpiob_out |= (1 << offset); - if (value) - gpio->gpiob_val |= (1 << offset); - else - gpio->gpiob_val &= ~(1 << offset); mutex_lock(&vb->lock); -- cgit v1.2.3 From 021304907bd06a92cee362c605bd4d9a83bb1927 Mon Sep 17 00:00:00 2001 From: Nikolay Balandin Date: Wed, 6 Mar 2013 15:06:44 +0400 Subject: Add TI TCA9554 to supported devices table Signed-off-by: Nikolay Balandin Acked-by: Kuninori Morimoto Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pcf857x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index a19b7457a72..a965620c1c2 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -45,6 +45,7 @@ static const struct i2c_device_id pcf857x_id[] = { { "pca9675", 16 }, { "max7328", 8 }, { "max7329", 8 }, + { "tca9554", 8 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf857x_id); -- cgit v1.2.3 From 3cbf1822b5fd98eccb641c94c8cd2455fdad9221 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Wed, 6 Mar 2013 13:49:36 -0800 Subject: gpio-sch: Allow for more than 8 lines in the resume well The E6xx (TunnelCreek) CPUs have 9 GPIO lines in the resume well. Update the resume functions to allow for more than 8 GPIO lines, using the core functions as a template. Cc: Grant Likely Cc: Linus Walleij Signed-off-by: Darren Hart Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index edae963f462..7e7b52be6e2 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -125,13 +125,17 @@ static int sch_gpio_resume_direction_in(struct gpio_chip *gc, unsigned gpio_num) { u8 curr_dirs; + unsigned short offset, bit; spin_lock(&gpio_lock); - curr_dirs = inb(gpio_ba + RGIO); + offset = RGIO + gpio_num / 8; + bit = gpio_num % 8; + + curr_dirs = inb(gpio_ba + offset); - if (!(curr_dirs & (1 << gpio_num))) - outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO); + if (!(curr_dirs & (1 << bit))) + outb(curr_dirs | (1 << bit), gpio_ba + offset); spin_unlock(&gpio_lock); return 0; @@ -139,22 +143,31 @@ static int sch_gpio_resume_direction_in(struct gpio_chip *gc, static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num) { - return !!(inb(gpio_ba + RGLV) & (1 << gpio_num)); + unsigned short offset, bit; + + offset = RGLV + gpio_num / 8; + bit = gpio_num % 8; + + return !!(inb(gpio_ba + offset) & (1 << bit)); } static void sch_gpio_resume_set(struct gpio_chip *gc, unsigned gpio_num, int val) { u8 curr_vals; + unsigned short offset, bit; spin_lock(&gpio_lock); - curr_vals = inb(gpio_ba + RGLV); + offset = RGLV + gpio_num / 8; + bit = gpio_num % 8; + + curr_vals = inb(gpio_ba + offset); if (val) - outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV); + outb(curr_vals | (1 << bit), gpio_ba + offset); else - outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV); + outb((curr_vals & ~(1 << bit)), gpio_ba + offset); spin_unlock(&gpio_lock); } @@ -163,14 +176,18 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc, unsigned gpio_num, int val) { u8 curr_dirs; + unsigned short offset, bit; sch_gpio_resume_set(gc, gpio_num, val); + offset = RGIO + gpio_num / 8; + bit = gpio_num % 8; + spin_lock(&gpio_lock); - curr_dirs = inb(gpio_ba + RGIO); - if (curr_dirs & (1 << gpio_num)) - outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO); + curr_dirs = inb(gpio_ba + offset); + if (curr_dirs & (1 << bit)) + outb(curr_dirs & ~(1 << bit), gpio_ba + offset); spin_unlock(&gpio_lock); return 0; -- cgit v1.2.3 From 61d793bbfb76ea6740dd1c1a4f2cdac57a0c1c5c Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 7 Mar 2013 10:48:19 +0200 Subject: gpio/gpio-ich: make ichx_gpio_check_available() return a pure boolean value It is more readable for humans to use double-bang (!!) to convert the value to pure boolean before it is returned. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ich.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 31682178c59..2829d6d5002 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -130,7 +130,7 @@ static int ichx_read_bit(int reg, unsigned nr) static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) { - return ichx_priv.use_gpio & (1 << (nr / 32)); + return !!(ichx_priv.use_gpio & (1 << (nr / 32))); } static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) -- cgit v1.2.3 From 977d16b87a78844f090af0565cbd2e3a94fd6337 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 8 Mar 2013 14:38:12 +0200 Subject: gpio-lynxpoint: Add X86 dependency and io-port handling header. Lynxpoint gpio driver uses X86 specific io-ports to control gpios Signed-off-by: Mathias Nyman Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-lynxpoint.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 93aaadf99f2..704d01d6752 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -303,7 +303,7 @@ config GPIO_GE_FPGA config GPIO_LYNXPOINT bool "Intel Lynxpoint GPIO support" - depends on ACPI + depends on ACPI && X86 select IRQ_DOMAIN help driver for GPIO functionality on Intel Lynxpoint PCH chipset diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 3472b05ac51..86c17de8769 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -32,6 +32,7 @@ #include #include #include +#include /* LynxPoint chipset has support for 94 gpio pins */ -- cgit v1.2.3 From 1cfe6f8cb1078039a0f8dfc833a4ae752220d2db Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 13 Mar 2013 20:06:30 +0900 Subject: gpio: em: Make use of devm functions Update the Emma Mobile GPIO driver to make use of devm functions. This simplifies the error handling and makes the code more compact. Signed-off-by: Magnus Damm Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 53 ++++++++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index d0536973585..5cba855638b 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -245,7 +245,7 @@ static int em_gio_probe(struct platform_device *pdev) const char *name = dev_name(&pdev->dev); int ret; - p = kzalloc(sizeof(*p), GFP_KERNEL); + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); if (!p) { dev_err(&pdev->dev, "failed to allocate driver data\n"); ret = -ENOMEM; @@ -264,21 +264,23 @@ static int em_gio_probe(struct platform_device *pdev) if (!io[0] || !io[1] || !irq[0] || !irq[1]) { dev_err(&pdev->dev, "missing IRQ or IOMEM\n"); ret = -EINVAL; - goto err1; + goto err0; } - p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0])); + p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start, + resource_size(io[0])); if (!p->base0) { dev_err(&pdev->dev, "failed to remap low I/O memory\n"); ret = -ENXIO; - goto err1; + goto err0; } - p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1])); + p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start, + resource_size(io[1])); if (!p->base1) { dev_err(&pdev->dev, "failed to remap high I/O memory\n"); ret = -ENXIO; - goto err2; + goto err0; } if (!pdata) { @@ -289,13 +291,13 @@ static int em_gio_probe(struct platform_device *pdev) &pdata->number_of_pins)) { dev_err(&pdev->dev, "Missing ngpios OF property\n"); ret = -EINVAL; - goto err3; + goto err0; } ret = of_alias_get_id(pdev->dev.of_node, "gpio"); if (ret < 0) { dev_err(&pdev->dev, "Couldn't get OF id\n"); - goto err3; + goto err0; } pdata->gpio_base = ret * 32; /* 32 GPIOs per instance */ } @@ -327,40 +329,32 @@ static int em_gio_probe(struct platform_device *pdev) if (!p->irq_domain) { ret = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); - goto err3; + goto err0; } - if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) { + if (devm_request_irq(&pdev->dev, irq[0]->start, + em_gio_irq_handler, 0, name, p)) { dev_err(&pdev->dev, "failed to request low IRQ\n"); ret = -ENOENT; - goto err4; + goto err1; } - if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) { + if (devm_request_irq(&pdev->dev, irq[1]->start, + em_gio_irq_handler, 0, name, p)) { dev_err(&pdev->dev, "failed to request high IRQ\n"); ret = -ENOENT; - goto err5; + goto err1; } ret = gpiochip_add(gpio_chip); if (ret) { dev_err(&pdev->dev, "failed to add GPIO controller\n"); - goto err6; + goto err1; } return 0; -err6: - free_irq(irq[1]->start, pdev); -err5: - free_irq(irq[0]->start, pdev); -err4: - irq_domain_remove(p->irq_domain); -err3: - iounmap(p->base1); -err2: - iounmap(p->base0); err1: - kfree(p); + irq_domain_remove(p->irq_domain); err0: return ret; } @@ -368,22 +362,13 @@ err0: static int em_gio_remove(struct platform_device *pdev) { struct em_gio_priv *p = platform_get_drvdata(pdev); - struct resource *irq[2]; int ret; ret = gpiochip_remove(&p->gpio_chip); if (ret) return ret; - irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - - free_irq(irq[1]->start, pdev); - free_irq(irq[0]->start, pdev); irq_domain_remove(p->irq_domain); - iounmap(p->base1); - iounmap(p->base0); - kfree(p); return 0; } -- cgit v1.2.3 From 808c513ee64be7cec6a7dcfff1687bc0995362bc Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 4 Mar 2013 14:39:39 +0530 Subject: gpio/vt8500: Convert to devm_ioremap_resource() Use the newly introduced devm_ioremap_resource() instead of devm_request_and_ioremap() which provides more consistent error handling. devm_ioremap_resource() provides its own error messages; so all explicit error messages can be removed from the failure code paths. Signed-off-by: Sachin Kamat Reviewed-by: Thierry Reding Acked-by: Tony Prisk Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vt8500.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c index 81683ca35ac..b2d8d6f0c52 100644 --- a/drivers/gpio/gpio-vt8500.c +++ b/drivers/gpio/gpio-vt8500.c @@ -309,11 +309,9 @@ static int vt8500_gpio_probe(struct platform_device *pdev) return -ENODEV; } - gpio_base = devm_request_and_ioremap(&pdev->dev, res); - if (!gpio_base) { - dev_err(&pdev->dev, "Unable to map GPIO registers\n"); - return -ENOMEM; - } + gpio_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio_base)) + return PTR_ERR(gpio_base); ret = vt8500_add_chips(pdev, gpio_base, of_id->data); -- cgit v1.2.3 From 24bb3813d525322e007c47134cd476f04dbb554f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 15 Mar 2013 18:14:01 +0900 Subject: gpio: adp5520: use devm_kzalloc() Use devm_kzalloc() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adp5520.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index 8afa95f831b..f33f78dcada 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -105,7 +105,7 @@ static int adp5520_gpio_probe(struct platform_device *pdev) return -ENODEV; } - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (dev == NULL) { dev_err(&pdev->dev, "failed to alloc memory\n"); return -ENOMEM; @@ -163,7 +163,6 @@ static int adp5520_gpio_probe(struct platform_device *pdev) return 0; err: - kfree(dev); return ret; } @@ -180,7 +179,6 @@ static int adp5520_gpio_remove(struct platform_device *pdev) return ret; } - kfree(dev); return 0; } -- cgit v1.2.3 From c3fe2bf4916e85fabc66690c8784bbce3ef4d2b4 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 15 Mar 2013 18:14:46 +0900 Subject: gpio: max7300: use devm_kzalloc() Use devm_kzalloc() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max7300.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c index 4b6b9a04e32..40ab6dfb602 100644 --- a/drivers/gpio/gpio-max7300.c +++ b/drivers/gpio/gpio-max7300.c @@ -41,7 +41,7 @@ static int max7300_probe(struct i2c_client *client, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - ts = kzalloc(sizeof(struct max7301), GFP_KERNEL); + ts = devm_kzalloc(&client->dev, sizeof(struct max7301), GFP_KERNEL); if (!ts) return -ENOMEM; @@ -50,8 +50,6 @@ static int max7300_probe(struct i2c_client *client, ts->dev = &client->dev; ret = __max730x_probe(ts); - if (ret) - kfree(ts); return ret; } -- cgit v1.2.3 From 4cb06cd58c23f6520dc00d67e62267ef17d69206 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 15 Mar 2013 18:15:06 +0900 Subject: gpio: max7301: use devm_kzalloc() Use devm_kzalloc() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max7301.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index c6c535c1310..6e1c984a75d 100644 --- a/drivers/gpio/gpio-max7301.c +++ b/drivers/gpio/gpio-max7301.c @@ -61,7 +61,7 @@ static int max7301_probe(struct spi_device *spi) if (ret < 0) return ret; - ts = kzalloc(sizeof(struct max7301), GFP_KERNEL); + ts = devm_kzalloc(&spi->dev, sizeof(struct max7301), GFP_KERNEL); if (!ts) return -ENOMEM; @@ -70,8 +70,6 @@ static int max7301_probe(struct spi_device *spi) ts->dev = &spi->dev; ret = __max730x_probe(ts); - if (ret) - kfree(ts); return ret; } -- cgit v1.2.3 From b09638a4d6b8032f6569e6ec8a5cc373ced045aa Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 15 Mar 2013 18:15:28 +0900 Subject: gpio: max732x: use devm_kzalloc() Use devm_kzalloc() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 1e0467ce4c3..d4b51b163b0 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -589,7 +589,8 @@ static int max732x_probe(struct i2c_client *client, return -EINVAL; } - chip = kzalloc(sizeof(struct max732x_chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof(struct max732x_chip), + GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->client = client; @@ -647,7 +648,6 @@ static int max732x_probe(struct i2c_client *client, out_failed: max732x_irq_teardown(chip); - kfree(chip); return ret; } @@ -680,7 +680,6 @@ static int max732x_remove(struct i2c_client *client) if (chip->client_dummy) i2c_unregister_device(chip->client_dummy); - kfree(chip); return 0; } -- cgit v1.2.3 From 632d8e55d1f0304579315669bfadcab7352973fd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 15 Mar 2013 18:15:49 +0900 Subject: gpio: mc33880: use devm_kzalloc() Use devm_kzalloc() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mc33880.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 6a8fdc26ae6..b16148913a7 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -101,7 +101,7 @@ static int mc33880_probe(struct spi_device *spi) if (ret < 0) return ret; - mc = kzalloc(sizeof(struct mc33880), GFP_KERNEL); + mc = devm_kzalloc(&spi->dev, sizeof(struct mc33880), GFP_KERNEL); if (!mc) return -ENOMEM; @@ -143,7 +143,6 @@ static int mc33880_probe(struct spi_device *spi) exit_destroy: dev_set_drvdata(&spi->dev, NULL); mutex_destroy(&mc->lock); - kfree(mc); return ret; } @@ -159,10 +158,9 @@ static int mc33880_remove(struct spi_device *spi) dev_set_drvdata(&spi->dev, NULL); ret = gpiochip_remove(&mc->chip); - if (!ret) { + if (!ret) mutex_destroy(&mc->lock); - kfree(mc); - } else + else dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n", ret); -- cgit v1.2.3 From f39f54af032ce900815d0d718df5f1717eed50fe Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 15 Mar 2013 18:16:11 +0900 Subject: gpio: pcf857x: use devm_kzalloc() Use devm_kzalloc() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pcf857x.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index a965620c1c2..e8faf53f387 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -268,7 +268,7 @@ static int pcf857x_probe(struct i2c_client *client, } /* Allocate, initialize, and register this gpio_chip. */ - gpio = kzalloc(sizeof *gpio, GFP_KERNEL); + gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); if (!gpio) return -ENOMEM; @@ -391,7 +391,6 @@ fail: if (pdata && client->irq) pcf857x_irq_domain_cleanup(gpio); - kfree(gpio); return status; } @@ -416,9 +415,7 @@ static int pcf857x_remove(struct i2c_client *client) pcf857x_irq_domain_cleanup(gpio); status = gpiochip_remove(&gpio->chip); - if (status == 0) - kfree(gpio); - else + if (status) dev_err(&client->dev, "%s --> %d\n", "remove", status); return status; } -- cgit v1.2.3 From 30db2bd1c88cedf73e1eb753225249130cc00970 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 15 Mar 2013 18:16:49 +0900 Subject: gpio: mc33880: use dev_err() instead of printk() dev_err() is more preferred than printk(). Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mc33880.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index b16148913a7..33958799bd3 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -130,7 +130,8 @@ static int mc33880_probe(struct spi_device *spi) ret = mc33880_write_config(mc); if (ret) { - printk(KERN_ERR "Failed writing to " DRIVER_NAME ": %d\n", ret); + dev_err(&spi->dev, "Failed writing to " DRIVER_NAME ": %d\n", + ret); goto exit_destroy; } -- cgit v1.2.3 From 6c0cf42be3f8e1039d3f31c2e8e16b4d375527c7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 15 Mar 2013 18:17:18 +0900 Subject: gpio: 74x164: use spi_get_drvdata() and spi_set_drvdata() Use the wrapper functions for getting and setting the driver data using spi_device instead of using dev_{get|set}_drvdata with &spi->dev, so we can directly pass a struct spi_device. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-74x164.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 464be961f60..721607904d0 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -137,7 +137,7 @@ static int gen_74x164_probe(struct spi_device *spi) mutex_init(&chip->lock); - dev_set_drvdata(&spi->dev, chip); + spi_set_drvdata(spi, chip); chip->spi = spi; @@ -176,7 +176,7 @@ static int gen_74x164_probe(struct spi_device *spi) return ret; exit_destroy: - dev_set_drvdata(&spi->dev, NULL); + spi_set_drvdata(spi, NULL); mutex_destroy(&chip->lock); return ret; } @@ -186,11 +186,11 @@ static int gen_74x164_remove(struct spi_device *spi) struct gen_74x164_chip *chip; int ret; - chip = dev_get_drvdata(&spi->dev); + chip = spi_get_drvdata(spi); if (chip == NULL) return -ENODEV; - dev_set_drvdata(&spi->dev, NULL); + spi_set_drvdata(spi, NULL); ret = gpiochip_remove(&chip->gpio_chip); if (!ret) -- cgit v1.2.3 From 493294d4a82470c44bf7ac9b21b901fb3e56dc3b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 15 Mar 2013 18:17:54 +0900 Subject: gpio: mc33880: use spi_get_drvdata() and spi_set_drvdata() Use the wrapper functions for getting and setting the driver data using spi_device instead of using dev_{get|set}_drvdata with &spi->dev, so we can directly pass a struct spi_device. Signed-off-by: Jingoo Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mc33880.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 33958799bd3..63a7a1bfb2d 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -107,7 +107,7 @@ static int mc33880_probe(struct spi_device *spi) mutex_init(&mc->lock); - dev_set_drvdata(&spi->dev, mc); + spi_set_drvdata(spi, mc); mc->spi = spi; @@ -142,7 +142,7 @@ static int mc33880_probe(struct spi_device *spi) return ret; exit_destroy: - dev_set_drvdata(&spi->dev, NULL); + spi_set_drvdata(spi, NULL); mutex_destroy(&mc->lock); return ret; } @@ -152,11 +152,11 @@ static int mc33880_remove(struct spi_device *spi) struct mc33880 *mc; int ret; - mc = dev_get_drvdata(&spi->dev); + mc = spi_get_drvdata(spi); if (mc == NULL) return -ENODEV; - dev_set_drvdata(&spi->dev, NULL); + spi_set_drvdata(spi, NULL); ret = gpiochip_remove(&mc->chip); if (!ret) -- cgit v1.2.3 From 9ccb1a26cedf0a03a59f70f270565f3884ec08f6 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:15:55 +0100 Subject: gpio: gpiolib-of.c: fix checkpatch error Fix : gpio/gpiolib-of.c:64: ERROR: code indent should use tabs where possible Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index a71a54a3e3f..8940793912d 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -61,7 +61,7 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) * in flags for the GPIO. */ int of_get_named_gpio_flags(struct device_node *np, const char *propname, - int index, enum of_gpio_flags *flags) + int index, enum of_gpio_flags *flags) { /* Return -EPROBE_DEFER to support probe() functions to be called * later when the GPIO actually becomes available -- cgit v1.2.3 From f4dcd2d9417c2909362d2b42f038ecf1cdf86834 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:15:56 +0100 Subject: gpio: gpio-mvebu.c: fix checkpatch errors Fix : gpio/gpio-mvebu.c:120: ERROR: space required before the open parenthesis '(' gpio/gpio-mvebu.c:136: ERROR: space required before the open parenthesis '(' gpio/gpio-mvebu.c:154: ERROR: space required before the open parenthesis '(' gpio/gpio-mvebu.c:404: ERROR: space required before the open parenthesis '(' gpio/gpio-mvebu.c:476: ERROR: "(foo*)" should be "(foo *)" gpio/gpio-mvebu.c:480: ERROR: "(foo*)" should be "(foo *)" gpio/gpio-mvebu.c:484: ERROR: "(foo*)" should be "(foo *)" gpio/gpio-mvebu.c:512: ERROR: space prohibited after that '!' (ctx:BxW) gpio/gpio-mvebu.c:518: ERROR: space prohibited after that '!' (ctx:BxW) gpio/gpio-mvebu.c:518: ERROR: space required before the open brace '{' gpio/gpio-mvebu.c:563: ERROR: space prohibited after that '!' (ctx:BxW) gpio/gpio-mvebu.c:570: ERROR: trailing whitespace gpio/gpio-mvebu.c:577: ERROR: space required before the open parenthesis '(' gpio/gpio-mvebu.c:635: ERROR: space prohibited after that '!' (ctx:BxW) Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 7472182967c..474823e403f 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -116,7 +116,7 @@ static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvc { int cpu; - switch(mvchip->soc_variant) { + switch (mvchip->soc_variant) { case MVEBU_GPIO_SOC_VARIANT_ORION: case MVEBU_GPIO_SOC_VARIANT_MV78200: return mvchip->membase + GPIO_EDGE_CAUSE_OFF; @@ -132,7 +132,7 @@ static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvch { int cpu; - switch(mvchip->soc_variant) { + switch (mvchip->soc_variant) { case MVEBU_GPIO_SOC_VARIANT_ORION: return mvchip->membase + GPIO_EDGE_MASK_OFF; case MVEBU_GPIO_SOC_VARIANT_MV78200: @@ -150,7 +150,7 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) { int cpu; - switch(mvchip->soc_variant) { + switch (mvchip->soc_variant) { case MVEBU_GPIO_SOC_VARIANT_ORION: return mvchip->membase + GPIO_LEVEL_MASK_OFF; case MVEBU_GPIO_SOC_VARIANT_MV78200: @@ -400,7 +400,7 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) /* * Configure interrupt polarity. */ - switch(type) { + switch (type) { case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); @@ -472,15 +472,15 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) static struct of_device_id mvebu_gpio_of_match[] = { { .compatible = "marvell,orion-gpio", - .data = (void*) MVEBU_GPIO_SOC_VARIANT_ORION, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, }, { .compatible = "marvell,mv78200-gpio", - .data = (void*) MVEBU_GPIO_SOC_VARIANT_MV78200, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, }, { .compatible = "marvell,armadaxp-gpio", - .data = (void*) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, }, { /* sentinel */ @@ -507,13 +507,13 @@ static int mvebu_gpio_probe(struct platform_device *pdev) soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (! res) { + if (!res) { dev_err(&pdev->dev, "Cannot get memory resource\n"); return -ENODEV; } mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL); - if (! mvchip){ + if (!mvchip) { dev_err(&pdev->dev, "Cannot allocate memory\n"); return -ENOMEM; } @@ -553,21 +553,21 @@ static int mvebu_gpio_probe(struct platform_device *pdev) * per-CPU registers */ if (soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) { res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (! res) { + if (!res) { dev_err(&pdev->dev, "Cannot get memory resource\n"); return -ENODEV; } mvchip->percpu_membase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mvchip->percpu_membase)) + if (IS_ERR(mvchip->percpu_membase)) return PTR_ERR(mvchip->percpu_membase); } /* * Mask and clear GPIO interrupts. */ - switch(soc_variant) { + switch (soc_variant) { case MVEBU_GPIO_SOC_VARIANT_ORION: writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF); writel_relaxed(0, mvchip->membase + GPIO_EDGE_MASK_OFF); @@ -625,7 +625,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase, mvchip->membase, handle_level_irq); - if (! gc) { + if (!gc) { dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n"); return -ENOMEM; } -- cgit v1.2.3 From e83507b763541cbbdf5a9e047c69755fec52aed9 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:15:57 +0100 Subject: gpio: gpio-omap.c: fix checkpatch error Fix : gpio/gpio-omap.c:697: ERROR: space required before the open parenthesis '(' Signed-off-by: Laurent Navet Acked-by: Santosh Shilimkar Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0d30c7acf0c..352f9949c05 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -703,7 +703,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (WARN_ON(!isr_reg)) goto exit; - while(1) { + while (1) { u32 isr_saved, level_mask = 0; u32 enabled; -- cgit v1.2.3 From 50e44430c6c1872a761c57161338dea069dc36db Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:15:58 +0100 Subject: gpio: gpio-pca953x.c: fix checkpatch error Fix : gpio/gpio-pca953x.c:150: ERROR: else should follow close brace '}' Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 24059462c87..15dbc36340b 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -146,8 +146,7 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) ret = i2c_smbus_write_i2c_block_data(chip->client, (reg << bank_shift) | REG_ADDR_AI, NBANK(chip), val); - } - else { + } else { switch (chip->chip_type) { case PCA953X_TYPE: ret = i2c_smbus_write_word_data(chip->client, -- cgit v1.2.3 From e37f4af762125c87749cda0efb6c18199e49f0ed Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:15:59 +0100 Subject: gpio: gpio-pxa.c: fix checkpatch errors Fix : gpio/gpio-pxa.c:605: ERROR: space required after that ',' (ctx:VxV) gpio/gpio-pxa.c:672: ERROR: space prohibited after that open parenthesis '(' Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pxa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 9cc108d2b77..6d01914538e 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -602,7 +602,7 @@ static int pxa_gpio_probe(struct platform_device *pdev) for_each_gpio_chip(gpio, c) { writel_relaxed(0, c->regbase + GFER_OFFSET); writel_relaxed(0, c->regbase + GRER_OFFSET); - writel_relaxed(~0,c->regbase + GEDR_OFFSET); + writel_relaxed(~0, c->regbase + GEDR_OFFSET); /* unmask GPIO edge detect for AP side */ if (gpio_is_mmp_type(gpio_type)) writel_relaxed(~0, c->regbase + ED_MASK_OFFSET); @@ -669,7 +669,7 @@ static void pxa_gpio_resume(void) for_each_gpio_chip(gpio, c) { /* restore level with set/clear */ - writel_relaxed( c->saved_gplr, c->regbase + GPSR_OFFSET); + writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET); writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET); writel_relaxed(c->saved_grer, c->regbase + GRER_OFFSET); -- cgit v1.2.3 From be41cf589b0b7613c845802878afabc7e214cb79 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:16:00 +0100 Subject: gpio: gpio-sch.c: fix checkpatch error Fix : gpio/gpio-sch.c:206: ERROR: switch and case should be at the same indent Also remove blank lines Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch.c | 74 +++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 7e7b52be6e2..1e4de16ceb4 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -221,45 +221,41 @@ static int sch_gpio_probe(struct platform_device *pdev) gpio_ba = res->start; switch (id) { - case PCI_DEVICE_ID_INTEL_SCH_LPC: - sch_gpio_core.base = 0; - sch_gpio_core.ngpio = 10; - - sch_gpio_resume.base = 10; - sch_gpio_resume.ngpio = 4; - - /* - * GPIO[6:0] enabled by default - * GPIO7 is configured by the CMC as SLPIOVR - * Enable GPIO[9:8] core powered gpios explicitly - */ - outb(0x3, gpio_ba + CGEN + 1); - /* - * SUS_GPIO[2:0] enabled by default - * Enable SUS_GPIO3 resume powered gpio explicitly - */ - outb(0x8, gpio_ba + RGEN); - break; - - case PCI_DEVICE_ID_INTEL_ITC_LPC: - sch_gpio_core.base = 0; - sch_gpio_core.ngpio = 5; - - sch_gpio_resume.base = 5; - sch_gpio_resume.ngpio = 9; - break; - - case PCI_DEVICE_ID_INTEL_CENTERTON_ILB: - sch_gpio_core.base = 0; - sch_gpio_core.ngpio = 21; - - sch_gpio_resume.base = 21; - sch_gpio_resume.ngpio = 9; - break; - - default: - err = -ENODEV; - goto err_sch_gpio_core; + case PCI_DEVICE_ID_INTEL_SCH_LPC: + sch_gpio_core.base = 0; + sch_gpio_core.ngpio = 10; + sch_gpio_resume.base = 10; + sch_gpio_resume.ngpio = 4; + /* + * GPIO[6:0] enabled by default + * GPIO7 is configured by the CMC as SLPIOVR + * Enable GPIO[9:8] core powered gpios explicitly + */ + outb(0x3, gpio_ba + CGEN + 1); + /* + * SUS_GPIO[2:0] enabled by default + * Enable SUS_GPIO3 resume powered gpio explicitly + */ + outb(0x8, gpio_ba + RGEN); + break; + + case PCI_DEVICE_ID_INTEL_ITC_LPC: + sch_gpio_core.base = 0; + sch_gpio_core.ngpio = 5; + sch_gpio_resume.base = 5; + sch_gpio_resume.ngpio = 9; + break; + + case PCI_DEVICE_ID_INTEL_CENTERTON_ILB: + sch_gpio_core.base = 0; + sch_gpio_core.ngpio = 21; + sch_gpio_resume.base = 21; + sch_gpio_resume.ngpio = 9; + break; + + default: + err = -ENODEV; + goto err_sch_gpio_core; } sch_gpio_core.dev = &pdev->dev; -- cgit v1.2.3 From 8ab2a6d20ec65e9607254f718bd295dd3361d6c3 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:16:01 +0100 Subject: gpio: gpio-stp-xway.c: fix checkpatch error Fix : gpio/gpio-stp-xway.c:220: ERROR: trailing whitespace Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpio-stp-xway.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index c20e0515121..04882a911b6 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -217,7 +217,7 @@ static int xway_stp_probe(struct platform_device *pdev) chip->virt = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(chip->virt)) return PTR_ERR(chip->virt); - + chip->gc.dev = &pdev->dev; chip->gc.label = "stp-xway"; chip->gc.direction_output = xway_stp_dir_out; -- cgit v1.2.3 From e90c636be6afbbd46779d180594bda60bc01a821 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:16:02 +0100 Subject: gpio: gpio-tc3589x.c: fix checkpatch errors Fix : gpio/gpio-tc3589x.c:285: ERROR: code indent should use tabs where possible gpio/gpio-tc3589x.c:286: ERROR: code indent should use tabs where possible gpio/gpio-tc3589x.c:287: ERROR: code indent should use tabs where possible gpio/gpio-tc3589x.c:347: ERROR: code indent should use tabs where possible Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tc3589x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index c0595bbf326..d34d80dfb08 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -282,9 +282,9 @@ static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) } static struct irq_domain_ops tc3589x_irq_ops = { - .map = tc3589x_gpio_irq_map, - .unmap = tc3589x_gpio_irq_unmap, - .xlate = irq_domain_xlate_twocell, + .map = tc3589x_gpio_irq_map, + .unmap = tc3589x_gpio_irq_unmap, + .xlate = irq_domain_xlate_twocell, }; static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, @@ -344,7 +344,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) tc3589x_gpio->chip.base = (pdata) ? pdata->gpio_base : -1; #ifdef CONFIG_OF_GPIO - tc3589x_gpio->chip.of_node = np; + tc3589x_gpio->chip.of_node = np; #endif tc3589x_gpio->irq_base = tc3589x->irq_base ? -- cgit v1.2.3 From 8a29a409671f82a21a56aeb42835f99795d0deb3 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:16:03 +0100 Subject: gpio: gpio-timberdale.c: fix checkpatch error Fix : gpio/gpio-timberdale.c:171: ERROR: else should follow close brace '}' Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpio-timberdale.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 702cca9284f..43774058b69 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -167,8 +167,7 @@ static int timbgpio_irq_type(struct irq_data *d, unsigned trigger) if (ver < 3) { ret = -EINVAL; goto out; - } - else { + } else { flr |= 1 << offset; bflr |= 1 << offset; } -- cgit v1.2.3 From 195c65e83ccc0094bc4143176a1b21de2ba9237b Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 20 Mar 2013 13:16:04 +0100 Subject: gpio: gpio-tps65910.c: fix checkpatch error Fix : gpio/gpio-tps65910.c:136: ERROR: space required before the open parenthesis '(' Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tps65910.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 5083825a034..06146219d9d 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -133,7 +133,7 @@ static int tps65910_gpio_probe(struct platform_device *pdev) tps65910_gpio->gpio_chip.owner = THIS_MODULE; tps65910_gpio->gpio_chip.label = tps65910->i2c_client->name; - switch(tps65910_chip_id(tps65910)) { + switch (tps65910_chip_id(tps65910)) { case TPS65910: tps65910_gpio->gpio_chip.ngpio = TPS65910_NUM_GPIO; break; -- cgit v1.2.3 From 047b93a35961f7a6561e6f5dcb040738f822b892 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 22 Mar 2013 13:10:09 +0100 Subject: MAX7301 GPIO: Do not force SPI speed when using OF Platform The bit_per_word can be set in the OF Device tree, so no need to force it as with the platform_data when using OF Platform Signed-off-by: Patrick Vasseur Signed-off-by: Christophe Leroy Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max7301.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index 6e1c984a75d..3b16ab70163 100644 --- a/drivers/gpio/gpio-max7301.c +++ b/drivers/gpio/gpio-max7301.c @@ -56,7 +56,8 @@ static int max7301_probe(struct spi_device *spi) int ret; /* bits_per_word cannot be configured in platform data */ - spi->bits_per_word = 16; + if (spi->dev.platform_data) + spi->bits_per_word = 16; ret = spi_setup(spi); if (ret < 0) return ret; -- cgit v1.2.3 From a4ba5e1b92b69b9c7a15529657bb1cebed4539f3 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Sun, 24 Mar 2013 15:45:29 +0100 Subject: gpio: mvebu: add dbg_show function This patch adds a dedicated dbg_show function to the gpio-mvebu driver. In addition to the generic gpiolib informations, this function displays informations related with the specific Marvell registers (blink enable, data in polarity, interrupt masks and cause). Signed-off-by: Simon Guinot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 474823e403f..f7db3b33634 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -469,6 +469,64 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } } +#ifdef CONFIG_DEBUG_FS +#include + +static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct mvebu_gpio_chip *mvchip = + container_of(chip, struct mvebu_gpio_chip, chip); + u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk; + int i; + + out = readl_relaxed(mvebu_gpioreg_out(mvchip)); + io_conf = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)); + blink = readl_relaxed(mvebu_gpioreg_blink(mvchip)); + in_pol = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); + data_in = readl_relaxed(mvebu_gpioreg_data_in(mvchip)); + cause = readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)); + edg_msk = readl_relaxed(mvebu_gpioreg_edge_mask(mvchip)); + lvl_msk = readl_relaxed(mvebu_gpioreg_level_mask(mvchip)); + + for (i = 0; i < chip->ngpio; i++) { + const char *label; + u32 msk; + bool is_out; + + label = gpiochip_is_requested(chip, i); + if (!label) + continue; + + msk = 1 << i; + is_out = !(io_conf & msk); + + seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label); + + if (is_out) { + seq_printf(s, " out %s %s\n", + out & msk ? "hi" : "lo", + blink & msk ? "(blink )" : ""); + continue; + } + + seq_printf(s, " in %s (act %s) - IRQ", + (data_in ^ in_pol) & msk ? "hi" : "lo", + in_pol & msk ? "lo" : "hi"); + if (!((edg_msk | lvl_msk) & msk)) { + seq_printf(s, " disabled\n"); + continue; + } + if (edg_msk & msk) + seq_printf(s, " edge "); + if (lvl_msk & msk) + seq_printf(s, " level"); + seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear "); + } +} +#else +#define mvebu_gpio_dbg_show NULL +#endif + static struct of_device_id mvebu_gpio_of_match[] = { { .compatible = "marvell,orion-gpio", @@ -543,6 +601,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.ngpio = ngpios; mvchip->chip.can_sleep = 0; mvchip->chip.of_node = np; + mvchip->chip.dbg_show = mvebu_gpio_dbg_show; spin_lock_init(&mvchip->lock); mvchip->membase = devm_ioremap_resource(&pdev->dev, res); -- cgit v1.2.3 From 43158441934fd9f1d2a2434c9eec1b682391a49b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 16 Mar 2013 12:21:12 +0800 Subject: gpio: samsung: Add terminating entry for exynos_pinctrl_ids The of_device_id table is supposed to be zero-terminated. Signed-off-by: Axel Lin Acked-by: Grant Likely Acked-by: Kukjin Kim Signed-off-by: Linus Walleij --- drivers/gpio/gpio-samsung.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index b3643ff007e..c4b51d82041 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -3025,6 +3025,7 @@ static __init int samsung_gpiolib_init(void) { .compatible = "samsung,exynos4210-pinctrl", }, { .compatible = "samsung,exynos4x12-pinctrl", }, { .compatible = "samsung,exynos5440-pinctrl", }, + { } }; for_each_matching_node(pctrl_np, exynos_pinctrl_ids) if (pctrl_np && of_device_is_available(pctrl_np)) -- cgit v1.2.3 From 2b78f1e1389aef263071b9edf41c0980b092e601 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Fri, 15 Mar 2013 14:45:38 +0100 Subject: gpio: gpio-generic: Add 16 and 32 bit big endian byte order support There is no general support for 64-bit big endian accesses, so that is left unsupported. Signed-off-by: Andreas Larsson Acked-by: Anton Vorontsov Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 56 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 05fcc0f247c..42d470632ae 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -104,6 +104,26 @@ static unsigned long bgpio_read64(void __iomem *reg) } #endif /* BITS_PER_LONG >= 64 */ +static void bgpio_write16be(void __iomem *reg, unsigned long data) +{ + iowrite16be(data, reg); +} + +static unsigned long bgpio_read16be(void __iomem *reg) +{ + return ioread16be(reg); +} + +static void bgpio_write32be(void __iomem *reg, unsigned long data) +{ + iowrite32be(data, reg); +} + +static unsigned long bgpio_read32be(void __iomem *reg) +{ + return ioread32be(reg); +} + static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin) { return 1 << pin; @@ -249,7 +269,8 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) static int bgpio_setup_accessors(struct device *dev, struct bgpio_chip *bgc, - bool be) + bool bit_be, + bool byte_be) { switch (bgc->bits) { @@ -258,17 +279,33 @@ static int bgpio_setup_accessors(struct device *dev, bgc->write_reg = bgpio_write8; break; case 16: - bgc->read_reg = bgpio_read16; - bgc->write_reg = bgpio_write16; + if (byte_be) { + bgc->read_reg = bgpio_read16be; + bgc->write_reg = bgpio_write16be; + } else { + bgc->read_reg = bgpio_read16; + bgc->write_reg = bgpio_write16; + } break; case 32: - bgc->read_reg = bgpio_read32; - bgc->write_reg = bgpio_write32; + if (byte_be) { + bgc->read_reg = bgpio_read32be; + bgc->write_reg = bgpio_write32be; + } else { + bgc->read_reg = bgpio_read32; + bgc->write_reg = bgpio_write32; + } break; #if BITS_PER_LONG >= 64 case 64: - bgc->read_reg = bgpio_read64; - bgc->write_reg = bgpio_write64; + if (byte_be) { + dev_err(dev, + "64 bit big endian byte order unsupported\n"); + return -EINVAL; + } else { + bgc->read_reg = bgpio_read64; + bgc->write_reg = bgpio_write64; + } break; #endif /* BITS_PER_LONG >= 64 */ default: @@ -276,7 +313,7 @@ static int bgpio_setup_accessors(struct device *dev, return -EINVAL; } - bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask; + bgc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask; return 0; } @@ -385,7 +422,8 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, if (ret) return ret; - ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN); + ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN, + flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER); if (ret) return ret; -- cgit v1.2.3 From 879fe32438be9ff1ea2cf44e39e11b58206a76b2 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 4 Apr 2013 15:16:12 -0500 Subject: gpio/omap: free irq domain in probe() failure paths Currently the IRQ domain is not freed once allocated, in the case where omap_gpio_probe() fails. Therefore, ensure we free the domain if the probe does fail. Furthermore, the local variable "ret" is not needed and so remove this. Signed-off-by: Jon Hunter Acked-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 352f9949c05..0de2e0d71b9 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1094,7 +1094,6 @@ static int omap_gpio_probe(struct platform_device *pdev) const struct omap_gpio_platform_data *pdata; struct resource *res; struct gpio_bank *bank; - int ret = 0; match = of_match_device(of_match_ptr(omap_gpio_match), dev); @@ -1143,18 +1142,21 @@ static int omap_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!res)) { dev_err(dev, "Invalid mem resource\n"); + irq_domain_remove(bank->domain); return -ENODEV; } if (!devm_request_mem_region(dev, res->start, resource_size(res), pdev->name)) { dev_err(dev, "Region already claimed\n"); + irq_domain_remove(bank->domain); return -EBUSY; } bank->base = devm_ioremap(dev, res->start, resource_size(res)); if (!bank->base) { dev_err(dev, "Could not ioremap\n"); + irq_domain_remove(bank->domain); return -ENOMEM; } @@ -1178,7 +1180,7 @@ static int omap_gpio_probe(struct platform_device *pdev) list_add_tail(&bank->node, &omap_gpio_list); - return ret; + return 0; } #ifdef CONFIG_ARCH_OMAP2PLUS -- cgit v1.2.3 From 60b18b9aa4daa616a8b360feb35d1bfe4d606019 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Thu, 4 Apr 2013 15:16:13 -0500 Subject: gpio/omap: remove extra context restores in *_runtime_resume() 68942edb09f69b6e09522d1d346665eb3aadde49 (gpio/omap: fix wakeups on level-triggered GPIOs) already restores the fallingdetect and risingdetect contexts in *_runtime_resume(). These registers were modified in *_runtime_suspend() to include even those configured as level-triggered since only edge-triggered gpios can generate wakeup events. Therefore, the old context restores of the same registers present later in the code is not needed any more. Remove them. Signed-off-by: Tarun Kanti DebBarma Signed-off-by: Jon Hunter Acked-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0de2e0d71b9..405ce6fd2e5 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1292,10 +1292,6 @@ static int omap_gpio_runtime_resume(struct device *dev) return 0; } - __raw_writel(bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - __raw_writel(bank->context.risingdetect, - bank->base + bank->regs->risingdetect); l = __raw_readl(bank->base + bank->regs->datain); /* -- cgit v1.2.3 From 3513cdeccc647d41c4a9ff923af17deaaac04a66 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 4 Apr 2013 15:16:14 -0500 Subject: gpio/omap: optimise interrupt service routine The OMAP GPIO interrupt service routine is checking each bit in the GPIO interrupt status register to see which bits are set. It is not efficient to check every bit especially if only a few bits are set. Therefore, instead of checking every bit use the __ffs() function, which returns the location of the first set bit, to find all the set bits. This optimisation was suggested-by and developed in collaboration with Felipe Balbi. Signed-off-by: Jon Hunter Reviewed-by: Felipe Balbi Acked-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 405ce6fd2e5..f46b600e5e5 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -689,7 +689,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { void __iomem *isr_reg = NULL; u32 isr; - unsigned int i; + unsigned int bit; struct gpio_bank *bank; int unmasked = 0; struct irq_chip *chip = irq_desc_get_chip(desc); @@ -730,9 +730,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (!isr) break; - for (i = 0; isr != 0; isr >>= 1, i++) { - if (!(isr & 1)) - continue; + while (isr) { + bit = __ffs(isr); + isr &= ~(1 << bit); /* * Some chips can't respond to both rising and falling @@ -741,10 +741,10 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) * to respond to the IRQ for the opposite direction. * This will be indicated in the bank toggle_mask. */ - if (bank->toggle_mask & (1 << i)) - _toggle_gpio_edge_triggering(bank, i); + if (bank->toggle_mask & (1 << bit)) + _toggle_gpio_edge_triggering(bank, bit); - generic_handle_irq(irq_find_mapping(bank->domain, i)); + generic_handle_irq(irq_find_mapping(bank->domain, bit)); } } /* if bank has any level sensitive GPIO pin interrupt -- cgit v1.2.3 From a2797beadfcb5a0974a30929b613b4d1adb023d1 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 4 Apr 2013 15:16:15 -0500 Subject: gpio/omap: force restore if context loss is not detectable When booting with device-tree the function pointer for detecting context loss is not populated. Ideally, the pm_runtime framework should be enhanced to allow a means for reporting context/state loss and we could avoid populating such function pointers altogether. In the interim until a generic non-device specific solution is in place, force a restore of the gpio bank when enabling the gpio controller. Adds a new device-tree property for the OMAP GPIO controller to indicate if the GPIO controller is located in a power-domain that never loses power and hence will always maintain its logic state. Signed-off-by: Jon Hunter Acked-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f46b600e5e5..bb1e54f168b 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1120,11 +1120,17 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->width = pdata->bank_width; bank->is_mpuio = pdata->is_mpuio; bank->non_wakeup_gpios = pdata->non_wakeup_gpios; - bank->loses_context = pdata->loses_context; bank->regs = pdata->regs; #ifdef CONFIG_OF_GPIO bank->chip.of_node = of_node_get(node); #endif + if (node) { + if (!of_property_read_bool(node, "ti,gpio-always-on")) + bank->loses_context = true; + } else { + bank->loses_context = pdata->loses_context; + } + bank->domain = irq_domain_add_linear(node, bank->width, &irq_domain_simple_ops, NULL); @@ -1258,9 +1264,9 @@ static int omap_gpio_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct gpio_bank *bank = platform_get_drvdata(pdev); - int context_lost_cnt_after; u32 l = 0, gen, gen0, gen1; unsigned long flags; + int c; spin_lock_irqsave(&bank->lock, flags); _gpio_dbck_enable(bank); @@ -1276,14 +1282,17 @@ static int omap_gpio_runtime_resume(struct device *dev) __raw_writel(bank->context.risingdetect, bank->base + bank->regs->risingdetect); - if (bank->get_context_loss_count) { - context_lost_cnt_after = - bank->get_context_loss_count(bank->dev); - if (context_lost_cnt_after != bank->context_loss_count) { + if (bank->loses_context) { + if (!bank->get_context_loss_count) { omap_gpio_restore_context(bank); } else { - spin_unlock_irqrestore(&bank->lock, flags); - return 0; + c = bank->get_context_loss_count(bank->dev); + if (c != bank->context_loss_count) { + omap_gpio_restore_context(bank); + } else { + spin_unlock_irqrestore(&bank->lock, flags); + return 0; + } } } -- cgit v1.2.3 From 97ddb1c88b4ebe057b63346660abfee165ddd468 Mon Sep 17 00:00:00 2001 From: Lars Poeschel Date: Thu, 4 Apr 2013 12:02:02 +0200 Subject: gpio: mcp23s08: convert driver to DT This converts the mcp23s08 driver to be able to be used with device tree. There is a "spi-present-mask" device tree property, that allows to use multiple of this spi chips on the same chipselect. v4: - removed the ability to specify the pullup from device tree - updated binding doc v3: - removed mcp,chips device tree property in favour of a mcp,spi-present-mask and a flag for the pullup of every gpio - seperated the match table. Now there is one for i2c and one for spi - do the of reading stuff on stack of the probe function - no devm any more v2: - squashed booth patches together - fixed build warning, when CONFIG_OF is not defined - use of_match_ptr macro for of_match_table Signed-off-by: Lars Poeschel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mcp23s08.c | 137 +++++++++++++++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 3cea0ea79e8..6a4470b8448 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include /** * MCP types supported by driver @@ -383,6 +385,10 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, mcp->chip.direction_output = mcp23s08_direction_output; mcp->chip.set = mcp23s08_set; mcp->chip.dbg_show = mcp23s08_dbg_show; +#ifdef CONFIG_OF + mcp->chip.of_gpio_n_cells = 2; + mcp->chip.of_node = dev->of_node; +#endif switch (type) { #ifdef CONFIG_SPI_MASTER @@ -473,6 +479,35 @@ fail: /*----------------------------------------------------------------------*/ +#ifdef CONFIG_OF +#ifdef CONFIG_SPI_MASTER +static struct of_device_id mcp23s08_spi_of_match[] = { + { + .compatible = "mcp,mcp23s08", .data = (void *) MCP_TYPE_S08, + }, + { + .compatible = "mcp,mcp23s17", .data = (void *) MCP_TYPE_S17, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match); +#endif + +#if IS_ENABLED(CONFIG_I2C) +static struct of_device_id mcp23s08_i2c_of_match[] = { + { + .compatible = "mcp,mcp23008", .data = (void *) MCP_TYPE_008, + }, + { + .compatible = "mcp,mcp23017", .data = (void *) MCP_TYPE_017, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match); +#endif +#endif /* CONFIG_OF */ + + #if IS_ENABLED(CONFIG_I2C) static int mcp230xx_probe(struct i2c_client *client, @@ -480,12 +515,23 @@ static int mcp230xx_probe(struct i2c_client *client, { struct mcp23s08_platform_data *pdata; struct mcp23s08 *mcp; - int status; - - pdata = client->dev.platform_data; - if (!pdata || !gpio_is_valid(pdata->base)) { - dev_dbg(&client->dev, "invalid or missing platform data\n"); - return -EINVAL; + int status, base, pullups; + const struct of_device_id *match; + + match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match), + &client->dev); + if (match) { + base = -1; + pullups = 0; + } else { + pdata = client->dev.platform_data; + if (!pdata || !gpio_is_valid(pdata->base)) { + dev_dbg(&client->dev, + "invalid or missing platform data\n"); + return -EINVAL; + } + base = pdata->base; + pullups = pdata->chip[0].pullups; } mcp = kzalloc(sizeof *mcp, GFP_KERNEL); @@ -493,8 +539,7 @@ static int mcp230xx_probe(struct i2c_client *client, return -ENOMEM; status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr, - id->driver_data, pdata->base, - pdata->chip[0].pullups); + id->driver_data, base, pullups); if (status) goto fail; @@ -531,6 +576,7 @@ static struct i2c_driver mcp230xx_driver = { .driver = { .name = "mcp230xx", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mcp23s08_i2c_of_match), }, .probe = mcp230xx_probe, .remove = mcp230xx_remove, @@ -565,28 +611,55 @@ static int mcp23s08_probe(struct spi_device *spi) unsigned chips = 0; struct mcp23s08_driver_data *data; int status, type; - unsigned base; - - type = spi_get_device_id(spi)->driver_data; - - pdata = spi->dev.platform_data; - if (!pdata || !gpio_is_valid(pdata->base)) { - dev_dbg(&spi->dev, "invalid or missing platform data\n"); - return -EINVAL; - } + unsigned base = -1, + ngpio = 0, + pullups[ARRAY_SIZE(pdata->chip)]; + const struct of_device_id *match; + u32 spi_present_mask = 0; + + match = of_match_device(of_match_ptr(mcp23s08_spi_of_match), &spi->dev); + if (match) { + type = (int)match->data; + status = of_property_read_u32(spi->dev.of_node, + "mcp,spi-present-mask", &spi_present_mask); + if (status) { + dev_err(&spi->dev, "DT has no spi-present-mask\n"); + return -ENODEV; + } + if ((spi_present_mask <= 0) || (spi_present_mask >= 256)) { + dev_err(&spi->dev, "invalid spi-present-mask\n"); + return -ENODEV; + } - for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { - if (!pdata->chip[addr].is_present) - continue; - chips++; - if ((type == MCP_TYPE_S08) && (addr > 3)) { - dev_err(&spi->dev, - "mcp23s08 only supports address 0..3\n"); + for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) + pullups[addr] = 0; + } else { + type = spi_get_device_id(spi)->driver_data; + pdata = spi->dev.platform_data; + if (!pdata || !gpio_is_valid(pdata->base)) { + dev_dbg(&spi->dev, + "invalid or missing platform data\n"); return -EINVAL; } + + for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { + if (!pdata->chip[addr].is_present) + continue; + chips++; + if ((type == MCP_TYPE_S08) && (addr > 3)) { + dev_err(&spi->dev, + "mcp23s08 only supports address 0..3\n"); + return -EINVAL; + } + spi_present_mask |= 1 << addr; + pullups[addr] = pdata->chip[addr].pullups; + } + + if (!chips) + return -ENODEV; + + base = pdata->base; } - if (!chips) - return -ENODEV; data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08), GFP_KERNEL); @@ -594,21 +667,22 @@ static int mcp23s08_probe(struct spi_device *spi) return -ENOMEM; spi_set_drvdata(spi, data); - base = pdata->base; for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { - if (!pdata->chip[addr].is_present) + if (!(spi_present_mask & (1 << addr))) continue; chips--; data->mcp[addr] = &data->chip[chips]; status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi, 0x40 | (addr << 1), type, base, - pdata->chip[addr].pullups); + pullups[addr]); if (status < 0) goto fail; - base += (type == MCP_TYPE_S17) ? 16 : 8; + if (base != -1) + base += (type == MCP_TYPE_S17) ? 16 : 8; + ngpio += (type == MCP_TYPE_S17) ? 16 : 8; } - data->ngpio = base - pdata->base; + data->ngpio = ngpio; /* NOTE: these chips have a relatively sane IRQ framework, with * per-signal masking and level/edge triggering. It's not yet @@ -668,6 +742,7 @@ static struct spi_driver mcp23s08_driver = { .driver = { .name = "mcp23s08", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mcp23s08_spi_of_match), }, }; -- cgit v1.2.3 From fdc7a9f85ab4c19acfc21e4da6ff8b7000bb686c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 7 Apr 2013 20:28:20 +0800 Subject: gpio: lpc32xx: Fix off-by-one valid range checking for bank The valid bank should be 0 ... ARRAY_SIZE(lpc32xx_gpiochip) - 1. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-lpc32xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 36d7dee07b2..dda6a756a3d 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -533,7 +533,7 @@ static int lpc32xx_of_xlate(struct gpio_chip *gc, { /* Is this the correct bank? */ u32 bank = gpiospec->args[0]; - if ((bank > ARRAY_SIZE(lpc32xx_gpiochip) || + if ((bank >= ARRAY_SIZE(lpc32xx_gpiochip) || (gc != &lpc32xx_gpiochip[bank].chip))) return -EINVAL; -- cgit v1.2.3 From 7fc7acb9a0b0ff3ffdf21818fe0735ebaf4fecb8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 9 Apr 2013 15:57:25 +0200 Subject: gpio / ACPI: Handle ACPI events in accordance with the spec Commit 0d1c28a (gpiolib-acpi: Add ACPI5 event model support to gpio.) that added support for ACPI events signalled through GPIO interrupts covered only GPIO pins whose numbers are less than or equal to 255. However, there may be GPIO pins with numbers greater than 255 and the ACPI spec (ACPI 5.0, Section 5.6.5.1) requires the _EVT method to be used for handling events corresponding to those pins. Moreover, according to the spec, _EVT is the default mechanism for handling all ACPI events signalled through GPIO interrupts, so if the _Exx/_Lxx method is not present for the given pin, _EVT should be used instead. If present, though, _Exx/_Lxx take precedence over _EVT which shouldn't be executed in that case (ACPI 5.0, Section 5.6.5.3). Modify acpi_gpiochip_request_interrupts() to follow the spec as described above and add acpi_gpiochip_free_interrupts() needed to free interrupts associated with _EVT. Signed-off-by: Rafael J. Wysocki Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 140 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 120 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index a063eb04b6c..89336c4f82c 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -17,6 +17,13 @@ #include #include +struct acpi_gpio_evt_pin { + struct list_head node; + acpi_handle *evt_handle; + unsigned int pin; + unsigned int irq; +}; + static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) { if (!gc->dev) @@ -54,7 +61,6 @@ int acpi_get_gpio(char *path, int pin) } EXPORT_SYMBOL_GPL(acpi_get_gpio); - static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) { acpi_handle handle = data; @@ -64,6 +70,27 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) +{ + struct acpi_gpio_evt_pin *evt_pin = data; + struct acpi_object_list args; + union acpi_object arg; + + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = evt_pin->pin; + args.count = 1; + args.pointer = &arg; + + acpi_evaluate_object(evt_pin->evt_handle, NULL, &args, NULL); + + return IRQ_HANDLED; +} + +static void acpi_gpio_evt_dh(acpi_handle handle, void *data) +{ + /* The address of this function is used as a key. */ +} + /** * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events * @chip: gpio chip @@ -73,15 +100,13 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which * gpio pins have acpi event methods and assigns interrupt handlers that calls * the acpi event methods for those pins. - * - * Interrupts are automatically freed on driver detach */ - void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_resource *res; - acpi_handle handle, ev_handle; + acpi_handle handle, evt_handle; + struct list_head *evt_pins = NULL; acpi_status status; unsigned int pin; int irq, ret; @@ -98,13 +123,30 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) if (ACPI_FAILURE(status)) return; - /* If a gpio interrupt has an acpi event handler method, then - * set up an interrupt handler that calls the acpi event handler - */ + status = acpi_get_handle(handle, "_EVT", &evt_handle); + if (ACPI_SUCCESS(status)) { + evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL); + if (evt_pins) { + INIT_LIST_HEAD(evt_pins); + status = acpi_attach_data(handle, acpi_gpio_evt_dh, + evt_pins); + if (ACPI_FAILURE(status)) { + kfree(evt_pins); + evt_pins = NULL; + } + } + } + /* + * If a GPIO interrupt has an ACPI event handler method, or _EVT is + * present, set up an interrupt handler that calls the ACPI event + * handler. + */ for (res = buf.pointer; res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); res = ACPI_NEXT_RESOURCE(res)) { + irq_handler_t handler = NULL; + void *data; if (res->type != ACPI_RESOURCE_TYPE_GPIO || res->data.gpio.connection_type != @@ -115,23 +157,42 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) if (pin > chip->ngpio) continue; - sprintf(ev_name, "_%c%02X", - res->data.gpio.triggering ? 'E' : 'L', pin); - - status = acpi_get_handle(handle, ev_name, &ev_handle); - if (ACPI_FAILURE(status)) - continue; - irq = chip->to_irq(chip, pin); if (irq < 0) continue; + if (pin <= 255) { + acpi_handle ev_handle; + + sprintf(ev_name, "_%c%02X", + res->data.gpio.triggering ? 'E' : 'L', pin); + status = acpi_get_handle(handle, ev_name, &ev_handle); + if (ACPI_SUCCESS(status)) { + handler = acpi_gpio_irq_handler; + data = ev_handle; + } + } + if (!handler && evt_pins) { + struct acpi_gpio_evt_pin *evt_pin; + + evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL); + if (!evt_pin) + continue; + + list_add_tail(&evt_pin->node, evt_pins); + evt_pin->evt_handle = evt_handle; + evt_pin->pin = pin; + evt_pin->irq = irq; + handler = acpi_gpio_irq_handler_evt; + data = evt_pin; + } + if (!handler) + continue; + /* Assume BIOS sets the triggering, so no flags */ - ret = devm_request_threaded_irq(chip->dev, irq, NULL, - acpi_gpio_irq_handler, - 0, - "GPIO-signaled-ACPI-event", - ev_handle); + ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, + 0, "GPIO-signaled-ACPI-event", + data); if (ret) dev_err(chip->dev, "Failed to request IRQ %d ACPI event handler\n", @@ -139,3 +200,42 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) } } EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); + + +/** + * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. + * @chip: gpio chip + * + * Free interrupts associated with the _EVT method for the given GPIO chip. + * + * The remaining ACPI event interrupts associated with the chip are freed + * automatically. + */ +void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) +{ + acpi_handle handle; + acpi_status status; + struct list_head *evt_pins; + struct acpi_gpio_evt_pin *evt_pin, *ep; + + if (!chip->dev || !chip->to_irq) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); + if (ACPI_FAILURE(status)) + return; + + list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { + devm_free_irq(chip->dev, evt_pin->irq, evt_pin); + list_del(&evt_pin->node); + kfree(evt_pin); + } + + acpi_detach_data(handle, acpi_gpio_evt_dh); + kfree(evt_pins); +} +EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); -- cgit v1.2.3 From 2ce7c62d1b18dca13c715c6bc2eea17f723576ff Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 11 Apr 2013 21:23:22 +0400 Subject: GPIO: gpio-generic: remove kfree() from bgpio_remove call Memory for basic-mmio-gpio driver is allocated by the driver using it, whether it's the generic GPIO driver itself or another driver. In either case, the owner shall allocate and free the struct bgpio_chip it is using, preferably using a managed resource. Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 42d470632ae..d2196bf7384 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -390,11 +390,7 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, int bgpio_remove(struct bgpio_chip *bgc) { - int err = gpiochip_remove(&bgc->gc); - - kfree(bgc); - - return err; + return gpiochip_remove(&bgc->gc); } EXPORT_SYMBOL_GPL(bgpio_remove); -- cgit v1.2.3 From 12028d2d216220618f76284af5f8ed510b11da55 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 3 Apr 2013 13:56:54 +0300 Subject: gpiolib-acpi: introduce acpi_get_gpio_by_index() helper Instead of open-coding ACPI GPIO resource lookup in each driver, we provide a helper function analogous to Device Tree version that allows drivers to specify which GPIO resource they are interested (using an index to the GPIO resources). The function then finds out the correct resource, translates the ACPI GPIO number to the corresponding Linux GPIO number and returns that. Signed-off-by: Mika Westerberg Acked-by: Rafael J. Wysocki Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 77 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 89336c4f82c..5c1ef2b3ef1 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -201,6 +201,83 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) } EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); +struct acpi_gpio_lookup { + struct acpi_gpio_info info; + int index; + int gpio; + int n; +}; + +static int acpi_find_gpio(struct acpi_resource *ares, void *data) +{ + struct acpi_gpio_lookup *lookup = data; + + if (ares->type != ACPI_RESOURCE_TYPE_GPIO) + return 1; + + if (lookup->n++ == lookup->index && lookup->gpio < 0) { + const struct acpi_resource_gpio *agpio = &ares->data.gpio; + + lookup->gpio = acpi_get_gpio(agpio->resource_source.string_ptr, + agpio->pin_table[0]); + lookup->info.gpioint = + agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; + } + + return 1; +} + +/** + * acpi_get_gpio_by_index() - get a GPIO number from device resources + * @dev: pointer to a device to get GPIO from + * @index: index of GpioIo/GpioInt resource (starting from %0) + * @info: info pointer to fill in (optional) + * + * Function goes through ACPI resources for @dev and based on @index looks + * up a GpioIo/GpioInt resource, translates it to the Linux GPIO number, + * and returns it. @index matches GpioIo/GpioInt resources only so if there + * are total %3 GPIO resources, the index goes from %0 to %2. + * + * If the GPIO cannot be translated or there is an error, negative errno is + * returned. + * + * Note: if the GPIO resource has multiple entries in the pin list, this + * function only returns the first. + */ +int acpi_get_gpio_by_index(struct device *dev, int index, + struct acpi_gpio_info *info) +{ + struct acpi_gpio_lookup lookup; + struct list_head resource_list; + struct acpi_device *adev; + acpi_handle handle; + int ret; + + if (!dev) + return -EINVAL; + + handle = ACPI_HANDLE(dev); + if (!handle || acpi_bus_get_device(handle, &adev)) + return -ENODEV; + + memset(&lookup, 0, sizeof(lookup)); + lookup.index = index; + lookup.gpio = -ENODEV; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, + &lookup); + if (ret < 0) + return ret; + + acpi_dev_free_resource_list(&resource_list); + + if (lookup.gpio >= 0 && info) + *info = lookup.info; + + return lookup.gpio; +} +EXPORT_SYMBOL_GPL(acpi_get_gpio_by_index); /** * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. -- cgit v1.2.3 From ddb27f3bf771b53e0e7aa93d0186ea5c03381e23 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Wed, 17 Apr 2013 14:36:50 +0200 Subject: gpio: grgpio: Add device driver for GRGPIO cores This driver supports GRGPIO gpio cores available in the GRLIB VHDL IP core library from Aeroflex Gaisler. Signed-off-by: Andreas Larsson Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 9 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-grgpio.c | 149 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 drivers/gpio/gpio-grgpio.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 704d01d6752..345c6672709 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -309,6 +309,15 @@ config GPIO_LYNXPOINT driver for GPIO functionality on Intel Lynxpoint PCH chipset Requires ACPI device enumeration code to set up a platform device. +config GPIO_GRGPIO + tristate "Aeroflex Gaisler GRGPIO support" + depends on OF + select GPIO_GENERIC + select IRQ_DOMAIN + help + Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB + VHDL IP core library. + comment "I2C GPIO expanders:" config GPIO_ARIZONA diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 22e07bc9fcb..3e6be513412 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o +obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c new file mode 100644 index 00000000000..466a1c757fa --- /dev/null +++ b/drivers/gpio/gpio-grgpio.c @@ -0,0 +1,149 @@ +/* + * Driver for Aeroflex Gaisler GRGPIO General Purpose I/O cores. + * + * 2013 (c) Aeroflex Gaisler AB + * + * This driver supports the GRGPIO GPIO core available in the GRLIB VHDL + * IP core library. + * + * Full documentation of the GRGPIO core can be found here: + * http://www.gaisler.com/products/grlib/grip.pdf + * + * See "Documentation/devicetree/bindings/gpio/gpio-grgpio.txt" for + * information on open firmware properties. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Contributors: Andreas Larsson + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GRGPIO_MAX_NGPIO 32 + +#define GRGPIO_DATA 0x00 +#define GRGPIO_OUTPUT 0x04 +#define GRGPIO_DIR 0x08 +#define GRGPIO_IMASK 0x0c +#define GRGPIO_IPOL 0x10 +#define GRGPIO_IEDGE 0x14 +#define GRGPIO_BYPASS 0x18 +#define GRGPIO_IMAP_BASE 0x20 + +struct grgpio_priv { + struct bgpio_chip bgc; + void __iomem *regs; + struct device *dev; +}; + +static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return container_of(bgc, struct grgpio_priv, bgc); +} + +static int grgpio_probe(struct platform_device *ofdev) +{ + struct device_node *np = ofdev->dev.of_node; + void __iomem *regs; + struct gpio_chip *gc; + struct bgpio_chip *bgc; + struct grgpio_priv *priv; + struct resource *res; + int err; + u32 prop; + + priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&ofdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + bgc = &priv->bgc; + err = bgpio_init(bgc, &ofdev->dev, 4, regs + GRGPIO_DATA, + regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL, + BGPIOF_BIG_ENDIAN_BYTE_ORDER); + if (err) { + dev_err(&ofdev->dev, "bgpio_init() failed\n"); + return err; + } + + priv->regs = regs; + priv->dev = &ofdev->dev; + + gc = &bgc->gc; + gc->of_node = np; + gc->owner = THIS_MODULE; + gc->label = np->full_name; + gc->base = -1; + + err = of_property_read_u32(np, "nbits", &prop); + if (err || prop <= 0 || prop > GRGPIO_MAX_NGPIO) { + gc->ngpio = GRGPIO_MAX_NGPIO; + dev_dbg(&ofdev->dev, + "No or invalid nbits property: assume %d\n", gc->ngpio); + } else { + gc->ngpio = prop; + } + + platform_set_drvdata(ofdev, priv); + + err = gpiochip_add(gc); + if (err) { + dev_err(&ofdev->dev, "Could not add gpiochip\n"); + return err; + } + + dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d\n", + priv->regs, gc->base, gc->ngpio); + + return 0; +} + +static int grgpio_remove(struct platform_device *ofdev) +{ + struct grgpio_priv *priv = platform_get_drvdata(ofdev); + + return gpiochip_remove(&priv->bgc.gc); +} + +static struct of_device_id grgpio_match[] = { + {.name = "GAISLER_GPIO"}, + {.name = "01_01a"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, grgpio_match); + +static struct platform_driver grgpio_driver = { + .driver = { + .name = "grgpio", + .owner = THIS_MODULE, + .of_match_table = grgpio_match, + }, + .probe = grgpio_probe, + .remove = grgpio_remove, +}; +module_platform_driver(grgpio_driver); + +MODULE_AUTHOR("Aeroflex Gaisler AB."); +MODULE_DESCRIPTION("Driver for Aeroflex Gaisler GRGPIO"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 08ffb2229fafc2c3a696b325a74bf4198d6b91d7 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Wed, 17 Apr 2013 14:36:51 +0200 Subject: gpio: grgpio: Add irq support The drivers sets up an irq domain and hands out unique irqs to irq capable gpio lines regardless of how underlying irq maps to gpio lines. Any gpio line can map to any one or none of the irqs of the core, independently of each other. Signed-off-by: Andreas Larsson Signed-off-by: Linus Walleij --- drivers/gpio/gpio-grgpio.c | 362 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 359 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 466a1c757fa..8e08b864765 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include #define GRGPIO_MAX_NGPIO 32 @@ -44,10 +47,49 @@ #define GRGPIO_BYPASS 0x18 #define GRGPIO_IMAP_BASE 0x20 +/* Structure for an irq of the core - called an underlying irq */ +struct grgpio_uirq { + u8 refcnt; /* Reference counter to manage requesting/freeing of uirq */ + u8 uirq; /* Underlying irq of the gpio driver */ +}; + +/* + * Structure for an irq of a gpio line handed out by this driver. The index is + * used to map to the corresponding underlying irq. + */ +struct grgpio_lirq { + s8 index; /* Index into struct grgpio_priv's uirqs, or -1 */ + u8 irq; /* irq for the gpio line */ +}; + struct grgpio_priv { struct bgpio_chip bgc; void __iomem *regs; struct device *dev; + + u32 imask; /* irq mask shadow register */ + + /* + * The grgpio core can have multiple "underlying" irqs. The gpio lines + * can be mapped to any one or none of these underlying irqs + * independently of each other. This driver sets up an irq domain and + * hands out separate irqs to each gpio line + */ + struct irq_domain *domain; + + /* + * This array contains information on each underlying irq, each + * irq of the grgpio core itself. + */ + struct grgpio_uirq uirqs[GRGPIO_MAX_NGPIO]; + + /* + * This array contains information for each gpio line on the irqs + * obtains from this driver. An index value of -1 for a certain gpio + * line indicates that the line has no irq. Otherwise the index connects + * the irq to the underlying irq by pointing into the uirqs array. + */ + struct grgpio_lirq lirqs[GRGPIO_MAX_NGPIO]; }; static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc) @@ -57,6 +99,246 @@ static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc) return container_of(bgc, struct grgpio_priv, bgc); } +static void grgpio_set_imask(struct grgpio_priv *priv, unsigned int offset, + int val) +{ + struct bgpio_chip *bgc = &priv->bgc; + unsigned long mask = bgc->pin2mask(bgc, offset); + unsigned long flags; + + spin_lock_irqsave(&bgc->lock, flags); + + if (val) + priv->imask |= mask; + else + priv->imask &= ~mask; + bgc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask); + + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct grgpio_priv *priv = grgpio_gc_to_priv(gc); + + if (offset > gc->ngpio) + return -ENXIO; + + if (priv->lirqs[offset].index < 0) + return -ENXIO; + + return irq_create_mapping(priv->domain, offset); +} + +/* -------------------- IRQ chip functions -------------------- */ + +static int grgpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct grgpio_priv *priv = irq_data_get_irq_chip_data(d); + unsigned long flags; + u32 mask = BIT(d->hwirq); + u32 ipol; + u32 iedge; + u32 pol; + u32 edge; + + switch (type) { + case IRQ_TYPE_LEVEL_LOW: + pol = 0; + edge = 0; + break; + case IRQ_TYPE_LEVEL_HIGH: + pol = mask; + edge = 0; + break; + case IRQ_TYPE_EDGE_FALLING: + pol = 0; + edge = mask; + break; + case IRQ_TYPE_EDGE_RISING: + pol = mask; + edge = mask; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&priv->bgc.lock, flags); + + ipol = priv->bgc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask; + iedge = priv->bgc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask; + + priv->bgc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol); + priv->bgc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge); + + spin_unlock_irqrestore(&priv->bgc.lock, flags); + + return 0; +} + +static void grgpio_irq_mask(struct irq_data *d) +{ + struct grgpio_priv *priv = irq_data_get_irq_chip_data(d); + int offset = d->hwirq; + + grgpio_set_imask(priv, offset, 0); +} + +static void grgpio_irq_unmask(struct irq_data *d) +{ + struct grgpio_priv *priv = irq_data_get_irq_chip_data(d); + int offset = d->hwirq; + + grgpio_set_imask(priv, offset, 1); +} + +static struct irq_chip grgpio_irq_chip = { + .name = "grgpio", + .irq_mask = grgpio_irq_mask, + .irq_unmask = grgpio_irq_unmask, + .irq_set_type = grgpio_irq_set_type, +}; + +static irqreturn_t grgpio_irq_handler(int irq, void *dev) +{ + struct grgpio_priv *priv = dev; + int ngpio = priv->bgc.gc.ngpio; + unsigned long flags; + int i; + int match = 0; + + spin_lock_irqsave(&priv->bgc.lock, flags); + + /* + * For each gpio line, call its interrupt handler if it its underlying + * irq matches the current irq that is handled. + */ + for (i = 0; i < ngpio; i++) { + struct grgpio_lirq *lirq = &priv->lirqs[i]; + + if (priv->imask & BIT(i) && lirq->index >= 0 && + priv->uirqs[lirq->index].uirq == irq) { + generic_handle_irq(lirq->irq); + match = 1; + } + } + + spin_unlock_irqrestore(&priv->bgc.lock, flags); + + if (!match) + dev_warn(priv->dev, "No gpio line matched irq %d\n", irq); + + return IRQ_HANDLED; +} + +/* + * This function will be called as a consequence of the call to + * irq_create_mapping in grgpio_to_irq + */ +int grgpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct grgpio_priv *priv = d->host_data; + struct grgpio_lirq *lirq; + struct grgpio_uirq *uirq; + unsigned long flags; + int offset = hwirq; + int ret = 0; + + if (!priv) + return -EINVAL; + + lirq = &priv->lirqs[offset]; + if (lirq->index < 0) + return -EINVAL; + + dev_dbg(priv->dev, "Mapping irq %d for gpio line %d\n", + irq, offset); + + spin_lock_irqsave(&priv->bgc.lock, flags); + + /* Request underlying irq if not already requested */ + lirq->irq = irq; + uirq = &priv->uirqs[lirq->index]; + if (uirq->refcnt == 0) { + ret = request_irq(uirq->uirq, grgpio_irq_handler, 0, + dev_name(priv->dev), priv); + if (ret) { + dev_err(priv->dev, + "Could not request underlying irq %d\n", + uirq->uirq); + + spin_unlock_irqrestore(&priv->bgc.lock, flags); + + return ret; + } + } + uirq->refcnt++; + + spin_unlock_irqrestore(&priv->bgc.lock, flags); + + /* Setup irq */ + irq_set_chip_data(irq, priv); + irq_set_chip_and_handler(irq, &grgpio_irq_chip, + handle_simple_irq); + irq_clear_status_flags(irq, IRQ_NOREQUEST); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + + return ret; +} + +void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + struct grgpio_priv *priv = d->host_data; + int index; + struct grgpio_lirq *lirq; + struct grgpio_uirq *uirq; + unsigned long flags; + int ngpio = priv->bgc.gc.ngpio; + int i; + +#ifdef CONFIG_ARM + set_irq_flags(irq, 0); +#endif + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); + + spin_lock_irqsave(&priv->bgc.lock, flags); + + /* Free underlying irq if last user unmapped */ + index = -1; + for (i = 0; i < ngpio; i++) { + lirq = &priv->lirqs[i]; + if (lirq->irq == irq) { + grgpio_set_imask(priv, i, 0); + lirq->irq = 0; + index = lirq->index; + break; + } + } + WARN_ON(index < 0); + + if (index >= 0) { + uirq = &priv->uirqs[lirq->index]; + uirq->refcnt--; + if (uirq->refcnt == 0) + free_irq(uirq->uirq, priv); + } + + spin_unlock_irqrestore(&priv->bgc.lock, flags); +} + +static struct irq_domain_ops grgpio_irq_domain_ops = { + .map = grgpio_irq_map, + .unmap = grgpio_irq_unmap, +}; + +/* ------------------------------------------------------------ */ + static int grgpio_probe(struct platform_device *ofdev) { struct device_node *np = ofdev->dev.of_node; @@ -67,6 +349,9 @@ static int grgpio_probe(struct platform_device *ofdev) struct resource *res; int err; u32 prop; + s32 *irqmap; + int size; + int i; priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -87,11 +372,13 @@ static int grgpio_probe(struct platform_device *ofdev) } priv->regs = regs; + priv->imask = bgc->read_reg(regs + GRGPIO_IMASK); priv->dev = &ofdev->dev; gc = &bgc->gc; gc->of_node = np; gc->owner = THIS_MODULE; + gc->to_irq = grgpio_to_irq; gc->label = np->full_name; gc->base = -1; @@ -104,6 +391,51 @@ static int grgpio_probe(struct platform_device *ofdev) gc->ngpio = prop; } + /* + * The irqmap contains the index values indicating which underlying irq, + * if anyone, is connected to that line + */ + irqmap = (s32 *)of_get_property(np, "irqmap", &size); + if (irqmap) { + if (size < gc->ngpio) { + dev_err(&ofdev->dev, + "irqmap shorter than ngpio (%d < %d)\n", + size, gc->ngpio); + return -EINVAL; + } + + priv->domain = irq_domain_add_linear(np, gc->ngpio, + &grgpio_irq_domain_ops, + priv); + if (!priv->domain) { + dev_err(&ofdev->dev, "Could not add irq domain\n"); + return -EINVAL; + } + + for (i = 0; i < gc->ngpio; i++) { + struct grgpio_lirq *lirq; + int ret; + + lirq = &priv->lirqs[i]; + lirq->index = irqmap[i]; + + if (lirq->index < 0) + continue; + + ret = platform_get_irq(ofdev, lirq->index); + if (ret <= 0) { + /* + * Continue without irq functionality for that + * gpio line + */ + dev_err(priv->dev, + "Failed to get irq for offset %d\n", i); + continue; + } + priv->uirqs[lirq->index].uirq = ret; + } + } + platform_set_drvdata(ofdev, priv); err = gpiochip_add(gc); @@ -112,8 +444,8 @@ static int grgpio_probe(struct platform_device *ofdev) return err; } - dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d\n", - priv->regs, gc->base, gc->ngpio); + dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n", + priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off"); return 0; } @@ -121,8 +453,32 @@ static int grgpio_probe(struct platform_device *ofdev) static int grgpio_remove(struct platform_device *ofdev) { struct grgpio_priv *priv = platform_get_drvdata(ofdev); + unsigned long flags; + int i; + int ret = 0; + + spin_lock_irqsave(&priv->bgc.lock, flags); + + if (priv->domain) { + for (i = 0; i < GRGPIO_MAX_NGPIO; i++) { + if (priv->uirqs[i].refcnt != 0) { + ret = -EBUSY; + goto out; + } + } + } + + ret = gpiochip_remove(&priv->bgc.gc); + if (ret) + goto out; + + if (priv->domain) + irq_domain_remove(priv->domain); + +out: + spin_unlock_irqrestore(&priv->bgc.lock, flags); - return gpiochip_remove(&priv->bgc.gc); + return ret; } static struct of_device_id grgpio_match[] = { -- cgit v1.2.3