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 diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 414ad91..a78a81f 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 159f5c5..c3598d1 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index c3598d1..0d30c7a 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index deca78f..d053697 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index f9dbd50..3168217 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index 59d7239..095ab14 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index a19b745..a965620 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index edae963..7e7b52b 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 3168217..2829d6d 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 v0.10.2 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 diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 93aaadf..704d01d 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 3472b05..86c17de 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index d053697..5cba855 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c index 81683ca..b2d8d6f 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index 8afa95f..f33f78d 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c index 4b6b9a0..40ab6df 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index c6c535c..6e1c984 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 1e0467c..d4b51b1 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 6a8fdc2..b161489 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index a965620..e8faf53 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index b161489..3395879 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 464be96..7216079 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 3395879..63a7a1b 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 v0.10.2 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 diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index a71a54a..8940793 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 7472182..474823e 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0d30c7a..352f994 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 2405946..15dbc36 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 9cc108d..6d01914 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 7e7b52b..1e4de16 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index c20e051..04882a9 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index c0595bb..d34d80d 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 702cca9..4377405 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 5083825..0614621 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index 6e1c984..3b16ab7 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 474823e..f7db3b3 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index b3643ff..c4b51d8 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 05fcc0f..42d4706 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; diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h index 1c504ca..d8a97ec 100644 --- a/include/linux/basic_mmio_gpio.h +++ b/include/linux/basic_mmio_gpio.h @@ -72,5 +72,6 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, #define BGPIOF_BIG_ENDIAN BIT(0) #define BGPIOF_UNREADABLE_REG_SET BIT(1) /* reg_set is unreadable */ #define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */ +#define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3) #endif /* __BASIC_MMIO_GPIO_H */ -- cgit v0.10.2 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 diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 352f994..0de2e0d 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0de2e0d..405ce6f 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 405ce6f..f46b600 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 v0.10.2 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 diff --git a/Documentation/devicetree/bindings/gpio/gpio-omap.txt b/Documentation/devicetree/bindings/gpio/gpio-omap.txt index bff51a2..1b524c0 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-omap.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-omap.txt @@ -20,8 +20,11 @@ Required properties: 8 = active low level-sensitive. OMAP specific properties: -- ti,hwmods: Name of the hwmod associated to the GPIO: - "gpio", being the 1-based instance number from the HW spec +- ti,hwmods: Name of the hwmod associated to the GPIO: + "gpio", being the 1-based instance number + from the HW spec. +- ti,gpio-always-on: Indicates if a GPIO bank is always powered and + so will never lose its logic state. Example: diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f46b600..bb1e54f 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 v0.10.2 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 diff --git a/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt b/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt new file mode 100644 index 0000000..629d0ef --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt @@ -0,0 +1,47 @@ +Microchip MCP2308/MCP23S08/MCP23017/MCP23S17 driver for +8-/16-bit I/O expander with serial interface (I2C/SPI) + +Required properties: +- compatible : Should be + - "mcp,mcp23s08" for 8 GPIO SPI version + - "mcp,mcp23s17" for 16 GPIO SPI version + - "mcp,mcp23008" for 8 GPIO I2C version or + - "mcp,mcp23017" for 16 GPIO I2C version of the chip +- #gpio-cells : Should be two. + - first cell is the pin number + - second cell is used to specify flags. Flags are currently unused. +- gpio-controller : Marks the device node as a GPIO controller. +- reg : For an address on its bus. I2C uses this a the I2C address of the chip. + SPI uses this to specify the chipselect line which the chip is + connected to. The driver and the SPI variant of the chip support + multiple chips on the same chipselect. Have a look at + mcp,spi-present-mask below. + +Required device specific properties (only for SPI chips): +- mcp,spi-present-mask : This is a present flag, that makes only sense for SPI + chips - as the name suggests. Multiple SPI chips can share the same + SPI chipselect. Set a bit in bit0-7 in this mask to 1 if there is a + chip connected with the corresponding spi address set. For example if + you have a chip with address 3 connected, you have to set bit3 to 1, + which is 0x08. mcp23s08 chip variant only supports bits 0-3. It is not + possible to mix mcp23s08 and mcp23s17 on the same chipselect. Set at + least one bit to 1 for SPI chips. +- spi-max-frequency = The maximum frequency this chip is able to handle + +Example I2C: +gpiom1: gpio@20 { + compatible = "mcp,mcp23017"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; +}; + +Example SPI: +gpiom1: gpio@0 { + compatible = "mcp,mcp23s17"; + gpio-controller; + #gpio-cells = <2>; + spi-present-mask = <0x01>; + reg = <0>; + spi-max-frequency = <1000000>; +}; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 3cea0ea..6a4470b 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 v0.10.2 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 diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 36d7dee..dda6a75 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 v0.10.2 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 diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index a063eb0..89336c4 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); diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h index b76ebd0..213135f 100644 --- a/include/linux/acpi_gpio.h +++ b/include/linux/acpi_gpio.h @@ -8,6 +8,7 @@ int acpi_get_gpio(char *path, int pin); void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); +void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); #else /* CONFIG_GPIO_ACPI */ @@ -17,6 +18,7 @@ static inline int acpi_get_gpio(char *path, int pin) } static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } +static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } #endif /* CONFIG_GPIO_ACPI */ -- cgit v0.10.2 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 diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 42d4706..d2196bf 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 v0.10.2 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 diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt index 94a6561..b0d5410 100644 --- a/Documentation/acpi/enumeration.txt +++ b/Documentation/acpi/enumeration.txt @@ -199,6 +199,8 @@ the device to the driver. For example: { Name (SBUF, ResourceTemplate() { + ... + // Used to power on/off the device GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly, "\\_SB.PCI0.GPI0", 0x00, ResourceConsumer,,) @@ -206,10 +208,20 @@ the device to the driver. For example: // Pin List 0x0055 } + + // Interrupt for the device + GpioInt (Edge, ActiveHigh, ExclusiveAndWake, PullNone, + 0x0000, "\\_SB.PCI0.GPI0", 0x00, ResourceConsumer,,) + { + // Pin list + 0x0058 + } + ... - Return (SBUF) } + + Return (SBUF) } These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0" @@ -220,6 +232,24 @@ The driver can do this by including and then calling acpi_get_gpio(path, gpio). This will return the Linux GPIO number or negative errno if there was no translation found. +In a simple case of just getting the Linux GPIO number from device +resources one can use acpi_get_gpio_by_index() helper function. It takes +pointer to the device and index of the GpioIo/GpioInt descriptor in the +device resources list. For example: + + int gpio_irq, gpio_power; + int ret; + + gpio_irq = acpi_get_gpio_by_index(dev, 1, NULL); + if (gpio_irq < 0) + /* handle error */ + + gpio_power = acpi_get_gpio_by_index(dev, 0, NULL); + if (gpio_power < 0) + /* handle error */ + + /* Now we can use the GPIO numbers */ + Other GpioIo parameters must be converted first by the driver to be suitable to the gpiolib before passing them. diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 89336c4..5c1ef2b 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. diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h index 213135f..4c120a1 100644 --- a/include/linux/acpi_gpio.h +++ b/include/linux/acpi_gpio.h @@ -1,12 +1,23 @@ #ifndef _LINUX_ACPI_GPIO_H_ #define _LINUX_ACPI_GPIO_H_ +#include #include #include +/** + * struct acpi_gpio_info - ACPI GPIO specific information + * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo + */ +struct acpi_gpio_info { + bool gpioint; +}; + #ifdef CONFIG_GPIO_ACPI int acpi_get_gpio(char *path, int pin); +int acpi_get_gpio_by_index(struct device *dev, int index, + struct acpi_gpio_info *info); void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); @@ -17,6 +28,12 @@ static inline int acpi_get_gpio(char *path, int pin) return -ENODEV; } +static inline int acpi_get_gpio_by_index(struct device *dev, int index, + struct acpi_gpio_info *info) +{ + return -ENODEV; +} + static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } -- cgit v0.10.2 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 diff --git a/Documentation/devicetree/bindings/gpio/gpio-grgpio.txt b/Documentation/devicetree/bindings/gpio/gpio-grgpio.txt new file mode 100644 index 0000000..1ec46fd --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-grgpio.txt @@ -0,0 +1,21 @@ +Aeroflex Gaisler GRGPIO General Purpose I/O cores. + +The GRGPIO GPIO core is available in the GRLIB VHDL IP core library. + +Note: In the ordinary environment for the GRGPIO core, a Leon SPARC system, +these properties are built from information in the AMBA plug&play. + +Required properties: + +- name : Should be "GAISLER_GPIO" or "01_01a" + +- reg : Address and length of the register set for the device + +- interrupts : Interrupt numbers for this device + +Optional properties: + +- nbits : The number of gpio lines. If not present driver assumes 32 lines. + +For further information look in the documentation for the GLIB IP core library: +http://www.gaisler.com/products/grlib/grip.pdf diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 704d01d..345c667 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 22e07bc..3e6be51 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 0000000..466a1c7 --- /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 v0.10.2 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 diff --git a/Documentation/devicetree/bindings/gpio/gpio-grgpio.txt b/Documentation/devicetree/bindings/gpio/gpio-grgpio.txt index 1ec46fd..e466598 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-grgpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-grgpio.txt @@ -17,5 +17,10 @@ Optional properties: - nbits : The number of gpio lines. If not present driver assumes 32 lines. +- irqmap : An array with an index for each gpio line. An index is either a valid + index into the interrupts property array, or 0xffffffff that indicates + no irq for that line. Driver provides no interrupt support if not + present. + For further information look in the documentation for the GLIB IP core library: http://www.gaisler.com/products/grlib/grip.pdf diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 466a1c7..8e08b86 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 v0.10.2