diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 6 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-em.c | 418 | ||||
-rw-r--r-- | drivers/gpio/gpio-omap.c | 9 | ||||
-rw-r--r-- | drivers/gpio/gpio-pch.c | 57 | ||||
-rw-r--r-- | drivers/gpio/gpio-pxa.c | 116 | ||||
-rw-r--r-- | drivers/gpio/gpio-samsung.c | 18 |
7 files changed, 566 insertions, 59 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e03653d6935..eb80ba30045 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -91,6 +91,12 @@ config GPIO_IT8761E help Say yes here to support GPIO functionality of IT8761E super I/O chip. +config GPIO_EM + tristate "Emma Mobile GPIO" + depends on ARM + help + Say yes here to support GPIO on Renesas Emma Mobile SoCs. + config GPIO_EP93XX def_bool y depends on ARCH_EP93XX diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a4193ab1b26..708ffb2165e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o 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_IT8761E) += gpio-it8761e.o diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c new file mode 100644 index 00000000000..150d9768811 --- /dev/null +++ b/drivers/gpio/gpio-em.c @@ -0,0 +1,418 @@ +/* + * Emma Mobile GPIO Support - GIO + * + * Copyright (C) 2012 Magnus Damm + * + * 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 + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_data/gpio-em.h> + +struct em_gio_priv { + void __iomem *base0; + void __iomem *base1; + unsigned int irq_base; + spinlock_t sense_lock; + struct platform_device *pdev; + struct gpio_chip gpio_chip; + struct irq_chip irq_chip; + struct irq_domain *irq_domain; +}; + +#define GIO_E1 0x00 +#define GIO_E0 0x04 +#define GIO_EM 0x04 +#define GIO_OL 0x08 +#define GIO_OH 0x0c +#define GIO_I 0x10 +#define GIO_IIA 0x14 +#define GIO_IEN 0x18 +#define GIO_IDS 0x1c +#define GIO_IIM 0x1c +#define GIO_RAW 0x20 +#define GIO_MST 0x24 +#define GIO_IIR 0x28 + +#define GIO_IDT0 0x40 +#define GIO_IDT1 0x44 +#define GIO_IDT2 0x48 +#define GIO_IDT3 0x4c +#define GIO_RAWBL 0x50 +#define GIO_RAWBH 0x54 +#define GIO_IRBL 0x58 +#define GIO_IRBH 0x5c + +#define GIO_IDT(n) (GIO_IDT0 + ((n) * 4)) + +static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs) +{ + if (offs < GIO_IDT0) + return ioread32(p->base0 + offs); + else + return ioread32(p->base1 + (offs - GIO_IDT0)); +} + +static inline void em_gio_write(struct em_gio_priv *p, int offs, + unsigned long value) +{ + if (offs < GIO_IDT0) + iowrite32(value, p->base0 + offs); + else + iowrite32(value, p->base1 + (offs - GIO_IDT0)); +} + +static inline struct em_gio_priv *irq_to_priv(struct irq_data *d) +{ + struct irq_chip *chip = irq_data_get_irq_chip(d); + return container_of(chip, struct em_gio_priv, irq_chip); +} + +static void em_gio_irq_disable(struct irq_data *d) +{ + struct em_gio_priv *p = irq_to_priv(d); + + em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d))); +} + +static void em_gio_irq_enable(struct irq_data *d) +{ + struct em_gio_priv *p = irq_to_priv(d); + + em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d))); +} + +#define GIO_ASYNC(x) (x + 8) + +static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { + [IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00), + [IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01), + [IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02), + [IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03), + [IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04), +}; + +static int em_gio_irq_set_type(struct irq_data *d, unsigned int type) +{ + unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK]; + struct em_gio_priv *p = irq_to_priv(d); + unsigned int reg, offset, shift; + unsigned long flags; + unsigned long tmp; + + if (!value) + return -EINVAL; + + offset = irqd_to_hwirq(d); + + pr_debug("gio: sense irq = %d, mode = %d\n", offset, value); + + /* 8 x 4 bit fields in 4 IDT registers */ + reg = GIO_IDT(offset >> 3); + shift = (offset & 0x07) << 4; + + spin_lock_irqsave(&p->sense_lock, flags); + + /* disable the interrupt in IIA */ + tmp = em_gio_read(p, GIO_IIA); + tmp &= ~BIT(offset); + em_gio_write(p, GIO_IIA, tmp); + + /* change the sense setting in IDT */ + tmp = em_gio_read(p, reg); + tmp &= ~(0xf << shift); + tmp |= value << shift; + em_gio_write(p, reg, tmp); + + /* clear pending interrupts */ + em_gio_write(p, GIO_IIR, BIT(offset)); + + /* enable the interrupt in IIA */ + tmp = em_gio_read(p, GIO_IIA); + tmp |= BIT(offset); + em_gio_write(p, GIO_IIA, tmp); + + spin_unlock_irqrestore(&p->sense_lock, flags); + + return 0; +} + +static irqreturn_t em_gio_irq_handler(int irq, void *dev_id) +{ + struct em_gio_priv *p = dev_id; + unsigned long pending; + unsigned int offset, irqs_handled = 0; + + while ((pending = em_gio_read(p, GIO_MST))) { + offset = __ffs(pending); + em_gio_write(p, GIO_IIR, BIT(offset)); + generic_handle_irq(irq_find_mapping(p->irq_domain, offset)); + irqs_handled++; + } + + return irqs_handled ? IRQ_HANDLED : IRQ_NONE; +} + +static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip) +{ + return container_of(chip, struct em_gio_priv, gpio_chip); +} + +static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + em_gio_write(gpio_to_priv(chip), GIO_E0, BIT(offset)); + return 0; +} + +static int em_gio_get(struct gpio_chip *chip, unsigned offset) +{ + return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset)); +} + +static void __em_gio_set(struct gpio_chip *chip, unsigned int reg, + unsigned shift, int value) +{ + /* upper 16 bits contains mask and lower 16 actual value */ + em_gio_write(gpio_to_priv(chip), reg, + (1 << (shift + 16)) | (value << shift)); +} + +static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + /* output is split into two registers */ + if (offset < 16) + __em_gio_set(chip, GIO_OL, offset, value); + else + __em_gio_set(chip, GIO_OH, offset - 16, value); +} + +static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + /* write GPIO value to output before selecting output mode of pin */ + em_gio_set(chip, offset, value); + em_gio_write(gpio_to_priv(chip), GIO_E1, BIT(offset)); + return 0; +} + +static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset); +} + +static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct em_gio_priv *p = h->host_data; + + pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq); + + irq_set_chip_data(virq, h->host_data); + irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); + set_irq_flags(virq, IRQF_VALID); /* kill me now */ + return 0; +} + +static struct irq_domain_ops em_gio_irq_domain_ops = { + .map = em_gio_irq_domain_map, +}; + +static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p) +{ + struct platform_device *pdev = p->pdev; + struct gpio_em_config *pdata = pdev->dev.platform_data; + + p->irq_base = irq_alloc_descs(pdata->irq_base, 0, + pdata->number_of_pins, numa_node_id()); + if (IS_ERR_VALUE(p->irq_base)) { + dev_err(&pdev->dev, "cannot get irq_desc\n"); + return -ENXIO; + } + pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n", + pdata->gpio_base, pdata->number_of_pins, p->irq_base); + + p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node, + pdata->number_of_pins, + p->irq_base, 0, + &em_gio_irq_domain_ops, p); + if (!p->irq_domain) { + irq_free_descs(p->irq_base, pdata->number_of_pins); + return -ENXIO; + } + + return 0; +} + +static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p) +{ + struct gpio_em_config *pdata = p->pdev->dev.platform_data; + + irq_free_descs(p->irq_base, pdata->number_of_pins); + /* FIXME: irq domain wants to be freed! */ +} + +static int __devinit em_gio_probe(struct platform_device *pdev) +{ + struct gpio_em_config *pdata = pdev->dev.platform_data; + struct em_gio_priv *p; + struct resource *io[2], *irq[2]; + struct gpio_chip *gpio_chip; + struct irq_chip *irq_chip; + const char *name = dev_name(&pdev->dev); + int ret; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + ret = -ENOMEM; + goto err0; + } + + p->pdev = pdev; + platform_set_drvdata(pdev, p); + spin_lock_init(&p->sense_lock); + + io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0); + io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1); + 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"); + ret = -EINVAL; + goto err1; + } + + p->base0 = ioremap_nocache(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; + } + + p->base1 = ioremap_nocache(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; + } + + gpio_chip = &p->gpio_chip; + gpio_chip->direction_input = em_gio_direction_input; + gpio_chip->get = em_gio_get; + gpio_chip->direction_output = em_gio_direction_output; + gpio_chip->set = em_gio_set; + gpio_chip->to_irq = em_gio_to_irq; + gpio_chip->label = name; + gpio_chip->owner = THIS_MODULE; + gpio_chip->base = pdata->gpio_base; + gpio_chip->ngpio = pdata->number_of_pins; + + irq_chip = &p->irq_chip; + irq_chip->name = name; + irq_chip->irq_mask = em_gio_irq_disable; + irq_chip->irq_unmask = em_gio_irq_enable; + irq_chip->irq_enable = em_gio_irq_enable; + irq_chip->irq_disable = em_gio_irq_disable; + irq_chip->irq_set_type = em_gio_irq_set_type; + irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; + + ret = em_gio_irq_domain_init(p); + if (ret) { + dev_err(&pdev->dev, "cannot initialize irq domain\n"); + goto err3; + } + + if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) { + dev_err(&pdev->dev, "failed to request low IRQ\n"); + ret = -ENOENT; + goto err4; + } + + if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) { + dev_err(&pdev->dev, "failed to request high IRQ\n"); + ret = -ENOENT; + goto err5; + } + + ret = gpiochip_add(gpio_chip); + if (ret) { + dev_err(&pdev->dev, "failed to add GPIO controller\n"); + goto err6; + } + return 0; + +err6: + free_irq(irq[1]->start, pdev); +err5: + free_irq(irq[0]->start, pdev); +err4: + em_gio_irq_domain_cleanup(p); +err3: + iounmap(p->base1); +err2: + iounmap(p->base0); +err1: + kfree(p); +err0: + return ret; +} + +static int __devexit 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); + em_gio_irq_domain_cleanup(p); + iounmap(p->base1); + iounmap(p->base0); + kfree(p); + return 0; +} + +static struct platform_driver em_gio_device_driver = { + .probe = em_gio_probe, + .remove = __devexit_p(em_gio_remove), + .driver = { + .name = "em_gio", + } +}; + +module_platform_driver(em_gio_device_driver); + +MODULE_AUTHOR("Magnus Damm"); +MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 1adc2ec1e38..4461540653a 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -965,18 +965,15 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) } _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv); - _gpio_rmw(base, bank->regs->irqstatus, l, - bank->regs->irqenable_inv == false); - _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->debounce_en != 0); - _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->ctrl != 0); + _gpio_rmw(base, bank->regs->irqstatus, l, !bank->regs->irqenable_inv); if (bank->regs->debounce_en) - _gpio_rmw(base, bank->regs->debounce_en, 0, 1); + __raw_writel(0, base + bank->regs->debounce_en); /* Save OE default value (0xffffffff) in the context */ bank->context.oe = __raw_readl(bank->base + bank->regs->direction); /* Initialize interface clk ungated, module enabled */ if (bank->regs->ctrl) - _gpio_rmw(base, bank->regs->ctrl, 0, 1); + __raw_writel(0, base + bank->regs->ctrl); } static __devinit void diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index e8729cc2ba2..2cd958e0b82 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -230,16 +230,12 @@ static void pch_gpio_setup(struct pch_gpio *chip) static int pch_irq_type(struct irq_data *d, unsigned int type) { - u32 im; - u32 __iomem *im_reg; - u32 ien; - u32 im_pos; - int ch; - unsigned long flags; - u32 val; - int irq = d->irq; struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct pch_gpio *chip = gc->private; + u32 im, im_pos, val; + u32 __iomem *im_reg; + unsigned long flags; + int ch, irq = d->irq; ch = irq - chip->irq_base; if (irq <= chip->irq_base + 7) { @@ -270,30 +266,22 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) case IRQ_TYPE_LEVEL_LOW: val = PCH_LEVEL_L; break; - case IRQ_TYPE_PROBE: - goto end; default: - dev_warn(chip->dev, "%s: unknown type(%dd)", - __func__, type); - goto end; + goto unlock; } /* Set interrupt mode */ im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4)); iowrite32(im | (val << (im_pos * 4)), im_reg); - /* iclr */ - iowrite32(BIT(ch), &chip->reg->iclr); + /* And the handler */ + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + __irq_set_handler_locked(d->irq, handle_level_irq); + else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + __irq_set_handler_locked(d->irq, handle_edge_irq); - /* IMASKCLR */ - iowrite32(BIT(ch), &chip->reg->imaskclr); - - /* Enable interrupt */ - ien = ioread32(&chip->reg->ien); - iowrite32(ien | BIT(ch), &chip->reg->ien); -end: +unlock: spin_unlock_irqrestore(&chip->spinlock, flags); - return 0; } @@ -313,18 +301,24 @@ static void pch_irq_mask(struct irq_data *d) iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imask); } +static void pch_irq_ack(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct pch_gpio *chip = gc->private; + + iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->iclr); +} + static irqreturn_t pch_gpio_handler(int irq, void *dev_id) { struct pch_gpio *chip = dev_id; u32 reg_val = ioread32(&chip->reg->istatus); - int i; - int ret = IRQ_NONE; + int i, ret = IRQ_NONE; for (i = 0; i < gpio_pins[chip->ioh]; i++) { if (reg_val & BIT(i)) { dev_dbg(chip->dev, "%s:[%d]:irq=%d status=0x%x\n", __func__, i, irq, reg_val); - iowrite32(BIT(i), &chip->reg->iclr); generic_handle_irq(chip->irq_base + i); ret = IRQ_HANDLED; } @@ -343,6 +337,7 @@ static __devinit void pch_gpio_alloc_generic_chip(struct pch_gpio *chip, gc->private = chip; ct = gc->chip_types; + ct->chip.irq_ack = pch_irq_ack; ct->chip.irq_mask = pch_irq_mask; ct->chip.irq_unmask = pch_irq_unmask; ct->chip.irq_set_type = pch_irq_type; @@ -357,6 +352,7 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev, s32 ret; struct pch_gpio *chip; int irq_base; + u32 msk; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) @@ -408,8 +404,13 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev, } chip->irq_base = irq_base; + /* Mask all interrupts, but enable them */ + msk = (1 << gpio_pins[chip->ioh]) - 1; + iowrite32(msk, &chip->reg->imask); + iowrite32(msk, &chip->reg->ien); + ret = request_irq(pdev->irq, pch_gpio_handler, - IRQF_SHARED, KBUILD_MODNAME, chip); + IRQF_SHARED, KBUILD_MODNAME, chip); if (ret != 0) { dev_err(&pdev->dev, "%s request_irq failed\n", __func__); @@ -418,8 +419,6 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev, pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]); - /* Initialize interrupt ien register */ - iowrite32(0, &chip->reg->ien); end: return 0; diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index fc3ace3fd4c..58a6a63a6ec 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -11,13 +11,17 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <linux/module.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/gpio-pxa.h> #include <linux/init.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/syscore_ops.h> #include <linux/slab.h> @@ -56,6 +60,10 @@ int pxa_last_gpio; +#ifdef CONFIG_OF +static struct irq_domain *domain; +#endif + struct pxa_gpio_chip { struct gpio_chip chip; void __iomem *regbase; @@ -81,7 +89,6 @@ enum { PXA3XX_GPIO, PXA93X_GPIO, MMP_GPIO = 0x10, - MMP2_GPIO, }; static DEFINE_SPINLOCK(gpio_lock); @@ -475,22 +482,92 @@ static int pxa_gpio_nums(void) gpio_type = MMP_GPIO; } else if (cpu_is_mmp2()) { count = 191; - gpio_type = MMP2_GPIO; + gpio_type = MMP_GPIO; } #endif /* CONFIG_ARCH_MMP */ return count; } +static struct of_device_id pxa_gpio_dt_ids[] = { + { .compatible = "mrvl,pxa-gpio" }, + { .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO }, + {} +}; + +static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + return 0; +} + +const struct irq_domain_ops pxa_irq_domain_ops = { + .map = pxa_irq_domain_map, +}; + +#ifdef CONFIG_OF +static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev) +{ + int ret, nr_banks, nr_gpios, irq_base; + struct device_node *prev, *next, *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(pxa_gpio_dt_ids, &pdev->dev); + + if (!of_id) { + dev_err(&pdev->dev, "Failed to find gpio controller\n"); + return -EFAULT; + } + gpio_type = (int)of_id->data; + + next = of_get_next_child(np, NULL); + prev = next; + if (!next) { + dev_err(&pdev->dev, "Failed to find child gpio node\n"); + ret = -EINVAL; + goto err; + } + for (nr_banks = 1; ; nr_banks++) { + next = of_get_next_child(np, prev); + if (!next) + break; + prev = next; + } + of_node_put(prev); + nr_gpios = nr_banks << 5; + pxa_last_gpio = nr_gpios - 1; + + irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0); + if (irq_base < 0) { + dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); + goto err; + } + domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0, + &pxa_irq_domain_ops, NULL); + return 0; +err: + iounmap(gpio_reg_base); + return ret; +} +#else +#define pxa_gpio_probe_dt(pdev) (-1) +#endif + static int __devinit pxa_gpio_probe(struct platform_device *pdev) { struct pxa_gpio_chip *c; struct resource *res; struct clk *clk; struct pxa_gpio_platform_data *info; - int gpio, irq, ret; + int gpio, irq, ret, use_of = 0; int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0; - pxa_last_gpio = pxa_gpio_nums(); + ret = pxa_gpio_probe_dt(pdev); + if (ret < 0) + pxa_last_gpio = pxa_gpio_nums(); + else + use_of = 1; if (!pxa_last_gpio) return -EINVAL; @@ -545,25 +622,27 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev) writel_relaxed(~0, c->regbase + ED_MASK_OFFSET); } + if (!use_of) { #ifdef CONFIG_ARCH_PXA - irq = gpio_to_irq(0); - irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler); - - irq = gpio_to_irq(1); - irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler); -#endif + irq = gpio_to_irq(0); + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler); - for (irq = gpio_to_irq(gpio_offset); - irq <= gpio_to_irq(pxa_last_gpio); irq++) { + irq = gpio_to_irq(1); irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler); +#endif + + for (irq = gpio_to_irq(gpio_offset); + irq <= gpio_to_irq(pxa_last_gpio); irq++) { + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } } irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler); @@ -574,6 +653,7 @@ static struct platform_driver pxa_gpio_driver = { .probe = pxa_gpio_probe, .driver = { .name = "pxa-gpio", + .of_match_table = pxa_gpio_dt_ids, }, }; diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 19d6fc0229c..e991d917196 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -452,12 +452,14 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = { }; #endif +#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5) static struct samsung_gpio_cfg exynos_gpio_cfg = { .set_pull = exynos_gpio_setpull, .get_pull = exynos_gpio_getpull, .set_config = samsung_gpio_setcfg_4bit, .get_config = samsung_gpio_getcfg_4bit, }; +#endif #if defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450) static struct samsung_gpio_cfg s5p64x0_gpio_cfg_rbank = { @@ -2123,8 +2125,8 @@ static struct samsung_gpio_chip s5pv210_gpios_4bit[] = { * uses the above macro and depends on the banks being listed in order here. */ -static struct samsung_gpio_chip exynos4_gpios_1[] = { #ifdef CONFIG_ARCH_EXYNOS4 +static struct samsung_gpio_chip exynos4_gpios_1[] = { { .chip = { .base = EXYNOS4_GPA0(0), @@ -2222,11 +2224,11 @@ static struct samsung_gpio_chip exynos4_gpios_1[] = { .label = "GPF3", }, }, -#endif }; +#endif -static struct samsung_gpio_chip exynos4_gpios_2[] = { #ifdef CONFIG_ARCH_EXYNOS4 +static struct samsung_gpio_chip exynos4_gpios_2[] = { { .chip = { .base = EXYNOS4_GPJ0(0), @@ -2367,11 +2369,11 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = { .to_irq = samsung_gpiolib_to_irq, }, }, -#endif }; +#endif -static struct samsung_gpio_chip exynos4_gpios_3[] = { #ifdef CONFIG_ARCH_EXYNOS4 +static struct samsung_gpio_chip exynos4_gpios_3[] = { { .chip = { .base = EXYNOS4_GPZ(0), @@ -2379,8 +2381,8 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = { .label = "GPZ", }, }, -#endif }; +#endif #ifdef CONFIG_ARCH_EXYNOS5 static struct samsung_gpio_chip exynos5_gpios_1[] = { @@ -2719,7 +2721,9 @@ static __init int samsung_gpiolib_init(void) { struct samsung_gpio_chip *chip; int i, nr_chips; +#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS5250) void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4; +#endif int group = 0; samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs)); @@ -2971,6 +2975,7 @@ static __init int samsung_gpiolib_init(void) return 0; +#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS5250) err_ioremap4: iounmap(gpio_base3); err_ioremap3: @@ -2979,6 +2984,7 @@ err_ioremap2: iounmap(gpio_base1); err_ioremap1: return -ENOMEM; +#endif } core_initcall(samsung_gpiolib_init); |