diff options
Diffstat (limited to 'drivers/gpio')
30 files changed, 1164 insertions, 290 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b166e30..ff7f0c8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -297,12 +297,21 @@ 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 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 a274d7d..6aab73d 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-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) 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; } diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index deca78f..5cba855 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]; @@ -243,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; @@ -259,24 +261,45 @@ 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; + 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) { + 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 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 err0; + } + pdata->gpio_base = ret * 32; /* 32 GPIOs per instance */ } gpio_chip = &p->gpio_chip; @@ -306,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; } @@ -347,34 +362,43 @@ 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; } +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"); diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 05fcc0f..d2196bf 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; } @@ -353,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); @@ -385,7 +418,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/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c new file mode 100644 index 0000000..8e08b86 --- /dev/null +++ b/drivers/gpio/gpio-grgpio.c @@ -0,0 +1,505 @@ +/* + * 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 <andreas@gaisler.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_platform.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/basic_mmio_gpio.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> + +#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 + +/* 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) +{ + struct bgpio_chip *bgc = to_bgpio_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; + void __iomem *regs; + struct gpio_chip *gc; + struct bgpio_chip *bgc; + struct grgpio_priv *priv; + struct resource *res; + int err; + u32 prop; + s32 *irqmap; + int size; + int i; + + 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->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; + + 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; + } + + /* + * 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); + if (err) { + dev_err(&ofdev->dev, "Could not add gpiochip\n"); + return err; + } + + 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; +} + +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 ret; +} + +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"); diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index de3c317..e16d932 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -130,14 +130,11 @@ 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) { - 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 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; 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 <linux/acpi.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/io.h> /* LynxPoint chipset has support for 94 gpio pins */ 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; } diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index c6c535c..3b16ab7 100644 --- a/drivers/gpio/gpio-max7301.c +++ b/drivers/gpio/gpio-max7301.c @@ -56,12 +56,13 @@ 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; - ts = kzalloc(sizeof(struct max7301), GFP_KERNEL); + ts = devm_kzalloc(&spi->dev, sizeof(struct max7301), GFP_KERNEL); if (!ts) return -ENOMEM; @@ -70,8 +71,6 @@ static int max7301_probe(struct spi_device *spi) ts->dev = &spi->dev; ret = __max730x_probe(ts); - if (ret) - kfree(ts); return ret; } 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; } diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 6a8fdc2..63a7a1b 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -101,13 +101,13 @@ 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; mutex_init(&mc->lock); - dev_set_drvdata(&spi->dev, mc); + spi_set_drvdata(spi, mc); mc->spi = spi; @@ -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; } @@ -141,9 +142,8 @@ 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); - kfree(mc); return ret; } @@ -152,17 +152,16 @@ 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) { + if (!ret) mutex_destroy(&mc->lock); - kfree(mc); - } else + else dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n", ret); 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 <linux/spi/mcp23s08.h> #include <linux/slab.h> #include <asm/byteorder.h> +#include <linux/of.h> +#include <linux/of_device.h> /** * 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), }, }; diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 61a6fde..bf69a7e 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -117,7 +117,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; @@ -133,7 +133,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: @@ -151,7 +151,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: @@ -401,7 +401,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)); @@ -470,18 +470,76 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } } +#ifdef CONFIG_DEBUG_FS +#include <linux/seq_file.h> + +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", - .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 */ @@ -509,13 +567,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; } @@ -550,6 +608,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); @@ -560,21 +619,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); @@ -632,7 +691,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; } diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index a612ea1..2050891 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -52,7 +52,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; @@ -88,7 +87,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) @@ -420,13 +426,16 @@ 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); #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; @@ -579,7 +588,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); } @@ -679,7 +688,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 bit; struct gpio_bank *bank; int unmasked = 0; struct irq_chip *chip = irq_desc_get_chip(desc); @@ -693,7 +702,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; @@ -720,14 +729,9 @@ 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); - - if (!(isr & 1)) - continue; - - gpio_index = GPIO_INDEX(bank, gpio); + while (isr) { + bit = __ffs(isr); + isr &= ~(1 << bit); /* * Some chips can't respond to both rising and falling @@ -736,10 +740,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 << bit)) + _toggle_gpio_edge_triggering(bank, bit); - generic_handle_irq(gpio_irq); + generic_handle_irq(irq_find_mapping(bank->domain, bit)); } } /* if bank has any level sensitive GPIO pin interrupt @@ -755,7 +759,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); @@ -766,7 +770,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); } @@ -774,7 +778,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); @@ -786,7 +790,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; @@ -952,14 +956,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) @@ -1056,7 +1052,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) @@ -1071,15 +1067,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); @@ -1096,7 +1093,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); @@ -1123,20 +1119,22 @@ 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 - - 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"); - return -ENODEV; + 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_legacy(node, bank->width, bank->irq_base, - 0, &irq_domain_simple_ops, NULL); + + bank->domain = irq_domain_add_linear(node, bank->width, + &irq_domain_simple_ops, NULL); + if (!bank->domain) + return -ENODEV; if (bank->regs->set_dataout && bank->regs->clr_dataout) bank->set_dataout = _set_gpio_dataout_reg; @@ -1149,18 +1147,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; } @@ -1184,7 +1185,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 @@ -1262,9 +1263,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); @@ -1280,14 +1281,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; + } } } @@ -1296,10 +1300,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); /* diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 9391cf1..426c51d 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, diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index a19b745..e8faf53 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); @@ -267,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; @@ -390,7 +391,6 @@ fail: if (pdata && client->irq) pcf857x_irq_domain_cleanup(gpio); - kfree(gpio); return status; } @@ -415,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; } diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index d7a5c9d..df2199d 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -628,7 +628,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); @@ -712,7 +712,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); diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 99e0fa4..b22ca79 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -3030,6 +3030,7 @@ static __init int samsung_gpiolib_init(void) { .compatible = "samsung,exynos4x12-pinctrl", }, { .compatible = "samsung,exynos5250-pinctrl", }, { .compatible = "samsung,exynos5440-pinctrl", }, + { } }; for_each_matching_node(pctrl_np, exynos_pinctrl_ids) if (pctrl_np && of_device_is_available(pctrl_np)) diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index edae963..1e4de16 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; @@ -204,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; 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; 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 ? diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index dde0656..da4cb5b 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -414,10 +414,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; @@ -478,9 +479,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); 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; } 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; 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); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index a063eb0..5c1ef2b 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -17,6 +17,13 @@ #include <linux/acpi.h> #include <linux/interrupt.h> +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,119 @@ 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. + * @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/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 465f4ca..665f953 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 |