From 8944df726c7d2916764d18be8e944bd7ea3f2f51 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Oct 2012 11:45:28 +0200 Subject: [PATCH 01/65] gpio/gpio-pl061: Covert to use devm_* functions Use the devm_* family of functions during probe to reduce the error handling code footprint. Signed-off-by: Tobias Klauser Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 59 +++++++++++++++------------------------ 1 file changed, 22 insertions(+), 37 deletions(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b4b5da4fd2cc..31d9c9e79ea9 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -216,39 +216,34 @@ static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base) IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); } -static int pl061_probe(struct amba_device *dev, const struct amba_id *id) +static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { - struct pl061_platform_data *pdata; + struct device *dev = &adev->dev; + struct pl061_platform_data *pdata = dev->platform_data; struct pl061_gpio *chip; int ret, irq, i; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; - pdata = dev->dev.platform_data; if (pdata) { chip->gc.base = pdata->gpio_base; chip->irq_base = pdata->irq_base; - } else if (dev->dev.of_node) { + } else if (adev->dev.of_node) { chip->gc.base = -1; chip->irq_base = 0; - } else { - ret = -ENODEV; - goto free_mem; - } + } else + return -ENODEV; - if (!request_mem_region(dev->res.start, - resource_size(&dev->res), "pl061")) { - ret = -EBUSY; - goto free_mem; - } + if (!devm_request_mem_region(dev, adev->res.start, + resource_size(&adev->res), "pl061")) + return -EBUSY; - chip->base = ioremap(dev->res.start, resource_size(&dev->res)); - if (chip->base == NULL) { - ret = -ENOMEM; - goto release_region; - } + chip->base = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); + if (chip->base == NULL) + return -ENOMEM; spin_lock_init(&chip->lock); @@ -258,13 +253,13 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) chip->gc.set = pl061_set_value; chip->gc.to_irq = pl061_to_irq; chip->gc.ngpio = PL061_GPIO_NR; - chip->gc.label = dev_name(&dev->dev); - chip->gc.dev = &dev->dev; + chip->gc.label = dev_name(dev); + chip->gc.dev = dev; chip->gc.owner = THIS_MODULE; ret = gpiochip_add(&chip->gc); if (ret) - goto iounmap; + return ret; /* * irq_chip support @@ -276,11 +271,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) pl061_init_gc(chip, chip->irq_base); writeb(0, chip->base + GPIOIE); /* disable irqs */ - irq = dev->irq[0]; - if (irq < 0) { - ret = -ENODEV; - goto iounmap; - } + irq = adev->irq[0]; + if (irq < 0) + return -ENODEV; + irq_set_chained_handler(irq, pl061_irq_handler); irq_set_handler_data(irq, chip); @@ -294,18 +288,9 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) } } - amba_set_drvdata(dev, chip); + amba_set_drvdata(adev, chip); return 0; - -iounmap: - iounmap(chip->base); -release_region: - release_mem_region(dev->res.start, resource_size(&dev->res)); -free_mem: - kfree(chip); - - return ret; } #ifdef CONFIG_PM From 086d585f13542de205c25fd225a37aa0cadc3be0 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Oct 2012 11:37:38 +0200 Subject: [PATCH 02/65] gpio/gpio-omap: Use existing pointer to struct device A pointer to "pdev->dev" is already stored in "dev", so use it in devm_kzalloc. Signed-off-by: Tobias Klauser Acked-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 94cbc842fbc3..eb73dee0ab33 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1070,7 +1070,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL); + bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL); if (!bank) { dev_err(dev, "Memory alloc failed\n"); return -ENOMEM; From 04ed4279715f685857b8d5b84a48bf7bd43a36c5 Mon Sep 17 00:00:00 2001 From: Ashish Jangam Date: Fri, 14 Sep 2012 19:00:16 +0530 Subject: [PATCH 03/65] DA9055 GPIO driver This is the GPIO patch for the DA9055 PMIC. This patch has got dependency on the DA9055 MFD core. This patch is functionally tested on SMDK6410 board. Signed-off-by: David Dajun Chen Signed-off-by: Ashish Jangam Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 11 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-da9055.c | 204 +++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 drivers/gpio/gpio-da9055.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d055cee36942..150eeb705fbc 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -86,6 +86,17 @@ config GPIO_DA9052 help Say yes here to enable the GPIO driver for the DA9052 chip. +config GPIO_DA9055 + tristate "Dialog Semiconductor DA9055 GPIO" + depends on MFD_DA9055 + help + Say yes here to enable the GPIO driver for the DA9055 chip. + + The Dialog DA9055 PMIC chip has 3 GPIO pins that can be + be controller by this driver. + + If driver is built as a module it will be called gpio-da9055. + config GPIO_MAX730X tristate diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9aeed6707326..e6f8e379a2ec 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o +obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c new file mode 100644 index 000000000000..55d83c7d9c7f --- /dev/null +++ b/drivers/gpio/gpio-da9055.c @@ -0,0 +1,204 @@ +/* + * GPIO Driver for Dialog DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen + * + * 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. + * + */ +#include +#include +#include + +#include +#include +#include + +#define DA9055_VDD_IO 0x0 +#define DA9055_PUSH_PULL 0x3 +#define DA9055_ACT_LOW 0x0 +#define DA9055_GPI 0x1 +#define DA9055_PORT_MASK 0x3 +#define DA9055_PORT_SHIFT(offset) (4 * (offset % 2)) + +#define DA9055_INPUT DA9055_GPI +#define DA9055_OUTPUT DA9055_PUSH_PULL +#define DA9055_IRQ_GPI0 3 + +struct da9055_gpio { + struct da9055 *da9055; + struct gpio_chip gp; +}; + +static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct da9055_gpio, gp); +} + +static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + int gpio_direction = 0; + int ret; + + /* Get GPIO direction */ + ret = da9055_reg_read(gpio->da9055, (offset >> 1) + DA9055_REG_GPIO0_1); + if (ret < 0) + return ret; + + gpio_direction = ret & (DA9055_PORT_MASK) << DA9055_PORT_SHIFT(offset); + gpio_direction >>= DA9055_PORT_SHIFT(offset); + switch (gpio_direction) { + case DA9055_INPUT: + ret = da9055_reg_read(gpio->da9055, DA9055_REG_STATUS_B); + if (ret < 0) + return ret; + break; + case DA9055_OUTPUT: + ret = da9055_reg_read(gpio->da9055, DA9055_REG_GPIO_MODE0_2); + if (ret < 0) + return ret; + } + + return ret & (1 << offset); + +} + +static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + + da9055_reg_update(gpio->da9055, + DA9055_REG_GPIO_MODE0_2, + 1 << offset, + value << offset); +} + +static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + unsigned char reg_byte; + + reg_byte = (DA9055_ACT_LOW | DA9055_GPI) + << DA9055_PORT_SHIFT(offset); + + return da9055_reg_update(gpio->da9055, (offset >> 1) + + DA9055_REG_GPIO0_1, + DA9055_PORT_MASK << + DA9055_PORT_SHIFT(offset), + reg_byte); +} + +static int da9055_gpio_direction_output(struct gpio_chip *gc, + unsigned offset, int value) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + unsigned char reg_byte; + int ret; + + reg_byte = (DA9055_VDD_IO | DA9055_PUSH_PULL) + << DA9055_PORT_SHIFT(offset); + + ret = da9055_reg_update(gpio->da9055, (offset >> 1) + + DA9055_REG_GPIO0_1, + DA9055_PORT_MASK << + DA9055_PORT_SHIFT(offset), + reg_byte); + if (ret < 0) + return ret; + + da9055_gpio_set(gc, offset, value); + + return 0; +} + +static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + struct da9055 *da9055 = gpio->da9055; + + return regmap_irq_get_virq(da9055->irq_data, + DA9055_IRQ_GPI0 + offset); +} + +static struct gpio_chip reference_gp __devinitdata = { + .label = "da9055-gpio", + .owner = THIS_MODULE, + .get = da9055_gpio_get, + .set = da9055_gpio_set, + .direction_input = da9055_gpio_direction_input, + .direction_output = da9055_gpio_direction_output, + .to_irq = da9055_gpio_to_irq, + .can_sleep = 1, + .ngpio = 3, + .base = -1, +}; + +static int __devinit da9055_gpio_probe(struct platform_device *pdev) +{ + struct da9055_gpio *gpio; + struct da9055_pdata *pdata; + int ret; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (gpio == NULL) + return -ENOMEM; + + gpio->da9055 = dev_get_drvdata(pdev->dev.parent); + pdata = gpio->da9055->dev->platform_data; + + gpio->gp = reference_gp; + if (pdata && pdata->gpio_base) + gpio->gp.base = pdata->gpio_base; + + ret = gpiochip_add(&gpio->gp); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + goto err_mem; + } + + platform_set_drvdata(pdev, gpio); + + return 0; + +err_mem: + return ret; +} + +static int __devexit da9055_gpio_remove(struct platform_device *pdev) +{ + struct da9055_gpio *gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&gpio->gp); +} + +static struct platform_driver da9055_gpio_driver = { + .probe = da9055_gpio_probe, + .remove = __devexit_p(da9055_gpio_remove), + .driver = { + .name = "da9055-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init da9055_gpio_init(void) +{ + return platform_driver_register(&da9055_gpio_driver); +} +subsys_initcall(da9055_gpio_init); + +static void __exit da9055_gpio_exit(void) +{ + platform_driver_unregister(&da9055_gpio_driver); +} +module_exit(da9055_gpio_exit); + +MODULE_AUTHOR("David Dajun Chen "); +MODULE_DESCRIPTION("DA9055 GPIO Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-gpio"); From a3b8d4a513574e6adf76bcacad21c95ee6b8ce4b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 9 Oct 2012 20:05:56 +0400 Subject: [PATCH 04/65] GPIO: Add support for GPIO on CLPS711X-target platform The CLPS711X CPUs provide some GPIOs for use in the system. This driver provides support for these via gpiolib. Due to platform limitations, driver does not support interrupts, only inputs and outputs. Signed-off-by: Alexander Shiyan Acked-by: Russell King Signed-off-by: Linus Walleij --- arch/arm/Kconfig | 1 + arch/arm/mach-clps711x/include/mach/gpio.h | 13 ++ drivers/gpio/Kconfig | 4 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-clps711x.c | 163 +++++++++++++++++++++ 5 files changed, 182 insertions(+) create mode 100644 arch/arm/mach-clps711x/include/mach/gpio.h create mode 100644 drivers/gpio/gpio-clps711x.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 73067efd4845..f456cf4ae3ca 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -364,6 +364,7 @@ config ARCH_CNS3XXX config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" + select ARCH_REQUIRE_GPIOLIB select ARCH_USES_GETTIMEOFFSET select CLKDEV_LOOKUP select COMMON_CLK diff --git a/arch/arm/mach-clps711x/include/mach/gpio.h b/arch/arm/mach-clps711x/include/mach/gpio.h new file mode 100644 index 000000000000..8ac6889fabcd --- /dev/null +++ b/arch/arm/mach-clps711x/include/mach/gpio.h @@ -0,0 +1,13 @@ +/* + * This file contains the CLPS711X GPIO definitions. + * + * Copyright (C) 2012 Alexander Shiyan + * + * 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. + */ + +/* Simple helper for convert port & pin to GPIO number */ +#define CLPS711X_GPIO(port, bit) ((port) * 8 + (bit)) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 150eeb705fbc..9e3fb3438718 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -102,6 +102,10 @@ config GPIO_MAX730X comment "Memory mapped GPIO drivers:" +config GPIO_CLPS711X + def_bool y + depends on ARCH_CLPS711X + config GPIO_GENERIC_PLATFORM tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" select GPIO_GENERIC diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index e6f8e379a2ec..1c1b63fcaeb3 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o +obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c new file mode 100644 index 000000000000..ea21822b3de9 --- /dev/null +++ b/drivers/gpio/gpio-clps711x.c @@ -0,0 +1,163 @@ +/* + * CLPS711X GPIO driver + * + * Copyright (C) 2012 Alexander Shiyan + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define CLPS711X_GPIO_PORTS 5 +#define CLPS711X_GPIO_NAME "gpio-clps711x" + +struct clps711x_gpio { + struct gpio_chip chip[CLPS711X_GPIO_PORTS]; + spinlock_t lock; +}; + +static void __iomem *clps711x_ports[] = { + CLPS711X_VIRT_BASE + PADR, + CLPS711X_VIRT_BASE + PBDR, + CLPS711X_VIRT_BASE + PCDR, + CLPS711X_VIRT_BASE + PDDR, + CLPS711X_VIRT_BASE + PEDR, +}; + +static void __iomem *clps711x_pdirs[] = { + CLPS711X_VIRT_BASE + PADDR, + CLPS711X_VIRT_BASE + PBDDR, + CLPS711X_VIRT_BASE + PCDDR, + CLPS711X_VIRT_BASE + PDDDR, + CLPS711X_VIRT_BASE + PEDDR, +}; + +#define clps711x_port(x) clps711x_ports[x->base / 8] +#define clps711x_pdir(x) clps711x_pdirs[x->base / 8] + +static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) +{ + return !!readb(clps711x_port(chip)) & (1 << offset); +} + +static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_port(chip)) & ~(1 << offset); + if (value) + tmp |= 1 << offset; + writeb(tmp, clps711x_port(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); + writeb(tmp, clps711x_pdir(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset, + int value) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) | (1 << offset); + writeb(tmp, clps711x_pdir(chip)); + tmp = readb(clps711x_port(chip)) & ~(1 << offset); + if (value) + tmp |= 1 << offset; + writeb(tmp, clps711x_port(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +struct clps711x_gpio_port { + char *name; + int nr; +}; + +static const struct clps711x_gpio_port clps711x_gpio_ports[] __initconst = { + { "PORTA", 8, }, + { "PORTB", 8, }, + { "PORTC", 8, }, + { "PORTD", 8, }, + { "PORTE", 3, }, +}; + +static int __init gpio_clps711x_init(void) +{ + int i; + struct platform_device *pdev; + struct clps711x_gpio *gpio; + + pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0); + if (!pdev) { + pr_err("Cannot create platform device: %s\n", + CLPS711X_GPIO_NAME); + return -ENOMEM; + } + + platform_device_add(pdev); + + gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio), + GFP_KERNEL); + if (!gpio) { + dev_err(&pdev->dev, "GPIO allocating memory error\n"); + platform_device_del(pdev); + platform_device_put(pdev); + return -ENOMEM; + } + + platform_set_drvdata(pdev, gpio); + + spin_lock_init(&gpio->lock); + + for (i = 0; i < CLPS711X_GPIO_PORTS; i++) { + gpio->chip[i].owner = THIS_MODULE; + gpio->chip[i].dev = &pdev->dev; + gpio->chip[i].label = clps711x_gpio_ports[i].name; + gpio->chip[i].base = i * 8; + gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr; + gpio->chip[i].direction_input = gpio_clps711x_direction_in; + gpio->chip[i].get = gpio_clps711x_get; + gpio->chip[i].direction_output = gpio_clps711x_direction_out; + gpio->chip[i].set = gpio_clps711x_set; + WARN_ON(gpiochip_add(&gpio->chip[i])); + } + + dev_info(&pdev->dev, "GPIO driver initialized\n"); + + return 0; +} +arch_initcall(gpio_clps711x_init); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("CLPS711X GPIO driver"); From a6d7092a3460ebb32a63d691c5c3a1ff2a656424 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 15 Oct 2012 22:32:37 +0200 Subject: [PATCH 05/65] gpio: clps711x: delete local header This header file is unused and we shall not add new headers to the namespace. The macro may be reintroduced when there is a user for it. Cc: Alexander Shiyan Cc: Arnd Bergmann Cc: Russell King Signed-off-by: Linus Walleij --- arch/arm/mach-clps711x/include/mach/gpio.h | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 arch/arm/mach-clps711x/include/mach/gpio.h diff --git a/arch/arm/mach-clps711x/include/mach/gpio.h b/arch/arm/mach-clps711x/include/mach/gpio.h deleted file mode 100644 index 8ac6889fabcd..000000000000 --- a/arch/arm/mach-clps711x/include/mach/gpio.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file contains the CLPS711X GPIO definitions. - * - * Copyright (C) 2012 Alexander Shiyan - * - * 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. - */ - -/* Simple helper for convert port & pin to GPIO number */ -#define CLPS711X_GPIO(port, bit) ((port) * 8 + (bit)) From 67a0d4993d85ee2f42c9909127794553df69dd59 Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Thu, 18 Oct 2012 07:18:13 +1300 Subject: [PATCH 06/65] GPIO: vt8500: Add extended gpio bank for WM8505/WM8650 These SoC's have an extended bank of GPIO's seperate to the main GPIO block. This patch adds the additional 5 GPIO's located in this block which control I2C and PWMOUT. Signed-off-by: Tony Prisk Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vt8500.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c index bcd8e4aa7c7d..9ed2a2b347fa 100644 --- a/drivers/gpio/gpio-vt8500.c +++ b/drivers/gpio/gpio-vt8500.c @@ -96,6 +96,7 @@ static struct vt8500_gpio_data wm8505_data = { VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), + VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), }, }; @@ -115,6 +116,7 @@ static struct vt8500_gpio_data wm8650_data = { VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32), VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32), VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32), + VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), }, }; From fc4e2514995d9cd7f3e1a67098ce65d72acf8ec7 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Mon, 22 Oct 2012 11:39:12 +1100 Subject: [PATCH 07/65] gpiolib: Refactor gpio_export The gpio_export function uses nested if statements and the status variable to handle the failure cases. This makes the function logic difficult to follow. Refactor the code to abort immediately on failure using goto. This makes the code slightly longer, but significantly reduces the nesting and number of split lines and makes the code easier to read. Signed-off-by: Ryan Mallon Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 85 +++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5d6c71edc739..d5f9742d9ac1 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -702,8 +702,9 @@ int gpio_export(unsigned gpio, bool direction_may_change) { unsigned long flags; struct gpio_desc *desc; - int status = -EINVAL; + int status; const char *ioname = NULL; + struct device *dev; /* can't export until sysfs is available ... */ if (!gpio_class.p) { @@ -711,59 +712,65 @@ int gpio_export(unsigned gpio, bool direction_may_change) return -ENOENT; } - if (!gpio_is_valid(gpio)) - goto done; + if (!gpio_is_valid(gpio)) { + pr_debug("%s: gpio %d is not valid\n", __func__, gpio); + return -EINVAL; + } mutex_lock(&sysfs_lock); spin_lock_irqsave(&gpio_lock, flags); desc = &gpio_desc[gpio]; - if (test_bit(FLAG_REQUESTED, &desc->flags) - && !test_bit(FLAG_EXPORT, &desc->flags)) { - status = 0; - if (!desc->chip->direction_input - || !desc->chip->direction_output) - direction_may_change = false; + if (!test_bit(FLAG_REQUESTED, &desc->flags) || + test_bit(FLAG_EXPORT, &desc->flags)) { + spin_unlock_irqrestore(&gpio_lock, flags); + pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", + __func__, gpio, + test_bit(FLAG_REQUESTED, &desc->flags), + test_bit(FLAG_EXPORT, &desc->flags)); + return -EPERM; } + + if (!desc->chip->direction_input || !desc->chip->direction_output) + direction_may_change = false; spin_unlock_irqrestore(&gpio_lock, flags); if (desc->chip->names && desc->chip->names[gpio - desc->chip->base]) ioname = desc->chip->names[gpio - desc->chip->base]; - if (status == 0) { - struct device *dev; - - dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, ioname ? ioname : "gpio%u", gpio); - if (!IS_ERR(dev)) { - status = sysfs_create_group(&dev->kobj, - &gpio_attr_group); - - if (!status && direction_may_change) - status = device_create_file(dev, - &dev_attr_direction); - - if (!status && gpio_to_irq(gpio) >= 0 - && (direction_may_change - || !test_bit(FLAG_IS_OUT, - &desc->flags))) - status = device_create_file(dev, - &dev_attr_edge); - - if (status != 0) - device_unregister(dev); - } else - status = PTR_ERR(dev); - if (status == 0) - set_bit(FLAG_EXPORT, &desc->flags); + dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), + desc, ioname ? ioname : "gpio%u", gpio); + if (IS_ERR(dev)) { + status = PTR_ERR(dev); + goto fail_unlock; } - mutex_unlock(&sysfs_lock); - -done: + status = sysfs_create_group(&dev->kobj, &gpio_attr_group); if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + goto fail_unregister_device; + + if (direction_may_change) { + status = device_create_file(dev, &dev_attr_direction); + if (status) + goto fail_unregister_device; + } + if (gpio_to_irq(gpio) >= 0 && (direction_may_change || + !test_bit(FLAG_IS_OUT, &desc->flags))) { + status = device_create_file(dev, &dev_attr_edge); + if (status) + goto fail_unregister_device; + } + + set_bit(FLAG_EXPORT, &desc->flags); + mutex_unlock(&sysfs_lock); + return 0; + +fail_unregister_device: + device_unregister(dev); +fail_unlock: + mutex_unlock(&sysfs_lock); + pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); return status; } EXPORT_SYMBOL_GPL(gpio_export); From 41b3996e3b6825bd3a0624d62fde53fbad092ed0 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 24 Oct 2012 10:58:57 +0400 Subject: [PATCH 08/65] GPIO: clps711x: Fix return value for gpio_clps711x_get Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-clps711x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index ea21822b3de9..0753b3a9a34d 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -47,7 +47,7 @@ static void __iomem *clps711x_pdirs[] = { static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) { - return !!readb(clps711x_port(chip)) & (1 << offset); + return !!(readb(clps711x_port(chip)) & (1 << offset)); } static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, From d6a2fa0424aefe97289aa561444ec3ae09bdbba0 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 24 Oct 2012 12:34:46 +0400 Subject: [PATCH 09/65] GPIO: clps711x: Fix direction logic for PORTD PORTD have different direction logic, i.e. "0" is output and "1" is input. This patch fix this issue. Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-clps711x.c | 65 ++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index 0753b3a9a34d..ad181db79508 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -65,7 +65,7 @@ static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, spin_unlock_irqrestore(&gpio->lock, flags); } -static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset) +static int gpio_clps711x_dir_in(struct gpio_chip *chip, unsigned offset) { int tmp; unsigned long flags; @@ -79,8 +79,8 @@ static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset) return 0; } -static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset, - int value) +static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset, + int value) { int tmp; unsigned long flags; @@ -98,17 +98,49 @@ static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset, return 0; } -struct clps711x_gpio_port { +static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) | (1 << offset); + writeb(tmp, clps711x_pdir(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset, + int value) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); + writeb(tmp, clps711x_pdir(chip)); + tmp = readb(clps711x_port(chip)) & ~(1 << offset); + if (value) + tmp |= 1 << offset; + writeb(tmp, clps711x_port(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static struct { char *name; int nr; -}; - -static const struct clps711x_gpio_port clps711x_gpio_ports[] __initconst = { - { "PORTA", 8, }, - { "PORTB", 8, }, - { "PORTC", 8, }, - { "PORTD", 8, }, - { "PORTE", 3, }, + int inv_dir; +} clps711x_gpio_ports[] __initconst = { + { "PORTA", 8, 0, }, + { "PORTB", 8, 0, }, + { "PORTC", 8, 0, }, + { "PORTD", 8, 1, }, + { "PORTE", 3, 0, }, }; static int __init gpio_clps711x_init(void) @@ -145,10 +177,15 @@ static int __init gpio_clps711x_init(void) gpio->chip[i].label = clps711x_gpio_ports[i].name; gpio->chip[i].base = i * 8; gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr; - gpio->chip[i].direction_input = gpio_clps711x_direction_in; gpio->chip[i].get = gpio_clps711x_get; - gpio->chip[i].direction_output = gpio_clps711x_direction_out; gpio->chip[i].set = gpio_clps711x_set; + if (!clps711x_gpio_ports[i].inv_dir) { + gpio->chip[i].direction_input = gpio_clps711x_dir_in; + gpio->chip[i].direction_output = gpio_clps711x_dir_out; + } else { + gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv; + gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv; + } WARN_ON(gpiochip_add(&gpio->chip[i])); } From 80b0a6029272247f19146bf8f88e5d4bba94cba5 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Wed, 24 Oct 2012 17:25:27 +0300 Subject: [PATCH 10/65] gpiolib: add gpio get direction callback support Add .get_direction callback to gpio_chip. This allows gpiolib to check the current direction of a gpio. Used to show the correct gpio direction in sysfs and debug entries. If callback is not set then gpiolib will work as previously; e.g. guessing everything is input until a direction is set. Signed-off-by: Mathias Nyman Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 38 +++++++++++++++++++++++++++++++++++++- include/asm-generic/gpio.h | 5 ++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d5f9742d9ac1..e468eed261c5 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -191,6 +191,32 @@ int __init gpiochip_reserve(int start, int ngpio) return ret; } +/* caller ensures gpio is valid and requested, chip->get_direction may sleep */ +static int gpio_get_direction(unsigned gpio) +{ + struct gpio_chip *chip; + struct gpio_desc *desc = &gpio_desc[gpio]; + int status = -EINVAL; + + chip = gpio_to_chip(gpio); + gpio -= chip->base; + + if (!chip->get_direction) + return status; + + status = chip->get_direction(chip, gpio); + if (status > 0) { + /* GPIOF_DIR_IN, or other positive */ + status = 1; + clear_bit(FLAG_IS_OUT, &desc->flags); + } + if (status == 0) { + /* GPIOF_DIR_OUT */ + set_bit(FLAG_IS_OUT, &desc->flags); + } + return status; +} + #ifdef CONFIG_GPIO_SYSFS /* lock protects against unexport_gpio() being called while @@ -223,6 +249,7 @@ static ssize_t gpio_direction_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct gpio_desc *desc = dev_get_drvdata(dev); + unsigned gpio = desc - gpio_desc; ssize_t status; mutex_lock(&sysfs_lock); @@ -230,6 +257,7 @@ static ssize_t gpio_direction_show(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else + gpio_get_direction(gpio); status = sprintf(buf, "%s\n", test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in"); @@ -1080,6 +1108,7 @@ int gpiochip_add(struct gpio_chip *chip) * inputs (often with pullups enabled) so power * usage is minimized. Linux code should set the * gpio direction first thing; but until it does, + * and in case chip->get_direction is not set, * we may expose the wrong direction in sysfs. */ gpio_desc[id].flags = !chip->direction_input @@ -1231,9 +1260,15 @@ int gpio_request(unsigned gpio, const char *label) desc_set_label(desc, NULL); module_put(chip->owner); clear_bit(FLAG_REQUESTED, &desc->flags); + goto done; } } - + if (chip->get_direction) { + /* chip->get_direction may sleep */ + spin_unlock_irqrestore(&gpio_lock, flags); + gpio_get_direction(gpio); + spin_lock_irqsave(&gpio_lock, flags); + } done: if (status) pr_debug("gpio_request: gpio-%d (%s) status %d\n", @@ -1769,6 +1804,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) continue; + gpio_get_direction(gpio); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", gpio, gdesc->label, diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a9432fc6b8ba..eb70ca295971 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -56,6 +56,8 @@ struct device_node; * enabling module power and clock; may sleep * @free: optional hook for chip-specific deactivation, such as * disabling module power and clock; may sleep + * @get_direction: returns direction for signal "offset", 0=out, 1=in, + * (same as GPIOF_DIR_XXX), or negative error * @direction_input: configures signal "offset" as input, or returns error * @get: returns value for signal "offset"; for output signals this * returns either the value actually sensed, or zero @@ -100,7 +102,8 @@ struct gpio_chip { unsigned offset); void (*free)(struct gpio_chip *chip, unsigned offset); - + int (*get_direction)(struct gpio_chip *chip, + unsigned offset); int (*direction_input)(struct gpio_chip *chip, unsigned offset); int (*get)(struct gpio_chip *chip, From 529f2ad5e374f61987a8312603963c61d75a890a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 26 Oct 2012 09:59:43 +0300 Subject: [PATCH 11/65] gpiolib: unlock on error in gpio_export() We need to unlock here before returning. Signed-off-by: Dan Carpenter Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e468eed261c5..fd2b71c70997 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -756,7 +756,8 @@ int gpio_export(unsigned gpio, bool direction_may_change) __func__, gpio, test_bit(FLAG_REQUESTED, &desc->flags), test_bit(FLAG_EXPORT, &desc->flags)); - return -EPERM; + status = -EPERM; + goto fail_unlock; } if (!desc->chip->direction_input || !desc->chip->direction_output) From d0235677311cbd404a3dcd3c0f24bf15dd24dd36 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Oct 2012 21:00:09 +0200 Subject: [PATCH 12/65] gpio/tegra: convert to use linear irqdomain The Tegra driver tries to do the work of irq_domain_add_linear() by reserving a bunch of descriptors somewhere and keeping track of the base offset, then calling irq_domain_add_legacy(). Let's stop doing that and simply use the linear IRQ domain. For this to work: use irq_create_mapping() in the IRQ iterator so that the descriptors get allocated here. Cc: Rob Herring Cc: Grant Likely Tested-by: Stephen Warren Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index d982593d7563..c7c175a4aff1 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -380,7 +380,6 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) { const struct of_device_id *match; struct tegra_gpio_soc_config *config; - int irq_base; struct resource *res; struct tegra_gpio_bank *bank; int gpio; @@ -417,14 +416,11 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return -ENODEV; } - irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0); - if (irq_base < 0) { - dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); - return -ENODEV; - } - irq_domain = irq_domain_add_legacy(pdev->dev.of_node, - tegra_gpio_chip.ngpio, irq_base, 0, + irq_domain = irq_domain_add_linear(pdev->dev.of_node, + tegra_gpio_chip.ngpio, &irq_domain_simple_ops, NULL); + if (!irq_domain) + return -ENODEV; for (i = 0; i < tegra_gpio_bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); @@ -464,7 +460,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { - int irq = irq_find_mapping(irq_domain, gpio); + int irq = irq_create_mapping(irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; From ce931f571b6dcf8534e8740e8cd16565cf362536 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Oct 2012 20:21:04 +0200 Subject: [PATCH 13/65] gpio/mvebu: convert to use irq_domain_add_simple() The MVEBU driver probably just wants a few IRQs. Using the simple domain has the upside of allocating IRQ descriptors if need be, especially in a SPARSE_IRQ environment. Cc: Rob Herring Cc: Grant Likely Cc: Thomas Petazzoni Cc: Sebastian Hesselbarth Cc: Andrew Lunn Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 902af437eaf2..e0bde063221f 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -645,8 +645,8 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev) IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); /* Setup irq domain on top of the generic chip. */ - mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio, - mvchip->irqbase, 0, + mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio, + mvchip->irqbase, &irq_domain_simple_ops, mvchip); if (!mvchip->domain) { From 7385500a49b769c95438c111aff92110b06ff751 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Oct 2012 20:15:02 +0200 Subject: [PATCH 14/65] gpio/em: convert to linear IRQ domain The code in the em driver seems to want to try to do the job of the linear IRQ domain (allocate descriptors and grab a virtual range). So why not just use the linear IRQ domain? The code is now cut down so we don't need isolated functions for this. Also note that we use irq_create_mapping() to make sure descriptors are allocated for these IRQs. Also fixed the FIXME to remove the domain after use. Cc: Grant Likely Cc: Magnus Damm Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 46 +++++++----------------------------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index efb4c2d0d132..88bdfe37816f 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -35,7 +35,6 @@ 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; @@ -214,7 +213,7 @@ static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset, static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset) { - return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset); + return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); } static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, @@ -234,40 +233,6 @@ 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 (p->irq_base < 0) { - dev_err(&pdev->dev, "cannot get irq_desc\n"); - return p->irq_base; - } - 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 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; @@ -334,8 +299,11 @@ static int __devinit em_gio_probe(struct platform_device *pdev) 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) { + p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, + pdata->number_of_pins, + &em_gio_irq_domain_ops, p); + if (!p->irq_domain) + err = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); goto err3; } @@ -364,7 +332,7 @@ static int __devinit em_gio_probe(struct platform_device *pdev) err5: free_irq(irq[0]->start, pdev); err4: - em_gio_irq_domain_cleanup(p); + irq_domain_remove(p->irq_domain); err3: iounmap(p->base1); err2: From a362605b341d95e7209ead8052363cb28dda1c44 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Oct 2012 19:43:53 +0200 Subject: [PATCH 15/65] gpio/tc3589x: convert to use the simple irqdomain The special checks for whether we have a base IRQ offset or not is surplus if we use the simple IRQ domain. The IRQ offset zero will be interpreted as a linear domain case. Plus this makes sure we allocate descriptors where need be, or warn if they are preallocated with SPARSE_IRQ. Cc: Grant Likely Cc: Rob Herring Cc: Lee Jones Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tc3589x.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 1e48317e70fb..8c8447c7d2a8 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -292,17 +292,15 @@ static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, { int base = tc3589x_gpio->irq_base; - if (base) { - tc3589x_gpio->domain = irq_domain_add_legacy( - NULL, tc3589x_gpio->chip.ngpio, base, - 0, &tc3589x_irq_ops, tc3589x_gpio); - } - else { - tc3589x_gpio->domain = irq_domain_add_linear( - np, tc3589x_gpio->chip.ngpio, - &tc3589x_irq_ops, tc3589x_gpio); - } - + /* + * If this results in a linear domain, irq_create_mapping() will + * take care of allocating IRQ descriptors at runtime. When a base + * is provided, the IRQ descriptors will be allocated when the + * domain is instantiated. + */ + tc3589x_gpio->domain = irq_domain_add_simple(np, + tc3589x_gpio->chip.ngpio, base, &tc3589x_irq_ops, + tc3589x_gpio); if (!tc3589x_gpio->domain) { dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n"); return -ENOSYS; From 2cad6a8a4c31175578943f087e1dbef9f52e6ec3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 26 Oct 2012 23:15:05 +0800 Subject: [PATCH 16/65] GPIO: clps711x: use platform_device_unregister in gpio_clps711x_init() platform_device_unregister() only calls platform_device_del() and platform_device_put(), thus use platform_device_unregister() to simplify the code. Also the documents in platform.c shows that platform_device_del and platform_device_put must _only_ be externally called in error cases. All other usage is a bug. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Linus Walleij --- drivers/gpio/gpio-clps711x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index ad181db79508..ce63b75b13f5 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -162,8 +162,7 @@ static int __init gpio_clps711x_init(void) GFP_KERNEL); if (!gpio) { dev_err(&pdev->dev, "GPIO allocating memory error\n"); - platform_device_del(pdev); - platform_device_put(pdev); + platform_device_unregister(pdev); return -ENOMEM; } From 1631081993b1e6a6d668b3eb089904b88f0efc2b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 31 Oct 2012 17:03:33 +0800 Subject: [PATCH 17/65] gpio: em: Fix build errors Fix below build errors: CC [M] drivers/gpio/gpio-em.o drivers/gpio/gpio-em.c: In function 'em_gio_probe': drivers/gpio/gpio-em.c:306: error: 'err' undeclared (first use in this function) drivers/gpio/gpio-em.c:306: error: (Each undeclared identifier is reported only once drivers/gpio/gpio-em.c:306: error: for each function it appears in.) drivers/gpio/gpio-em.c:308: error: label 'err3' used but not defined drivers/gpio/gpio-em.c:279: error: label 'err2' used but not defined drivers/gpio/gpio-em.c:265: error: label 'err1' used but not defined drivers/gpio/gpio-em.c:250: error: label 'err0' used but not defined drivers/gpio/gpio-em.c:309: warning: no return statement in function returning non-void drivers/gpio/gpio-em.c: At top level: drivers/gpio/gpio-em.c:311: error: expected identifier or '(' before 'if' drivers/gpio/gpio-em.c:317: error: expected identifier or '(' before 'if' drivers/gpio/gpio-em.c:323: warning: data definition has no type or storage class drivers/gpio/gpio-em.c:323: warning: type defaults to 'int' in declaration of 'ret' drivers/gpio/gpio-em.c:323: error: 'gpio_chip' undeclared here (not in a function) drivers/gpio/gpio-em.c:323: error: initializer element is not constant drivers/gpio/gpio-em.c:324: error: expected identifier or '(' before 'if' drivers/gpio/gpio-em.c:328: error: expected identifier or '(' before 'return' drivers/gpio/gpio-em.c:330: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:332: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:334: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:336: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:338: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:340: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:342: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:344: error: expected identifier or '(' before '}' token drivers/gpio/gpio-em.c: In function 'em_gio_remove': drivers/gpio/gpio-em.c:361: error: implicit declaration of function 'em_gio_irq_domain_cleanup' make[2]: *** [drivers/gpio/gpio-em.o] Error 1 make[1]: *** [drivers/gpio] Error 2 make: *** [drivers] Error 2 Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 88bdfe37816f..b00706329d26 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -302,8 +302,8 @@ static int __devinit em_gio_probe(struct platform_device *pdev) p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, pdata->number_of_pins, &em_gio_irq_domain_ops, p); - if (!p->irq_domain) - err = -ENXIO; + if (!p->irq_domain) { + ret = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); goto err3; } @@ -358,7 +358,7 @@ static int __devexit em_gio_remove(struct platform_device *pdev) free_irq(irq[1]->start, pdev); free_irq(irq[0]->start, pdev); - em_gio_irq_domain_cleanup(p); + irq_domain_remove(p->irq_domain); iounmap(p->base1); iounmap(p->base0); kfree(p); From 5c868fc629b0e645a68aec3a6834d965e71531f4 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 2 Nov 2012 16:02:25 +0100 Subject: [PATCH 18/65] gpio-pch: Set parent dev for gpio chip This will show the gpio chip as a child node under /sys/bus/pci/devices/xxxx:xx:xx.x/ Signed-off-by: Alexander Stein Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 4ad0c4f9171c..e3a14fef79e1 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -215,6 +215,7 @@ static void pch_gpio_setup(struct pch_gpio *chip) struct gpio_chip *gpio = &chip->gpio; gpio->label = dev_name(chip->dev); + gpio->dev = chip->dev; gpio->owner = THIS_MODULE; gpio->direction_input = pch_gpio_direction_input; gpio->get = pch_gpio_get; From 8939ddc76a2f3399be98a60246ae0b365442f008 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 7 Nov 2012 20:31:32 +0530 Subject: [PATCH 19/65] gpio: tegra: fix suspend/resume apis Following are changes done to fix the suspend/resume functionality of tegra gpio driver: - Protect suspend/resume callbacks with CONFIG_PM_SLEEP because CONFIG_PM doesn't actually enable any of the PM callbacks, it only allows to enable CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. This means if CONFIG_PM is used to protect system sleep callbacks then it may end up unreferenced if only runtime PM is enabled. - Fix the suspend/resume APIs declaration as per callback prototype. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index c7c175a4aff1..da32754fb25b 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -64,7 +65,7 @@ struct tegra_gpio_bank { int bank; int irq; spinlock_t lvl_lock[4]; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP u32 cnf[4]; u32 out[4]; u32 oe[4]; @@ -285,8 +286,8 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } -#ifdef CONFIG_PM -void tegra_gpio_resume(void) +#ifdef CONFIG_PM_SLEEP +static int tegra_gpio_resume(struct device *dev) { unsigned long flags; int b; @@ -308,9 +309,10 @@ void tegra_gpio_resume(void) } local_irq_restore(flags); + return 0; } -void tegra_gpio_suspend(void) +static int tegra_gpio_suspend(struct device *dev) { unsigned long flags; int b; @@ -330,6 +332,7 @@ void tegra_gpio_suspend(void) } } local_irq_restore(flags); + return 0; } static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable) @@ -345,11 +348,15 @@ static struct irq_chip tegra_gpio_irq_chip = { .irq_mask = tegra_gpio_irq_mask, .irq_unmask = tegra_gpio_irq_unmask, .irq_set_type = tegra_gpio_irq_set_type, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .irq_set_wake = tegra_gpio_wake_enable, #endif }; +static const struct dev_pm_ops tegra_gpio_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) +}; + struct tegra_gpio_soc_config { u32 bank_stride; u32 upper_offset; @@ -489,6 +496,7 @@ static struct platform_driver tegra_gpio_driver = { .driver = { .name = "tegra-gpio", .owner = THIS_MODULE, + .pm = &tegra_gpio_pm_ops, .of_match_table = tegra_gpio_of_match, }, .probe = tegra_gpio_probe, From 924a09873c658a23e416258c6f81348cba2cfe87 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Nov 2012 10:45:24 +0800 Subject: [PATCH 20/65] gpio: tegra: Staticize non-exported symbols Both tegra_gpio_request() and tegra_gpio_free() are not referenced outside of this file, make them static. Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index da32754fb25b..5ad4ceb14daa 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -118,12 +118,12 @@ static void tegra_gpio_disable(int gpio) } EXPORT_SYMBOL_GPL(tegra_gpio_disable); -int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) { return pinctrl_request_gpio(offset); } -void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) +static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) { pinctrl_free_gpio(offset); tegra_gpio_disable(offset); From 65b6ca466748a8e0a906e40a470e1582bc565d79 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Nov 2012 10:47:02 +0800 Subject: [PATCH 21/65] gpio: tegra: Drop exporting static functions Both tegra_gpio_enable() and tegra_gpio_disable() are static functions, it does not make sense to export them. Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 5ad4ceb14daa..cfd9b723002b 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -110,13 +110,11 @@ static void tegra_gpio_enable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); } -EXPORT_SYMBOL_GPL(tegra_gpio_enable); static void tegra_gpio_disable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); } -EXPORT_SYMBOL_GPL(tegra_gpio_disable); static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) { From 3764bdde1dc2fe53a87db1777440c2532cfccd58 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Nov 2012 10:27:29 +0800 Subject: [PATCH 22/65] gpio: mvebu: Set free callback for gpio_chip We call pinctrl_request_gpio() in request callback, thus we need to call pinctrl_free_gpio() in free callback. Both mvebu_gpio_request() and mvebu_gpio_free() are not referenced outside of this file, make them static. Signed-off-by: Axel Lin Acked-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index e0bde063221f..8b3065703566 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -163,12 +163,12 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) * Functions implementing the gpio_chip methods */ -int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin) +static int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin) { return pinctrl_request_gpio(chip->base + pin); } -void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin) +static void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin) { pinctrl_free_gpio(chip->base + pin); } @@ -518,6 +518,7 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.label = dev_name(&pdev->dev); mvchip->chip.dev = &pdev->dev; mvchip->chip.request = mvebu_gpio_request; + mvchip->chip.free = mvebu_gpio_free; mvchip->chip.direction_input = mvebu_gpio_direction_input; mvchip->chip.get = mvebu_gpio_get; mvchip->chip.direction_output = mvebu_gpio_direction_output; From 1a78958dc212f3698fdc543857af80155cb30f7f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 20:51:54 +0200 Subject: [PATCH 23/65] pinctrl: reserve pins when states are activated This switches the way that pins are reserved for multiplexing: We used to do this when the map was parsed, at the creation of the settings inside the pinctrl handle, in pinmux_map_to_setting(). However this does not work for us, because we want to use the same set of pins with different devices at different times: the current code assumes that the pin groups in a pinmux state will only be used with one single device, albeit different groups can be active at different times. For example if a single I2C driver block is used to drive two different busses located on two pin groups A and B, then the pins for all possible states of a function are reserved when fetching the pinctrl handle: the I2C bus can choose either set A or set B by a mux state at runtime, but all pins in both group A and B (the superset) are effectively reserved for that I2C function and mapped to the device. Another device can never get in and use the pins in group A, even if the device/function is using group B at the moment. Instead: let use reserve the pins when the state is activated and drop them when the state is disabled, i.e. when we move to another state. This way different devices/functions can use the same pins at different times. We know that this is an odd way of doing things, but we really need to switch e.g. an SD-card slot to become a tracing output sink at runtime: we plug in a special "tracing card" then mux the pins that used to be an SD slot around to the tracing unit and push out tracing data there instead of SD-card traffic. As a side effect pinmux_free_setting() is unused but the stubs are kept for future additions of code. Cc: Patrice Chotard Cc: Loic Pallardy Acked-by: Stephen Warren Tested-by: Jean Nicolas Graux Signed-off-by: Linus Walleij --- Documentation/pinctrl.txt | 4 ++- drivers/pinctrl/core.c | 2 ++ drivers/pinctrl/core.h | 2 ++ drivers/pinctrl/pinmux.c | 67 +++++++++++++-------------------------- 4 files changed, 29 insertions(+), 46 deletions(-) diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 3b4ee5328868..a1cd2f9428d7 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -1193,4 +1193,6 @@ foo_switch() ... } -The above has to be done from process context. +The above has to be done from process context. The reservation of the pins +will be done when the state is activated, so in effect one specific pin +can be used by different functions at different times on a running system. diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 2e39c04fc16b..cec6072cd7c1 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -563,6 +563,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map) return -EPROBE_DEFER; } + setting->dev_name = map->dev_name; + switch (map->type) { case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_map_to_setting(map, setting); diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 1f40ff68a8c4..12f5694f3d5d 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -105,12 +105,14 @@ struct pinctrl_setting_configs { * @type: the type of setting * @pctldev: pin control device handling to be programmed. Not used for * PIN_MAP_TYPE_DUMMY_STATE. + * @dev_name: the name of the device using this state * @data: Data specific to the setting type */ struct pinctrl_setting { struct list_head node; enum pinctrl_map_type type; struct pinctrl_dev *pctldev; + const char *dev_name; union { struct pinctrl_setting_mux mux; struct pinctrl_setting_configs configs; diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 9301a7a95eff..0ef01ee2835f 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -314,14 +314,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinmux_ops *pmxops = pctldev->desc->pmxops; - const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; char const * const *groups; unsigned num_groups; int ret; const char *group; int i; - const unsigned *pins; - unsigned num_pins; if (!pmxops) { dev_err(pctldev->dev, "does not support mux function\n"); @@ -376,53 +373,12 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, } setting->data.mux.group = ret; - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins, - &num_pins); - if (ret) { - dev_err(pctldev->dev, - "could not get pins for device %s group selector %d\n", - pinctrl_dev_get_name(pctldev), setting->data.mux.group); - return -ENODEV; - } - - /* Try to allocate all pins in this group, one by one */ - for (i = 0; i < num_pins; i++) { - ret = pin_request(pctldev, pins[i], map->dev_name, NULL); - if (ret) { - dev_err(pctldev->dev, - "could not request pin %d on device %s\n", - pins[i], pinctrl_dev_get_name(pctldev)); - /* On error release all taken pins */ - i--; /* this pin just failed */ - for (; i >= 0; i--) - pin_free(pctldev, pins[i], NULL); - return -ENODEV; - } - } - return 0; } void pinmux_free_setting(struct pinctrl_setting const *setting) { - struct pinctrl_dev *pctldev = setting->pctldev; - const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; - const unsigned *pins; - unsigned num_pins; - int ret; - int i; - - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, - &pins, &num_pins); - if (ret) { - dev_err(pctldev->dev, - "could not get pins for device %s group selector %d\n", - pinctrl_dev_get_name(pctldev), setting->data.mux.group); - return; - } - - for (i = 0; i < num_pins; i++) - pin_free(pctldev, pins[i], NULL); + /* This function is currently unused */ } int pinmux_enable_setting(struct pinctrl_setting const *setting) @@ -446,6 +402,22 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting) num_pins = 0; } + /* Try to allocate all pins in this group, one by one */ + for (i = 0; i < num_pins; i++) { + ret = pin_request(pctldev, pins[i], setting->dev_name, NULL); + if (ret) { + dev_err(pctldev->dev, + "could not request pin %d on device %s\n", + pins[i], pinctrl_dev_get_name(pctldev)); + /* On error release all taken pins */ + i--; /* this pin just failed */ + for (; i >= 0; i--) + pin_free(pctldev, pins[i], NULL); + return -ENODEV; + } + } + + /* Now that we have acquired the pins, encode the mux setting */ for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc == NULL) { @@ -482,6 +454,7 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) num_pins = 0; } + /* Flag the descs that no setting is active */ for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc == NULL) { @@ -493,6 +466,10 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) desc->mux_setting = NULL; } + /* And release the pins */ + for (i = 0; i < num_pins; i++) + pin_free(pctldev, pins[i], NULL); + if (ops->disable) ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group); } From 55d2e40d4acf9081daee5a95d0eb474511408968 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 24 Oct 2012 23:38:56 +0200 Subject: [PATCH 24/65] pinctrl: mvebu: allow plat-orion architectures to use pinctrl-mvebu The mach-kirkwood and mach-dove architectures have not yet been integrated into the mach-mvebu directory, which should ultimately contain the support for all Marvell SoCs from the Engineering Business Unit. However, before this can happen, we need to let mach-kirkwood and mach-dove use the pinctrl-mvebu driver, which supports the kirkwood and dove SoC families. In order to do that, we make this driver available as soon as PLAT_ORION is selected, instead of using ARCH_MVEBU as a condition. In the long term, PLAT_ORION should disappear and be fully replaced by ARCH_MVEBU, but the plan is to make the migration step by step, by first having the existing mach-* directories for Marvell SoCs converge on several infrastructures, including the pinctrl one. Also, like the spear pinctrl driver, we put all pinctrl-mvebu Kconfig options under a if, in order to avoid having certain options (PINCTRL_DOVE, PINCTRL_KIRKWOOD, etc.) selecting an option (PINCTLR_MVEBU) which itself has a dependency (on ARCH_MVEBU). In this a construct, the dependency is in fact ignored due to the selects. Signed-off-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d96caefd914a..2cc8fd929d90 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -188,9 +188,10 @@ config PINCTRL_EXYNOS4 depends on OF && GPIOLIB select PINCTRL_SAMSUNG +if PLAT_ORION + config PINCTRL_MVEBU bool - depends on ARCH_MVEBU select PINMUX select PINCONF @@ -210,6 +211,8 @@ config PINCTRL_ARMADA_XP bool select PINCTRL_MVEBU +endif + source "drivers/pinctrl/spear/Kconfig" config PINCTRL_XWAY From de1d76258f438414633cb92cb1a195ba3835972c Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 24 Oct 2012 23:38:57 +0200 Subject: [PATCH 25/65] pinctrl: mvebu: remove useless include Including the core.h header for the pinctrl subsystem is not necessary, and it is actually causing problems when moving the pinctrl-mvebu drivers into a separate subdirectory. Signed-off-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-mvebu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-mvebu.c b/drivers/pinctrl/pinctrl-mvebu.c index 8e6266c6249a..6c44b7e8964c 100644 --- a/drivers/pinctrl/pinctrl-mvebu.c +++ b/drivers/pinctrl/pinctrl-mvebu.c @@ -24,7 +24,6 @@ #include #include -#include "core.h" #include "pinctrl-mvebu.h" #define MPPS_PER_REG 8 From 06763c741b0a19160482c9b34e5bbc3e50dba79a Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 24 Oct 2012 23:38:58 +0200 Subject: [PATCH 26/65] pinctrl: mvebu: move to its own directory Like the spear platform, the mvebu platform has multiple files: one core file, and then one file per SoC family. More files will be added later, as support for mach-orion5x and mach-mv78xx0 SoCs is added to pinctrl-mvebu. For those reasons, having a separate subdirectory, drivers/pinctrl/mvebu/ makes sense, and it had already been suggested by Linus Wallej when the driver was originally submitted. Signed-off-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 25 +------------------ drivers/pinctrl/Makefile | 6 +---- drivers/pinctrl/mvebu/Kconfig | 24 ++++++++++++++++++ drivers/pinctrl/mvebu/Makefile | 5 ++++ .../pinctrl/{ => mvebu}/pinctrl-armada-370.c | 0 .../pinctrl/{ => mvebu}/pinctrl-armada-xp.c | 0 drivers/pinctrl/{ => mvebu}/pinctrl-dove.c | 0 .../pinctrl/{ => mvebu}/pinctrl-kirkwood.c | 0 drivers/pinctrl/{ => mvebu}/pinctrl-mvebu.c | 0 drivers/pinctrl/{ => mvebu}/pinctrl-mvebu.h | 0 10 files changed, 31 insertions(+), 29 deletions(-) create mode 100644 drivers/pinctrl/mvebu/Kconfig create mode 100644 drivers/pinctrl/mvebu/Makefile rename drivers/pinctrl/{ => mvebu}/pinctrl-armada-370.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-armada-xp.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-dove.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-kirkwood.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-mvebu.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-mvebu.h (100%) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 2cc8fd929d90..011133772d2a 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -188,30 +188,7 @@ config PINCTRL_EXYNOS4 depends on OF && GPIOLIB select PINCTRL_SAMSUNG -if PLAT_ORION - -config PINCTRL_MVEBU - bool - select PINMUX - select PINCONF - -config PINCTRL_DOVE - bool - select PINCTRL_MVEBU - -config PINCTRL_KIRKWOOD - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_370 - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_XP - bool - select PINCTRL_MVEBU - -endif +source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/spear/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f395ba5cec25..3cb6a0a668a8 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -36,12 +36,8 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o -obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o -obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o -obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o -obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o -obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o +obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig new file mode 100644 index 000000000000..366fa541ee91 --- /dev/null +++ b/drivers/pinctrl/mvebu/Kconfig @@ -0,0 +1,24 @@ +if PLAT_ORION + +config PINCTRL_MVEBU + bool + select PINMUX + select PINCONF + +config PINCTRL_DOVE + bool + select PINCTRL_MVEBU + +config PINCTRL_KIRKWOOD + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_370 + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_XP + bool + select PINCTRL_MVEBU + +endif diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile new file mode 100644 index 000000000000..37c253297af0 --- /dev/null +++ b/drivers/pinctrl/mvebu/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o +obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o +obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o +obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o +obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o diff --git a/drivers/pinctrl/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c similarity index 100% rename from drivers/pinctrl/pinctrl-armada-370.c rename to drivers/pinctrl/mvebu/pinctrl-armada-370.c diff --git a/drivers/pinctrl/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c similarity index 100% rename from drivers/pinctrl/pinctrl-armada-xp.c rename to drivers/pinctrl/mvebu/pinctrl-armada-xp.c diff --git a/drivers/pinctrl/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c similarity index 100% rename from drivers/pinctrl/pinctrl-dove.c rename to drivers/pinctrl/mvebu/pinctrl-dove.c diff --git a/drivers/pinctrl/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c similarity index 100% rename from drivers/pinctrl/pinctrl-kirkwood.c rename to drivers/pinctrl/mvebu/pinctrl-kirkwood.c diff --git a/drivers/pinctrl/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c similarity index 100% rename from drivers/pinctrl/pinctrl-mvebu.c rename to drivers/pinctrl/mvebu/pinctrl-mvebu.c diff --git a/drivers/pinctrl/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h similarity index 100% rename from drivers/pinctrl/pinctrl-mvebu.h rename to drivers/pinctrl/mvebu/pinctrl-mvebu.h From d3e26f2fe993b5dbc8b4b2275d77f9ad3e08c81a Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 27 Sep 2012 17:56:30 +0800 Subject: [PATCH 27/65] pinctrl: sirf: enable the driver support new SiRFmarco SoC The driver supports old up SiRFprimaII SoCs, this patch makes it support the new SiRFmarco as well. SiRFmarco, as a SMP SoC, adds new SIRFSOC_GPIO_PAD_EN_CLR registers, to disable GPIO pad, we should write 1 to the corresponding bit in the new CLEAR register instead of writing 0 to SIRFSOC_GPIO_PAD_EN. Signed-off-by: Barry Song Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 4 +-- drivers/pinctrl/pinctrl-sirf.c | 48 ++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 011133772d2a..5f2f9dc43e3b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -143,8 +143,8 @@ config PINCTRL_SINGLE This selects the device tree based generic pinctrl driver. config PINCTRL_SIRF - bool "CSR SiRFprimaII pin controller driver" - depends on ARCH_PRIMA2 + bool "CSR SiRFprimaII/SiRFmarco pin controller driver" + depends on ARCH_SIRF select PINMUX config PINCTRL_TEGRA diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 9ecacf3d0a75..16ec7d4d81ee 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -32,10 +32,10 @@ #define SIRFSOC_NUM_PADS 622 #define SIRFSOC_RSC_PIN_MUX 0x4 -#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) +#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) +#define SIRFSOC_GPIO_PAD_EN_CLR(g) ((g)*0x100 + 0x90) #define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4) #define SIRFSOC_GPIO_DSP_EN0 (0x80) -#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) #define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C) #define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1 @@ -60,6 +60,7 @@ struct sirfsoc_gpio_bank { int id; int parent_irq; spinlock_t lock; + bool is_marco; /* for marco, some registers are different with prima2 */ }; static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS]; @@ -191,6 +192,7 @@ struct sirfsoc_pmx { struct pinctrl_dev *pmx; void __iomem *gpio_virtbase; void __iomem *rsc_virtbase; + bool is_marco; }; /* SIRFSOC_GPIO_PAD_EN set */ @@ -1088,12 +1090,21 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector for (i = 0; i < mux->muxmask_counts; i++) { u32 muxval; - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); - if (enable) - muxval = muxval & ~mask[i].mask; - else - muxval = muxval | mask[i].mask; - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + if (!spmx->is_marco) { + muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + if (enable) + muxval = muxval & ~mask[i].mask; + else + muxval = muxval | mask[i].mask; + writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + } else { + if (enable) + writel(mask[i].mask, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group)); + else + writel(mask[i].mask, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + } } if (mux->funcmask && enable) { @@ -1158,9 +1169,14 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, spmx = pinctrl_dev_get_drvdata(pmxdev); - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); - muxval = muxval | (1 << (offset - range->pin_base)); - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + if (!spmx->is_marco) { + muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + muxval = muxval | (1 << (offset - range->pin_base)); + writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + } else { + writel(1 << (offset - range->pin_base), spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(group)); + } return 0; } @@ -1218,6 +1234,7 @@ static void __iomem *sirfsoc_rsc_of_iomap(void) { const struct of_device_id rsc_ids[] = { { .compatible = "sirf,prima2-rsc" }, + { .compatible = "sirf,marco-rsc" }, {} }; struct device_node *np; @@ -1259,6 +1276,9 @@ static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev) goto out_no_rsc_remap; } + if (of_device_is_compatible(np, "sirf,marco-pinctrl")) + spmx->is_marco = 1; + /* Now register the pin controller and all pins it handles */ spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx); if (!spmx->pmx) { @@ -1287,6 +1307,7 @@ static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev) static const struct of_device_id pinmux_ids[] __devinitconst = { { .compatible = "sirf,prima2-pinctrl" }, + { .compatible = "sirf,marco-pinctrl" }, {} }; @@ -1648,6 +1669,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) struct sirfsoc_gpio_bank *bank; void *regs; struct platform_device *pdev; + bool is_marco = false; pdev = of_find_device_by_node(np); if (!pdev) @@ -1657,6 +1679,9 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) if (!regs) return -ENOMEM; + if (of_device_is_compatible(np, "sirf,marco-pinctrl")) + is_marco = 1; + for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { bank = &sgpio_bank[i]; spin_lock_init(&bank->lock); @@ -1673,6 +1698,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) bank->chip.gc.of_node = np; bank->chip.regs = regs; bank->id = i; + bank->is_marco = is_marco; bank->parent_irq = platform_get_irq(pdev, i); if (bank->parent_irq < 0) { err = bank->parent_irq; From afa538c2bf00cf6cd28fc6b5fcea1a75894228a0 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 2 Nov 2012 21:46:13 +0800 Subject: [PATCH 28/65] pinctrl: exynos: Add terminating entry for of_device_id table The of_device_id table is supposed to be zero-terminated. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-exynos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 21362f48d370..6ff665209a4c 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -36,6 +36,7 @@ /* list of external wakeup controllers supported */ static const struct of_device_id exynos_wkup_irq_ids[] = { { .compatible = "samsung,exynos4210-wakeup-eint", }, + { } }; static void exynos_gpio_irq_unmask(struct irq_data *irqd) From 7e10ee68f8ccc62e0934ff02f39ce541f3879844 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 27 Oct 2012 15:21:35 +0530 Subject: [PATCH 29/65] Revert "pinctrl: remove pinctrl_remove_gpio_range" This reverts earlier commit which removed pinctrl_remove_gpio_range(), because at that time there weren't any more users of that routine. It was removed as the removal of ranges was done in unregister of pinctrl. But as we are now registering stuff from gpiolib, we may remove and insert a gpio module multiple times. So, we need this routine again. Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 14 ++++++++++++++ include/linux/pinctrl/pinctrl.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index cec6072cd7c1..b1086dcde15d 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -345,6 +345,20 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges); +/** + * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller + * @pctldev: pin controller device to remove the range from + * @range: the GPIO range to remove + */ +void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range) +{ + mutex_lock(&pinctrl_mutex); + list_del(&range->node); + mutex_unlock(&pinctrl_mutex); +} +EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range); + /** * pinctrl_get_group_selector() - returns the group selector for a group * @pctldev: the pin controller handling the group diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index 7d087f03e91e..eda04674633d 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -134,6 +134,8 @@ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev, extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *ranges, unsigned nranges); +extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range); extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev); extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev); #else From f23f1516b6757c326cc638bed8c402c77e2a596e Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Sat, 27 Oct 2012 15:21:36 +0530 Subject: [PATCH 30/65] gpiolib: provide provision to register pin ranges pinctrl subsystem needs gpio chip base to prepare set of gpio pin ranges, which a given pinctrl driver can handle. This is important to handle pinctrl gpio request calls in order to program a given pin properly for gpio operation. As gpio base is allocated dynamically during gpiochip registration, presently there exists no clean way to pass this information to the pinctrl subsystem. After few discussions from [1], it was concluded that may be gpio controller reporting the pin range it supports, is a better way than pinctrl subsystem directly registering it. [1] http://comments.gmane.org/gmane.linux.ports.arm.kernel/184816 Cc: Grant Likely Signed-off-by: Viresh Kumar Signed-off-by: Shiraz Hashim [Edited documentation a bit] Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio.txt | 36 ++++++++++++ Documentation/gpio.txt | 42 ++++++++++++++ Documentation/pinctrl.txt | 3 + drivers/gpio/gpiolib-of.c | 56 +++++++++++++++++++ drivers/gpio/gpiolib.c | 43 ++++++++++++++ drivers/pinctrl/core.c | 13 +++++ drivers/pinctrl/devicetree.c | 13 +++++ include/asm-generic/gpio.h | 25 +++++++++ include/linux/gpio.h | 3 + include/linux/pinctrl/pinctrl.h | 17 ++++++ 10 files changed, 251 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index 4e16ba4feab0..a33628759d36 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -75,4 +75,40 @@ Example of two SOC GPIO banks defined as gpio-controller nodes: gpio-controller; }; +2.1) gpio-controller and pinctrl subsystem +------------------------------------------ +gpio-controller on a SOC might be tightly coupled with the pinctrl +subsystem, in the sense that the pins can be used by other functions +together with optional gpio feature. + +While the pin allocation is totally managed by the pin ctrl subsystem, +gpio (under gpiolib) is still maintained by gpio drivers. It may happen +that different pin ranges in a SoC is managed by different gpio drivers. + +This makes it logical to let gpio drivers announce their pin ranges to +the pin ctrl subsystem and call 'pinctrl_request_gpio' in order to +request the corresponding pin before any gpio usage. + +For this, the gpio controller can use a pinctrl phandle and pins to +announce the pinrange to the pin ctrl subsystem. For example, + + qe_pio_e: gpio-controller@1460 { + #gpio-cells = <2>; + compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank"; + reg = <0x1460 0x18>; + gpio-controller; + gpio-ranges = <&pinctrl1 20 10>, <&pinctrl2 50 20>; + + } + +where, + &pinctrl1 and &pinctrl2 is the phandle to the pinctrl DT node. + + Next values specify the base pin and number of pins for the range + handled by 'qe_pio_e' gpio. In the given example from base pin 20 to + pin 29 under pinctrl1 and pin 50 to pin 69 under pinctrl2 is handled + by this gpio controller. + +The pinctrl node must have "#gpio-range-cells" property to show number of +arguments to pass with phandle from gpio controllers node. diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index e08a883de36e..77a1d11af723 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -439,6 +439,48 @@ slower clock delays the rising edge of SCK, and the I2C master adjusts its signaling rate accordingly. +GPIO controllers and the pinctrl subsystem +------------------------------------------ + +A GPIO controller on a SOC might be tightly coupled with the pinctrl +subsystem, in the sense that the pins can be used by other functions +together with an optional gpio feature. We have already covered the +case where e.g. a GPIO controller need to reserve a pin or set the +direction of a pin by calling any of: + +pinctrl_request_gpio() +pinctrl_free_gpio() +pinctrl_gpio_direction_input() +pinctrl_gpio_direction_output() + +But how does the pin control subsystem cross-correlate the GPIO +numbers (which are a global business) to a certain pin on a certain +pin controller? + +This is done by registering "ranges" of pins, which are essentially +cross-reference tables. These are described in +Documentation/pinctrl.txt + +While the pin allocation is totally managed by the pinctrl subsystem, +gpio (under gpiolib) is still maintained by gpio drivers. It may happen +that different pin ranges in a SoC is managed by different gpio drivers. + +This makes it logical to let gpio drivers announce their pin ranges to +the pin ctrl subsystem before it will call 'pinctrl_request_gpio' in order +to request the corresponding pin to be prepared by the pinctrl subsystem +before any gpio usage. + +For this, the gpio controller can register its pin range with pinctrl +subsystem. There are two ways of doing it currently: with or without DT. + +For with DT support refer to Documentation/devicetree/bindings/gpio/gpio.txt. + +For non-DT support, user can call gpiochip_add_pin_range() with appropriate +parameters to register a range of gpio pins with a pinctrl driver. For this +exact name string of pinctrl device has to be passed as one of the +argument to this routine. + + What do these conventions omit? =============================== One of the biggest things these conventions omit is pin multiplexing, since diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index a1cd2f9428d7..da40efbef6ec 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -364,6 +364,9 @@ will get an pin number into its handled number range. Further it is also passed the range ID value, so that the pin controller knows which range it should deal with. +Calling pinctrl_add_gpio_range from pinctrl driver is DEPRECATED. Please see +section 2.1 of Documentation/devicetree/bindings/gpio/gpio.txt on how to bind +pinctrl and gpio drivers. PINMUX interfaces ================= diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index f1a45997aea8..a5b90c8e9844 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -19,6 +19,7 @@ #include #include #include +#include #include /* Private data structure for of_gpiochip_find_and_xlate */ @@ -216,6 +217,58 @@ int of_mm_gpiochip_add(struct device_node *np, } EXPORT_SYMBOL(of_mm_gpiochip_add); +#ifdef CONFIG_PINCTRL +void of_gpiochip_add_pin_range(struct gpio_chip *chip) +{ + struct device_node *np = chip->of_node; + struct gpio_pin_range *pin_range; + struct of_phandle_args pinspec; + int index = 0, ret; + + if (!np) + return; + + do { + ret = of_parse_phandle_with_args(np, "gpio-ranges", + "#gpio-range-cells", index, &pinspec); + if (ret) + break; + + pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), + GFP_KERNEL); + if (!pin_range) { + pr_err("%s: GPIO chip: failed to allocate pin ranges\n", + chip->label); + break; + } + + pin_range->range.name = chip->label; + pin_range->range.base = chip->base; + pin_range->range.pin_base = pinspec.args[0]; + pin_range->range.npins = pinspec.args[1]; + pin_range->pctldev = of_pinctrl_add_gpio_range(pinspec.np, + &pin_range->range); + + list_add_tail(&pin_range->node, &chip->pin_ranges); + + } while (index++); +} + +void of_gpiochip_remove_pin_range(struct gpio_chip *chip) +{ + struct gpio_pin_range *pin_range, *tmp; + + list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) { + list_del(&pin_range->node); + pinctrl_remove_gpio_range(pin_range->pctldev, + &pin_range->range); + } +} +#else +void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} +void of_gpiochip_remove_pin_range(struct gpio_chip *chip) {} +#endif + void of_gpiochip_add(struct gpio_chip *chip) { if ((!chip->of_node) && (chip->dev)) @@ -229,11 +282,14 @@ void of_gpiochip_add(struct gpio_chip *chip) chip->of_xlate = of_gpio_simple_xlate; } + of_gpiochip_add_pin_range(chip); of_node_get(chip->of_node); } void of_gpiochip_remove(struct gpio_chip *chip) { + of_gpiochip_remove_pin_range(chip); + if (chip->of_node) of_node_put(chip->of_node); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1c8d9e3380e1..f0b07bbfcc9a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1083,6 +1083,10 @@ int gpiochip_add(struct gpio_chip *chip) } } +#ifdef CONFIG_PINCTRL + INIT_LIST_HEAD(&chip->pin_ranges); +#endif + of_gpiochip_add(chip); unlock: @@ -1180,6 +1184,45 @@ struct gpio_chip *gpiochip_find(void *data, } EXPORT_SYMBOL_GPL(gpiochip_find); +#ifdef CONFIG_PINCTRL +void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) +{ + struct gpio_pin_range *pin_range; + + pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), GFP_KERNEL); + if (!pin_range) { + pr_err("%s: GPIO chip: failed to allocate pin ranges\n", + chip->label); + return; + } + + pin_range->range.name = chip->label; + pin_range->range.base = chip->base; + pin_range->range.pin_base = pin_base; + pin_range->range.npins = npins; + pin_range->pctldev = find_pinctrl_and_add_gpio_range(pinctl_name, + &pin_range->range); + + list_add_tail(&pin_range->node, &chip->pin_ranges); +} + +void gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ + struct gpio_pin_range *pin_range, *tmp; + + list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) { + list_del(&pin_range->node); + pinctrl_remove_gpio_range(pin_range->pctldev, + &pin_range->range); + } +} +#else +void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) {} +void gpiochip_remove_pin_ranges(struct gpio_chip *chip) {} +#endif + /* These "optional" allocation calls help prevent drivers from stomping * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index b1086dcde15d..71db586b2afd 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -345,6 +345,19 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges); +struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname, + struct pinctrl_gpio_range *range) +{ + struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname); + + if (!pctldev) + return NULL; + + pinctrl_add_gpio_range(pctldev, range); + return pctldev; +} +EXPORT_SYMBOL_GPL(find_pinctrl_and_add_gpio_range); + /** * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller * @pctldev: pin controller device to remove the range from diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index fcb1de45473c..6728ec71cb65 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -106,6 +106,19 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np) return NULL; } +struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, + struct pinctrl_gpio_range *range) +{ + struct pinctrl_dev *pctldev; + + pctldev = find_pinctrl_by_of_node(np); + if (!pctldev) + return NULL; + + pinctrl_add_gpio_range(pctldev, range); + return pctldev; +} + static int dt_to_map_one_config(struct pinctrl *p, const char *statename, struct device_node *np_config) { diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a9432fc6b8ba..92e5c432421c 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef CONFIG_GPIOLIB @@ -47,6 +48,21 @@ struct seq_file; struct module; struct device_node; +#ifdef CONFIG_PINCTRL +/** + * struct gpio_pin_range - pin range controlled by a gpio chip + * @head: list for maintaining set of pin ranges, used internally + * @pctldev: pinctrl device which handles corresponding pins + * @range: actual range of pins controlled by a gpio controller + */ + +struct gpio_pin_range { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_gpio_range range; +}; +#endif + /** * struct gpio_chip - abstract a GPIO controller * @label: for diagnostics @@ -134,6 +150,15 @@ struct gpio_chip { int (*of_xlate)(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags); #endif +#ifdef CONFIG_PINCTRL + /* + * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally + * describe the actual pin range which they serve in an SoC. This + * information would be used by pinctrl subsystem to configure + * corresponding pins for gpio usage. + */ + struct list_head pin_ranges; +#endif }; extern const char *gpiochip_is_requested(struct gpio_chip *chip, diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 2e31e8b3a190..a28445992b7f 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -231,6 +231,9 @@ static inline int irq_to_gpio(unsigned irq) return -EINVAL; } +void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins); +void gpiochip_remove_pin_ranges(struct gpio_chip *chip); #endif #endif /* __LINUX_GPIO_H */ diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index eda04674633d..434e5a94e131 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -136,6 +136,23 @@ extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, unsigned nranges); extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range); + +extern struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname, + struct pinctrl_gpio_range *range); + +#ifdef CONFIG_OF +extern struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, + struct pinctrl_gpio_range *range); +#else +static inline +struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, + struct pinctrl_gpio_range *range) +{ + return NULL; +} + +#endif /* CONFIG_OF */ + extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev); extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev); #else From 604bb7da77803cc01366c85fd5bcbc88b6dbe33a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 27 Oct 2012 15:21:37 +0530 Subject: [PATCH 31/65] pinctrl: SPEAr: Add plgpio driver Most of SPEAr SoCs, which support pinctrl, can configure & use pads as gpio. This patch adds plgpio driver for configuring these pads as gpio. Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/pinctrl/spear/Kconfig | 7 + drivers/pinctrl/spear/Makefile | 1 + drivers/pinctrl/spear/pinctrl-plgpio.c | 746 +++++++++++++++++++++++++ 3 files changed, 754 insertions(+) create mode 100644 drivers/pinctrl/spear/pinctrl-plgpio.c diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig index 91558791e766..6f9a1e8bf575 100644 --- a/drivers/pinctrl/spear/Kconfig +++ b/drivers/pinctrl/spear/Kconfig @@ -41,4 +41,11 @@ config PINCTRL_SPEAR1340 depends on MACH_SPEAR1340 select PINCTRL_SPEAR +config PINCTRL_SPEAR_PLGPIO + bool "SPEAr SoC PLGPIO Controller" + depends on GPIOLIB && PINCTRL_SPEAR + help + Say yes here to support PLGPIO controller on ST Microelectronics SPEAr + SoCs. + endif diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile index b28a7ba22443..0e400ebeb8ff 100644 --- a/drivers/pinctrl/spear/Makefile +++ b/drivers/pinctrl/spear/Makefile @@ -1,5 +1,6 @@ # SPEAr pinmux support +obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO) += pinctrl-plgpio.o obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c new file mode 100644 index 000000000000..1044ad3f3c86 --- /dev/null +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -0,0 +1,746 @@ +/* + * SPEAr platform PLGPIO driver + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_GPIO_PER_REG 32 +#define PIN_OFFSET(pin) (pin % MAX_GPIO_PER_REG) +#define REG_OFFSET(base, reg, pin) (base + reg + (pin / MAX_GPIO_PER_REG) \ + * sizeof(int *)) + +/* + * plgpio pins in all machines are not one to one mapped, bitwise with registers + * bits. These set of macros define register masks for which below functions + * (pin_to_offset and offset_to_pin) are required to be called. + */ +#define PTO_ENB_REG 0x001 +#define PTO_WDATA_REG 0x002 +#define PTO_DIR_REG 0x004 +#define PTO_IE_REG 0x008 +#define PTO_RDATA_REG 0x010 +#define PTO_MIS_REG 0x020 + +struct plgpio_regs { + u32 enb; /* enable register */ + u32 wdata; /* write data register */ + u32 dir; /* direction set register */ + u32 rdata; /* read data register */ + u32 ie; /* interrupt enable register */ + u32 mis; /* mask interrupt status register */ + u32 eit; /* edge interrupt type */ +}; + +/* + * struct plgpio: plgpio driver specific structure + * + * lock: lock for guarding gpio registers + * base: base address of plgpio block + * irq_base: irq number of plgpio0 + * chip: gpio framework specific chip information structure + * p2o: function ptr for pin to offset conversion. This is required only for + * machines where mapping b/w pin and offset is not 1-to-1. + * o2p: function ptr for offset to pin conversion. This is required only for + * machines where mapping b/w pin and offset is not 1-to-1. + * p2o_regs: mask of registers for which p2o and o2p are applicable + * regs: register offsets + * csave_regs: context save registers for standby/sleep/hibernate cases + */ +struct plgpio { + spinlock_t lock; + void __iomem *base; + struct clk *clk; + unsigned irq_base; + struct irq_domain *irq_domain; + struct gpio_chip chip; + int (*p2o)(int pin); /* pin_to_offset */ + int (*o2p)(int offset); /* offset_to_pin */ + u32 p2o_regs; + struct plgpio_regs regs; +#ifdef CONFIG_PM + struct plgpio_regs *csave_regs; +#endif +}; + +/* register manipulation inline functions */ +static inline u32 is_plgpio_set(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + return !!(val & (1 << offset)); +} + +static inline void plgpio_reg_set(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + writel_relaxed(val | (1 << offset), reg_off); +} + +static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + writel_relaxed(val & ~(1 << offset), reg_off); +} + +/* gpio framework specific routines */ +static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_DIR_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return -EINVAL; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.dir); + spin_unlock_irqrestore(&plgpio->lock, flags); + + return 0; +} + +static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + unsigned long flags; + unsigned dir_offset = offset, wdata_offset = offset, tmp; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & (PTO_DIR_REG | PTO_WDATA_REG))) { + tmp = plgpio->p2o(offset); + if (tmp == -1) + return -EINVAL; + + if (plgpio->p2o_regs & PTO_DIR_REG) + dir_offset = tmp; + if (plgpio->p2o_regs & PTO_WDATA_REG) + wdata_offset = tmp; + } + + spin_lock_irqsave(&plgpio->lock, flags); + if (value) + plgpio_reg_set(plgpio->base, wdata_offset, + plgpio->regs.wdata); + else + plgpio_reg_reset(plgpio->base, wdata_offset, + plgpio->regs.wdata); + + plgpio_reg_reset(plgpio->base, dir_offset, plgpio->regs.dir); + spin_unlock_irqrestore(&plgpio->lock, flags); + + return 0; +} + +static int plgpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (offset >= chip->ngpio) + return -EINVAL; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_RDATA_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return -EINVAL; + } + + return is_plgpio_set(plgpio->base, offset, plgpio->regs.rdata); +} + +static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (offset >= chip->ngpio) + return; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_WDATA_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + if (value) + plgpio_reg_set(plgpio->base, offset, plgpio->regs.wdata); + else + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.wdata); +} + +static int plgpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + int gpio = chip->base + offset; + unsigned long flags; + int ret = 0; + + if (offset >= chip->ngpio) + return -EINVAL; + + ret = pinctrl_request_gpio(gpio); + if (ret) + return ret; + + if (!IS_ERR(plgpio->clk)) { + ret = clk_prepare_enable(plgpio->clk); + if (ret) + goto err0; + } + + if (plgpio->regs.enb == -1) + return 0; + + /* + * put gpio in IN mode before enabling it. This make enabling gpio safe + */ + ret = plgpio_direction_input(chip, offset); + if (ret) + goto err1; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) { + ret = -EINVAL; + goto err1; + } + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.enb); + spin_unlock_irqrestore(&plgpio->lock, flags); + return 0; + +err1: + clk_disable_unprepare(plgpio->clk); +err0: + pinctrl_free_gpio(gpio); + return ret; +} + +static void plgpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + int gpio = chip->base + offset; + unsigned long flags; + + if (offset >= chip->ngpio) + return; + + if (plgpio->regs.enb == -1) + goto disable_clk; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.enb); + spin_unlock_irqrestore(&plgpio->lock, flags); + +disable_clk: + if (!IS_ERR(plgpio->clk)) + clk_disable_unprepare(plgpio->clk); + + pinctrl_free_gpio(gpio); +} + +static int plgpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (plgpio->irq_base < 0) + return -EINVAL; + + return irq_find_mapping(plgpio->irq_domain, offset); +} + +/* PLGPIO IRQ */ +static void plgpio_irq_disable(struct irq_data *d) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.ie); + spin_unlock_irqrestore(&plgpio->lock, flags); +} + +static void plgpio_irq_enable(struct irq_data *d) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.ie); + spin_unlock_irqrestore(&plgpio->lock, flags); +} + +static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + void __iomem *reg_off; + unsigned int supported_type = 0, val; + + if (offset >= plgpio->chip.ngpio) + return -EINVAL; + + if (plgpio->regs.eit == -1) + supported_type = IRQ_TYPE_LEVEL_HIGH; + else + supported_type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + + if (!(trigger & supported_type)) + return -EINVAL; + + if (plgpio->regs.eit == -1) + return 0; + + reg_off = REG_OFFSET(plgpio->base, plgpio->regs.eit, offset); + val = readl_relaxed(reg_off); + + offset = PIN_OFFSET(offset); + if (trigger & IRQ_TYPE_EDGE_RISING) + writel_relaxed(val | (1 << offset), reg_off); + else + writel_relaxed(val & ~(1 << offset), reg_off); + + return 0; +} + +static struct irq_chip plgpio_irqchip = { + .name = "PLGPIO", + .irq_enable = plgpio_irq_enable, + .irq_disable = plgpio_irq_disable, + .irq_set_type = plgpio_irq_set_type, +}; + +static void plgpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct plgpio *plgpio = irq_get_handler_data(irq); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + int regs_count, count, pin, offset, i = 0; + unsigned long pending; + + count = plgpio->chip.ngpio; + regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG); + + chained_irq_enter(irqchip, desc); + /* check all plgpio MIS registers for a possible interrupt */ + for (; i < regs_count; i++) { + pending = readl_relaxed(plgpio->base + plgpio->regs.mis + + i * sizeof(int *)); + if (!pending) + continue; + + /* clear interrupts */ + writel_relaxed(~pending, plgpio->base + plgpio->regs.mis + + i * sizeof(int *)); + /* + * clear extra bits in last register having gpios < MAX/REG + * ex: Suppose there are max 102 plgpios. then last register + * must have only (102 - MAX_GPIO_PER_REG * 3) = 6 relevant bits + * so, we must not take other 28 bits into consideration for + * checking interrupt. so clear those bits. + */ + count = count - i * MAX_GPIO_PER_REG; + if (count < MAX_GPIO_PER_REG) + pending &= (1 << count) - 1; + + for_each_set_bit(offset, &pending, MAX_GPIO_PER_REG) { + /* get correct pin for "offset" */ + if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) { + pin = plgpio->o2p(offset); + if (pin == -1) + continue; + } else + pin = offset; + + /* get correct irq line number */ + pin = i * MAX_GPIO_PER_REG + pin; + generic_handle_irq(plgpio_to_irq(&plgpio->chip, pin)); + } + } + chained_irq_exit(irqchip, desc); +} + +/* + * pin to offset and offset to pin converter functions + * + * In spear310 there is inconsistency among bit positions in plgpio regiseters, + * for different plgpio pins. For example: for pin 27, bit offset is 23, pin + * 28-33 are not supported, pin 95 has offset bit 95, bit 100 has offset bit 1 + */ +static int spear310_p2o(int pin) +{ + int offset = pin; + + if (pin <= 27) + offset += 4; + else if (pin <= 33) + offset = -1; + else if (pin <= 97) + offset -= 2; + else if (pin <= 101) + offset = 101 - pin; + else + offset = -1; + + return offset; +} + +int spear310_o2p(int offset) +{ + if (offset <= 3) + return 101 - offset; + else if (offset <= 31) + return offset - 4; + else + return offset + 2; +} + +static int __devinit plgpio_probe_dt(struct platform_device *pdev, + struct plgpio *plgpio) +{ + struct device_node *np = pdev->dev.of_node; + int ret = -EINVAL; + u32 val; + + if (of_machine_is_compatible("st,spear310")) { + plgpio->p2o = spear310_p2o; + plgpio->o2p = spear310_o2p; + plgpio->p2o_regs = PTO_WDATA_REG | PTO_DIR_REG | PTO_IE_REG | + PTO_RDATA_REG | PTO_MIS_REG; + } + + if (!of_property_read_u32(np, "st-plgpio,ngpio", &val)) { + plgpio->chip.ngpio = val; + } else { + dev_err(&pdev->dev, "DT: Invalid ngpio field\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,enb-reg", &val)) + plgpio->regs.enb = val; + else + plgpio->regs.enb = -1; + + if (!of_property_read_u32(np, "st-plgpio,wdata-reg", &val)) { + plgpio->regs.wdata = val; + } else { + dev_err(&pdev->dev, "DT: Invalid wdata reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,dir-reg", &val)) { + plgpio->regs.dir = val; + } else { + dev_err(&pdev->dev, "DT: Invalid dir reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,ie-reg", &val)) { + plgpio->regs.ie = val; + } else { + dev_err(&pdev->dev, "DT: Invalid ie reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,rdata-reg", &val)) { + plgpio->regs.rdata = val; + } else { + dev_err(&pdev->dev, "DT: Invalid rdata reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,mis-reg", &val)) { + plgpio->regs.mis = val; + } else { + dev_err(&pdev->dev, "DT: Invalid mis reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,eit-reg", &val)) + plgpio->regs.eit = val; + else + plgpio->regs.eit = -1; + + return 0; + +end: + return ret; +} +static int __devinit plgpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct plgpio *plgpio; + struct resource *res; + int ret, irq, i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n"); + return -EBUSY; + } + + plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL); + if (!plgpio) { + dev_err(&pdev->dev, "memory allocation fail\n"); + return -ENOMEM; + } + + plgpio->base = devm_request_and_ioremap(&pdev->dev, res); + if (!plgpio->base) { + dev_err(&pdev->dev, "request and ioremap fail\n"); + return -ENOMEM; + } + + ret = plgpio_probe_dt(pdev, plgpio); + if (ret) { + dev_err(&pdev->dev, "DT probe failed\n"); + return ret; + } + + plgpio->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(plgpio->clk)) + dev_warn(&pdev->dev, "clk_get() failed, work without it\n"); + +#ifdef CONFIG_PM + plgpio->csave_regs = devm_kzalloc(&pdev->dev, + sizeof(*plgpio->csave_regs) * + DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG), + GFP_KERNEL); + if (!plgpio->csave_regs) { + dev_err(&pdev->dev, "csave registers memory allocation fail\n"); + return -ENOMEM; + } +#endif + + platform_set_drvdata(pdev, plgpio); + spin_lock_init(&plgpio->lock); + + plgpio->irq_base = -1; + plgpio->chip.base = -1; + plgpio->chip.request = plgpio_request; + plgpio->chip.free = plgpio_free; + plgpio->chip.direction_input = plgpio_direction_input; + plgpio->chip.direction_output = plgpio_direction_output; + plgpio->chip.get = plgpio_get_value; + plgpio->chip.set = plgpio_set_value; + plgpio->chip.to_irq = plgpio_to_irq; + plgpio->chip.label = dev_name(&pdev->dev); + plgpio->chip.dev = &pdev->dev; + plgpio->chip.owner = THIS_MODULE; + + ret = gpiochip_add(&plgpio->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpio chip\n"); + return ret; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_info(&pdev->dev, "irqs not supported\n"); + return 0; + } + + plgpio->irq_base = irq_alloc_descs(-1, 0, plgpio->chip.ngpio, 0); + if (IS_ERR_VALUE(plgpio->irq_base)) { + /* we would not support irq for gpio */ + dev_warn(&pdev->dev, "couldn't allocate irq base\n"); + return 0; + } + + plgpio->irq_domain = irq_domain_add_legacy(np, plgpio->chip.ngpio, + plgpio->irq_base, 0, &irq_domain_simple_ops, NULL); + if (WARN_ON(!plgpio->irq_domain)) { + dev_err(&pdev->dev, "irq domain init failed\n"); + irq_free_descs(plgpio->irq_base, plgpio->chip.ngpio); + ret = -ENXIO; + goto remove_gpiochip; + } + + irq_set_chained_handler(irq, plgpio_irq_handler); + for (i = 0; i < plgpio->chip.ngpio; i++) { + irq_set_chip_and_handler(i + plgpio->irq_base, &plgpio_irqchip, + handle_simple_irq); + set_irq_flags(i + plgpio->irq_base, IRQF_VALID); + irq_set_chip_data(i + plgpio->irq_base, plgpio); + } + + irq_set_handler_data(irq, plgpio); + dev_info(&pdev->dev, "PLGPIO registered with IRQs\n"); + + return 0; + +remove_gpiochip: + dev_info(&pdev->dev, "Remove gpiochip\n"); + if (gpiochip_remove(&plgpio->chip)) + dev_err(&pdev->dev, "unable to remove gpiochip\n"); + + return ret; +} + +#ifdef CONFIG_PM +static int plgpio_suspend(struct device *dev) +{ + struct plgpio *plgpio = dev_get_drvdata(dev); + int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); + void __iomem *off; + + for (i = 0; i < reg_count; i++) { + off = plgpio->base + i * sizeof(int *); + + if (plgpio->regs.enb != -1) + plgpio->csave_regs[i].enb = + readl_relaxed(plgpio->regs.enb + off); + if (plgpio->regs.eit != -1) + plgpio->csave_regs[i].eit = + readl_relaxed(plgpio->regs.eit + off); + plgpio->csave_regs[i].wdata = readl_relaxed(plgpio->regs.wdata + + off); + plgpio->csave_regs[i].dir = readl_relaxed(plgpio->regs.dir + + off); + plgpio->csave_regs[i].ie = readl_relaxed(plgpio->regs.ie + off); + } + + return 0; +} + +/* + * This is used to correct the values in end registers. End registers contain + * extra bits that might be used for other purpose in platform. So, we shouldn't + * overwrite these bits. This macro, reads given register again, preserves other + * bit values (non-plgpio bits), and retain captured value (plgpio bits). + */ +#define plgpio_prepare_reg(__reg, _off, _mask, _tmp) \ +{ \ + _tmp = readl_relaxed(plgpio->regs.__reg + _off); \ + _tmp &= ~_mask; \ + plgpio->csave_regs[i].__reg = \ + _tmp | (plgpio->csave_regs[i].__reg & _mask); \ +} + +static int plgpio_resume(struct device *dev) +{ + struct plgpio *plgpio = dev_get_drvdata(dev); + int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); + void __iomem *off; + u32 mask, tmp; + + for (i = 0; i < reg_count; i++) { + off = plgpio->base + i * sizeof(int *); + + if (i == reg_count - 1) { + mask = (1 << (plgpio->chip.ngpio - i * + MAX_GPIO_PER_REG)) - 1; + + if (plgpio->regs.enb != -1) + plgpio_prepare_reg(enb, off, mask, tmp); + + if (plgpio->regs.eit != -1) + plgpio_prepare_reg(eit, off, mask, tmp); + + plgpio_prepare_reg(wdata, off, mask, tmp); + plgpio_prepare_reg(dir, off, mask, tmp); + plgpio_prepare_reg(ie, off, mask, tmp); + } + + writel_relaxed(plgpio->csave_regs[i].wdata, plgpio->regs.wdata + + off); + writel_relaxed(plgpio->csave_regs[i].dir, plgpio->regs.dir + + off); + + if (plgpio->regs.eit != -1) + writel_relaxed(plgpio->csave_regs[i].eit, + plgpio->regs.eit + off); + + writel_relaxed(plgpio->csave_regs[i].ie, plgpio->regs.ie + off); + + if (plgpio->regs.enb != -1) + writel_relaxed(plgpio->csave_regs[i].enb, + plgpio->regs.enb + off); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(plgpio_dev_pm_ops, plgpio_suspend, plgpio_resume); + +static const struct of_device_id plgpio_of_match[] = { + { .compatible = "st,spear-plgpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, plgpio_of_match); + +static struct platform_driver plgpio_driver = { + .probe = plgpio_probe, + .driver = { + .owner = THIS_MODULE, + .name = "spear-plgpio", + .pm = &plgpio_dev_pm_ops, + .of_match_table = of_match_ptr(plgpio_of_match), + }, +}; + +static int __init plgpio_init(void) +{ + return platform_driver_register(&plgpio_driver); +} +subsys_initcall(plgpio_init); + +MODULE_AUTHOR("Viresh Kumar "); +MODULE_DESCRIPTION("ST Microlectronics SPEAr PLGPIO driver"); +MODULE_LICENSE("GPL"); From d4a31ee8997b2fbd82837182363cf8fa84abf347 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 13:16:46 +0200 Subject: [PATCH 32/65] ARM: U300: bump IRQs to offset 32 The U300 IRQs were bumped once to offset to 1 (in order to avoid using IRQ 0 which is now NO_IRQ). This was OK as we were still passing the number of irqs in the .nr_irqs field of the machine, with descriptors allocated at boot time. However .nr_irqs should be 0, leading the system to reserve the first 16 IRQs. Then the VIC driver will complain that IRQs 1 thru 15 are pre-allocated, so to avoid this and use free descriptors, move all IRQs up to offset 32. This will all be done away with as we migrate to device tree, so it is an interim solution. Acked-by: Olof Johansson Signed-off-by: Linus Walleij --- arch/arm/mach-u300/core.c | 2 +- arch/arm/mach-u300/include/mach/irqs.h | 116 ++++++++++++------------- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index b8efac4daed8..603c08ec8786 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -1804,7 +1804,7 @@ MACHINE_START(U300, "Ericsson AB U335 S335/B335 Prototype Board") /* Maintainer: Linus Walleij */ .atag_offset = 0x100, .map_io = u300_map_io, - .nr_irqs = NR_IRQS_U300, + .nr_irqs = 0, .init_irq = u300_init_irq, .handle_irq = vic_handle_irq, .timer = &u300_timer, diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h index e27425a63fa1..e85ec3868d04 100644 --- a/arch/arm/mach-u300/include/mach/irqs.h +++ b/arch/arm/mach-u300/include/mach/irqs.h @@ -12,70 +12,70 @@ #ifndef __MACH_IRQS_H #define __MACH_IRQS_H -#define IRQ_U300_INTCON0_START 1 -#define IRQ_U300_INTCON1_START 33 +#define IRQ_U300_INTCON0_START 32 +#define IRQ_U300_INTCON1_START 64 /* These are on INTCON0 - 30 lines */ -#define IRQ_U300_IRQ0_EXT 1 -#define IRQ_U300_IRQ1_EXT 2 -#define IRQ_U300_DMA 3 -#define IRQ_U300_VIDEO_ENC_0 4 -#define IRQ_U300_VIDEO_ENC_1 5 -#define IRQ_U300_AAIF_RX 6 -#define IRQ_U300_AAIF_TX 7 -#define IRQ_U300_AAIF_VGPIO 8 -#define IRQ_U300_AAIF_WAKEUP 9 -#define IRQ_U300_PCM_I2S0_FRAME 10 -#define IRQ_U300_PCM_I2S0_FIFO 11 -#define IRQ_U300_PCM_I2S1_FRAME 12 -#define IRQ_U300_PCM_I2S1_FIFO 13 -#define IRQ_U300_XGAM_GAMCON 14 -#define IRQ_U300_XGAM_CDI 15 -#define IRQ_U300_XGAM_CDICON 16 -#define IRQ_U300_XGAM_PDI 18 -#define IRQ_U300_XGAM_PDICON 19 -#define IRQ_U300_XGAM_GAMEACC 20 -#define IRQ_U300_XGAM_MCIDCT 21 -#define IRQ_U300_APEX 22 -#define IRQ_U300_UART0 23 -#define IRQ_U300_SPI 24 -#define IRQ_U300_TIMER_APP_OS 25 -#define IRQ_U300_TIMER_APP_DD 26 -#define IRQ_U300_TIMER_APP_GP1 27 -#define IRQ_U300_TIMER_APP_GP2 28 -#define IRQ_U300_TIMER_OS 29 -#define IRQ_U300_TIMER_MS 30 -#define IRQ_U300_KEYPAD_KEYBF 31 -#define IRQ_U300_KEYPAD_KEYBR 32 +#define IRQ_U300_IRQ0_EXT 32 +#define IRQ_U300_IRQ1_EXT 33 +#define IRQ_U300_DMA 34 +#define IRQ_U300_VIDEO_ENC_0 35 +#define IRQ_U300_VIDEO_ENC_1 36 +#define IRQ_U300_AAIF_RX 37 +#define IRQ_U300_AAIF_TX 38 +#define IRQ_U300_AAIF_VGPIO 39 +#define IRQ_U300_AAIF_WAKEUP 40 +#define IRQ_U300_PCM_I2S0_FRAME 41 +#define IRQ_U300_PCM_I2S0_FIFO 42 +#define IRQ_U300_PCM_I2S1_FRAME 43 +#define IRQ_U300_PCM_I2S1_FIFO 44 +#define IRQ_U300_XGAM_GAMCON 45 +#define IRQ_U300_XGAM_CDI 46 +#define IRQ_U300_XGAM_CDICON 47 +#define IRQ_U300_XGAM_PDI 49 +#define IRQ_U300_XGAM_PDICON 50 +#define IRQ_U300_XGAM_GAMEACC 51 +#define IRQ_U300_XGAM_MCIDCT 52 +#define IRQ_U300_APEX 53 +#define IRQ_U300_UART0 54 +#define IRQ_U300_SPI 55 +#define IRQ_U300_TIMER_APP_OS 56 +#define IRQ_U300_TIMER_APP_DD 57 +#define IRQ_U300_TIMER_APP_GP1 58 +#define IRQ_U300_TIMER_APP_GP2 59 +#define IRQ_U300_TIMER_OS 60 +#define IRQ_U300_TIMER_MS 61 +#define IRQ_U300_KEYPAD_KEYBF 62 +#define IRQ_U300_KEYPAD_KEYBR 63 /* These are on INTCON1 - 32 lines */ -#define IRQ_U300_GPIO_PORT0 33 -#define IRQ_U300_GPIO_PORT1 34 -#define IRQ_U300_GPIO_PORT2 35 +#define IRQ_U300_GPIO_PORT0 64 +#define IRQ_U300_GPIO_PORT1 65 +#define IRQ_U300_GPIO_PORT2 66 /* These are for DB3150, DB3200 and DB3350 */ -#define IRQ_U300_WDOG 36 -#define IRQ_U300_EVHIST 37 -#define IRQ_U300_MSPRO 38 -#define IRQ_U300_MMCSD_MCIINTR0 39 -#define IRQ_U300_MMCSD_MCIINTR1 40 -#define IRQ_U300_I2C0 41 -#define IRQ_U300_I2C1 42 -#define IRQ_U300_RTC 43 -#define IRQ_U300_NFIF 44 -#define IRQ_U300_NFIF2 45 +#define IRQ_U300_WDOG 67 +#define IRQ_U300_EVHIST 68 +#define IRQ_U300_MSPRO 69 +#define IRQ_U300_MMCSD_MCIINTR0 70 +#define IRQ_U300_MMCSD_MCIINTR1 71 +#define IRQ_U300_I2C0 72 +#define IRQ_U300_I2C1 73 +#define IRQ_U300_RTC 74 +#define IRQ_U300_NFIF 75 +#define IRQ_U300_NFIF2 76 /* The DB3350-specific interrupt lines */ -#define IRQ_U300_ISP_F0 46 -#define IRQ_U300_ISP_F1 47 -#define IRQ_U300_ISP_F2 48 -#define IRQ_U300_ISP_F3 49 -#define IRQ_U300_ISP_F4 50 -#define IRQ_U300_GPIO_PORT3 51 -#define IRQ_U300_SYSCON_PLL_LOCK 52 -#define IRQ_U300_UART1 53 -#define IRQ_U300_GPIO_PORT4 54 -#define IRQ_U300_GPIO_PORT5 55 -#define IRQ_U300_GPIO_PORT6 56 -#define U300_VIC_IRQS_END 57 +#define IRQ_U300_ISP_F0 77 +#define IRQ_U300_ISP_F1 78 +#define IRQ_U300_ISP_F2 79 +#define IRQ_U300_ISP_F3 80 +#define IRQ_U300_ISP_F4 81 +#define IRQ_U300_GPIO_PORT3 82 +#define IRQ_U300_SYSCON_PLL_LOCK 83 +#define IRQ_U300_UART1 84 +#define IRQ_U300_GPIO_PORT4 85 +#define IRQ_U300_GPIO_PORT5 86 +#define IRQ_U300_GPIO_PORT6 87 +#define U300_VIC_IRQS_END 88 /* Maximum 8*7 GPIO lines */ #ifdef CONFIG_PINCTRL_COH901 From a6c45b99a658521291cfb66ecf035cc58b38f206 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 18:31:20 +0200 Subject: [PATCH 33/65] pinctrl/coh901: use irqdomain, allocate irqdescs This switches the COH 901 pinctrl driver to allocate its GPIO IRQs dynamically, and start to use a linear irqdomain to map from the hardware IRQs. This way we can cut away the complex allocation of IRQ numbers from the file. Signed-off-by: Linus Walleij --- arch/arm/mach-u300/core.c | 1 - arch/arm/mach-u300/include/mach/irqs.h | 10 ---- drivers/pinctrl/pinctrl-coh901.c | 60 +++++++++++++++----- include/linux/platform_data/pinctrl-coh901.h | 2 - 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 603c08ec8786..ce2de0d6f2eb 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -1445,7 +1445,6 @@ static struct platform_device pinctrl_device = { static struct u300_gpio_platform u300_gpio_plat = { .ports = 7, .gpio_base = 0, - .gpio_irq_base = IRQ_U300_GPIO_BASE, .pinctrl_device = &pinctrl_device, }; diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h index e85ec3868d04..21d5e76a6cd3 100644 --- a/arch/arm/mach-u300/include/mach/irqs.h +++ b/arch/arm/mach-u300/include/mach/irqs.h @@ -77,14 +77,4 @@ #define IRQ_U300_GPIO_PORT6 87 #define U300_VIC_IRQS_END 88 -/* Maximum 8*7 GPIO lines */ -#ifdef CONFIG_PINCTRL_COH901 -#define IRQ_U300_GPIO_BASE (U300_VIC_IRQS_END) -#define IRQ_U300_GPIO_END (IRQ_U300_GPIO_BASE + 56) -#else -#define IRQ_U300_GPIO_END (U300_VIC_IRQS_END) -#endif - -#define NR_IRQS_U300 (IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START) - #endif diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index b446c9641212..152efae3df8f 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -67,7 +68,6 @@ struct u300_gpio { struct resource *memres; void __iomem *base; struct device *dev; - int irq_base; u32 stride; /* Register offsets */ u32 pcr; @@ -83,6 +83,7 @@ struct u300_gpio_port { struct list_head node; struct u300_gpio *gpio; char name[8]; + struct irq_domain *domain; int irq; int number; u8 toggle_edge_mode; @@ -314,10 +315,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct u300_gpio *gpio = to_u300_gpio(chip); - int retirq = gpio->irq_base + offset; + int portno = offset >> 3; + struct u300_gpio_port *port = NULL; + struct list_head *p; + int retirq; - dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset, - retirq); + list_for_each(p, &gpio->port_list) { + port = list_entry(p, struct u300_gpio_port, node); + if (port->number == portno) + break; + } + if (port == NULL) { + dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n", + offset); + return -EINVAL; + } + + /* + * The local hwirqs on the port are the lower three bits, there + * are exactly 8 IRQs per port since they are 8-bit + */ + retirq = irq_find_mapping(port->domain, (offset & 0x7)); + + dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n", + offset, retirq, port->number); return retirq; } @@ -467,7 +488,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; if ((trigger & IRQF_TRIGGER_RISING) && @@ -503,10 +524,12 @@ static void u300_gpio_irq_enable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; + dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", + d->hwirq, port->name, offset); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -517,7 +540,7 @@ static void u300_gpio_irq_disable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; @@ -555,8 +578,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) int irqoffset; for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { - int pin_irq = gpio->irq_base + (port->number << 3) - + irqoffset; + int pin_irq = irq_find_mapping(port->domain, irqoffset); int offset = pinoffset + irqoffset; dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n", @@ -631,6 +653,8 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio) list_for_each_safe(p, n, &gpio->port_list) { port = list_entry(p, struct u300_gpio_port, node); list_del(&port->node); + if (port->domain) + irq_domain_remove(port->domain); kfree(port); } } @@ -653,7 +677,6 @@ static int __init u300_gpio_probe(struct platform_device *pdev) gpio->chip = u300_gpio_chip; gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; - gpio->irq_base = plat->gpio_irq_base; gpio->chip.dev = &pdev->dev; gpio->chip.base = plat->gpio_base; gpio->dev = &pdev->dev; @@ -732,18 +755,26 @@ static int __init u300_gpio_probe(struct platform_device *pdev) port->irq = platform_get_irq_byname(pdev, port->name); - dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq, + dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq, port->name); + port->domain = irq_domain_add_linear(pdev->dev.of_node, + U300_GPIO_PINS_PER_PORT, + &irq_domain_simple_ops, + port); + if (!port->domain) + goto err_no_domain; + irq_set_chained_handler(port->irq, u300_gpio_irq_handler); irq_set_handler_data(port->irq, port); /* For each GPIO pin set the unique IRQ handler */ for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { - int irqno = gpio->irq_base + (portno << 3) + i; + int irqno = irq_create_mapping(port->domain, i); - dev_dbg(gpio->dev, "handler for IRQ %d on %s\n", - irqno, port->name); + dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n", + gpio->chip.base + (port->number << 3) + i, + port->name, irqno); irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, handle_simple_irq); set_irq_flags(irqno, IRQF_VALID); @@ -776,6 +807,7 @@ static int __init u300_gpio_probe(struct platform_device *pdev) err_no_pinctrl: err = gpiochip_remove(&gpio->chip); err_no_chip: +err_no_domain: err_no_port: u300_gpio_free_ports(gpio); iounmap(gpio->base); diff --git a/include/linux/platform_data/pinctrl-coh901.h b/include/linux/platform_data/pinctrl-coh901.h index 30dea251b835..27a23b318cef 100644 --- a/include/linux/platform_data/pinctrl-coh901.h +++ b/include/linux/platform_data/pinctrl-coh901.h @@ -13,13 +13,11 @@ * struct u300_gpio_platform - U300 GPIO platform data * @ports: number of GPIO block ports * @gpio_base: first GPIO number for this block (use a free range) - * @gpio_irq_base: first GPIO IRQ number for this block (use a free range) * @pinctrl_device: pin control device to spawn as child */ struct u300_gpio_platform { u8 ports; int gpio_base; - int gpio_irq_base; struct platform_device *pinctrl_device; }; From 585583f54f577d7fd93247101b9f61c8bbbd21f1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 18:49:05 +0200 Subject: [PATCH 34/65] pinctrl/coh901: convert to use managed resources This switches the COH 901 pin controller to use managed resources (devm_*) for memory remaps, clocks, etc. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-coh901.c | 62 ++++++++++---------------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 152efae3df8f..5c7daf9169e8 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -65,7 +65,6 @@ struct u300_gpio { struct gpio_chip chip; struct list_head port_list; struct clk *clk; - struct resource *memres; void __iomem *base; struct device *dev; u32 stride; @@ -663,17 +662,16 @@ static int __init u300_gpio_probe(struct platform_device *pdev) { struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); struct u300_gpio *gpio; + struct resource *memres; int err = 0; int portno; u32 val; u32 ifr; int i; - gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL); - if (gpio == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + gpio = devm_kzalloc(&pdev->dev, sizeof(struct u300_gpio), GFP_KERNEL); + if (gpio == NULL) return -ENOMEM; - } gpio->chip = u300_gpio_chip; gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; @@ -681,37 +679,29 @@ static int __init u300_gpio_probe(struct platform_device *pdev) gpio->chip.base = plat->gpio_base; gpio->dev = &pdev->dev; - /* Get GPIO clock */ - gpio->clk = clk_get(gpio->dev, NULL); + memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!memres) { + dev_err(gpio->dev, "could not get GPIO memory resource\n"); + return -ENODEV; + } + + gpio->base = devm_request_and_ioremap(&pdev->dev, memres); + if (!gpio->base) { + dev_err(gpio->dev, "could not get remap memory\n"); + return -ENOMEM; + } + + gpio->clk = devm_clk_get(gpio->dev, NULL); if (IS_ERR(gpio->clk)) { err = PTR_ERR(gpio->clk); dev_err(gpio->dev, "could not get GPIO clock\n"); - goto err_no_clk; + return err; } + err = clk_prepare_enable(gpio->clk); if (err) { dev_err(gpio->dev, "could not enable GPIO clock\n"); - goto err_no_clk_enable; - } - - gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!gpio->memres) { - dev_err(gpio->dev, "could not get GPIO memory resource\n"); - err = -ENODEV; - goto err_no_resource; - } - - if (!request_mem_region(gpio->memres->start, - resource_size(gpio->memres), - "GPIO Controller")) { - err = -ENODEV; - goto err_no_ioregion; - } - - gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres)); - if (!gpio->base) { - err = -ENOMEM; - goto err_no_ioremap; + return err; } dev_info(gpio->dev, @@ -810,16 +800,7 @@ static int __init u300_gpio_probe(struct platform_device *pdev) err_no_domain: err_no_port: u300_gpio_free_ports(gpio); - iounmap(gpio->base); -err_no_ioremap: - release_mem_region(gpio->memres->start, resource_size(gpio->memres)); -err_no_ioregion: -err_no_resource: clk_disable_unprepare(gpio->clk); -err_no_clk_enable: - clk_put(gpio->clk); -err_no_clk: - kfree(gpio); dev_info(&pdev->dev, "module ERROR:%d\n", err); return err; } @@ -838,13 +819,8 @@ static int __exit u300_gpio_remove(struct platform_device *pdev) return err; } u300_gpio_free_ports(gpio); - iounmap(gpio->base); - release_mem_region(gpio->memres->start, - resource_size(gpio->memres)); clk_disable_unprepare(gpio->clk); - clk_put(gpio->clk); platform_set_drvdata(pdev, NULL); - kfree(gpio); return 0; } From b36bdc5911effe819e415b144388853bf07a543b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 19:17:56 +0200 Subject: [PATCH 35/65] pinctrl/u300: use managed resources This converts the U300 pin controller to use managed resources (devm_*) for it's memory region. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-u300.c | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 309f5b9a70ec..2e9825e304af 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -663,8 +663,6 @@ static const struct pinctrl_pin_desc u300_pads[] = { struct u300_pmx { struct device *dev; struct pinctrl_dev *pctl; - u32 phybase; - u32 physize; void __iomem *virtbase; }; @@ -1110,7 +1108,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) struct u300_pmx *upmx; struct resource *res; struct gpio_chip *gpio_chip = dev_get_platdata(&pdev->dev); - int ret; int i; /* Create state holders etc for this driver */ @@ -1123,26 +1120,15 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; - upmx->phybase = res->start; - upmx->physize = resource_size(res); - - if (request_mem_region(upmx->phybase, upmx->physize, - DRIVER_NAME) == NULL) { - ret = -ENOMEM; - goto out_no_memregion; - } - upmx->virtbase = ioremap(upmx->phybase, upmx->physize); - if (!upmx->virtbase) { - ret = -ENOMEM; - goto out_no_remap; - } + upmx->virtbase = devm_request_and_ioremap(&pdev->dev, res); + if (!upmx->virtbase) + return -ENOMEM; upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx); if (!upmx->pctl) { dev_err(&pdev->dev, "could not register U300 pinmux driver\n"); - ret = -EINVAL; - goto out_no_pmx; + return -EINVAL; } /* We will handle a range of GPIO pins */ @@ -1156,14 +1142,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) dev_info(&pdev->dev, "initialized U300 pin control driver\n"); return 0; - -out_no_pmx: - iounmap(upmx->virtbase); -out_no_remap: - platform_set_drvdata(pdev, NULL); -out_no_memregion: - release_mem_region(upmx->phybase, upmx->physize); - return ret; } static int __devexit u300_pmx_remove(struct platform_device *pdev) @@ -1171,8 +1149,6 @@ static int __devexit u300_pmx_remove(struct platform_device *pdev) struct u300_pmx *upmx = platform_get_drvdata(pdev); pinctrl_unregister(upmx->pctl); - iounmap(upmx->virtbase); - release_mem_region(upmx->phybase, upmx->physize); platform_set_drvdata(pdev, NULL); return 0; From e1b29abef69e34a42169cd65d7249b18574c94e8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 5 Nov 2012 21:42:16 +0800 Subject: [PATCH 36/65] pinctrl: u300: Staticize non-exported symbols Staticize u300_pin_config_get() and u300_pin_config_set() functions. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-u300.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 2e9825e304af..d756cce588fd 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -1052,9 +1052,8 @@ static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin) return NULL; } -int u300_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *config) +static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *config) { struct pinctrl_gpio_range *range = u300_match_gpio_range(pin); @@ -1067,9 +1066,8 @@ int u300_pin_config_get(struct pinctrl_dev *pctldev, config); } -int u300_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long config) +static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long config) { struct pinctrl_gpio_range *range = u300_match_gpio_range(pin); int ret; From 33dfc41461b77e2b38673ec1b5622b1d9340324d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 5 Nov 2012 21:44:28 +0800 Subject: [PATCH 37/65] pinctrl: sirf: Staticize non-exported symbol Staticize sirfsoc_gpio_irq_map() function. Signed-off-by: Axel Lin Acked-by: Barry Song Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-sirf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 16ec7d4d81ee..a3905e58d1b3 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -1642,8 +1642,8 @@ static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset, spin_unlock_irqrestore(&bank->lock, flags); } -int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) +static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct sirfsoc_gpio_bank *bank = d->host_data; From 165adc9c1734a3f3bdbc6dc7c7a29bbefb424006 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 14:49:39 +0100 Subject: [PATCH 38/65] gpiolib: fix up function prototypes etc Commit 69e1601bca88809dc118abd1becb02c15a02ec71 "gpiolib: provide provision to register pin ranges" Got most of it's function prototypes wrong, so fix this up by: - Moving the void declarations into static inlines in (previously the actual prototypes were declared here...) - Declare the gpiochip_add_pin_range() and gpiochip_remove_pin_ranges() functions in together with the pin range struct declaration itself. - Actually only implement these very functions in gpiolib.c if CONFIG_PINCTRL is set. - Additionally export the symbols since modules will need to be able to do this. Reviewed-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 10 +++++----- include/asm-generic/gpio.h | 6 ++++++ include/linux/gpio.h | 24 ++++++++++++++++++------ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f0b07bbfcc9a..1e1a7cabc57e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1185,6 +1185,7 @@ struct gpio_chip *gpiochip_find(void *data, EXPORT_SYMBOL_GPL(gpiochip_find); #ifdef CONFIG_PINCTRL + void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, unsigned int pin_base, unsigned int npins) { @@ -1206,6 +1207,7 @@ void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, list_add_tail(&pin_range->node, &chip->pin_ranges); } +EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); void gpiochip_remove_pin_ranges(struct gpio_chip *chip) { @@ -1217,11 +1219,9 @@ void gpiochip_remove_pin_ranges(struct gpio_chip *chip) &pin_range->range); } } -#else -void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins) {} -void gpiochip_remove_pin_ranges(struct gpio_chip *chip) {} -#endif +EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); + +#endif /* CONFIG_PINCTRL */ /* These "optional" allocation calls help prevent drivers from stomping * on each other, and help provide better diagnostics in debugfs. diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 92e5c432421c..2e60de4265ac 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -49,6 +49,7 @@ struct module; struct device_node; #ifdef CONFIG_PINCTRL + /** * struct gpio_pin_range - pin range controlled by a gpio chip * @head: list for maintaining set of pin ranges, used internally @@ -61,6 +62,11 @@ struct gpio_pin_range { struct pinctrl_dev *pctldev; struct pinctrl_gpio_range range; }; + +void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins); +void gpiochip_remove_pin_ranges(struct gpio_chip *chip); + #endif /** diff --git a/include/linux/gpio.h b/include/linux/gpio.h index a28445992b7f..21d28b930dc7 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -72,9 +72,9 @@ static inline int irq_to_gpio(unsigned int irq) return -EINVAL; } -#endif +#endif /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */ -#else +#else /* ! CONFIG_GENERIC_GPIO */ #include #include @@ -231,9 +231,21 @@ static inline int irq_to_gpio(unsigned irq) return -EINVAL; } -void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins); -void gpiochip_remove_pin_ranges(struct gpio_chip *chip); -#endif +#ifdef CONFIG_PINCTRL + +static inline void +gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) +{ +} + +static inline void +gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ +} + +#endif /* CONFIG_PINCTRL */ + +#endif /* ! CONFIG_GENERIC_GPIO */ #endif /* __LINUX_GPIO_H */ From 167c1af9443757bb9d27ceff8ba4304302cb0651 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 14:58:55 +0100 Subject: [PATCH 39/65] gpiolib-of: staticize the pin range calls Commit 69e1601bca88809dc118abd1becb02c15a02ec71 "gpiolib: provide provision to register pin ranges" Declared the of_gpiochip_[add|remove]_pin_range() global while they should be static as they are only ever used in this file. Let's convert them to static. Reviewed-by: Stephen Warren Reviewed-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index a5b90c8e9844..220caa5978f7 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -218,7 +218,7 @@ int of_mm_gpiochip_add(struct device_node *np, EXPORT_SYMBOL(of_mm_gpiochip_add); #ifdef CONFIG_PINCTRL -void of_gpiochip_add_pin_range(struct gpio_chip *chip) +static void of_gpiochip_add_pin_range(struct gpio_chip *chip) { struct device_node *np = chip->of_node; struct gpio_pin_range *pin_range; @@ -254,7 +254,7 @@ void of_gpiochip_add_pin_range(struct gpio_chip *chip) } while (index++); } -void of_gpiochip_remove_pin_range(struct gpio_chip *chip) +static void of_gpiochip_remove_pin_range(struct gpio_chip *chip) { struct gpio_pin_range *pin_range, *tmp; @@ -265,8 +265,8 @@ void of_gpiochip_remove_pin_range(struct gpio_chip *chip) } } #else -void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} -void of_gpiochip_remove_pin_range(struct gpio_chip *chip) {} +static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} +static void of_gpiochip_remove_pin_range(struct gpio_chip *chip) {} #endif void of_gpiochip_add(struct gpio_chip *chip) From e93fa3f24353e45b189bae656ba000d0533777a3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 15:03:47 +0100 Subject: [PATCH 40/65] gpiolib: remove duplicate pin range code Commit 69e1601bca88809dc118abd1becb02c15a02ec71 "gpiolib: provide provision to register pin ranges" Introduced both of_gpiochip_remove_pin_range() and gpiochip_remove_pin_ranges(). But the contents are exactly the same so remove the OF one and rely on the range deletion in the core. Reviewed-by: Stephen Warren Reviewed-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 220caa5978f7..67403e47e4dc 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -254,19 +254,8 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) } while (index++); } -static void of_gpiochip_remove_pin_range(struct gpio_chip *chip) -{ - struct gpio_pin_range *pin_range, *tmp; - - list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) { - list_del(&pin_range->node); - pinctrl_remove_gpio_range(pin_range->pctldev, - &pin_range->range); - } -} #else static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} -static void of_gpiochip_remove_pin_range(struct gpio_chip *chip) {} #endif void of_gpiochip_add(struct gpio_chip *chip) @@ -288,7 +277,7 @@ void of_gpiochip_add(struct gpio_chip *chip) void of_gpiochip_remove(struct gpio_chip *chip) { - of_gpiochip_remove_pin_range(chip); + gpiochip_remove_pin_ranges(chip); if (chip->of_node) of_node_put(chip->of_node); From 9ef0d6f7628bdcb5cc3c11623930f2527a3881a0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 15:15:44 +0100 Subject: [PATCH 41/65] gpiolib: call pin removal in chip removal function This makes us call gpiochio_remove_pin_ranges() in the gpiochip_remove() function, so we get rid of ranges when freeing the chip. Reviewed-by: Stephen Warren Reviewed-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1e1a7cabc57e..bcf9b9914fb7 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1127,6 +1127,7 @@ int gpiochip_remove(struct gpio_chip *chip) spin_lock_irqsave(&gpio_lock, flags); + gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); for (id = chip->base; id < chip->base + chip->ngpio; id++) { From 1e63d7b9363f0c57d00991f9f2e0af374dfc591a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 16:03:35 +0100 Subject: [PATCH 42/65] gpiolib: separation of pin concerns The fact that of_gpiochip_add_pin_range() and gpiochip_add_pin_range() share too much code is fragile and will invariably mean that bugs need to be fixed in two places instead of one. So separate the concerns of gpiolib.c and gpiolib-of.c and have the latter call the former as back-end. This is necessary also when going forward with other device descriptions such as ACPI. This is done by: - Adding a return code to gpiochip_add_pin_range() so we can reliably check whether this succeeds. - Get rid of the custom of_pinctrl_add_gpio_range() from pinctrl. Instead create of_pinctrl_get() to just retrive the pin controller per se from an OF node. This composite function was just begging to be deleted, it was way to purpose-specific. - Use pinctrl_dev_get_name() to get the name of the retrieved pin controller and use that to call back into the generic gpiochip_add_pin_range(). Now the pin range is only allocated and tied to a pin controller from the core implementation in gpiolib.c. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 23 +++++++++-------------- drivers/gpio/gpiolib.c | 8 +++++--- drivers/pinctrl/devicetree.c | 4 +--- include/asm-generic/gpio.h | 4 ++-- include/linux/gpio.h | 2 +- include/linux/pinctrl/pinctrl.h | 7 ++----- 6 files changed, 20 insertions(+), 28 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 67403e47e4dc..a40cd84c5c10 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -221,8 +221,8 @@ EXPORT_SYMBOL(of_mm_gpiochip_add); static void of_gpiochip_add_pin_range(struct gpio_chip *chip) { struct device_node *np = chip->of_node; - struct gpio_pin_range *pin_range; struct of_phandle_args pinspec; + struct pinctrl_dev *pctldev; int index = 0, ret; if (!np) @@ -234,22 +234,17 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) if (ret) break; - pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), - GFP_KERNEL); - if (!pin_range) { - pr_err("%s: GPIO chip: failed to allocate pin ranges\n", - chip->label); + pctldev = of_pinctrl_get(pinspec.np); + if (!pctldev) break; - } - pin_range->range.name = chip->label; - pin_range->range.base = chip->base; - pin_range->range.pin_base = pinspec.args[0]; - pin_range->range.npins = pinspec.args[1]; - pin_range->pctldev = of_pinctrl_add_gpio_range(pinspec.np, - &pin_range->range); + ret = gpiochip_add_pin_range(chip, + pinctrl_dev_get_name(pctldev), + pinspec.args[0], + pinspec.args[1]); - list_add_tail(&pin_range->node, &chip->pin_ranges); + if (ret) + break; } while (index++); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bcf9b9914fb7..c5f650095faa 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1187,8 +1187,8 @@ EXPORT_SYMBOL_GPL(gpiochip_find); #ifdef CONFIG_PINCTRL -void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins) +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) { struct gpio_pin_range *pin_range; @@ -1196,7 +1196,7 @@ void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, if (!pin_range) { pr_err("%s: GPIO chip: failed to allocate pin ranges\n", chip->label); - return; + return -ENOMEM; } pin_range->range.name = chip->label; @@ -1207,6 +1207,8 @@ void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, &pin_range->range); list_add_tail(&pin_range->node, &chip->pin_ranges); + + return 0; } EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 6728ec71cb65..fe2d1af7cfa0 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -106,8 +106,7 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np) return NULL; } -struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, - struct pinctrl_gpio_range *range) +struct pinctrl_dev *of_pinctrl_get(struct device_node *np) { struct pinctrl_dev *pctldev; @@ -115,7 +114,6 @@ struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, if (!pctldev) return NULL; - pinctrl_add_gpio_range(pctldev, range); return pctldev; } diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 2e60de4265ac..50d995e7e44a 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -63,8 +63,8 @@ struct gpio_pin_range { struct pinctrl_gpio_range range; }; -void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins); +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins); void gpiochip_remove_pin_ranges(struct gpio_chip *chip); #endif diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 21d28b930dc7..81bbfe5b5de6 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -233,7 +233,7 @@ static inline int irq_to_gpio(unsigned irq) #ifdef CONFIG_PINCTRL -static inline void +static inline int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, unsigned int pin_base, unsigned int npins) { diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index 434e5a94e131..4a58428bc793 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -141,16 +141,13 @@ extern struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname, struct pinctrl_gpio_range *range); #ifdef CONFIG_OF -extern struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, - struct pinctrl_gpio_range *range); +extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np); #else static inline -struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, - struct pinctrl_gpio_range *range) +struct pinctrl_dev *of_pinctrl_get(struct device_node *np) { return NULL; } - #endif /* CONFIG_OF */ extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev); From 50309a9c2e576ac4ad29e30f5854acb87bdc2ac4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 17:16:39 +0100 Subject: [PATCH 43/65] gpiolib: iron out include ladder mistakes The <*/gpio.h> includes are updated again: now we need to account for the problem introduced by commit: 595679a8038584df7b9398bf34f61db3c038bfea "gpiolib: fix up function prototypes etc" Actually we need static inlines in include/asm-generic/gpio.h as well since we may have GPIOLIB but not PINCTRL. Make sure to move all the CONFIG_PINCTRL business to the end of the file so we are sure we have declared struct gpio_chip. And we need to keep the static inlines in but here for the !CONFIG_GENERIC_GPIO case, and then we may as well throw in a few warnings like the other prototypes there, if someone would have the bad taste of compiling without GENERIC_GPIO even. Signed-off-by: Linus Walleij --- include/asm-generic/gpio.h | 56 ++++++++++++++++++++++++-------------- include/linux/gpio.h | 7 ++--- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 50d995e7e44a..2b84fc32fae2 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -48,27 +48,6 @@ struct seq_file; struct module; struct device_node; -#ifdef CONFIG_PINCTRL - -/** - * struct gpio_pin_range - pin range controlled by a gpio chip - * @head: list for maintaining set of pin ranges, used internally - * @pctldev: pinctrl device which handles corresponding pins - * @range: actual range of pins controlled by a gpio controller - */ - -struct gpio_pin_range { - struct list_head node; - struct pinctrl_dev *pctldev; - struct pinctrl_gpio_range range; -}; - -int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins); -void gpiochip_remove_pin_ranges(struct gpio_chip *chip); - -#endif - /** * struct gpio_chip - abstract a GPIO controller * @label: for diagnostics @@ -288,4 +267,39 @@ static inline void gpio_unexport(unsigned gpio) } #endif /* CONFIG_GPIO_SYSFS */ +#ifdef CONFIG_PINCTRL + +/** + * struct gpio_pin_range - pin range controlled by a gpio chip + * @head: list for maintaining set of pin ranges, used internally + * @pctldev: pinctrl device which handles corresponding pins + * @range: actual range of pins controlled by a gpio controller + */ + +struct gpio_pin_range { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_gpio_range range; +}; + +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins); +void gpiochip_remove_pin_ranges(struct gpio_chip *chip); + +#else + +static inline int +gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) +{ + return 0; +} + +static inline void +gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ +} + +#endif /* CONFIG_PINCTRL */ + #endif /* _ASM_GENERIC_GPIO_H */ diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 81bbfe5b5de6..7ba2762abbc9 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -231,21 +231,20 @@ static inline int irq_to_gpio(unsigned irq) return -EINVAL; } -#ifdef CONFIG_PINCTRL - static inline int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, unsigned int pin_base, unsigned int npins) { + WARN_ON(1); + return -EINVAL; } static inline void gpiochip_remove_pin_ranges(struct gpio_chip *chip) { + WARN_ON(1); } -#endif /* CONFIG_PINCTRL */ - #endif /* ! CONFIG_GENERIC_GPIO */ #endif /* __LINUX_GPIO_H */ From f4f8e5635f398645d614dff5a07598651faf3ead Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 27 Oct 2012 15:21:38 +0530 Subject: [PATCH 44/65] pinctrl: SPEAr: Add gpio ranges support Most of SPEAr SoCs, which support pinctrl, can configure & use pads as gpio. This patch gpio enable support for SPEAr pinctrl drivers. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Linus Walleij --- drivers/pinctrl/spear/Kconfig | 4 + drivers/pinctrl/spear/pinctrl-spear.c | 107 +++++++-- drivers/pinctrl/spear/pinctrl-spear.h | 46 ++++ drivers/pinctrl/spear/pinctrl-spear1310.c | 264 ++++++++++++++++++++++ drivers/pinctrl/spear/pinctrl-spear300.c | 2 + drivers/pinctrl/spear/pinctrl-spear310.c | 2 + drivers/pinctrl/spear/pinctrl-spear320.c | 2 + drivers/pinctrl/spear/pinctrl-spear3xx.c | 37 +++ 8 files changed, 447 insertions(+), 17 deletions(-) diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig index 6f9a1e8bf575..04d93e602674 100644 --- a/drivers/pinctrl/spear/Kconfig +++ b/drivers/pinctrl/spear/Kconfig @@ -25,21 +25,25 @@ config PINCTRL_SPEAR310 bool "ST Microelectronics SPEAr310 SoC pin controller driver" depends on MACH_SPEAR310 select PINCTRL_SPEAR3XX + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR320 bool "ST Microelectronics SPEAr320 SoC pin controller driver" depends on MACH_SPEAR320 select PINCTRL_SPEAR3XX + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR1310 bool "ST Microelectronics SPEAr1310 SoC pin controller driver" depends on MACH_SPEAR1310 select PINCTRL_SPEAR + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR1340 bool "ST Microelectronics SPEAr1340 SoC pin controller driver" depends on MACH_SPEAR1340 select PINCTRL_SPEAR + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR_PLGPIO bool "SPEAr SoC PLGPIO Controller" diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index b1fd6ee33c6c..cbca6dc66eb7 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,28 @@ static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg) writel_relaxed(val, pmx->vbase + reg); } +static void muxregs_endisable(struct spear_pmx *pmx, + struct spear_muxreg *muxregs, u8 count, bool enable) +{ + struct spear_muxreg *muxreg; + u32 val, temp, j; + + for (j = 0; j < count; j++) { + muxreg = &muxregs[j]; + + val = pmx_readl(pmx, muxreg->reg); + val &= ~muxreg->mask; + + if (enable) + temp = muxreg->val; + else + temp = ~muxreg->val; + + val |= muxreg->mask & temp; + pmx_writel(pmx, val, muxreg->reg); + } +} + static int set_mode(struct spear_pmx *pmx, int mode) { struct spear_pmx_mode *pmx_mode = NULL; @@ -70,6 +93,17 @@ static int set_mode(struct spear_pmx *pmx, int mode) return 0; } +void __devinit +pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup, + unsigned count, u16 reg) +{ + int i = 0, j = 0; + + for (; i < count; i++) + for (; j < gpio_pingroup[i].nmuxregs; j++) + gpio_pingroup[i].muxregs[j].reg = reg; +} + void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg) { struct spear_pingroup *pgroup; @@ -216,9 +250,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct spear_pingroup *pgroup; const struct spear_modemux *modemux; - struct spear_muxreg *muxreg; - u32 val, temp; - int i, j; + int i; bool found = false; pgroup = pmx->machdata->groups[group]; @@ -233,20 +265,8 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, } found = true; - for (j = 0; j < modemux->nmuxregs; j++) { - muxreg = &modemux->muxregs[j]; - - val = pmx_readl(pmx, muxreg->reg); - val &= ~muxreg->mask; - - if (enable) - temp = muxreg->val; - else - temp = ~muxreg->val; - - val |= muxreg->mask & temp; - pmx_writel(pmx, val, muxreg->reg); - } + muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs, + enable); } if (!found) { @@ -270,12 +290,65 @@ static void spear_pinctrl_disable(struct pinctrl_dev *pctldev, spear_pinctrl_endisable(pctldev, function, group, false); } +/* gpio with pinmux */ +static struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx, + unsigned pin) +{ + struct spear_gpio_pingroup *gpio_pingroup; + int i = 0, j; + + if (!pmx->machdata->gpio_pingroups) + return NULL; + + for (; i < pmx->machdata->ngpio_pingroups; i++) { + gpio_pingroup = &pmx->machdata->gpio_pingroups[i]; + + for (j = 0; j < gpio_pingroup->npins; j++) { + if (gpio_pingroup->pins[j] == pin) + return gpio_pingroup; + } + } + + return ERR_PTR(-EINVAL); +} + +static int gpio_request_endisable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool enable) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + struct spear_gpio_pingroup *gpio_pingroup; + + gpio_pingroup = get_gpio_pingroup(pmx, offset); + if (IS_ERR(gpio_pingroup)) + return PTR_ERR(gpio_pingroup); + + if (gpio_pingroup) + muxregs_endisable(pmx, gpio_pingroup->muxregs, + gpio_pingroup->nmuxregs, enable); + + return 0; +} + +static int gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + return gpio_request_endisable(pctldev, range, offset, true); +} + +static void gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + gpio_request_endisable(pctldev, range, offset, false); +} + static struct pinmux_ops spear_pinmux_ops = { .get_functions_count = spear_pinctrl_get_funcs_count, .get_function_name = spear_pinctrl_get_func_name, .get_function_groups = spear_pinctrl_get_func_groups, .enable = spear_pinctrl_enable, .disable = spear_pinctrl_disable, + .gpio_request_enable = gpio_request_enable, + .gpio_disable_free = gpio_disable_free, }; static struct pinctrl_desc spear_pinctrl_desc = { diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h index d950eb78d939..94f142c10c19 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.h +++ b/drivers/pinctrl/spear/pinctrl-spear.h @@ -12,6 +12,7 @@ #ifndef __PINMUX_SPEAR_H__ #define __PINMUX_SPEAR_H__ +#include #include #include @@ -46,6 +47,44 @@ struct spear_muxreg { u32 val; }; +struct spear_gpio_pingroup { + const unsigned *pins; + unsigned npins; + struct spear_muxreg *muxregs; + u8 nmuxregs; +}; + +/* ste: set to enable */ +#define DEFINE_MUXREG(__pins, __muxreg, __mask, __ste) \ +static struct spear_muxreg __pins##_muxregs[] = { \ + { \ + .reg = __muxreg, \ + .mask = __mask, \ + .val = __ste ? __mask : 0, \ + }, \ +} + +#define DEFINE_2_MUXREG(__pins, __muxreg1, __muxreg2, __mask, __ste1, __ste2) \ +static struct spear_muxreg __pins##_muxregs[] = { \ + { \ + .reg = __muxreg1, \ + .mask = __mask, \ + .val = __ste1 ? __mask : 0, \ + }, { \ + .reg = __muxreg2, \ + .mask = __mask, \ + .val = __ste2 ? __mask : 0, \ + }, \ +} + +#define GPIO_PINGROUP(__pins) \ + { \ + .pins = __pins, \ + .npins = ARRAY_SIZE(__pins), \ + .muxregs = __pins##_muxregs, \ + .nmuxregs = ARRAY_SIZE(__pins##_muxregs), \ + } + /** * struct spear_modemux - SPEAr mode mux configuration * @modes: mode ids supported by this group of muxregs @@ -100,6 +139,8 @@ struct spear_function { * @nfunctions: The numbmer of entries in @functions. * @groups: An array describing all pin groups the pin SoC supports. * @ngroups: The numbmer of entries in @groups. + * @gpio_pingroups: gpio pingroups + * @ngpio_pingroups: gpio pingroups count * * @modes_supported: Does SoC support modes * @mode: mode configured from probe @@ -113,6 +154,8 @@ struct spear_pinctrl_machdata { unsigned nfunctions; struct spear_pingroup **groups; unsigned ngroups; + struct spear_gpio_pingroup *gpio_pingroups; + unsigned ngpio_pingroups; bool modes_supported; u16 mode; @@ -136,6 +179,9 @@ struct spear_pmx { /* exported routines */ void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg); +void __devinit +pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup, + unsigned count, u16 reg); int __devinit spear_pinctrl_probe(struct platform_device *pdev, struct spear_pinctrl_machdata *machdata); int __devexit spear_pinctrl_remove(struct platform_device *pdev); diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c index 0436fc7895d6..30134f727455 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1310.c +++ b/drivers/pinctrl/spear/pinctrl-spear1310.c @@ -2418,6 +2418,268 @@ static struct spear_function *spear1310_functions[] = { &gpt64_function, }; +static const unsigned pin18[] = { 18, }; +static const unsigned pin19[] = { 19, }; +static const unsigned pin20[] = { 20, }; +static const unsigned pin21[] = { 21, }; +static const unsigned pin22[] = { 22, }; +static const unsigned pin23[] = { 23, }; +static const unsigned pin54[] = { 54, }; +static const unsigned pin55[] = { 55, }; +static const unsigned pin56[] = { 56, }; +static const unsigned pin57[] = { 57, }; +static const unsigned pin58[] = { 58, }; +static const unsigned pin59[] = { 59, }; +static const unsigned pin60[] = { 60, }; +static const unsigned pin61[] = { 61, }; +static const unsigned pin62[] = { 62, }; +static const unsigned pin63[] = { 63, }; +static const unsigned pin143[] = { 143, }; +static const unsigned pin144[] = { 144, }; +static const unsigned pin145[] = { 145, }; +static const unsigned pin146[] = { 146, }; +static const unsigned pin147[] = { 147, }; +static const unsigned pin148[] = { 148, }; +static const unsigned pin149[] = { 149, }; +static const unsigned pin150[] = { 150, }; +static const unsigned pin151[] = { 151, }; +static const unsigned pin152[] = { 152, }; +static const unsigned pin205[] = { 205, }; +static const unsigned pin206[] = { 206, }; +static const unsigned pin211[] = { 211, }; +static const unsigned pin212[] = { 212, }; +static const unsigned pin213[] = { 213, }; +static const unsigned pin214[] = { 214, }; +static const unsigned pin215[] = { 215, }; +static const unsigned pin216[] = { 216, }; +static const unsigned pin217[] = { 217, }; +static const unsigned pin218[] = { 218, }; +static const unsigned pin219[] = { 219, }; +static const unsigned pin220[] = { 220, }; +static const unsigned pin221[] = { 221, }; +static const unsigned pin222[] = { 222, }; +static const unsigned pin223[] = { 223, }; +static const unsigned pin224[] = { 224, }; +static const unsigned pin225[] = { 225, }; +static const unsigned pin226[] = { 226, }; +static const unsigned pin227[] = { 227, }; +static const unsigned pin228[] = { 228, }; +static const unsigned pin229[] = { 229, }; +static const unsigned pin230[] = { 230, }; +static const unsigned pin231[] = { 231, }; +static const unsigned pin232[] = { 232, }; +static const unsigned pin233[] = { 233, }; +static const unsigned pin234[] = { 234, }; +static const unsigned pin235[] = { 235, }; +static const unsigned pin236[] = { 236, }; +static const unsigned pin237[] = { 237, }; +static const unsigned pin238[] = { 238, }; +static const unsigned pin239[] = { 239, }; +static const unsigned pin240[] = { 240, }; +static const unsigned pin241[] = { 241, }; +static const unsigned pin242[] = { 242, }; +static const unsigned pin243[] = { 243, }; +static const unsigned pin244[] = { 244, }; +static const unsigned pin245[] = { 245, }; + +static const unsigned pin_grp0[] = { 173, 174, }; +static const unsigned pin_grp1[] = { 175, 185, 188, 197, 198, }; +static const unsigned pin_grp2[] = { 176, 177, 178, 179, 184, 186, 187, 189, + 190, 191, 192, }; +static const unsigned pin_grp3[] = { 180, 181, 182, 183, 193, 194, 195, 196, }; +static const unsigned pin_grp4[] = { 199, 200, }; +static const unsigned pin_grp5[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, }; +static const unsigned pin_grp6[] = { 86, 87, 88, 89, 90, 91, 92, 93, }; +static const unsigned pin_grp7[] = { 98, 99, }; +static const unsigned pin_grp8[] = { 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, }; + +/* Define muxreg arrays */ +DEFINE_2_MUXREG(i2c0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2C0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SSP0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_cs0_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_cs1_2_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS1_2_MASK, 0, 1); +DEFINE_2_MUXREG(i2s0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2S0_MASK, 0, 1); +DEFINE_2_MUXREG(i2s1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_I2S1_MASK, 0, 1); +DEFINE_2_MUXREG(clcd_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_CLCD1_MASK, 0, 1); +DEFINE_2_MUXREG(clcd_high_res_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_CLCD2_MASK, 0, 1); +DEFINE_2_MUXREG(pin18, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO15_MASK, 0, 1); +DEFINE_2_MUXREG(pin19, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO14_MASK, 0, 1); +DEFINE_2_MUXREG(pin20, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO13_MASK, 0, 1); +DEFINE_2_MUXREG(pin21, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO12_MASK, 0, 1); +DEFINE_2_MUXREG(pin22, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO11_MASK, 0, 1); +DEFINE_2_MUXREG(pin23, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO10_MASK, 0, 1); +DEFINE_2_MUXREG(pin143, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO00_MASK, 0, 1); +DEFINE_2_MUXREG(pin144, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO01_MASK, 0, 1); +DEFINE_2_MUXREG(pin145, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO02_MASK, 0, 1); +DEFINE_2_MUXREG(pin146, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO03_MASK, 0, 1); +DEFINE_2_MUXREG(pin147, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO04_MASK, 0, 1); +DEFINE_2_MUXREG(pin148, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO05_MASK, 0, 1); +DEFINE_2_MUXREG(pin149, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO06_MASK, 0, 1); +DEFINE_2_MUXREG(pin150, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO07_MASK, 0, 1); +DEFINE_2_MUXREG(pin151, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO08_MASK, 0, 1); +DEFINE_2_MUXREG(pin152, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO09_MASK, 0, 1); +DEFINE_2_MUXREG(smi_2_chips_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SMI_MASK, 0, 1); +DEFINE_2_MUXREG(pin54, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS3_MASK, 0, 1); +DEFINE_2_MUXREG(pin55, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS2_MASK, 0, 1); +DEFINE_2_MUXREG(pin56, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFRSTPWDWN3_MASK, 0, 1); +DEFINE_2_MUXREG(pin57, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN2_MASK, 0, 1); +DEFINE_2_MUXREG(pin58, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN1_MASK, 0, 1); +DEFINE_2_MUXREG(pin59, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN0_MASK, 0, 1); +DEFINE_2_MUXREG(pin60, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFWPRT3_MASK, 0, 1); +DEFINE_2_MUXREG(pin61, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFCE3_MASK, 0, 1); +DEFINE_2_MUXREG(pin62, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD25_MASK, 0, 1); +DEFINE_2_MUXREG(pin63, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD24_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp0, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp1, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp2, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_RXCLK_RDV_TXEN_D03_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp3, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIID47_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp4, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MDC_MDIO_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp5, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD23_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp6, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MCI_DATA8_15_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp7, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFCE2_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp8, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND8_MASK, 0, 1); +DEFINE_2_MUXREG(nand_16bit_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND16BIT_1_MASK, 0, 1); +DEFINE_2_MUXREG(pin205, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL1_MASK | PMX_NFCE1_MASK, 0, 1); +DEFINE_2_MUXREG(pin206, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL0_MASK | PMX_NFCE2_MASK, 0, 1); +DEFINE_2_MUXREG(pin211, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW1_MASK | PMX_NFWPRT1_MASK, 0, 1); +DEFINE_2_MUXREG(pin212, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW0_MASK | PMX_NFWPRT2_MASK, 0, 1); +DEFINE_2_MUXREG(pin213, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA0_MASK, 0, 1); +DEFINE_2_MUXREG(pin214, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA1_MASK, 0, 1); +DEFINE_2_MUXREG(pin215, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA2_MASK, 0, 1); +DEFINE_2_MUXREG(pin216, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA3_MASK, 0, 1); +DEFINE_2_MUXREG(pin217, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA4_MASK, 0, 1); +DEFINE_2_MUXREG(pin218, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA5_MASK, 0, 1); +DEFINE_2_MUXREG(pin219, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA6_MASK, 0, 1); +DEFINE_2_MUXREG(pin220, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA7_MASK, 0, 1); +DEFINE_2_MUXREG(pin221, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA1SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin222, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA2SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin223, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA3SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin224, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR0ALE_MASK, 0, 1); +DEFINE_2_MUXREG(pin225, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR1CLECLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin226, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR2_MASK, 0, 1); +DEFINE_2_MUXREG(pin227, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICECF_MASK, 0, 1); +DEFINE_2_MUXREG(pin228, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICEXD_MASK, 0, 1); +DEFINE_2_MUXREG(pin229, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICESDMMC_MASK, 0, 1); +DEFINE_2_MUXREG(pin230, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF1_MASK, 0, 1); +DEFINE_2_MUXREG(pin231, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF2_MASK, 0, 1); +DEFINE_2_MUXREG(pin232, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDXD_MASK, 0, 1); +DEFINE_2_MUXREG(pin233, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDSDMMC_MASK, 0, 1); +DEFINE_2_MUXREG(pin234, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATADIR_MASK, 0, 1); +DEFINE_2_MUXREG(pin235, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMARQWP_MASK, 0, 1); +DEFINE_2_MUXREG(pin236, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDRE_MASK, 0, 1); +DEFINE_2_MUXREG(pin237, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIOWRWE_MASK, 0, 1); +DEFINE_2_MUXREG(pin238, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIRESETCF_MASK, 0, 1); +DEFINE_2_MUXREG(pin239, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS0CE_MASK, 0, 1); +DEFINE_2_MUXREG(pin240, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICFINTR_MASK, 0, 1); +DEFINE_2_MUXREG(pin241, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDY_MASK, 0, 1); +DEFINE_2_MUXREG(pin242, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS1_MASK, 0, 1); +DEFINE_2_MUXREG(pin243, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMAACK_MASK, 0, 1); +DEFINE_2_MUXREG(pin244, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCISDCMD_MASK, 0, 1); +DEFINE_2_MUXREG(pin245, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCILEDS_MASK, 0, 1); +DEFINE_2_MUXREG(keyboard_rowcol6_8_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROWCOL68_MASK, 0, 1); +DEFINE_2_MUXREG(uart0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_UART0_MASK, 0, 1); +DEFINE_2_MUXREG(uart0_modem_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_UART0_MODEM_MASK, 0, 1); +DEFINE_2_MUXREG(gpt0_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR0_MASK, 0, 1); +DEFINE_2_MUXREG(gpt0_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR1_MASK, 0, 1); +DEFINE_2_MUXREG(gpt1_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR0_MASK, 0, 1); +DEFINE_2_MUXREG(gpt1_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR1_MASK, 0, 1); +DEFINE_2_MUXREG(touch_xy_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_TOUCH_XY_MASK, 0, 1); + +static struct spear_gpio_pingroup spear1310_gpio_pingroup[] = { + GPIO_PINGROUP(i2c0_pins), + GPIO_PINGROUP(ssp0_pins), + GPIO_PINGROUP(ssp0_cs0_pins), + GPIO_PINGROUP(ssp0_cs1_2_pins), + GPIO_PINGROUP(i2s0_pins), + GPIO_PINGROUP(i2s1_pins), + GPIO_PINGROUP(clcd_pins), + GPIO_PINGROUP(clcd_high_res_pins), + GPIO_PINGROUP(pin18), + GPIO_PINGROUP(pin19), + GPIO_PINGROUP(pin20), + GPIO_PINGROUP(pin21), + GPIO_PINGROUP(pin22), + GPIO_PINGROUP(pin23), + GPIO_PINGROUP(pin143), + GPIO_PINGROUP(pin144), + GPIO_PINGROUP(pin145), + GPIO_PINGROUP(pin146), + GPIO_PINGROUP(pin147), + GPIO_PINGROUP(pin148), + GPIO_PINGROUP(pin149), + GPIO_PINGROUP(pin150), + GPIO_PINGROUP(pin151), + GPIO_PINGROUP(pin152), + GPIO_PINGROUP(smi_2_chips_pins), + GPIO_PINGROUP(pin54), + GPIO_PINGROUP(pin55), + GPIO_PINGROUP(pin56), + GPIO_PINGROUP(pin57), + GPIO_PINGROUP(pin58), + GPIO_PINGROUP(pin59), + GPIO_PINGROUP(pin60), + GPIO_PINGROUP(pin61), + GPIO_PINGROUP(pin62), + GPIO_PINGROUP(pin63), + GPIO_PINGROUP(pin_grp0), + GPIO_PINGROUP(pin_grp1), + GPIO_PINGROUP(pin_grp2), + GPIO_PINGROUP(pin_grp3), + GPIO_PINGROUP(pin_grp4), + GPIO_PINGROUP(pin_grp5), + GPIO_PINGROUP(pin_grp6), + GPIO_PINGROUP(pin_grp7), + GPIO_PINGROUP(pin_grp8), + GPIO_PINGROUP(nand_16bit_pins), + GPIO_PINGROUP(pin205), + GPIO_PINGROUP(pin206), + GPIO_PINGROUP(pin211), + GPIO_PINGROUP(pin212), + GPIO_PINGROUP(pin213), + GPIO_PINGROUP(pin214), + GPIO_PINGROUP(pin215), + GPIO_PINGROUP(pin216), + GPIO_PINGROUP(pin217), + GPIO_PINGROUP(pin218), + GPIO_PINGROUP(pin219), + GPIO_PINGROUP(pin220), + GPIO_PINGROUP(pin221), + GPIO_PINGROUP(pin222), + GPIO_PINGROUP(pin223), + GPIO_PINGROUP(pin224), + GPIO_PINGROUP(pin225), + GPIO_PINGROUP(pin226), + GPIO_PINGROUP(pin227), + GPIO_PINGROUP(pin228), + GPIO_PINGROUP(pin229), + GPIO_PINGROUP(pin230), + GPIO_PINGROUP(pin231), + GPIO_PINGROUP(pin232), + GPIO_PINGROUP(pin233), + GPIO_PINGROUP(pin234), + GPIO_PINGROUP(pin235), + GPIO_PINGROUP(pin236), + GPIO_PINGROUP(pin237), + GPIO_PINGROUP(pin238), + GPIO_PINGROUP(pin239), + GPIO_PINGROUP(pin240), + GPIO_PINGROUP(pin241), + GPIO_PINGROUP(pin242), + GPIO_PINGROUP(pin243), + GPIO_PINGROUP(pin244), + GPIO_PINGROUP(pin245), + GPIO_PINGROUP(keyboard_rowcol6_8_pins), + GPIO_PINGROUP(uart0_pins), + GPIO_PINGROUP(uart0_modem_pins), + GPIO_PINGROUP(gpt0_tmr0_pins), + GPIO_PINGROUP(gpt0_tmr1_pins), + GPIO_PINGROUP(gpt1_tmr0_pins), + GPIO_PINGROUP(gpt1_tmr1_pins), + GPIO_PINGROUP(touch_xy_pins), +}; + static struct spear_pinctrl_machdata spear1310_machdata = { .pins = spear1310_pins, .npins = ARRAY_SIZE(spear1310_pins), @@ -2425,6 +2687,8 @@ static struct spear_pinctrl_machdata spear1310_machdata = { .ngroups = ARRAY_SIZE(spear1310_pingroups), .functions = spear1310_functions, .nfunctions = ARRAY_SIZE(spear1310_functions), + .gpio_pingroups = spear1310_gpio_pingroup, + .ngpio_pingroups = ARRAY_SIZE(spear1310_gpio_pingroup), .modes_supported = false, }; diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c index 4dfc2849b172..9a491007f42d 100644 --- a/drivers/pinctrl/spear/pinctrl-spear300.c +++ b/drivers/pinctrl/spear/pinctrl-spear300.c @@ -661,6 +661,8 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups); spear3xx_machdata.functions = spear300_functions; spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions); + spear3xx_machdata.gpio_pingroups = NULL; + spear3xx_machdata.ngpio_pingroups = 0; spear3xx_machdata.modes_supported = true; spear3xx_machdata.pmx_modes = spear300_pmx_modes; diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c index 96883693fb7e..4d5dfe9c760a 100644 --- a/drivers/pinctrl/spear/pinctrl-spear310.c +++ b/drivers/pinctrl/spear/pinctrl-spear310.c @@ -388,6 +388,8 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions); pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups, + spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG); spear3xx_machdata.modes_supported = false; diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c index ca47b0e50780..c996e26e3b6c 100644 --- a/drivers/pinctrl/spear/pinctrl-spear320.c +++ b/drivers/pinctrl/spear/pinctrl-spear320.c @@ -3431,6 +3431,8 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes); pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups, + spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG); ret = spear_pinctrl_probe(pdev, &spear3xx_machdata); if (ret) diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c index 0242378f7cb8..12ee21af766b 100644 --- a/drivers/pinctrl/spear/pinctrl-spear3xx.c +++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c @@ -481,7 +481,44 @@ struct spear_function spear3xx_timer_2_3_function = { .ngroups = ARRAY_SIZE(timer_2_3_grps), }; +/* Define muxreg arrays */ +DEFINE_MUXREG(firda_pins, 0, PMX_FIRDA_MASK, 0); +DEFINE_MUXREG(i2c_pins, 0, PMX_I2C_MASK, 0); +DEFINE_MUXREG(ssp_cs_pins, 0, PMX_SSP_CS_MASK, 0); +DEFINE_MUXREG(ssp_pins, 0, PMX_SSP_MASK, 0); +DEFINE_MUXREG(mii_pins, 0, PMX_MII_MASK, 0); +DEFINE_MUXREG(gpio0_pin0_pins, 0, PMX_GPIO_PIN0_MASK, 0); +DEFINE_MUXREG(gpio0_pin1_pins, 0, PMX_GPIO_PIN1_MASK, 0); +DEFINE_MUXREG(gpio0_pin2_pins, 0, PMX_GPIO_PIN2_MASK, 0); +DEFINE_MUXREG(gpio0_pin3_pins, 0, PMX_GPIO_PIN3_MASK, 0); +DEFINE_MUXREG(gpio0_pin4_pins, 0, PMX_GPIO_PIN4_MASK, 0); +DEFINE_MUXREG(gpio0_pin5_pins, 0, PMX_GPIO_PIN5_MASK, 0); +DEFINE_MUXREG(uart0_ext_pins, 0, PMX_UART0_MODEM_MASK, 0); +DEFINE_MUXREG(uart0_pins, 0, PMX_UART0_MASK, 0); +DEFINE_MUXREG(timer_0_1_pins, 0, PMX_TIMER_0_1_MASK, 0); +DEFINE_MUXREG(timer_2_3_pins, 0, PMX_TIMER_2_3_MASK, 0); + +static struct spear_gpio_pingroup spear3xx_gpio_pingroup[] = { + GPIO_PINGROUP(firda_pins), + GPIO_PINGROUP(i2c_pins), + GPIO_PINGROUP(ssp_cs_pins), + GPIO_PINGROUP(ssp_pins), + GPIO_PINGROUP(mii_pins), + GPIO_PINGROUP(gpio0_pin0_pins), + GPIO_PINGROUP(gpio0_pin1_pins), + GPIO_PINGROUP(gpio0_pin2_pins), + GPIO_PINGROUP(gpio0_pin3_pins), + GPIO_PINGROUP(gpio0_pin4_pins), + GPIO_PINGROUP(gpio0_pin5_pins), + GPIO_PINGROUP(uart0_ext_pins), + GPIO_PINGROUP(uart0_pins), + GPIO_PINGROUP(timer_0_1_pins), + GPIO_PINGROUP(timer_2_3_pins), +}; + struct spear_pinctrl_machdata spear3xx_machdata = { .pins = spear3xx_pins, .npins = ARRAY_SIZE(spear3xx_pins), + .gpio_pingroups = spear3xx_gpio_pingroup, + .ngpio_pingroups = ARRAY_SIZE(spear3xx_gpio_pingroup), }; From 4ddb1c295752252f61670e35c791bf16e58bbce6 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 27 Oct 2012 15:21:39 +0530 Subject: [PATCH 45/65] ARM: SPEAr: Add plgpio node in device tree dtsi files This patch adds plgpio nodes in SPEAr DT files. Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij --- arch/arm/boot/dts/spear1310-evb.dts | 4 ++++ arch/arm/boot/dts/spear1310.dtsi | 27 +++++++++++++++++++++++++++ arch/arm/boot/dts/spear1340-evb.dts | 4 ++++ arch/arm/boot/dts/spear1340.dtsi | 26 ++++++++++++++++++++++++++ arch/arm/boot/dts/spear310.dtsi | 22 +++++++++++++++++++++- arch/arm/boot/dts/spear320-evb.dts | 4 ++++ arch/arm/boot/dts/spear320.dtsi | 23 ++++++++++++++++++++++- 7 files changed, 108 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index dd4358bc26e2..2e4c5727468e 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -181,6 +181,10 @@ status = "okay"; }; + gpio@d8400000 { + status = "okay"; + }; + i2c0: i2c@e0280000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi index 419ea7413d23..7cd25eb4f8e0 100644 --- a/arch/arm/boot/dts/spear1310.dtsi +++ b/arch/arm/boot/dts/spear1310.dtsi @@ -70,6 +70,12 @@ status = "disabled"; }; + pinmux: pinmux@e0700000 { + compatible = "st,spear1310-pinmux"; + reg = <0xe0700000 0x1000>; + #gpio-range-cells = <2>; + }; + spi1: spi@5d400000 { compatible = "arm,pl022", "arm,primecell"; reg = <0x5d400000 0x1000>; @@ -179,6 +185,27 @@ thermal@e07008c4 { st,thermal-flags = <0x7000>; }; + + gpiopinctrl: gpio@d8400000 { + compatible = "st,spear-plgpio"; + reg = <0xd8400000 0x1000>; + interrupts = <0 100 0x4>; + #interrupt-cells = <1>; + interrupt-controller; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinmux 0 246>; + status = "disabled"; + + st-plgpio,ngpio = <246>; + st-plgpio,enb-reg = <0xd0>; + st-plgpio,wdata-reg = <0x90>; + st-plgpio,dir-reg = <0xb0>; + st-plgpio,ie-reg = <0x30>; + st-plgpio,rdata-reg = <0x70>; + st-plgpio,mis-reg = <0x10>; + st-plgpio,eit-reg = <0x50>; + }; }; }; }; diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts index c9a54e06fb68..045f7123ffac 100644 --- a/arch/arm/boot/dts/spear1340-evb.dts +++ b/arch/arm/boot/dts/spear1340-evb.dts @@ -193,6 +193,10 @@ status = "okay"; }; + gpio@e2800000 { + status = "okay"; + }; + i2c0: i2c@e0280000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index d71fe2a68f09..6c09eb0a1b2b 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -24,6 +24,12 @@ status = "disabled"; }; + pinmux: pinmux@e0700000 { + compatible = "st,spear1340-pinmux"; + reg = <0xe0700000 0x1000>; + #gpio-range-cells = <2>; + }; + spi1: spi@5d400000 { compatible = "arm,pl022", "arm,primecell"; reg = <0x5d400000 0x1000>; @@ -51,6 +57,26 @@ thermal@e07008c4 { st,thermal-flags = <0x2a00>; }; + + gpiopinctrl: gpio@e2800000 { + compatible = "st,spear-plgpio"; + reg = <0xe2800000 0x1000>; + interrupts = <0 107 0x4>; + #interrupt-cells = <1>; + interrupt-controller; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinmux 0 252>; + status = "disabled"; + + st-plgpio,ngpio = <250>; + st-plgpio,wdata-reg = <0x40>; + st-plgpio,dir-reg = <0x00>; + st-plgpio,ie-reg = <0x80>; + st-plgpio,rdata-reg = <0x20>; + st-plgpio,mis-reg = <0xa0>; + st-plgpio,eit-reg = <0x60>; + }; }; }; }; diff --git a/arch/arm/boot/dts/spear310.dtsi b/arch/arm/boot/dts/spear310.dtsi index 62fc4fb3e5f9..930303e48df9 100644 --- a/arch/arm/boot/dts/spear310.dtsi +++ b/arch/arm/boot/dts/spear310.dtsi @@ -22,9 +22,10 @@ 0xb0000000 0xb0000000 0x10000000 0xd0000000 0xd0000000 0x30000000>; - pinmux@b4000000 { + pinmux: pinmux@b4000000 { compatible = "st,spear310-pinmux"; reg = <0xb4000000 0x1000>; + #gpio-range-cells = <2>; }; fsmc: flash@44000000 { @@ -75,6 +76,25 @@ reg = <0xb2200000 0x1000>; status = "disabled"; }; + + gpiopinctrl: gpio@b4000000 { + compatible = "st,spear-plgpio"; + reg = <0xb4000000 0x1000>; + #interrupt-cells = <1>; + interrupt-controller; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinmux 0 102>; + status = "disabled"; + + st-plgpio,ngpio = <102>; + st-plgpio,enb-reg = <0x10>; + st-plgpio,wdata-reg = <0x20>; + st-plgpio,dir-reg = <0x30>; + st-plgpio,ie-reg = <0x50>; + st-plgpio,rdata-reg = <0x40>; + st-plgpio,mis-reg = <0x60>; + }; }; }; }; diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts index 082328bd64ab..ad4bfc68ee05 100644 --- a/arch/arm/boot/dts/spear320-evb.dts +++ b/arch/arm/boot/dts/spear320-evb.dts @@ -164,6 +164,10 @@ status = "okay"; }; + gpio@b3000000 { + status = "okay"; + }; + i2c0: i2c@d0180000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi index 1f49d69595a0..67d7ada71275 100644 --- a/arch/arm/boot/dts/spear320.dtsi +++ b/arch/arm/boot/dts/spear320.dtsi @@ -21,9 +21,10 @@ ranges = <0x40000000 0x40000000 0x80000000 0xd0000000 0xd0000000 0x30000000>; - pinmux@b3000000 { + pinmux: pinmux@b3000000 { compatible = "st,spear320-pinmux"; reg = <0xb3000000 0x1000>; + #gpio-range-cells = <2>; }; clcd@90000000 { @@ -90,6 +91,26 @@ reg = <0xa4000000 0x1000>; status = "disabled"; }; + + gpiopinctrl: gpio@b3000000 { + compatible = "st,spear-plgpio"; + reg = <0xb3000000 0x1000>; + #interrupt-cells = <1>; + interrupt-controller; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinmux 0 102>; + status = "disabled"; + + st-plgpio,ngpio = <102>; + st-plgpio,enb-reg = <0x24>; + st-plgpio,wdata-reg = <0x34>; + st-plgpio,dir-reg = <0x44>; + st-plgpio,ie-reg = <0x64>; + st-plgpio,rdata-reg = <0x54>; + st-plgpio,mis-reg = <0x84>; + st-plgpio,eit-reg = <0x94>; + }; }; }; }; From 55ecd26373bc995c279a5d988ee36c2767e4f3ca Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Nov 2012 18:01:51 +0100 Subject: [PATCH 46/65] gpio: pca953x: Register an IRQ domain The PCA953x used to register no IRQ domain, which made it impossible to use it as an interrupt-parent from the device tree. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 9c693ae17956..5ba7e60de942 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,7 @@ struct pca953x_chip { u32 irq_trig_raise; u32 irq_trig_fall; int irq_base; + struct irq_domain *domain; #endif struct i2c_client *client; @@ -333,14 +335,14 @@ static void pca953x_irq_mask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask &= ~(1 << (d->irq - chip->irq_base)); + chip->irq_mask &= ~(1 << d->hwirq); } static void pca953x_irq_unmask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask |= 1 << (d->irq - chip->irq_base); + chip->irq_mask |= 1 << d->hwirq; } static void pca953x_irq_bus_lock(struct irq_data *d) @@ -372,8 +374,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - u32 level = d->irq - chip->irq_base; - u32 mask = 1 << level; + u32 mask = 1 << d->hwirq; if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", @@ -454,7 +455,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(level + chip->irq_base); + handle_nested_irq(irq_find_mapping(chip->domain, level)); pending &= ~(1 << level); } while (pending); @@ -499,6 +500,17 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (chip->irq_base < 0) goto out_failed; + chip->domain = irq_domain_add_legacy(client->dev.of_node, + chip->gpio_chip.ngpio, + chip->irq_base, + 0, + &irq_domain_simple_ops, + NULL); + if (!chip->domain) { + ret = -ENODEV; + goto out_irqdesc_free; + } + for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { int irq = lvl + chip->irq_base; @@ -521,7 +533,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); - goto out_failed; + goto out_irqdesc_free; } chip->gpio_chip.to_irq = pca953x_gpio_to_irq; @@ -529,6 +541,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return 0; +out_irqdesc_free: + irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio); out_failed: chip->irq_base = -1; return ret; From ed32620ea72889c8a9dda278a960bce01136d9a4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Nov 2012 18:01:52 +0100 Subject: [PATCH 47/65] gpio: pca953x: Add compatible strings to gpio-pca953x driver Even though the device tree binding code was already written, the compatible strings were not yet in the driver. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5ba7e60de942..0c5eaf5f4c90 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -765,9 +765,38 @@ static int pca953x_remove(struct i2c_client *client) return 0; } +static const struct of_device_id pca953x_dt_ids[] = { + { .compatible = "nxp,pca9534", }, + { .compatible = "nxp,pca9535", }, + { .compatible = "nxp,pca9536", }, + { .compatible = "nxp,pca9537", }, + { .compatible = "nxp,pca9538", }, + { .compatible = "nxp,pca9539", }, + { .compatible = "nxp,pca9554", }, + { .compatible = "nxp,pca9555", }, + { .compatible = "nxp,pca9556", }, + { .compatible = "nxp,pca9557", }, + { .compatible = "nxp,pca9574", }, + { .compatible = "nxp,pca9575", }, + + { .compatible = "maxim,max7310", }, + { .compatible = "maxim,max7312", }, + { .compatible = "maxim,max7313", }, + { .compatible = "maxim,max7315", }, + + { .compatible = "ti,pca6107", }, + { .compatible = "ti,tca6408", }, + { .compatible = "ti,tca6416", }, + { .compatible = "ti,tca6424", }, + { } +}; + +MODULE_DEVICE_TABLE(of, pca953x_dt_ids); + static struct i2c_driver pca953x_driver = { .driver = { .name = "pca953x", + .of_match_table = pca953x_dt_ids, }, .probe = pca953x_probe, .remove = pca953x_remove, From 195812e4b6a631e8eaad4046bf6890db4328ea1f Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 9 Nov 2012 11:34:20 +0530 Subject: [PATCH 48/65] gpio: tegra: read output value when gpio is set in direction_out Read the output value when gpio is set for the output mode for gpio_get_value(). Reading input value in direction out does not give correct value. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index cfd9b723002b..5389be8c2b51 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -134,6 +134,11 @@ static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) { + /* If gpio is in output mode then read from the out value */ + if ((tegra_gpio_readl(GPIO_OE(offset)) >> GPIO_BIT(offset)) & 1) + return (tegra_gpio_readl(GPIO_OUT(offset)) >> + GPIO_BIT(offset)) & 0x1; + return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; } From 9859eb99e9212339e2009b98c396b08260276edf Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 13 Nov 2012 10:35:13 +0100 Subject: [PATCH 49/65] gpio: twl4030: Use only TWL4030_MODULE_LED for LED configuration Avoid using the TWL4030_MODULE_PWMA/B as module ID. The LEDEN, PWMA ON/OFF and PWMB ON/OFF registers are in a continuous range starting from LED base. This is going to be helpful for further cleanup in the twl stack. No functional changes. Signed-off-by: Peter Ujfalusi Signed-off-by: Linus Walleij --- drivers/gpio/gpio-twl4030.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index c5f8ca233e1f..d2138b0fd4ca 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -88,11 +88,15 @@ static inline int gpio_twl4030_write(u8 address, u8 data) /*----------------------------------------------------------------------*/ /* - * LED register offsets (use TWL4030_MODULE_{LED,PWMA,PWMB})) + * LED register offsets from TWL_MODULE_LED base * PWMs A and B are dedicated to LEDs A and B, respectively. */ -#define TWL4030_LED_LEDEN 0x0 +#define TWL4030_LED_LEDEN_REG 0x00 +#define TWL4030_PWMAON_REG 0x01 +#define TWL4030_PWMAOFF_REG 0x02 +#define TWL4030_PWMBON_REG 0x03 +#define TWL4030_PWMBOFF_REG 0x04 /* LEDEN bits */ #define LEDEN_LEDAON BIT(0) @@ -104,9 +108,6 @@ static inline int gpio_twl4030_write(u8 address, u8 data) #define LEDEN_PWM_LENGTHA BIT(6) #define LEDEN_PWM_LENGTHB BIT(7) -#define TWL4030_PWMx_PWMxON 0x0 -#define TWL4030_PWMx_PWMxOFF 0x1 - #define PWMxON_LENGTH BIT(7) /*----------------------------------------------------------------------*/ @@ -145,7 +146,7 @@ static void twl4030_led_set_value(int led, int value) else cached_leden |= mask; status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, - TWL4030_LED_LEDEN); + TWL4030_LED_LEDEN_REG); mutex_unlock(&gpio_lock); } @@ -216,33 +217,33 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) if (offset >= TWL4030_GPIO_MAX) { u8 ledclr_mask = LEDEN_LEDAON | LEDEN_LEDAEXT | LEDEN_LEDAPWM | LEDEN_PWM_LENGTHA; - u8 module = TWL4030_MODULE_PWMA; + u8 reg = TWL4030_PWMAON_REG; offset -= TWL4030_GPIO_MAX; if (offset) { ledclr_mask <<= 1; - module = TWL4030_MODULE_PWMB; + reg = TWL4030_PWMBON_REG; } /* initialize PWM to always-drive */ - status = twl_i2c_write_u8(module, 0x7f, - TWL4030_PWMx_PWMxOFF); + /* Configure PWM OFF register first */ + status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg + 1); if (status < 0) goto done; - status = twl_i2c_write_u8(module, 0x7f, - TWL4030_PWMx_PWMxON); + + /* Followed by PWM ON register */ + status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg); if (status < 0) goto done; /* init LED to not-driven (high) */ - module = TWL4030_MODULE_LED; - status = twl_i2c_read_u8(module, &cached_leden, - TWL4030_LED_LEDEN); + status = twl_i2c_read_u8(TWL4030_MODULE_LED, &cached_leden, + TWL4030_LED_LEDEN_REG); if (status < 0) goto done; cached_leden &= ~ledclr_mask; - status = twl_i2c_write_u8(module, cached_leden, - TWL4030_LED_LEDEN); + status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, + TWL4030_LED_LEDEN_REG); if (status < 0) goto done; From 8754fccbae661a0020923cffd63e21de36d51e2e Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Thu, 15 Nov 2012 14:59:40 +0100 Subject: [PATCH 50/65] gpio: gpio-max710x: Support device tree probing For probing via device tree, we need to support the case without platform_data. In this case, chip.base is set to -1 for automatic numbering. Signed-off-by: Roland Stigge Acked-by: Wolfram Sang Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max730x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 05e2dac60b3b..c4bf86abd4d8 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -167,10 +167,6 @@ int __devinit __max730x_probe(struct max7301 *ts) int i, ret; pdata = dev->platform_data; - if (!pdata || !pdata->base) { - dev_err(dev, "incorrect or missing platform data\n"); - return -EINVAL; - } mutex_init(&ts->lock); dev_set_drvdata(dev, ts); @@ -178,7 +174,12 @@ int __devinit __max730x_probe(struct max7301 *ts) /* Power up the chip and disable IRQ output */ ts->write(dev, 0x04, 0x01); - ts->input_pullup_active = pdata->input_pullup_active; + if (pdata) { + ts->input_pullup_active = pdata->input_pullup_active; + ts->chip.base = pdata->base; + } else { + ts->chip.base = -1; + } ts->chip.label = dev->driver->name; ts->chip.direction_input = max7301_direction_input; @@ -186,7 +187,6 @@ int __devinit __max730x_probe(struct max7301 *ts) ts->chip.direction_output = max7301_direction_output; ts->chip.set = max7301_set; - ts->chip.base = pdata->base; ts->chip.ngpio = PIN_NUMBER; ts->chip.can_sleep = 1; ts->chip.dev = dev; From b53bc2819a71099ecfc3d61ba0796b3dcc6be321 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Fri, 16 Nov 2012 10:45:25 +0530 Subject: [PATCH 51/65] gpio: SPEAr: add spi chipselect control driver SPEAr platform provides a provision to control chipselects of ARM PL022 Prime Cell spi controller through its system registers, which otherwise remains under PL022 control which some protocols do not want. This commit intends to provide the spi chipselect control in software over gpiolib interface. spi chip drivers can use the exported gpiolib interface to define their chipselect through DT or platform data. Cc: Grant Likely Signed-off-by: Shiraz Hashim Reviewed-by: Vipin Kumar Acked-by: Arnd Bergmann Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/spear_spics.txt | 50 ++++ arch/arm/plat-spear/Kconfig | 1 + drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-spear-spics.c | 217 ++++++++++++++++++ 5 files changed, 276 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/spear_spics.txt create mode 100644 drivers/gpio/gpio-spear-spics.c diff --git a/Documentation/devicetree/bindings/gpio/spear_spics.txt b/Documentation/devicetree/bindings/gpio/spear_spics.txt new file mode 100644 index 000000000000..96c37eb15075 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/spear_spics.txt @@ -0,0 +1,50 @@ +=== ST Microelectronics SPEAr SPI CS Driver === + +SPEAr platform provides a provision to control chipselects of ARM PL022 Prime +Cell spi controller through its system registers, which otherwise remains under +PL022 control. If chipselect remain under PL022 control then they would be +released as soon as transfer is over and TxFIFO becomes empty. This is not +desired by some of the device protocols above spi which expect (multiple) +transfers without releasing their chipselects. + +Chipselects can be controlled by software by turning them as GPIOs. SPEAr +provides another interface through system registers through which software can +directly control each PL022 chipselect. Hence, it is natural for SPEAr to export +the control of this interface as gpio. + +Required properties: + + * compatible: should be defined as "st,spear-spics-gpio" + * reg: mentioning address range of spics controller + * st-spics,peripcfg-reg: peripheral configuration register offset + * st-spics,sw-enable-bit: bit offset to enable sw control + * st-spics,cs-value-bit: bit offset to drive chipselect low or high + * st-spics,cs-enable-mask: chip select number bit mask + * st-spics,cs-enable-shift: chip select number program offset + * gpio-controller: Marks the device node as gpio controller + * #gpio-cells: should be 1 and will mention chip select number + +All the above bit offsets are within peripcfg register. + +Example: +------- +spics: spics@e0700000{ + compatible = "st,spear-spics-gpio"; + reg = <0xe0700000 0x1000>; + st-spics,peripcfg-reg = <0x3b0>; + st-spics,sw-enable-bit = <12>; + st-spics,cs-value-bit = <11>; + st-spics,cs-enable-mask = <3>; + st-spics,cs-enable-shift = <8>; + gpio-controller; + #gpio-cells = <2>; +}; + + +spi0: spi@e0100000 { + status = "okay"; + num-cs = <3>; + cs-gpios = <&gpio1 7 0>, <&spics 0>, + <&spics 1>; + ... +} diff --git a/arch/arm/plat-spear/Kconfig b/arch/arm/plat-spear/Kconfig index f8db7b2deb36..87dbd81bdf51 100644 --- a/arch/arm/plat-spear/Kconfig +++ b/arch/arm/plat-spear/Kconfig @@ -12,6 +12,7 @@ config ARCH_SPEAR13XX bool "ST SPEAr13xx with Device Tree" select ARM_GIC select CPU_V7 + select GPIO_SPEAR_SPICS select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 select PINCTRL diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9e3fb3438718..4f592c615990 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -196,6 +196,13 @@ config GPIO_PXA help Say yes here to support the PXA GPIO device +config GPIO_SPEAR_SPICS + bool "ST SPEAr13xx SPI Chip Select as GPIO support" + depends on PLAT_SPEAR + select GENERIC_IRQ_CHIP + help + Say yes here to support ST SPEAr SPI Chip Select as GPIO device + config GPIO_STA2X11 bool "STA2x11/ConneXt GPIO support" depends on MFD_STA2X11 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1c1b63fcaeb3..a268d99f4e43 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o +obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c new file mode 100644 index 000000000000..5f45fc4ed5d1 --- /dev/null +++ b/drivers/gpio/gpio-spear-spics.c @@ -0,0 +1,217 @@ +/* + * SPEAr platform SPI chipselect abstraction over gpiolib + * + * Copyright (C) 2012 ST Microelectronics + * Shiraz Hashim + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* maximum chipselects */ +#define NUM_OF_GPIO 4 + +/* + * Provision is available on some SPEAr SoCs to control ARM PL022 spi cs + * through system registers. This register lies outside spi (pl022) + * address space into system registers. + * + * It provides control for spi chip select lines so that any chipselect + * (out of 4 possible chipselects in pl022) can be made low to select + * the particular slave. + */ + +/** + * struct spear_spics - represents spi chip select control + * @base: base address + * @perip_cfg: configuration register + * @sw_enable_bit: bit to enable s/w control over chipselects + * @cs_value_bit: bit to program high or low chipselect + * @cs_enable_mask: mask to select bits required to select chipselect + * @cs_enable_shift: bit pos of cs_enable_mask + * @use_count: use count of a spi controller cs lines + * @last_off: stores last offset caller of set_value() + * @chip: gpio_chip abstraction + */ +struct spear_spics { + void __iomem *base; + u32 perip_cfg; + u32 sw_enable_bit; + u32 cs_value_bit; + u32 cs_enable_mask; + u32 cs_enable_shift; + unsigned long use_count; + int last_off; + struct gpio_chip chip; +}; + +/* gpio framework specific routines */ +static int spics_get_value(struct gpio_chip *chip, unsigned offset) +{ + return -ENXIO; +} + +static void spics_set_value(struct gpio_chip *chip, unsigned offset, int value) +{ + struct spear_spics *spics = container_of(chip, struct spear_spics, + chip); + u32 tmp; + + /* select chip select from register */ + tmp = readl_relaxed(spics->base + spics->perip_cfg); + if (spics->last_off != offset) { + spics->last_off = offset; + tmp &= ~(spics->cs_enable_mask << spics->cs_enable_shift); + tmp |= offset << spics->cs_enable_shift; + } + + /* toggle chip select line */ + tmp &= ~(0x1 << spics->cs_value_bit); + tmp |= value << spics->cs_value_bit; + writel_relaxed(tmp, spics->base + spics->perip_cfg); +} + +static int spics_direction_input(struct gpio_chip *chip, unsigned offset) +{ + return -ENXIO; +} + +static int spics_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + spics_set_value(chip, offset, value); + return 0; +} + +static int spics_request(struct gpio_chip *chip, unsigned offset) +{ + struct spear_spics *spics = container_of(chip, struct spear_spics, + chip); + u32 tmp; + + if (!spics->use_count++) { + tmp = readl_relaxed(spics->base + spics->perip_cfg); + tmp |= 0x1 << spics->sw_enable_bit; + tmp |= 0x1 << spics->cs_value_bit; + writel_relaxed(tmp, spics->base + spics->perip_cfg); + } + + return 0; +} + +static void spics_free(struct gpio_chip *chip, unsigned offset) +{ + struct spear_spics *spics = container_of(chip, struct spear_spics, + chip); + u32 tmp; + + if (!--spics->use_count) { + tmp = readl_relaxed(spics->base + spics->perip_cfg); + tmp &= ~(0x1 << spics->sw_enable_bit); + writel_relaxed(tmp, spics->base + spics->perip_cfg); + } +} + +static int spics_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spear_spics *spics; + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n"); + return -EBUSY; + } + + spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL); + if (!spics) { + dev_err(&pdev->dev, "memory allocation fail\n"); + return -ENOMEM; + } + + spics->base = devm_request_and_ioremap(&pdev->dev, res); + if (!spics->base) { + dev_err(&pdev->dev, "request and ioremap fail\n"); + return -ENOMEM; + } + + if (of_property_read_u32(np, "st-spics,peripcfg-reg", + &spics->perip_cfg)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,sw-enable-bit", + &spics->sw_enable_bit)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,cs-value-bit", + &spics->cs_value_bit)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,cs-enable-mask", + &spics->cs_enable_mask)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,cs-enable-shift", + &spics->cs_enable_shift)) + goto err_dt_data; + + platform_set_drvdata(pdev, spics); + + spics->chip.ngpio = NUM_OF_GPIO; + spics->chip.base = -1; + spics->chip.request = spics_request; + spics->chip.free = spics_free; + spics->chip.direction_input = spics_direction_input; + spics->chip.direction_output = spics_direction_output; + spics->chip.get = spics_get_value; + spics->chip.set = spics_set_value; + spics->chip.label = dev_name(&pdev->dev); + spics->chip.dev = &pdev->dev; + spics->chip.owner = THIS_MODULE; + spics->last_off = -1; + + ret = gpiochip_add(&spics->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpio chip\n"); + return ret; + } + + dev_info(&pdev->dev, "spear spics registered\n"); + return 0; + +err_dt_data: + dev_err(&pdev->dev, "DT probe failed\n"); + return -EINVAL; +} + +static const struct of_device_id spics_gpio_of_match[] = { + { .compatible = "st,spear-spics-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, spics_gpio_of_match); + +static struct platform_driver spics_gpio_driver = { + .probe = spics_gpio_probe, + .driver = { + .owner = THIS_MODULE, + .name = "spear-spics-gpio", + .of_match_table = spics_gpio_of_match, + }, +}; + +static int __init spics_gpio_init(void) +{ + return platform_driver_register(&spics_gpio_driver); +} +subsys_initcall(spics_gpio_init); + +MODULE_AUTHOR("Shiraz Hashim "); +MODULE_DESCRIPTION("ST Microlectronics SPEAr SPI Chip Select Abstraction"); +MODULE_LICENSE("GPL"); From 7cef07d5cd25b1286376d1e8948f75b89d34a37e Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Mon, 3 Sep 2012 11:46:58 +0530 Subject: [PATCH 52/65] ARM: SPEAr13xx: DT: Add spics gpio controller nodes SPEAr platform provides a provision to control chipselects of ARM PL022 Prime Cell spi controller through its system registers, which otherwise remains under PL022 control which some protocols do not want. This patch adds spics controller nodes in device tree for various SPEAr13xx SoCs. Cc: Linus Walleij Signed-off-by: Shiraz Hashim Reviewed-by: Vipin Kumar Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/spear1310.dtsi | 12 ++++++++++++ arch/arm/boot/dts/spear1340.dtsi | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi index 7cd25eb4f8e0..f489f648c6eb 100644 --- a/arch/arm/boot/dts/spear1310.dtsi +++ b/arch/arm/boot/dts/spear1310.dtsi @@ -17,6 +17,18 @@ compatible = "st,spear1310"; ahb { + spics: spics@e0700000{ + compatible = "st,spear-spics-gpio"; + reg = <0xe0700000 0x1000>; + st-spics,peripcfg-reg = <0x3b0>; + st-spics,sw-enable-bit = <12>; + st-spics,cs-value-bit = <11>; + st-spics,cs-enable-mask = <3>; + st-spics,cs-enable-shift = <8>; + gpio-controller; + #gpio-cells = <2>; + }; + ahci@b1000000 { compatible = "snps,spear-ahci"; reg = <0xb1000000 0x10000>; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index 6c09eb0a1b2b..64d14fde215d 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -17,6 +17,20 @@ compatible = "st,spear1340"; ahb { + + spics: spics@e0700000{ + compatible = "st,spear-spics-gpio"; + reg = <0xe0700000 0x1000>; + st-spics,peripcfg-reg = <0x42c>; + st-spics,sw-enable-bit = <21>; + st-spics,cs-value-bit = <20>; + st-spics,cs-enable-mask = <3>; + st-spics,cs-enable-shift = <18>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + ahci@b1000000 { compatible = "snps,spear-ahci"; reg = <0xb1000000 0x10000>; From 7db083e0e1b70b0300eeb5945538e725c018f8e0 Mon Sep 17 00:00:00 2001 From: Vipul Kumar Samar Date: Thu, 5 Jul 2012 11:51:47 +0800 Subject: [PATCH 53/65] ARM: SPEAr: DT: Update pinctrl list This patch updates pinctrl configuration for SPEAr SoC's. Signed-off-by: Shiraz Hashim Signed-off-by: Vipul Kumar Samar Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/spear1310-evb.dts | 23 ++++++++++++++----- arch/arm/boot/dts/spear1340-evb.dts | 35 +++++++++++++++++------------ arch/arm/boot/dts/spear320-evb.dts | 6 +---- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index 2e4c5727468e..3448d60117ec 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -30,10 +30,14 @@ pinctrl-0 = <&state_default>; state_default: pinmux { - i2c0-pmx { + i2c0 { st,pins = "i2c0_grp"; st,function = "i2c0"; }; + i2s0 { + st,pins = "i2s0_grp"; + st,function = "i2s0"; + }; i2s1 { st,pins = "i2s1_grp"; st,function = "i2s1"; @@ -42,6 +46,10 @@ st,pins = "arm_gpio_grp"; st,function = "arm_gpio"; }; + clcd { + st,pins = "clcd_grp" , "clcd_high_res"; + st,function = "clcd"; + }; eth { st,pins = "gmii_grp"; st,function = "gmii"; @@ -74,11 +82,6 @@ st,pins = "i2c_1_2_grp"; st,function = "i2c_1_2"; }; - pci { - st,pins = "pcie0_grp","pcie1_grp", - "pcie2_grp"; - st,function = "pci"; - }; smii { st,pins = "smii_0_1_2_grp"; st,function = "smii_0_1_2"; @@ -88,6 +91,14 @@ "nand_16bit_grp"; st,function = "nand"; }; + sata { + st,pins = "sata0_grp"; + st,function = "sata"; + }; + pcie { + st,pins = "pcie1_grp", "pcie2_grp"; + st,function = "pci_express"; + }; }; }; diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts index 045f7123ffac..1fc558424d96 100644 --- a/arch/arm/boot/dts/spear1340-evb.dts +++ b/arch/arm/boot/dts/spear1340-evb.dts @@ -38,20 +38,15 @@ st,pins = "fsmc_8bit_grp"; st,function = "fsmc"; }; - kbd { - st,pins = "keyboard_row_col_grp", - "keyboard_col5_grp"; - st,function = "keyboard"; - }; uart0 { - st,pins = "uart0_grp", "uart0_enh_grp"; + st,pins = "uart0_grp"; st,function = "uart0"; }; - i2c0-pmx { + i2c0 { st,pins = "i2c0_grp"; st,function = "i2c0"; }; - i2c1-pmx { + i2c1 { st,pins = "i2c1_grp"; st,function = "i2c1"; }; @@ -64,14 +59,9 @@ st,function = "spdif_out"; }; ssp0 { - st,pins = "ssp0_grp", "ssp0_cs1_grp", - "ssp0_cs3_grp"; + st,pins = "ssp0_grp", "ssp0_cs1_grp", "ssp0_cs2_grp", "ssp0_cs3_grp"; st,function = "ssp0"; }; - pwm { - st,pins = "pwm2_grp", "pwm3_grp"; - st,function = "pwm"; - }; smi-pmx { st,pins = "smi_grp"; st,function = "smi"; @@ -84,6 +74,18 @@ st,pins = "gmii_grp", "rgmii_grp"; st,function = "gmac"; }; + cam0 { + st,pins = "cam0_grp"; + st,function = "cam0"; + }; + cam1 { + st,pins = "cam1_grp"; + st,function = "cam1"; + }; + cam2 { + st,pins = "cam2_grp"; + st,function = "cam2"; + }; cam3 { st,pins = "cam3_grp"; st,function = "cam3"; @@ -108,6 +110,11 @@ st,pins = "sata_grp"; st,function = "sata"; }; + pcie { + st,pins = "pcie_grp"; + st,function = "pcie"; + }; + }; }; diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts index ad4bfc68ee05..70c3498b16a4 100644 --- a/arch/arm/boot/dts/spear320-evb.dts +++ b/arch/arm/boot/dts/spear320-evb.dts @@ -76,13 +76,9 @@ st,function = "mii2"; }; pwm0_1 { - st,pins = "pwm0_1_pin_14_15_grp"; + st,pins = "pwm0_1_pin_37_38_grp"; st,function = "pwm0_1"; }; - pwm2 { - st,pins = "pwm2_pin_13_grp"; - st,function = "pwm2"; - }; }; }; From 482a8f3f53e9bc7a52ef54f6cd40bcf2c270e2f5 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Thu, 5 Jul 2012 11:51:47 +0800 Subject: [PATCH 54/65] ARM: SPEAr: DT: Update partition info for MTD devices This patch enhances partition information of MTD devices like fsmc-nand and spear-smi. Signed-off-by: Shiraz Hashim Signed-off-by: Vipin Kumar Signed-off-by: Vipul Kumar Samar Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/spear1310-evb.dts | 43 +++++++++++++++++++++++++---- arch/arm/boot/dts/spear1340-evb.dts | 43 +++++++++++++++++++++++++---- arch/arm/boot/dts/spear300-evb.dts | 18 ++++++++---- arch/arm/boot/dts/spear310-evb.dts | 18 ++++++++---- arch/arm/boot/dts/spear320-evb.dts | 18 ++++++++---- arch/arm/boot/dts/spear600-evb.dts | 18 ++++++++---- 6 files changed, 128 insertions(+), 30 deletions(-) diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index 3448d60117ec..010e21deb867 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -120,6 +120,31 @@ fsmc: flash@b0000000 { status = "okay"; + + partition@0 { + label = "xloader"; + reg = <0x0 0x80000>; + }; + partition@80000 { + label = "u-boot"; + reg = <0x80000 0x140000>; + }; + partition@1C0000 { + label = "environment"; + reg = <0x1C0000 0x40000>; + }; + partition@200000 { + label = "dtb"; + reg = <0x200000 0x40000>; + }; + partition@240000 { + label = "linux"; + reg = <0x240000 0xC00000>; + }; + partition@E40000 { + label = "rootfs"; + reg = <0xE40000 0x0>; + }; }; gmac0: eth@e2000000 { @@ -146,15 +171,23 @@ }; partition@10000 { label = "u-boot"; - reg = <0x10000 0x40000>; + reg = <0x10000 0x50000>; + }; + partition@60000 { + label = "environment"; + reg = <0x60000 0x10000>; + }; + partition@70000 { + label = "dtb"; + reg = <0x70000 0x10000>; }; - partition@50000 { + partition@80000 { label = "linux"; - reg = <0x50000 0x2c0000>; + reg = <0x80000 0x310000>; }; - partition@310000 { + partition@390000 { label = "rootfs"; - reg = <0x310000 0x4f0000>; + reg = <0x390000 0x0>; }; }; }; diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts index 1fc558424d96..b16f7569bf5b 100644 --- a/arch/arm/boot/dts/spear1340-evb.dts +++ b/arch/arm/boot/dts/spear1340-evb.dts @@ -128,6 +128,31 @@ fsmc: flash@b0000000 { status = "okay"; + + partition@0 { + label = "xloader"; + reg = <0x0 0x200000>; + }; + partition@200000 { + label = "u-boot"; + reg = <0x200000 0x200000>; + }; + partition@400000 { + label = "environment"; + reg = <0x400000 0x100000>; + }; + partition@500000 { + label = "dtb"; + reg = <0x500000 0x100000>; + }; + partition@600000 { + label = "linux"; + reg = <0x600000 0xC00000>; + }; + partition@1200000 { + label = "rootfs"; + reg = <0x1200000 0x0>; + }; }; gmac0: eth@e2000000 { @@ -154,15 +179,23 @@ }; partition@10000 { label = "u-boot"; - reg = <0x10000 0x40000>; + reg = <0x10000 0x50000>; + }; + partition@60000 { + label = "environment"; + reg = <0x60000 0x10000>; + }; + partition@70000 { + label = "dtb"; + reg = <0x70000 0x10000>; }; - partition@50000 { + partition@80000 { label = "linux"; - reg = <0x50000 0x2c0000>; + reg = <0x80000 0x310000>; }; - partition@310000 { + partition@390000 { label = "rootfs"; - reg = <0x310000 0x4f0000>; + reg = <0x390000 0x0>; }; }; }; diff --git a/arch/arm/boot/dts/spear300-evb.dts b/arch/arm/boot/dts/spear300-evb.dts index 1e7c7a8e2123..b3265f6f5958 100644 --- a/arch/arm/boot/dts/spear300-evb.dts +++ b/arch/arm/boot/dts/spear300-evb.dts @@ -100,15 +100,23 @@ }; partition@10000 { label = "u-boot"; - reg = <0x10000 0x40000>; + reg = <0x10000 0x50000>; }; - partition@50000 { + partition@60000 { + label = "environment"; + reg = <0x60000 0x10000>; + }; + partition@70000 { + label = "dtb"; + reg = <0x70000 0x10000>; + }; + partition@80000 { label = "linux"; - reg = <0x50000 0x2c0000>; + reg = <0x80000 0x310000>; }; - partition@310000 { + partition@390000 { label = "rootfs"; - reg = <0x310000 0x4f0000>; + reg = <0x390000 0x0>; }; }; }; diff --git a/arch/arm/boot/dts/spear310-evb.dts b/arch/arm/boot/dts/spear310-evb.dts index b00544e0cd5d..b30fa0e60010 100644 --- a/arch/arm/boot/dts/spear310-evb.dts +++ b/arch/arm/boot/dts/spear310-evb.dts @@ -114,15 +114,23 @@ }; partition@10000 { label = "u-boot"; - reg = <0x10000 0x40000>; + reg = <0x10000 0x50000>; }; - partition@50000 { + partition@60000 { + label = "environment"; + reg = <0x60000 0x10000>; + }; + partition@70000 { + label = "dtb"; + reg = <0x70000 0x10000>; + }; + partition@80000 { label = "linux"; - reg = <0x50000 0x2c0000>; + reg = <0x80000 0x310000>; }; - partition@310000 { + partition@390000 { label = "rootfs"; - reg = <0x310000 0x4f0000>; + reg = <0x390000 0x0>; }; }; }; diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts index 70c3498b16a4..5b73d9c805d9 100644 --- a/arch/arm/boot/dts/spear320-evb.dts +++ b/arch/arm/boot/dts/spear320-evb.dts @@ -118,15 +118,23 @@ }; partition@10000 { label = "u-boot"; - reg = <0x10000 0x40000>; + reg = <0x10000 0x50000>; }; - partition@50000 { + partition@60000 { + label = "environment"; + reg = <0x60000 0x10000>; + }; + partition@70000 { + label = "dtb"; + reg = <0x70000 0x10000>; + }; + partition@80000 { label = "linux"; - reg = <0x50000 0x2c0000>; + reg = <0x80000 0x310000>; }; - partition@310000 { + partition@390000 { label = "rootfs"; - reg = <0x310000 0x4f0000>; + reg = <0x390000 0x0>; }; }; }; diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts index 1119c22c9a82..16e4de46c7b8 100644 --- a/arch/arm/boot/dts/spear600-evb.dts +++ b/arch/arm/boot/dts/spear600-evb.dts @@ -49,15 +49,23 @@ }; partition@10000 { label = "u-boot"; - reg = <0x10000 0x40000>; + reg = <0x10000 0x50000>; }; - partition@50000 { + partition@60000 { + label = "environment"; + reg = <0x60000 0x10000>; + }; + partition@70000 { + label = "dtb"; + reg = <0x70000 0x10000>; + }; + partition@80000 { label = "linux"; - reg = <0x50000 0x2c0000>; + reg = <0x80000 0x310000>; }; - partition@310000 { + partition@390000 { label = "rootfs"; - reg = <0x310000 0x4f0000>; + reg = <0x390000 0x0>; }; }; }; From f631b984ee104bb3979cd26311abbcd4d23a715d Mon Sep 17 00:00:00 2001 From: Vipul Kumar Samar Date: Thu, 5 Jul 2012 11:51:47 +0800 Subject: [PATCH 55/65] ARM: SPEAr: DT: Fix existing DT support This patch fixes existing DT support for all SPEAr SoC's. This includes: - Removing few nodes from board files - Updating DT data of few nodes - Updating ranges of few busses - Moving devices to correct parent bus Signed-off-by: Bhavna Yadav Signed-off-by: Deepak Sikri Signed-off-by: Rajeev Kumar Signed-off-by: Shiraz Hashim Signed-off-by: Vijay Kumar Mishra Signed-off-by: Vipin Kumar Signed-off-by: Vipul Kumar Samar Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/spear1310-evb.dts | 13 +++++------- arch/arm/boot/dts/spear1310.dtsi | 14 ++++++------ arch/arm/boot/dts/spear1340-evb.dts | 9 ++++---- arch/arm/boot/dts/spear1340.dtsi | 1 + arch/arm/boot/dts/spear13xx.dtsi | 33 +++++++++++++++++++---------- arch/arm/boot/dts/spear300.dtsi | 2 +- arch/arm/boot/dts/spear320-evb.dts | 5 +---- arch/arm/boot/dts/spear320.dtsi | 4 ++-- arch/arm/boot/dts/spear3xx.dtsi | 2 +- 9 files changed, 45 insertions(+), 38 deletions(-) diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index 010e21deb867..668dcb27dafd 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -192,10 +192,6 @@ }; }; - spi0: spi@e0100000 { - status = "okay"; - }; - ehci@e4800000 { status = "okay"; }; @@ -233,10 +229,6 @@ status = "okay"; }; - i2c1: i2c@5cd00000 { - status = "okay"; - }; - kbd@e0300000 { linux,keymap = < 0x00000001 0x00010002 @@ -321,6 +313,7 @@ 0x08080052 >; autorepeat; st,mode = <0>; + suspended_rate = <2000000>; status = "okay"; }; @@ -332,6 +325,10 @@ status = "okay"; }; + spi0: spi@e0100000 { + status = "okay"; + }; + wdt@ec800620 { status = "okay"; }; diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi index f489f648c6eb..b2479be75905 100644 --- a/arch/arm/boot/dts/spear1310.dtsi +++ b/arch/arm/boot/dts/spear1310.dtsi @@ -88,13 +88,6 @@ #gpio-range-cells = <2>; }; - spi1: spi@5d400000 { - compatible = "arm,pl022", "arm,primecell"; - reg = <0x5d400000 0x1000>; - interrupts = <0 99 0x4>; - status = "disabled"; - }; - apb { i2c1: i2c@5cd00000 { #address-cells = <1>; @@ -159,6 +152,13 @@ status = "disabled"; }; + spi1: spi@5d400000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0x5d400000 0x1000>; + interrupts = <0 99 0x4>; + status = "disabled"; + }; + serial@5c800000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x5c800000 0x1000>; diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts index b16f7569bf5b..015601360f73 100644 --- a/arch/arm/boot/dts/spear1340-evb.dts +++ b/arch/arm/boot/dts/spear1340-evb.dts @@ -200,10 +200,6 @@ }; }; - spi0: spi@e0100000 { - status = "okay"; - }; - ehci@e4800000 { status = "okay"; }; @@ -329,6 +325,7 @@ 0x08080052 >; autorepeat; st,mode = <0>; + suspended_rate = <2000000>; status = "okay"; }; @@ -344,6 +341,10 @@ status = "okay"; }; + spi0: spi@e0100000 { + status = "okay"; + }; + wdt@ec800620 { status = "okay"; }; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index 64d14fde215d..c49781e196b6 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -58,6 +58,7 @@ compatible = "snps,designware-i2c"; reg = <0xb4000000 0x1000>; interrupts = <0 104 0x4>; + write-16bit; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index f7b84aced654..4d351442e581 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -70,6 +70,8 @@ compatible = "simple-bus"; ranges = <0x50000000 0x50000000 0x10000000 0xb0000000 0xb0000000 0x10000000 + 0xd0000000 0xd0000000 0x02000000 + 0xd8000000 0xd8000000 0x01000000 0xe0000000 0xe0000000 0x10000000>; sdhci@b3000000 { @@ -81,7 +83,7 @@ cf@b2800000 { compatible = "arasan,cf-spear1340"; - reg = <0xb2800000 0x100>; + reg = <0xb2800000 0x1000>; interrupts = <0 29 0x4>; status = "disabled"; }; @@ -113,6 +115,7 @@ 0 23 0x4>; st,ale-off = <0x20000>; st,cle-off = <0x10000>; + st,mode = <2>; status = "disabled"; }; @@ -134,17 +137,11 @@ status = "disabled"; }; - spi0: spi@e0100000 { - compatible = "arm,pl022", "arm,primecell"; - reg = <0xe0100000 0x1000>; - interrupts = <0 31 0x4>; - status = "disabled"; - }; - ehci@e4800000 { compatible = "st,spear600-ehci", "usb-ehci"; reg = <0xe4800000 0x1000>; interrupts = <0 64 0x4>; + usbh0_id = <0>; status = "disabled"; }; @@ -152,6 +149,7 @@ compatible = "st,spear600-ehci", "usb-ehci"; reg = <0xe5800000 0x1000>; interrupts = <0 66 0x4>; + usbh1_id = <1>; status = "disabled"; }; @@ -159,6 +157,7 @@ compatible = "st,spear600-ohci", "usb-ohci"; reg = <0xe4000000 0x1000>; interrupts = <0 65 0x4>; + usbh0_id = <0>; status = "disabled"; }; @@ -166,6 +165,7 @@ compatible = "st,spear600-ohci", "usb-ohci"; reg = <0xe5000000 0x1000>; interrupts = <0 67 0x4>; + usbh1_id = <1>; status = "disabled"; }; @@ -175,6 +175,8 @@ compatible = "simple-bus"; ranges = <0x50000000 0x50000000 0x10000000 0xb0000000 0xb0000000 0x10000000 + 0xd0000000 0xd0000000 0x02000000 + 0xd8000000 0xd8000000 0x01000000 0xe0000000 0xe0000000 0x10000000>; gpio0: gpio@e0600000 { @@ -215,8 +217,15 @@ status = "disabled"; }; + spi0: spi@e0100000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0xe0100000 0x1000>; + interrupts = <0 31 0x4>; + status = "disabled"; + }; + rtc@e0580000 { - compatible = "st,spear-rtc"; + compatible = "st,spear600-rtc"; reg = <0xe0580000 0x1000>; interrupts = <0 36 0x4>; status = "disabled"; @@ -232,7 +241,7 @@ adc@e0080000 { compatible = "st,spear600-adc"; reg = <0xe0080000 0x1000>; - interrupts = <0 44 0x4>; + interrupts = <0 12 0x4>; status = "disabled"; }; @@ -245,7 +254,8 @@ timer@ec800600 { compatible = "arm,cortex-a9-twd-timer"; reg = <0xec800600 0x20>; - interrupts = <1 13 0x301>; + interrupts = <1 13 0x4>; + status = "disabled"; }; wdt@ec800620 { @@ -257,6 +267,7 @@ thermal@e07008c4 { compatible = "st,thermal-spear1340"; reg = <0xe07008c4 0x4>; + thermal_flags = <0x7000>; }; }; }; diff --git a/arch/arm/boot/dts/spear300.dtsi b/arch/arm/boot/dts/spear300.dtsi index ed3627c116cc..fdac8713367a 100644 --- a/arch/arm/boot/dts/spear300.dtsi +++ b/arch/arm/boot/dts/spear300.dtsi @@ -27,7 +27,7 @@ }; clcd@60000000 { - compatible = "arm,clcd-pl110", "arm,primecell"; + compatible = "arm,pl110", "arm,primecell"; reg = <0x60000000 0x1000>; interrupts = <30>; status = "disabled"; diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts index 5b73d9c805d9..bf5848d9aa2b 100644 --- a/arch/arm/boot/dts/spear320-evb.dts +++ b/arch/arm/boot/dts/spear320-evb.dts @@ -82,10 +82,6 @@ }; }; - clcd@90000000 { - status = "okay"; - }; - dma@fc400000 { status = "okay"; }; @@ -99,6 +95,7 @@ }; sdhci@70000000 { + power-gpio = <&gpiopinctrl 61 1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi index 67d7ada71275..da29afba54e6 100644 --- a/arch/arm/boot/dts/spear320.dtsi +++ b/arch/arm/boot/dts/spear320.dtsi @@ -28,7 +28,7 @@ }; clcd@90000000 { - compatible = "arm,clcd-pl110", "arm,primecell"; + compatible = "arm,pl110", "arm,primecell"; reg = <0x90000000 0x1000>; interrupts = <33>; status = "disabled"; @@ -69,7 +69,7 @@ #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; - ranges = <0xa0000000 0xa0000000 0x10000000 + ranges = <0xa0000000 0xa0000000 0x20000000 0xd0000000 0xd0000000 0x30000000>; i2c1: i2c@a7000000 { diff --git a/arch/arm/boot/dts/spear3xx.dtsi b/arch/arm/boot/dts/spear3xx.dtsi index 3a8bb5736928..b02721fed166 100644 --- a/arch/arm/boot/dts/spear3xx.dtsi +++ b/arch/arm/boot/dts/spear3xx.dtsi @@ -120,7 +120,7 @@ }; rtc@fc900000 { - compatible = "st,spear-rtc"; + compatible = "st,spear600-rtc"; reg = <0xfc900000 0x1000>; interrupts = <10>; status = "disabled"; From 4c7a078f9003f31862f3a194dfa6a2dcf0937b39 Mon Sep 17 00:00:00 2001 From: Deepak Sikri Date: Thu, 9 Aug 2012 13:18:40 +0530 Subject: [PATCH 56/65] ARM: SPEAr: DT: Modify DT bindings for STMMAC This patch modifies the DT bindings for the GMAC IP existings for the SPEAr family. The DT bindings now additionally pass the phy mode as a configuration parameter for the ethernet device. Signed-off-by: Deepak Sikri Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/spear1310-evb.dts | 1 + arch/arm/boot/dts/spear1310.dtsi | 4 ++++ arch/arm/boot/dts/spear1340-evb.dts | 1 + arch/arm/boot/dts/spear3xx.dtsi | 1 + arch/arm/boot/dts/spear600.dtsi | 1 + 5 files changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index 668dcb27dafd..72f467575743 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -148,6 +148,7 @@ }; gmac0: eth@e2000000 { + phy-mode = "gmii"; status = "okay"; }; diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi index b2479be75905..e613452ec5bb 100644 --- a/arch/arm/boot/dts/spear1310.dtsi +++ b/arch/arm/boot/dts/spear1310.dtsi @@ -55,6 +55,7 @@ reg = <0x5c400000 0x8000>; interrupts = <0 95 0x4>; interrupt-names = "macirq"; + phy-mode = "mii"; status = "disabled"; }; @@ -63,6 +64,7 @@ reg = <0x5c500000 0x8000>; interrupts = <0 96 0x4>; interrupt-names = "macirq"; + phy-mode = "mii"; status = "disabled"; }; @@ -71,6 +73,7 @@ reg = <0x5c600000 0x8000>; interrupts = <0 97 0x4>; interrupt-names = "macirq"; + phy-mode = "rmii"; status = "disabled"; }; @@ -79,6 +82,7 @@ reg = <0x5c700000 0x8000>; interrupts = <0 98 0x4>; interrupt-names = "macirq"; + phy-mode = "rgmii"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts index 015601360f73..cfe82d126da3 100644 --- a/arch/arm/boot/dts/spear1340-evb.dts +++ b/arch/arm/boot/dts/spear1340-evb.dts @@ -156,6 +156,7 @@ }; gmac0: eth@e2000000 { + phy-mode = "rgmii"; status = "okay"; }; diff --git a/arch/arm/boot/dts/spear3xx.dtsi b/arch/arm/boot/dts/spear3xx.dtsi index b02721fed166..494636000f5c 100644 --- a/arch/arm/boot/dts/spear3xx.dtsi +++ b/arch/arm/boot/dts/spear3xx.dtsi @@ -53,6 +53,7 @@ reg = <0xe0800000 0x8000>; interrupts = <23 22>; interrupt-names = "macirq", "eth_wake_irq"; + phy-mode = "mii"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi index a3c36e47d7ef..f74feeaab1e0 100644 --- a/arch/arm/boot/dts/spear600.dtsi +++ b/arch/arm/boot/dts/spear600.dtsi @@ -59,6 +59,7 @@ interrupt-parent = <&vic1>; interrupts = <24 23>; interrupt-names = "macirq", "eth_wake_irq"; + phy-mode = "gmii"; status = "disabled"; }; From 7bceba83734dd4d50e978492959bd327f697fc23 Mon Sep 17 00:00:00 2001 From: Vipul Kumar Samar Date: Thu, 30 Aug 2012 09:32:24 +0530 Subject: [PATCH 57/65] ARM: SPEAr: DT: add uart state to fix warning amba-pl011 driver supports two pin state "default" and "sleep" and it expect from dt to provide this pinctrl states and phandler otherwise it gives a warning message. To remove this warning message pass default state with null phandler to uart pins in device node (In our case all the pins are configured in default states so we pass null phandler to pins). Signed-off-by: Vipul Kumar Samar Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/spear1310-evb.dts | 2 ++ arch/arm/boot/dts/spear1340-evb.dts | 4 ++++ arch/arm/boot/dts/spear300-evb.dts | 2 ++ arch/arm/boot/dts/spear310-evb.dts | 12 ++++++++++++ arch/arm/boot/dts/spear320-evb.dts | 6 ++++++ arch/arm/boot/dts/spear600-evb.dts | 4 ++++ 6 files changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index 72f467575743..8c97f34b99fb 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -324,6 +324,8 @@ serial@e0000000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; spi0: spi@e0100000 { diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts index cfe82d126da3..05c25495804b 100644 --- a/arch/arm/boot/dts/spear1340-evb.dts +++ b/arch/arm/boot/dts/spear1340-evb.dts @@ -336,10 +336,14 @@ serial@e0000000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; serial@b4100000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; spi0: spi@e0100000 { diff --git a/arch/arm/boot/dts/spear300-evb.dts b/arch/arm/boot/dts/spear300-evb.dts index b3265f6f5958..5de1431653e4 100644 --- a/arch/arm/boot/dts/spear300-evb.dts +++ b/arch/arm/boot/dts/spear300-evb.dts @@ -243,6 +243,8 @@ serial@d0000000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; wdt@fc880000 { diff --git a/arch/arm/boot/dts/spear310-evb.dts b/arch/arm/boot/dts/spear310-evb.dts index b30fa0e60010..b09632963d15 100644 --- a/arch/arm/boot/dts/spear310-evb.dts +++ b/arch/arm/boot/dts/spear310-evb.dts @@ -166,26 +166,38 @@ serial@d0000000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; serial@b2000000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; serial@b2080000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; serial@b2100000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; serial@b2180000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; serial@b2200000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; wdt@fc880000 { diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts index bf5848d9aa2b..fdedbb514102 100644 --- a/arch/arm/boot/dts/spear320-evb.dts +++ b/arch/arm/boot/dts/spear320-evb.dts @@ -183,14 +183,20 @@ serial@d0000000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; serial@a3000000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; serial@a4000000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; wdt@fc880000 { diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts index 16e4de46c7b8..5e6ef03cd04e 100644 --- a/arch/arm/boot/dts/spear600-evb.dts +++ b/arch/arm/boot/dts/spear600-evb.dts @@ -73,10 +73,14 @@ apb { serial@d0000000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; serial@d0080000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; }; i2c@d0200000 { From 8113ba917dfa74ba51b176f9f528f3a217c0eea2 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Sat, 10 Nov 2012 17:31:01 +0530 Subject: [PATCH 58/65] ARM: SPEAr: DT: Update device nodes This patch adds multiple device nodes for SPEAr machines and boards. Signed-off-by: Bhavna Yadav Signed-off-by: Deepak Sikri Signed-off-by: Rajeev Kumar Signed-off-by: Shiraz Hashim Signed-off-by: Vijay Kumar Mishra Signed-off-by: Vipin Kumar Signed-off-by: Vipul Kumar Samar Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/spear1310-evb.dts | 83 ++++++++++++++ arch/arm/boot/dts/spear1310.dtsi | 2 + arch/arm/boot/dts/spear1340-evb.dts | 163 ++++++++++++++++++++++++++++ arch/arm/boot/dts/spear1340.dtsi | 46 ++++++++ arch/arm/boot/dts/spear13xx.dtsi | 39 +++++++ arch/arm/boot/dts/spear320.dtsi | 11 ++ arch/arm/boot/dts/spear3xx.dtsi | 2 + arch/arm/boot/dts/spear600-evb.dts | 24 ++++ arch/arm/boot/dts/spear600.dtsi | 15 +++ 9 files changed, 385 insertions(+) diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index 8c97f34b99fb..b56a801e42a2 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -147,6 +147,20 @@ }; }; + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@1 { + label = "wakeup"; + linux,code = <0x100>; + gpios = <&gpio0 7 0x4>; + debounce-interval = <20>; + gpio-key,wakeup = <1>; + }; + }; + gmac0: eth@e2000000 { phy-mode = "gmii"; status = "okay"; @@ -330,6 +344,75 @@ spi0: spi@e0100000 { status = "okay"; + num-cs = <3>; + cs-gpios = <&gpio1 7 0>, <&spics 0>, <&spics 1>; + + stmpe610@0 { + compatible = "st,stmpe610"; + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <1000000>; + spi-cpha; + pl022,hierarchy = <0>; + pl022,interface = <0>; + pl022,slave-tx-disable; + pl022,com-mode = <0>; + pl022,rx-level-trig = <0>; + pl022,tx-level-trig = <0>; + pl022,ctrl-len = <0x7>; + pl022,wait-state = <0>; + pl022,duplex = <0>; + interrupts = <6 0x4>; + interrupt-parent = <&gpio1>; + irq-trigger = <0x2>; + + stmpe_touchscreen { + compatible = "st,stmpe-ts"; + ts,sample-time = <4>; + ts,mod-12b = <1>; + ts,ref-sel = <0>; + ts,adc-freq = <1>; + ts,ave-ctrl = <1>; + ts,touch-det-delay = <2>; + ts,settling = <2>; + ts,fraction-z = <7>; + ts,i-drive = <1>; + }; + }; + + m25p80@1 { + compatible = "st,m25p80"; + reg = <1>; + spi-max-frequency = <12000000>; + spi-cpol; + spi-cpha; + pl022,hierarchy = <0>; + pl022,interface = <0>; + pl022,slave-tx-disable; + pl022,com-mode = <0x2>; + pl022,rx-level-trig = <0>; + pl022,tx-level-trig = <0>; + pl022,ctrl-len = <0x11>; + pl022,wait-state = <0>; + pl022,duplex = <0>; + }; + + spidev@2 { + compatible = "spidev"; + reg = <2>; + spi-max-frequency = <25000000>; + spi-cpha; + pl022,hierarchy = <0>; + pl022,interface = <0>; + pl022,slave-tx-disable; + pl022,com-mode = <0x2>; + pl022,rx-level-trig = <0>; + pl022,tx-level-trig = <0>; + pl022,ctrl-len = <0x11>; + pl022,wait-state = <0>; + pl022,duplex = <0>; + }; }; wdt@ec800620 { diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi index e613452ec5bb..1513c1927cc8 100644 --- a/arch/arm/boot/dts/spear1310.dtsi +++ b/arch/arm/boot/dts/spear1310.dtsi @@ -160,6 +160,8 @@ compatible = "arm,pl022", "arm,primecell"; reg = <0x5d400000 0x1000>; interrupts = <0 99 0x4>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts index 05c25495804b..d6c30ae0a8d7 100644 --- a/arch/arm/boot/dts/spear1340-evb.dts +++ b/arch/arm/boot/dts/spear1340-evb.dts @@ -118,6 +118,10 @@ }; }; + ahci@b1000000 { + status = "okay"; + }; + dma@ea800000 { status = "okay"; }; @@ -205,10 +209,37 @@ status = "okay"; }; + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@1 { + label = "wakeup"; + linux,code = <0x100>; + gpios = <&gpio1 1 0x4>; + debounce-interval = <20>; + gpio-key,wakeup = <1>; + }; + }; + ehci@e5800000 { status = "okay"; }; + i2s0: i2s-play@b2400000 { + status = "okay"; + }; + + i2s1: i2s-rec@b2000000 { + status = "okay"; + }; + + incodec: dir-hifi { + compatible = "dummy,dir-hifi"; + status = "okay"; + }; + ohci@e4000000 { status = "okay"; }; @@ -217,11 +248,43 @@ status = "okay"; }; + outcodec: dit-hifi { + compatible = "dummy,dit-hifi"; + status = "okay"; + }; + + sound { + compatible = "spear,spear-evb"; + audio-controllers = <&spdif0 &spdif1 &i2s0 &i2s1>; + audio-codecs = <&incodec &outcodec &sta529 &sta529>; + codec_dai_name = "dir-hifi", "dit-hifi", "sta529-audio", "sta529-audio"; + stream_name = "spdif-cap", "spdif-play", "i2s-play", "i2s-cap"; + dai_name = "spdifin-pcm", "spdifout-pcm", "i2s0-pcm", "i2s1-pcm"; + nr_controllers = <4>; + status = "okay"; + }; + + spdif0: spdif-in@d0100000 { + status = "okay"; + }; + + spdif1: spdif-out@d0000000 { + status = "okay"; + }; + apb { adc@e0080000 { status = "okay"; }; + i2s-play@b2400000 { + status = "okay"; + }; + + i2s-rec@b2000000 { + status = "okay"; + }; + gpio0: gpio@e0600000 { status = "okay"; }; @@ -236,10 +299,36 @@ i2c0: i2c@e0280000 { status = "okay"; + + sta529: sta529@1a { + compatible = "st,sta529"; + reg = <0x1a>; + }; }; i2c1: i2c@b4000000 { status = "okay"; + + eeprom0@56 { + compatible = "st,eeprom"; + reg = <0x56>; + }; + + stmpe801@41 { + compatible = "st,stmpe801"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x41>; + interrupts = <4 0x4>; + interrupt-parent = <&gpio0>; + irq-trigger = <0x2>; + + stmpegpio: stmpe_gpio { + compatible = "st,stmpe-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + }; }; kbd@e0300000 { @@ -348,6 +437,80 @@ spi0: spi@e0100000 { status = "okay"; + num-cs = <3>; + cs-gpios = <&gpiopinctrl 80 0>, <&gpiopinctrl 24 0>, + <&gpiopinctrl 85 0>; + + m25p80@0 { + compatible = "m25p80"; + reg = <0>; + spi-max-frequency = <12000000>; + spi-cpol; + spi-cpha; + pl022,hierarchy = <0>; + pl022,interface = <0>; + pl022,slave-tx-disable; + pl022,com-mode = <0x2>; + pl022,rx-level-trig = <0>; + pl022,tx-level-trig = <0>; + pl022,ctrl-len = <0x11>; + pl022,wait-state = <0>; + pl022,duplex = <0>; + }; + + stmpe610@1 { + compatible = "st,stmpe610"; + spi-max-frequency = <1000000>; + spi-cpha; + reg = <1>; + pl022,hierarchy = <0>; + pl022,interface = <0>; + pl022,slave-tx-disable; + pl022,com-mode = <0>; + pl022,rx-level-trig = <0>; + pl022,tx-level-trig = <0>; + pl022,ctrl-len = <0x7>; + pl022,wait-state = <0>; + pl022,duplex = <0>; + interrupts = <100 0>; + interrupt-parent = <&gpiopinctrl>; + irq-trigger = <0x2>; + #address-cells = <1>; + #size-cells = <0>; + + stmpe_touchscreen { + compatible = "st,stmpe-ts"; + ts,sample-time = <4>; + ts,mod-12b = <1>; + ts,ref-sel = <0>; + ts,adc-freq = <1>; + ts,ave-ctrl = <1>; + ts,touch-det-delay = <2>; + ts,settling = <2>; + ts,fraction-z = <7>; + ts,i-drive = <1>; + }; + }; + + spidev@2 { + compatible = "spidev"; + reg = <2>; + spi-max-frequency = <25000000>; + spi-cpha; + pl022,hierarchy = <0>; + pl022,interface = <0>; + pl022,slave-tx-disable; + pl022,com-mode = <0x2>; + pl022,rx-level-trig = <0>; + pl022,tx-level-trig = <0>; + pl022,ctrl-len = <0x11>; + pl022,wait-state = <0>; + pl022,duplex = <0>; + }; + }; + + timer@ec800600 { + status = "okay"; }; wdt@ec800620 { diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index c49781e196b6..34da11aa6795 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -38,15 +38,61 @@ status = "disabled"; }; + i2s-play@b2400000 { + compatible = "snps,designware-i2s"; + reg = <0xb2400000 0x10000>; + interrupt-names = "play_irq"; + interrupts = <0 98 0x4 + 0 99 0x4>; + play; + channel = <8>; + status = "disabled"; + }; + + i2s-rec@b2000000 { + compatible = "snps,designware-i2s"; + reg = <0xb2000000 0x10000>; + interrupt-names = "record_irq"; + interrupts = <0 100 0x4 + 0 101 0x4>; + record; + channel = <8>; + status = "disabled"; + }; + pinmux: pinmux@e0700000 { compatible = "st,spear1340-pinmux"; reg = <0xe0700000 0x1000>; #gpio-range-cells = <2>; }; + pwm: pwm@e0180000 { + compatible ="st,spear13xx-pwm"; + reg = <0xe0180000 0x1000>; + #pwm-cells = <2>; + status = "disabled"; + }; + + spdif-in@d0100000 { + compatible = "st,spdif-in"; + reg = < 0xd0100000 0x20000 + 0xd0110000 0x10000 >; + interrupts = <0 84 0x4>; + status = "disabled"; + }; + + spdif-out@d0000000 { + compatible = "st,spdif-out"; + reg = <0xd0000000 0x20000>; + interrupts = <0 85 0x4>; + status = "disabled"; + }; + spi1: spi@5d400000 { compatible = "arm,pl022", "arm,primecell"; reg = <0x5d400000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; interrupts = <0 99 0x4>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index 4d351442e581..009096d1d2c3 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -64,6 +64,18 @@ bootargs = "console=ttyAMA0,115200"; }; + cpufreq { + compatible = "st,cpufreq-spear"; + cpufreq_tbl = < 166000 + 200000 + 250000 + 300000 + 400000 + 500000 + 600000 >; + status = "disable"; + }; + ahb { #address-cells = <1>; #size-cells = <1>; @@ -128,6 +140,13 @@ status = "disabled"; }; + pcm { + compatible = "st,pcm-audio"; + #address-cells = <0>; + #size-cells = <0>; + status = "disable"; + }; + smi: flash@ea000000 { compatible = "st,spear600-smi"; #address-cells = <1>; @@ -217,9 +236,29 @@ status = "disabled"; }; + i2s@e0180000 { + compatible = "st,designware-i2s"; + reg = <0xe0180000 0x1000>; + interrupt-names = "play_irq", "record_irq"; + interrupts = <0 10 0x4 + 0 11 0x4 >; + status = "disabled"; + }; + + i2s@e0200000 { + compatible = "st,designware-i2s"; + reg = <0xe0200000 0x1000>; + interrupt-names = "play_irq", "record_irq"; + interrupts = <0 26 0x4 + 0 53 0x4>; + status = "disabled"; + }; + spi0: spi@e0100000 { compatible = "arm,pl022", "arm,primecell"; reg = <0xe0100000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; interrupts = <0 31 0x4>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi index da29afba54e6..6ff0d1e0e461 100644 --- a/arch/arm/boot/dts/spear320.dtsi +++ b/arch/arm/boot/dts/spear320.dtsi @@ -56,15 +56,26 @@ spi1: spi@a5000000 { compatible = "arm,pl022", "arm,primecell"; reg = <0xa5000000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; spi2: spi@a6000000 { compatible = "arm,pl022", "arm,primecell"; reg = <0xa6000000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; + pwm: pwm@a8000000 { + compatible ="st,spear-pwm"; + reg = <0xa8000000 0x1000>; + #pwm-cells = <2>; + status = "disabled"; + }; + apb { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/spear3xx.dtsi b/arch/arm/boot/dts/spear3xx.dtsi index 494636000f5c..c2a852d43c48 100644 --- a/arch/arm/boot/dts/spear3xx.dtsi +++ b/arch/arm/boot/dts/spear3xx.dtsi @@ -70,6 +70,8 @@ compatible = "arm,pl022", "arm,primecell"; reg = <0xd0100000 0x1000>; interrupts = <20>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts index 5e6ef03cd04e..d865a891776d 100644 --- a/arch/arm/boot/dts/spear600-evb.dts +++ b/arch/arm/boot/dts/spear600-evb.dts @@ -24,15 +24,35 @@ }; ahb { + clcd@fc200000 { + status = "okay"; + }; + dma@fc400000 { status = "okay"; }; + ehci@e1800000 { + status = "okay"; + }; + + ehci@e2000000 { + status = "okay"; + }; + gmac: ethernet@e0800000 { phy-mode = "gmii"; status = "okay"; }; + ohci@e1900000 { + status = "okay"; + }; + + ohci@e2100000 { + status = "okay"; + }; + smi: flash@fc000000 { status = "okay"; clock-rate=<50000000>; @@ -83,6 +103,10 @@ pinctrl-0 = <>; }; + rtc@fc900000 { + status = "okay"; + }; + i2c@d0200000 { clock-frequency = <400000>; status = "okay"; diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi index f74feeaab1e0..e051dde5181f 100644 --- a/arch/arm/boot/dts/spear600.dtsi +++ b/arch/arm/boot/dts/spear600.dtsi @@ -45,6 +45,14 @@ #interrupt-cells = <1>; }; + clcd@fc200000 { + compatible = "arm,pl110", "arm,primecell"; + reg = <0xfc200000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <12>; + status = "disabled"; + }; + dma@fc400000 { compatible = "arm,pl080", "arm,primecell"; reg = <0xfc400000 0x1000>; @@ -179,6 +187,13 @@ status = "disabled"; }; + rtc@fc900000 { + compatible = "st,spear600-rtc"; + reg = <0xfc900000 0x1000>; + interrupts = <10>; + status = "disabled"; + }; + timer@f0000000 { compatible = "st,spear-timer"; reg = <0xf0000000 0x400>; From 07e812a0aeaaf21a23b3db5048a65c7042248321 Mon Sep 17 00:00:00 2001 From: Vipul Kumar Samar Date: Wed, 17 Oct 2012 12:08:26 +0530 Subject: [PATCH 59/65] ARM: SPEAr1310: Move 1310 specific misc register into machine specific files This patch moves some global macro definitions to the files where they are used. Its a step towards removing spear.h completely later on. Signed-off-by: Vipul Kumar Samar Signed-off-by: Viresh Kumar --- arch/arm/mach-spear13xx/include/mach/spear.h | 8 -------- arch/arm/mach-spear13xx/spear1310.c | 5 +++++ drivers/clk/spear/spear1310_clock.c | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-spear13xx/include/mach/spear.h b/arch/arm/mach-spear13xx/include/mach/spear.h index 07d90acc92c8..7cfa6818865a 100644 --- a/arch/arm/mach-spear13xx/include/mach/spear.h +++ b/arch/arm/mach-spear13xx/include/mach/spear.h @@ -47,14 +47,6 @@ #define DMAC1_BASE UL(0xEB000000) #define MCIF_CF_BASE UL(0xB2800000) -/* Devices present in SPEAr1310 */ -#ifdef CONFIG_MACH_SPEAR1310 -#define SPEAR1310_RAS_GRP1_BASE UL(0xD8000000) -#define VA_SPEAR1310_RAS_GRP1_BASE UL(0xFA000000) -#define SPEAR1310_RAS_BASE UL(0xD8400000) -#define VA_SPEAR1310_RAS_BASE IOMEM(UL(0xFA400000)) -#endif /* CONFIG_MACH_SPEAR1310 */ - /* Debug uart for linux, will be used for debug and uncompress messages */ #define SPEAR_DBG_UART_BASE UART_BASE #define VA_SPEAR_DBG_UART_BASE VA_UART_BASE diff --git a/arch/arm/mach-spear13xx/spear1310.c b/arch/arm/mach-spear13xx/spear1310.c index 9fbbfc5650aa..593a756dc7f7 100644 --- a/arch/arm/mach-spear13xx/spear1310.c +++ b/arch/arm/mach-spear13xx/spear1310.c @@ -27,6 +27,11 @@ #define SPEAR1310_SATA1_BASE UL(0xB1800000) #define SPEAR1310_SATA2_BASE UL(0xB4000000) +#define SPEAR1310_RAS_GRP1_BASE UL(0xD8000000) +#define VA_SPEAR1310_RAS_GRP1_BASE UL(0xFA000000) +#define SPEAR1310_RAS_BASE UL(0xD8400000) +#define VA_SPEAR1310_RAS_BASE IOMEM(UL(0xFA400000)) + /* ssp device registration */ static struct pl022_ssp_controller ssp1_plat_data = { .bus_id = 0, diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c index 0fcec2aae19c..cf7e17685a2c 100644 --- a/drivers/clk/spear/spear1310_clock.c +++ b/drivers/clk/spear/spear1310_clock.c @@ -20,6 +20,7 @@ #include #include "clk.h" +#define VA_SPEAR1310_RAS_BASE IOMEM(UL(0xFA400000)) /* PLL related registers and bit values */ #define SPEAR1310_PLL_CFG (VA_MISC_BASE + 0x210) /* PLL_CFG bit values */ From 3e270ba6e9158f0958e46a606cbeb14ddaf6979b Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Wed, 29 Aug 2012 21:57:36 +0530 Subject: [PATCH 60/65] ARM: SPEAr13xx: Remove fields not required for ssp controller Few fields are not required to be programmed in platform data of spi controller now, as it comes via DT. Remove them. Signed-off-by: Shiraz Hashim Signed-off-by: Viresh Kumar --- arch/arm/mach-spear13xx/spear1310.c | 2 -- arch/arm/mach-spear13xx/spear13xx.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/arch/arm/mach-spear13xx/spear1310.c b/arch/arm/mach-spear13xx/spear1310.c index 593a756dc7f7..451f3b1867b0 100644 --- a/arch/arm/mach-spear13xx/spear1310.c +++ b/arch/arm/mach-spear13xx/spear1310.c @@ -34,9 +34,7 @@ /* ssp device registration */ static struct pl022_ssp_controller ssp1_plat_data = { - .bus_id = 0, .enable_dma = 0, - .num_chipselect = 3, }; /* Add SPEAr1310 auxdata to pass platform data */ diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c index 5633d698f1e1..c4af775a8451 100644 --- a/arch/arm/mach-spear13xx/spear13xx.c +++ b/arch/arm/mach-spear13xx/spear13xx.c @@ -57,12 +57,10 @@ static struct dw_dma_slave ssp_dma_param[] = { }; struct pl022_ssp_controller pl022_plat_data = { - .bus_id = 0, .enable_dma = 1, .dma_filter = dw_dma_filter, .dma_rx_param = &ssp_dma_param[1], .dma_tx_param = &ssp_dma_param[0], - .num_chipselect = 3, }; /* CF device registration */ From 300a6856324a56955ab909e1dca93dabb8464c8a Mon Sep 17 00:00:00 2001 From: Vipul Kumar Samar Date: Mon, 15 Oct 2012 17:55:58 +0530 Subject: [PATCH 61/65] ARM: SPEAr1310: Fix AUXDATA for compact flash controller This patch fixes the platform data for compact flash controller. Signed-off-by: Vipul Kumar Samar Signed-off-by: Viresh Kumar --- arch/arm/mach-spear13xx/spear1310.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-spear13xx/spear1310.c b/arch/arm/mach-spear13xx/spear1310.c index 451f3b1867b0..02f4724bb0d4 100644 --- a/arch/arm/mach-spear13xx/spear1310.c +++ b/arch/arm/mach-spear13xx/spear1310.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,12 @@ #define SPEAR1310_RAS_BASE UL(0xD8400000) #define VA_SPEAR1310_RAS_BASE IOMEM(UL(0xFA400000)) +static struct arasan_cf_pdata cf_pdata = { + .cf_if_clk = CF_IF_CLK_166M, + .quirk = CF_BROKEN_UDMA, + .dma_priv = &cf_dma_priv, +}; + /* ssp device registration */ static struct pl022_ssp_controller ssp1_plat_data = { .enable_dma = 0, @@ -39,7 +46,7 @@ static struct pl022_ssp_controller ssp1_plat_data = { /* Add SPEAr1310 auxdata to pass platform data */ static struct of_dev_auxdata spear1310_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("arasan,cf-spear1340", MCIF_CF_BASE, NULL, &cf_dma_priv), + OF_DEV_AUXDATA("arasan,cf-spear1340", MCIF_CF_BASE, NULL, &cf_pdata), OF_DEV_AUXDATA("snps,dma-spear1340", DMAC0_BASE, NULL, &dmac_plat_data), OF_DEV_AUXDATA("snps,dma-spear1340", DMAC1_BASE, NULL, &dmac_plat_data), OF_DEV_AUXDATA("arm,pl022", SSP_BASE, NULL, &pl022_plat_data), From 80515a5a2e3c35e2994105f19af27650e8a16c51 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Fri, 3 Aug 2012 15:33:10 +0530 Subject: [PATCH 62/65] ARM: SPEAr3xx: shirq: simplify and move the shared irq multiplexor to DT SPEAr3xx architecture includes shared/multiplexed irqs for certain set of devices. The multiplexor provides a single interrupt to parent interrupt controller (VIC) on behalf of a group of devices. There can be multiple groups available on SPEAr3xx variants but not exceeding 4. The number of devices in a group can differ, further they may share same set of status/mask registers spanning across different bit masks. Also in some cases the group may not have enable or other registers. This makes software little complex. Present implementation was non-DT and had few complex data structures to decipher banks, number of irqs supported, mask and registers involved. This patch simplifies the overall design and convert it in to DT. It also removes all registration from individual SoC files and bring them in to common shirq.c. Also updated the corresponding documentation for DT binding of shirq. Signed-off-by: Shiraz Hashim Signed-off-by: Viresh Kumar --- .../devicetree/bindings/arm/spear/shirq.txt | 48 +++ arch/arm/mach-spear3xx/include/mach/irqs.h | 10 +- arch/arm/mach-spear3xx/spear300.c | 103 ------ arch/arm/mach-spear3xx/spear310.c | 202 ------------ arch/arm/mach-spear3xx/spear320.c | 204 ------------ arch/arm/mach-spear3xx/spear3xx.c | 4 + arch/arm/plat-spear/include/plat/shirq.h | 39 +-- arch/arm/plat-spear/shirq.c | 297 +++++++++++++++--- 8 files changed, 316 insertions(+), 591 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/spear/shirq.txt diff --git a/Documentation/devicetree/bindings/arm/spear/shirq.txt b/Documentation/devicetree/bindings/arm/spear/shirq.txt new file mode 100644 index 000000000000..13fbb8866bd6 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/spear/shirq.txt @@ -0,0 +1,48 @@ +* SPEAr Shared IRQ layer (shirq) + +SPEAr3xx architecture includes shared/multiplexed irqs for certain set +of devices. The multiplexor provides a single interrupt to parent +interrupt controller (VIC) on behalf of a group of devices. + +There can be multiple groups available on SPEAr3xx variants but not +exceeding 4. The number of devices in a group can differ, further they +may share same set of status/mask registers spanning across different +bit masks. Also in some cases the group may not have enable or other +registers. This makes software little complex. + +A single node in the device tree is used to describe the shared +interrupt multiplexor (one node for all groups). A group in the +interrupt controller shares config/control registers with other groups. +For example, a 32-bit interrupt enable/disable config register can +accommodate upto 4 interrupt groups. + +Required properties: + - compatible: should be, either of + - "st,spear300-shirq" + - "st,spear310-shirq" + - "st,spear320-shirq" + - interrupt-controller: Identifies the node as an interrupt controller. + - #interrupt-cells: should be <1> which basically contains the offset + (starting from 0) of interrupts for all the groups. + - reg: Base address and size of shirq registers. + - interrupts: The list of interrupts generated by the groups which are + then connected to a parent interrupt controller. Each group is + associated with one of the interrupts, hence number of interrupts (to + parent) is equal to number of groups. The format of the interrupt + specifier depends in the interrupt parent controller. + + Optional properties: + - interrupt-parent: pHandle of the parent interrupt controller, if not + inherited from the parent node. + +Example: + +The following is an example from the SPEAr320 SoC dtsi file. + +shirq: interrupt-controller@0xb3000000 { + compatible = "st,spear320-shirq"; + reg = <0xb3000000 0x1000>; + interrupts = <28 29 30 1>; + #interrupt-cells = <1>; + interrupt-controller; +}; diff --git a/arch/arm/mach-spear3xx/include/mach/irqs.h b/arch/arm/mach-spear3xx/include/mach/irqs.h index 803de76f5f36..f95e5b2b6686 100644 --- a/arch/arm/mach-spear3xx/include/mach/irqs.h +++ b/arch/arm/mach-spear3xx/include/mach/irqs.h @@ -14,14 +14,6 @@ #ifndef __MACH_IRQS_H #define __MACH_IRQS_H -/* FIXME: probe all these from DT */ -#define SPEAR3XX_IRQ_INTRCOMM_RAS_ARM 1 -#define SPEAR3XX_IRQ_GEN_RAS_1 28 -#define SPEAR3XX_IRQ_GEN_RAS_2 29 -#define SPEAR3XX_IRQ_GEN_RAS_3 30 -#define SPEAR3XX_IRQ_VIC_END 32 -#define SPEAR3XX_VIRQ_START SPEAR3XX_IRQ_VIC_END - -#define NR_IRQS 160 +#define NR_IRQS 256 #endif /* __MACH_IRQS_H */ diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c index 6ec300549960..a69cbfdb07ee 100644 --- a/arch/arm/mach-spear3xx/spear300.c +++ b/arch/arm/mach-spear3xx/spear300.c @@ -17,102 +17,9 @@ #include #include #include -#include #include #include -/* Base address of various IPs */ -#define SPEAR300_TELECOM_BASE UL(0x50000000) - -/* Interrupt registers offsets and masks */ -#define SPEAR300_INT_ENB_MASK_REG 0x54 -#define SPEAR300_INT_STS_MASK_REG 0x58 -#define SPEAR300_IT_PERS_S_IRQ_MASK (1 << 0) -#define SPEAR300_IT_CHANGE_S_IRQ_MASK (1 << 1) -#define SPEAR300_I2S_IRQ_MASK (1 << 2) -#define SPEAR300_TDM_IRQ_MASK (1 << 3) -#define SPEAR300_CAMERA_L_IRQ_MASK (1 << 4) -#define SPEAR300_CAMERA_F_IRQ_MASK (1 << 5) -#define SPEAR300_CAMERA_V_IRQ_MASK (1 << 6) -#define SPEAR300_KEYBOARD_IRQ_MASK (1 << 7) -#define SPEAR300_GPIO1_IRQ_MASK (1 << 8) - -#define SPEAR300_SHIRQ_RAS1_MASK 0x1FF - -#define SPEAR300_SOC_CONFIG_BASE UL(0x99000000) - - -/* SPEAr300 Virtual irq definitions */ -/* IRQs sharing IRQ_GEN_RAS_1 */ -#define SPEAR300_VIRQ_IT_PERS_S (SPEAR3XX_VIRQ_START + 0) -#define SPEAR300_VIRQ_IT_CHANGE_S (SPEAR3XX_VIRQ_START + 1) -#define SPEAR300_VIRQ_I2S (SPEAR3XX_VIRQ_START + 2) -#define SPEAR300_VIRQ_TDM (SPEAR3XX_VIRQ_START + 3) -#define SPEAR300_VIRQ_CAMERA_L (SPEAR3XX_VIRQ_START + 4) -#define SPEAR300_VIRQ_CAMERA_F (SPEAR3XX_VIRQ_START + 5) -#define SPEAR300_VIRQ_CAMERA_V (SPEAR3XX_VIRQ_START + 6) -#define SPEAR300_VIRQ_KEYBOARD (SPEAR3XX_VIRQ_START + 7) -#define SPEAR300_VIRQ_GPIO1 (SPEAR3XX_VIRQ_START + 8) - -/* IRQs sharing IRQ_GEN_RAS_3 */ -#define SPEAR300_IRQ_CLCD SPEAR3XX_IRQ_GEN_RAS_3 - -/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */ -#define SPEAR300_IRQ_SDHCI SPEAR3XX_IRQ_INTRCOMM_RAS_ARM - -/* spear3xx shared irq */ -static struct shirq_dev_config shirq_ras1_config[] = { - { - .virq = SPEAR300_VIRQ_IT_PERS_S, - .enb_mask = SPEAR300_IT_PERS_S_IRQ_MASK, - .status_mask = SPEAR300_IT_PERS_S_IRQ_MASK, - }, { - .virq = SPEAR300_VIRQ_IT_CHANGE_S, - .enb_mask = SPEAR300_IT_CHANGE_S_IRQ_MASK, - .status_mask = SPEAR300_IT_CHANGE_S_IRQ_MASK, - }, { - .virq = SPEAR300_VIRQ_I2S, - .enb_mask = SPEAR300_I2S_IRQ_MASK, - .status_mask = SPEAR300_I2S_IRQ_MASK, - }, { - .virq = SPEAR300_VIRQ_TDM, - .enb_mask = SPEAR300_TDM_IRQ_MASK, - .status_mask = SPEAR300_TDM_IRQ_MASK, - }, { - .virq = SPEAR300_VIRQ_CAMERA_L, - .enb_mask = SPEAR300_CAMERA_L_IRQ_MASK, - .status_mask = SPEAR300_CAMERA_L_IRQ_MASK, - }, { - .virq = SPEAR300_VIRQ_CAMERA_F, - .enb_mask = SPEAR300_CAMERA_F_IRQ_MASK, - .status_mask = SPEAR300_CAMERA_F_IRQ_MASK, - }, { - .virq = SPEAR300_VIRQ_CAMERA_V, - .enb_mask = SPEAR300_CAMERA_V_IRQ_MASK, - .status_mask = SPEAR300_CAMERA_V_IRQ_MASK, - }, { - .virq = SPEAR300_VIRQ_KEYBOARD, - .enb_mask = SPEAR300_KEYBOARD_IRQ_MASK, - .status_mask = SPEAR300_KEYBOARD_IRQ_MASK, - }, { - .virq = SPEAR300_VIRQ_GPIO1, - .enb_mask = SPEAR300_GPIO1_IRQ_MASK, - .status_mask = SPEAR300_GPIO1_IRQ_MASK, - }, -}; - -static struct spear_shirq shirq_ras1 = { - .irq = SPEAR3XX_IRQ_GEN_RAS_1, - .dev_config = shirq_ras1_config, - .dev_count = ARRAY_SIZE(shirq_ras1_config), - .regs = { - .enb_reg = SPEAR300_INT_ENB_MASK_REG, - .status_reg = SPEAR300_INT_STS_MASK_REG, - .status_reg_mask = SPEAR300_SHIRQ_RAS1_MASK, - .clear_reg = -1, - }, -}; - /* DMAC platform data's slave info */ struct pl08x_channel_data spear300_dma_info[] = { { @@ -285,21 +192,11 @@ static struct of_dev_auxdata spear300_auxdata_lookup[] __initdata = { static void __init spear300_dt_init(void) { - int ret; - pl080_plat_data.slave_channels = spear300_dma_info; pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear300_dma_info); of_platform_populate(NULL, of_default_bus_match_table, spear300_auxdata_lookup, NULL); - - /* shared irq registration */ - shirq_ras1.regs.base = ioremap(SPEAR300_TELECOM_BASE, SZ_4K); - if (shirq_ras1.regs.base) { - ret = spear_shirq_register(&shirq_ras1); - if (ret) - pr_err("Error registering Shared IRQ\n"); - } } static const char * const spear300_dt_board_compat[] = { diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c index 1d0e435b9045..b963ebb10b56 100644 --- a/arch/arm/mach-spear3xx/spear310.c +++ b/arch/arm/mach-spear3xx/spear310.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -27,176 +26,6 @@ #define SPEAR310_UART3_BASE UL(0xB2100000) #define SPEAR310_UART4_BASE UL(0xB2180000) #define SPEAR310_UART5_BASE UL(0xB2200000) -#define SPEAR310_SOC_CONFIG_BASE UL(0xB4000000) - -/* Interrupt registers offsets and masks */ -#define SPEAR310_INT_STS_MASK_REG 0x04 -#define SPEAR310_SMII0_IRQ_MASK (1 << 0) -#define SPEAR310_SMII1_IRQ_MASK (1 << 1) -#define SPEAR310_SMII2_IRQ_MASK (1 << 2) -#define SPEAR310_SMII3_IRQ_MASK (1 << 3) -#define SPEAR310_WAKEUP_SMII0_IRQ_MASK (1 << 4) -#define SPEAR310_WAKEUP_SMII1_IRQ_MASK (1 << 5) -#define SPEAR310_WAKEUP_SMII2_IRQ_MASK (1 << 6) -#define SPEAR310_WAKEUP_SMII3_IRQ_MASK (1 << 7) -#define SPEAR310_UART1_IRQ_MASK (1 << 8) -#define SPEAR310_UART2_IRQ_MASK (1 << 9) -#define SPEAR310_UART3_IRQ_MASK (1 << 10) -#define SPEAR310_UART4_IRQ_MASK (1 << 11) -#define SPEAR310_UART5_IRQ_MASK (1 << 12) -#define SPEAR310_EMI_IRQ_MASK (1 << 13) -#define SPEAR310_TDM_HDLC_IRQ_MASK (1 << 14) -#define SPEAR310_RS485_0_IRQ_MASK (1 << 15) -#define SPEAR310_RS485_1_IRQ_MASK (1 << 16) - -#define SPEAR310_SHIRQ_RAS1_MASK 0x000FF -#define SPEAR310_SHIRQ_RAS2_MASK 0x01F00 -#define SPEAR310_SHIRQ_RAS3_MASK 0x02000 -#define SPEAR310_SHIRQ_INTRCOMM_RAS_MASK 0x1C000 - -/* SPEAr310 Virtual irq definitions */ -/* IRQs sharing IRQ_GEN_RAS_1 */ -#define SPEAR310_VIRQ_SMII0 (SPEAR3XX_VIRQ_START + 0) -#define SPEAR310_VIRQ_SMII1 (SPEAR3XX_VIRQ_START + 1) -#define SPEAR310_VIRQ_SMII2 (SPEAR3XX_VIRQ_START + 2) -#define SPEAR310_VIRQ_SMII3 (SPEAR3XX_VIRQ_START + 3) -#define SPEAR310_VIRQ_WAKEUP_SMII0 (SPEAR3XX_VIRQ_START + 4) -#define SPEAR310_VIRQ_WAKEUP_SMII1 (SPEAR3XX_VIRQ_START + 5) -#define SPEAR310_VIRQ_WAKEUP_SMII2 (SPEAR3XX_VIRQ_START + 6) -#define SPEAR310_VIRQ_WAKEUP_SMII3 (SPEAR3XX_VIRQ_START + 7) - -/* IRQs sharing IRQ_GEN_RAS_2 */ -#define SPEAR310_VIRQ_UART1 (SPEAR3XX_VIRQ_START + 8) -#define SPEAR310_VIRQ_UART2 (SPEAR3XX_VIRQ_START + 9) -#define SPEAR310_VIRQ_UART3 (SPEAR3XX_VIRQ_START + 10) -#define SPEAR310_VIRQ_UART4 (SPEAR3XX_VIRQ_START + 11) -#define SPEAR310_VIRQ_UART5 (SPEAR3XX_VIRQ_START + 12) - -/* IRQs sharing IRQ_GEN_RAS_3 */ -#define SPEAR310_VIRQ_EMI (SPEAR3XX_VIRQ_START + 13) -#define SPEAR310_VIRQ_PLGPIO (SPEAR3XX_VIRQ_START + 14) - -/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */ -#define SPEAR310_VIRQ_TDM_HDLC (SPEAR3XX_VIRQ_START + 15) -#define SPEAR310_VIRQ_RS485_0 (SPEAR3XX_VIRQ_START + 16) -#define SPEAR310_VIRQ_RS485_1 (SPEAR3XX_VIRQ_START + 17) - - -/* spear3xx shared irq */ -static struct shirq_dev_config shirq_ras1_config[] = { - { - .virq = SPEAR310_VIRQ_SMII0, - .status_mask = SPEAR310_SMII0_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_SMII1, - .status_mask = SPEAR310_SMII1_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_SMII2, - .status_mask = SPEAR310_SMII2_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_SMII3, - .status_mask = SPEAR310_SMII3_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_WAKEUP_SMII0, - .status_mask = SPEAR310_WAKEUP_SMII0_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_WAKEUP_SMII1, - .status_mask = SPEAR310_WAKEUP_SMII1_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_WAKEUP_SMII2, - .status_mask = SPEAR310_WAKEUP_SMII2_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_WAKEUP_SMII3, - .status_mask = SPEAR310_WAKEUP_SMII3_IRQ_MASK, - }, -}; - -static struct spear_shirq shirq_ras1 = { - .irq = SPEAR3XX_IRQ_GEN_RAS_1, - .dev_config = shirq_ras1_config, - .dev_count = ARRAY_SIZE(shirq_ras1_config), - .regs = { - .enb_reg = -1, - .status_reg = SPEAR310_INT_STS_MASK_REG, - .status_reg_mask = SPEAR310_SHIRQ_RAS1_MASK, - .clear_reg = -1, - }, -}; - -static struct shirq_dev_config shirq_ras2_config[] = { - { - .virq = SPEAR310_VIRQ_UART1, - .status_mask = SPEAR310_UART1_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_UART2, - .status_mask = SPEAR310_UART2_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_UART3, - .status_mask = SPEAR310_UART3_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_UART4, - .status_mask = SPEAR310_UART4_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_UART5, - .status_mask = SPEAR310_UART5_IRQ_MASK, - }, -}; - -static struct spear_shirq shirq_ras2 = { - .irq = SPEAR3XX_IRQ_GEN_RAS_2, - .dev_config = shirq_ras2_config, - .dev_count = ARRAY_SIZE(shirq_ras2_config), - .regs = { - .enb_reg = -1, - .status_reg = SPEAR310_INT_STS_MASK_REG, - .status_reg_mask = SPEAR310_SHIRQ_RAS2_MASK, - .clear_reg = -1, - }, -}; - -static struct shirq_dev_config shirq_ras3_config[] = { - { - .virq = SPEAR310_VIRQ_EMI, - .status_mask = SPEAR310_EMI_IRQ_MASK, - }, -}; - -static struct spear_shirq shirq_ras3 = { - .irq = SPEAR3XX_IRQ_GEN_RAS_3, - .dev_config = shirq_ras3_config, - .dev_count = ARRAY_SIZE(shirq_ras3_config), - .regs = { - .enb_reg = -1, - .status_reg = SPEAR310_INT_STS_MASK_REG, - .status_reg_mask = SPEAR310_SHIRQ_RAS3_MASK, - .clear_reg = -1, - }, -}; - -static struct shirq_dev_config shirq_intrcomm_ras_config[] = { - { - .virq = SPEAR310_VIRQ_TDM_HDLC, - .status_mask = SPEAR310_TDM_HDLC_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_RS485_0, - .status_mask = SPEAR310_RS485_0_IRQ_MASK, - }, { - .virq = SPEAR310_VIRQ_RS485_1, - .status_mask = SPEAR310_RS485_1_IRQ_MASK, - }, -}; - -static struct spear_shirq shirq_intrcomm_ras = { - .irq = SPEAR3XX_IRQ_INTRCOMM_RAS_ARM, - .dev_config = shirq_intrcomm_ras_config, - .dev_count = ARRAY_SIZE(shirq_intrcomm_ras_config), - .regs = { - .enb_reg = -1, - .status_reg = SPEAR310_INT_STS_MASK_REG, - .status_reg_mask = SPEAR310_SHIRQ_INTRCOMM_RAS_MASK, - .clear_reg = -1, - }, -}; /* DMAC platform data's slave info */ struct pl08x_channel_data spear310_dma_info[] = { @@ -405,42 +234,11 @@ static struct of_dev_auxdata spear310_auxdata_lookup[] __initdata = { static void __init spear310_dt_init(void) { - void __iomem *base; - int ret; - pl080_plat_data.slave_channels = spear310_dma_info; pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear310_dma_info); of_platform_populate(NULL, of_default_bus_match_table, spear310_auxdata_lookup, NULL); - - /* shared irq registration */ - base = ioremap(SPEAR310_SOC_CONFIG_BASE, SZ_4K); - if (base) { - /* shirq 1 */ - shirq_ras1.regs.base = base; - ret = spear_shirq_register(&shirq_ras1); - if (ret) - pr_err("Error registering Shared IRQ 1\n"); - - /* shirq 2 */ - shirq_ras2.regs.base = base; - ret = spear_shirq_register(&shirq_ras2); - if (ret) - pr_err("Error registering Shared IRQ 2\n"); - - /* shirq 3 */ - shirq_ras3.regs.base = base; - ret = spear_shirq_register(&shirq_ras3); - if (ret) - pr_err("Error registering Shared IRQ 3\n"); - - /* shirq 4 */ - shirq_intrcomm_ras.regs.base = base; - ret = spear_shirq_register(&shirq_intrcomm_ras); - if (ret) - pr_err("Error registering Shared IRQ 4\n"); - } } static const char * const spear310_dt_board_compat[] = { diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c index fd823c624575..707504b84e0e 100644 --- a/arch/arm/mach-spear3xx/spear320.c +++ b/arch/arm/mach-spear3xx/spear320.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -28,184 +27,6 @@ #define SPEAR320_SSP0_BASE UL(0xA5000000) #define SPEAR320_SSP1_BASE UL(0xA6000000) -/* Interrupt registers offsets and masks */ -#define SPEAR320_INT_STS_MASK_REG 0x04 -#define SPEAR320_INT_CLR_MASK_REG 0x04 -#define SPEAR320_INT_ENB_MASK_REG 0x08 -#define SPEAR320_GPIO_IRQ_MASK (1 << 0) -#define SPEAR320_I2S_PLAY_IRQ_MASK (1 << 1) -#define SPEAR320_I2S_REC_IRQ_MASK (1 << 2) -#define SPEAR320_EMI_IRQ_MASK (1 << 7) -#define SPEAR320_CLCD_IRQ_MASK (1 << 8) -#define SPEAR320_SPP_IRQ_MASK (1 << 9) -#define SPEAR320_SDHCI_IRQ_MASK (1 << 10) -#define SPEAR320_CAN_U_IRQ_MASK (1 << 11) -#define SPEAR320_CAN_L_IRQ_MASK (1 << 12) -#define SPEAR320_UART1_IRQ_MASK (1 << 13) -#define SPEAR320_UART2_IRQ_MASK (1 << 14) -#define SPEAR320_SSP1_IRQ_MASK (1 << 15) -#define SPEAR320_SSP2_IRQ_MASK (1 << 16) -#define SPEAR320_SMII0_IRQ_MASK (1 << 17) -#define SPEAR320_MII1_SMII1_IRQ_MASK (1 << 18) -#define SPEAR320_WAKEUP_SMII0_IRQ_MASK (1 << 19) -#define SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK (1 << 20) -#define SPEAR320_I2C1_IRQ_MASK (1 << 21) - -#define SPEAR320_SHIRQ_RAS1_MASK 0x000380 -#define SPEAR320_SHIRQ_RAS3_MASK 0x000007 -#define SPEAR320_SHIRQ_INTRCOMM_RAS_MASK 0x3FF800 - -/* SPEAr320 Virtual irq definitions */ -/* IRQs sharing IRQ_GEN_RAS_1 */ -#define SPEAR320_VIRQ_EMI (SPEAR3XX_VIRQ_START + 0) -#define SPEAR320_VIRQ_CLCD (SPEAR3XX_VIRQ_START + 1) -#define SPEAR320_VIRQ_SPP (SPEAR3XX_VIRQ_START + 2) - -/* IRQs sharing IRQ_GEN_RAS_2 */ -#define SPEAR320_IRQ_SDHCI SPEAR3XX_IRQ_GEN_RAS_2 - -/* IRQs sharing IRQ_GEN_RAS_3 */ -#define SPEAR320_VIRQ_PLGPIO (SPEAR3XX_VIRQ_START + 3) -#define SPEAR320_VIRQ_I2S_PLAY (SPEAR3XX_VIRQ_START + 4) -#define SPEAR320_VIRQ_I2S_REC (SPEAR3XX_VIRQ_START + 5) - -/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */ -#define SPEAR320_VIRQ_CANU (SPEAR3XX_VIRQ_START + 6) -#define SPEAR320_VIRQ_CANL (SPEAR3XX_VIRQ_START + 7) -#define SPEAR320_VIRQ_UART1 (SPEAR3XX_VIRQ_START + 8) -#define SPEAR320_VIRQ_UART2 (SPEAR3XX_VIRQ_START + 9) -#define SPEAR320_VIRQ_SSP1 (SPEAR3XX_VIRQ_START + 10) -#define SPEAR320_VIRQ_SSP2 (SPEAR3XX_VIRQ_START + 11) -#define SPEAR320_VIRQ_SMII0 (SPEAR3XX_VIRQ_START + 12) -#define SPEAR320_VIRQ_MII1_SMII1 (SPEAR3XX_VIRQ_START + 13) -#define SPEAR320_VIRQ_WAKEUP_SMII0 (SPEAR3XX_VIRQ_START + 14) -#define SPEAR320_VIRQ_WAKEUP_MII1_SMII1 (SPEAR3XX_VIRQ_START + 15) -#define SPEAR320_VIRQ_I2C1 (SPEAR3XX_VIRQ_START + 16) - -/* spear3xx shared irq */ -static struct shirq_dev_config shirq_ras1_config[] = { - { - .virq = SPEAR320_VIRQ_EMI, - .status_mask = SPEAR320_EMI_IRQ_MASK, - .clear_mask = SPEAR320_EMI_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_CLCD, - .status_mask = SPEAR320_CLCD_IRQ_MASK, - .clear_mask = SPEAR320_CLCD_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_SPP, - .status_mask = SPEAR320_SPP_IRQ_MASK, - .clear_mask = SPEAR320_SPP_IRQ_MASK, - }, -}; - -static struct spear_shirq shirq_ras1 = { - .irq = SPEAR3XX_IRQ_GEN_RAS_1, - .dev_config = shirq_ras1_config, - .dev_count = ARRAY_SIZE(shirq_ras1_config), - .regs = { - .enb_reg = -1, - .status_reg = SPEAR320_INT_STS_MASK_REG, - .status_reg_mask = SPEAR320_SHIRQ_RAS1_MASK, - .clear_reg = SPEAR320_INT_CLR_MASK_REG, - .reset_to_clear = 1, - }, -}; - -static struct shirq_dev_config shirq_ras3_config[] = { - { - .virq = SPEAR320_VIRQ_PLGPIO, - .enb_mask = SPEAR320_GPIO_IRQ_MASK, - .status_mask = SPEAR320_GPIO_IRQ_MASK, - .clear_mask = SPEAR320_GPIO_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_I2S_PLAY, - .enb_mask = SPEAR320_I2S_PLAY_IRQ_MASK, - .status_mask = SPEAR320_I2S_PLAY_IRQ_MASK, - .clear_mask = SPEAR320_I2S_PLAY_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_I2S_REC, - .enb_mask = SPEAR320_I2S_REC_IRQ_MASK, - .status_mask = SPEAR320_I2S_REC_IRQ_MASK, - .clear_mask = SPEAR320_I2S_REC_IRQ_MASK, - }, -}; - -static struct spear_shirq shirq_ras3 = { - .irq = SPEAR3XX_IRQ_GEN_RAS_3, - .dev_config = shirq_ras3_config, - .dev_count = ARRAY_SIZE(shirq_ras3_config), - .regs = { - .enb_reg = SPEAR320_INT_ENB_MASK_REG, - .reset_to_enb = 1, - .status_reg = SPEAR320_INT_STS_MASK_REG, - .status_reg_mask = SPEAR320_SHIRQ_RAS3_MASK, - .clear_reg = SPEAR320_INT_CLR_MASK_REG, - .reset_to_clear = 1, - }, -}; - -static struct shirq_dev_config shirq_intrcomm_ras_config[] = { - { - .virq = SPEAR320_VIRQ_CANU, - .status_mask = SPEAR320_CAN_U_IRQ_MASK, - .clear_mask = SPEAR320_CAN_U_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_CANL, - .status_mask = SPEAR320_CAN_L_IRQ_MASK, - .clear_mask = SPEAR320_CAN_L_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_UART1, - .status_mask = SPEAR320_UART1_IRQ_MASK, - .clear_mask = SPEAR320_UART1_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_UART2, - .status_mask = SPEAR320_UART2_IRQ_MASK, - .clear_mask = SPEAR320_UART2_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_SSP1, - .status_mask = SPEAR320_SSP1_IRQ_MASK, - .clear_mask = SPEAR320_SSP1_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_SSP2, - .status_mask = SPEAR320_SSP2_IRQ_MASK, - .clear_mask = SPEAR320_SSP2_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_SMII0, - .status_mask = SPEAR320_SMII0_IRQ_MASK, - .clear_mask = SPEAR320_SMII0_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_MII1_SMII1, - .status_mask = SPEAR320_MII1_SMII1_IRQ_MASK, - .clear_mask = SPEAR320_MII1_SMII1_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_WAKEUP_SMII0, - .status_mask = SPEAR320_WAKEUP_SMII0_IRQ_MASK, - .clear_mask = SPEAR320_WAKEUP_SMII0_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_WAKEUP_MII1_SMII1, - .status_mask = SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK, - .clear_mask = SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK, - }, { - .virq = SPEAR320_VIRQ_I2C1, - .status_mask = SPEAR320_I2C1_IRQ_MASK, - .clear_mask = SPEAR320_I2C1_IRQ_MASK, - }, -}; - -static struct spear_shirq shirq_intrcomm_ras = { - .irq = SPEAR3XX_IRQ_INTRCOMM_RAS_ARM, - .dev_config = shirq_intrcomm_ras_config, - .dev_count = ARRAY_SIZE(shirq_intrcomm_ras_config), - .regs = { - .enb_reg = -1, - .status_reg = SPEAR320_INT_STS_MASK_REG, - .status_reg_mask = SPEAR320_SHIRQ_INTRCOMM_RAS_MASK, - .clear_reg = SPEAR320_INT_CLR_MASK_REG, - .reset_to_clear = 1, - }, -}; - /* DMAC platform data's slave info */ struct pl08x_channel_data spear320_dma_info[] = { { @@ -416,36 +237,11 @@ static struct of_dev_auxdata spear320_auxdata_lookup[] __initdata = { static void __init spear320_dt_init(void) { - void __iomem *base; - int ret; - pl080_plat_data.slave_channels = spear320_dma_info; pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear320_dma_info); of_platform_populate(NULL, of_default_bus_match_table, spear320_auxdata_lookup, NULL); - - /* shared irq registration */ - base = ioremap(SPEAR320_SOC_CONFIG_BASE, SZ_4K); - if (base) { - /* shirq 1 */ - shirq_ras1.regs.base = base; - ret = spear_shirq_register(&shirq_ras1); - if (ret) - pr_err("Error registering Shared IRQ 1\n"); - - /* shirq 3 */ - shirq_ras3.regs.base = base; - ret = spear_shirq_register(&shirq_ras3); - if (ret) - pr_err("Error registering Shared IRQ 3\n"); - - /* shirq 4 */ - shirq_intrcomm_ras.regs.base = base; - ret = spear_shirq_register(&shirq_intrcomm_ras); - if (ret) - pr_err("Error registering Shared IRQ 4\n"); - } } static const char * const spear320_dt_board_compat[] = { diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c index 98144baf8883..f1aaf5b168b2 100644 --- a/arch/arm/mach-spear3xx/spear3xx.c +++ b/arch/arm/mach-spear3xx/spear3xx.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -121,6 +122,9 @@ struct sys_timer spear3xx_timer = { static const struct of_device_id vic_of_match[] __initconst = { { .compatible = "arm,pl190-vic", .data = vic_of_init, }, + { .compatible = "st,spear300-shirq", .data = spear300_shirq_of_init, }, + { .compatible = "st,spear310-shirq", .data = spear310_shirq_of_init, }, + { .compatible = "st,spear320-shirq", .data = spear320_shirq_of_init, }, { /* Sentinel */ } }; diff --git a/arch/arm/plat-spear/include/plat/shirq.h b/arch/arm/plat-spear/include/plat/shirq.h index 88a7fbd24793..c51b355f00de 100644 --- a/arch/arm/plat-spear/include/plat/shirq.h +++ b/arch/arm/plat-spear/include/plat/shirq.h @@ -17,25 +17,9 @@ #include #include -/* - * struct shirq_dev_config: shared irq device configuration - * - * virq: virtual irq number of device - * enb_mask: enable mask of device - * status_mask: status mask of device - * clear_mask: clear mask of device - */ -struct shirq_dev_config { - u32 virq; - u32 enb_mask; - u32 status_mask; - u32 clear_mask; -}; - /* * struct shirq_regs: shared irq register configuration * - * base: base address of shared irq register * enb_reg: enable register offset * reset_to_enb: val 1 indicates, we need to clear bit for enabling interrupt * status_reg: status register offset @@ -44,11 +28,9 @@ struct shirq_dev_config { * reset_to_clear: val 1 indicates, we need to clear bit for clearing interrupt */ struct shirq_regs { - void __iomem *base; u32 enb_reg; u32 reset_to_enb; u32 status_reg; - u32 status_reg_mask; u32 clear_reg; u32 reset_to_clear; }; @@ -57,17 +39,28 @@ struct shirq_regs { * struct spear_shirq: shared irq structure * * irq: hardware irq number - * dev_config: array of device config structures which are using "irq" line - * dev_count: size of dev_config array + * irq_base: base irq in linux domain + * irq_nr: no. of shared interrupts in a particular block + * irq_bit_off: starting bit offset in the status register + * invalid_irq: irq group is currently disabled + * base: base address of shared irq register * regs: register configuration for shared irq block */ struct spear_shirq { u32 irq; - struct shirq_dev_config *dev_config; - u32 dev_count; + u32 irq_base; + u32 irq_nr; + u32 irq_bit_off; + int invalid_irq; + void __iomem *base; struct shirq_regs regs; }; -int spear_shirq_register(struct spear_shirq *shirq); +int __init spear300_shirq_of_init(struct device_node *np, + struct device_node *parent); +int __init spear310_shirq_of_init(struct device_node *np, + struct device_node *parent); +int __init spear320_shirq_of_init(struct device_node *np, + struct device_node *parent); #endif /* __PLAT_SHIRQ_H */ diff --git a/arch/arm/plat-spear/shirq.c b/arch/arm/plat-spear/shirq.c index 853e891e1184..955c7249a5c1 100644 --- a/arch/arm/plat-spear/shirq.c +++ b/arch/arm/plat-spear/shirq.c @@ -10,56 +10,182 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include +#include #include #include +#include +#include +#include +#include #include #include -struct spear_shirq *shirq; static DEFINE_SPINLOCK(lock); -static void shirq_irq_mask(struct irq_data *d) +/* spear300 shared irq registers offsets and masks */ +#define SPEAR300_INT_ENB_MASK_REG 0x54 +#define SPEAR300_INT_STS_MASK_REG 0x58 + +static struct spear_shirq spear300_shirq_ras1 = { + .irq_nr = 9, + .irq_bit_off = 0, + .regs = { + .enb_reg = SPEAR300_INT_ENB_MASK_REG, + .status_reg = SPEAR300_INT_STS_MASK_REG, + .clear_reg = -1, + }, +}; + +static struct spear_shirq *spear300_shirq_blocks[] = { + &spear300_shirq_ras1, +}; + +/* spear310 shared irq registers offsets and masks */ +#define SPEAR310_INT_STS_MASK_REG 0x04 + +static struct spear_shirq spear310_shirq_ras1 = { + .irq_nr = 8, + .irq_bit_off = 0, + .regs = { + .enb_reg = -1, + .status_reg = SPEAR310_INT_STS_MASK_REG, + .clear_reg = -1, + }, +}; + +static struct spear_shirq spear310_shirq_ras2 = { + .irq_nr = 5, + .irq_bit_off = 8, + .regs = { + .enb_reg = -1, + .status_reg = SPEAR310_INT_STS_MASK_REG, + .clear_reg = -1, + }, +}; + +static struct spear_shirq spear310_shirq_ras3 = { + .irq_nr = 1, + .irq_bit_off = 13, + .regs = { + .enb_reg = -1, + .status_reg = SPEAR310_INT_STS_MASK_REG, + .clear_reg = -1, + }, +}; + +static struct spear_shirq spear310_shirq_intrcomm_ras = { + .irq_nr = 3, + .irq_bit_off = 14, + .regs = { + .enb_reg = -1, + .status_reg = SPEAR310_INT_STS_MASK_REG, + .clear_reg = -1, + }, +}; + +static struct spear_shirq *spear310_shirq_blocks[] = { + &spear310_shirq_ras1, + &spear310_shirq_ras2, + &spear310_shirq_ras3, + &spear310_shirq_intrcomm_ras, +}; + +/* spear320 shared irq registers offsets and masks */ +#define SPEAR320_INT_STS_MASK_REG 0x04 +#define SPEAR320_INT_CLR_MASK_REG 0x04 +#define SPEAR320_INT_ENB_MASK_REG 0x08 + +static struct spear_shirq spear320_shirq_ras1 = { + .irq_nr = 3, + .irq_bit_off = 7, + .regs = { + .enb_reg = -1, + .status_reg = SPEAR320_INT_STS_MASK_REG, + .clear_reg = SPEAR320_INT_CLR_MASK_REG, + .reset_to_clear = 1, + }, +}; + +static struct spear_shirq spear320_shirq_ras2 = { + .irq_nr = 1, + .irq_bit_off = 10, + .regs = { + .enb_reg = -1, + .status_reg = SPEAR320_INT_STS_MASK_REG, + .clear_reg = SPEAR320_INT_CLR_MASK_REG, + .reset_to_clear = 1, + }, +}; + +static struct spear_shirq spear320_shirq_ras3 = { + .irq_nr = 3, + .irq_bit_off = 0, + .invalid_irq = 1, + .regs = { + .enb_reg = SPEAR320_INT_ENB_MASK_REG, + .reset_to_enb = 1, + .status_reg = SPEAR320_INT_STS_MASK_REG, + .clear_reg = SPEAR320_INT_CLR_MASK_REG, + .reset_to_clear = 1, + }, +}; + +static struct spear_shirq spear320_shirq_intrcomm_ras = { + .irq_nr = 11, + .irq_bit_off = 11, + .regs = { + .enb_reg = -1, + .status_reg = SPEAR320_INT_STS_MASK_REG, + .clear_reg = SPEAR320_INT_CLR_MASK_REG, + .reset_to_clear = 1, + }, +}; + +static struct spear_shirq *spear320_shirq_blocks[] = { + &spear320_shirq_ras3, + &spear320_shirq_ras1, + &spear320_shirq_ras2, + &spear320_shirq_intrcomm_ras, +}; + +static void shirq_irq_mask_unmask(struct irq_data *d, bool mask) { struct spear_shirq *shirq = irq_data_get_irq_chip_data(d); - u32 val, id = d->irq - shirq->dev_config[0].virq; + u32 val, offset = d->irq - shirq->irq_base; unsigned long flags; - if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1) + if (shirq->regs.enb_reg == -1) return; spin_lock_irqsave(&lock, flags); - val = readl(shirq->regs.base + shirq->regs.enb_reg); - if (shirq->regs.reset_to_enb) - val |= shirq->dev_config[id].enb_mask; + val = readl(shirq->base + shirq->regs.enb_reg); + + if (mask ^ shirq->regs.reset_to_enb) + val &= ~(0x1 << shirq->irq_bit_off << offset); else - val &= ~(shirq->dev_config[id].enb_mask); - writel(val, shirq->regs.base + shirq->regs.enb_reg); + val |= 0x1 << shirq->irq_bit_off << offset; + + writel(val, shirq->base + shirq->regs.enb_reg); spin_unlock_irqrestore(&lock, flags); + } -static void shirq_irq_unmask(struct irq_data *d) +static void shirq_irq_mask(struct irq_data *d) { - struct spear_shirq *shirq = irq_data_get_irq_chip_data(d); - u32 val, id = d->irq - shirq->dev_config[0].virq; - unsigned long flags; - - if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1) - return; + shirq_irq_mask_unmask(d, 1); +} - spin_lock_irqsave(&lock, flags); - val = readl(shirq->regs.base + shirq->regs.enb_reg); - if (shirq->regs.reset_to_enb) - val &= ~(shirq->dev_config[id].enb_mask); - else - val |= shirq->dev_config[id].enb_mask; - writel(val, shirq->regs.base + shirq->regs.enb_reg); - spin_unlock_irqrestore(&lock, flags); +static void shirq_irq_unmask(struct irq_data *d) +{ + shirq_irq_mask_unmask(d, 0); } static struct irq_chip shirq_chip = { - .name = "spear_shirq", + .name = "spear-shirq", .irq_ack = shirq_irq_mask, .irq_mask = shirq_irq_mask, .irq_unmask = shirq_irq_unmask, @@ -67,52 +193,123 @@ static struct irq_chip shirq_chip = { static void shirq_handler(unsigned irq, struct irq_desc *desc) { - u32 i, val, mask; + u32 i, j, val, mask, tmp; + struct irq_chip *chip; struct spear_shirq *shirq = irq_get_handler_data(irq); - desc->irq_data.chip->irq_ack(&desc->irq_data); - while ((val = readl(shirq->regs.base + shirq->regs.status_reg) & - shirq->regs.status_reg_mask)) { - for (i = 0; (i < shirq->dev_count) && val; i++) { - if (!(shirq->dev_config[i].status_mask & val)) + chip = irq_get_chip(irq); + chip->irq_ack(&desc->irq_data); + + mask = ((0x1 << shirq->irq_nr) - 1) << shirq->irq_bit_off; + while ((val = readl(shirq->base + shirq->regs.status_reg) & + mask)) { + + val >>= shirq->irq_bit_off; + for (i = 0, j = 1; i < shirq->irq_nr; i++, j <<= 1) { + + if (!(j & val)) continue; - generic_handle_irq(shirq->dev_config[i].virq); + generic_handle_irq(shirq->irq_base + i); /* clear interrupt */ - val &= ~shirq->dev_config[i].status_mask; - if ((shirq->regs.clear_reg == -1) || - shirq->dev_config[i].clear_mask == -1) + if (shirq->regs.clear_reg == -1) continue; - mask = readl(shirq->regs.base + shirq->regs.clear_reg); + + tmp = readl(shirq->base + shirq->regs.clear_reg); if (shirq->regs.reset_to_clear) - mask &= ~shirq->dev_config[i].clear_mask; + tmp &= ~(j << shirq->irq_bit_off); else - mask |= shirq->dev_config[i].clear_mask; - writel(mask, shirq->regs.base + shirq->regs.clear_reg); + tmp |= (j << shirq->irq_bit_off); + writel(tmp, shirq->base + shirq->regs.clear_reg); } } - desc->irq_data.chip->irq_unmask(&desc->irq_data); + chip->irq_unmask(&desc->irq_data); } -int spear_shirq_register(struct spear_shirq *shirq) +static void __init spear_shirq_register(struct spear_shirq *shirq) { int i; - if (!shirq || !shirq->dev_config || !shirq->regs.base) - return -EFAULT; - - if (!shirq->dev_count) - return -EINVAL; + if (shirq->invalid_irq) + return; irq_set_chained_handler(shirq->irq, shirq_handler); - for (i = 0; i < shirq->dev_count; i++) { - irq_set_chip_and_handler(shirq->dev_config[i].virq, + for (i = 0; i < shirq->irq_nr; i++) { + irq_set_chip_and_handler(shirq->irq_base + i, &shirq_chip, handle_simple_irq); - set_irq_flags(shirq->dev_config[i].virq, IRQF_VALID); - irq_set_chip_data(shirq->dev_config[i].virq, shirq); + set_irq_flags(shirq->irq_base + i, IRQF_VALID); + irq_set_chip_data(shirq->irq_base + i, shirq); } irq_set_handler_data(shirq->irq, shirq); +} + +static int __init shirq_init(struct spear_shirq **shirq_blocks, int block_nr, + struct device_node *np) +{ + int i, irq_base, hwirq = 0, irq_nr = 0; + static struct irq_domain *shirq_domain; + void __iomem *base; + + base = of_iomap(np, 0); + if (!base) { + pr_err("%s: failed to map shirq registers\n", __func__); + return -ENXIO; + } + + for (i = 0; i < block_nr; i++) + irq_nr += shirq_blocks[i]->irq_nr; + + irq_base = irq_alloc_descs(-1, 0, irq_nr, 0); + if (IS_ERR_VALUE(irq_base)) { + pr_err("%s: irq desc alloc failed\n", __func__); + goto err_unmap; + } + + shirq_domain = irq_domain_add_legacy(np, irq_nr, irq_base, 0, + &irq_domain_simple_ops, NULL); + if (WARN_ON(!shirq_domain)) { + pr_warn("%s: irq domain init failed\n", __func__); + goto err_free_desc; + } + + for (i = 0; i < block_nr; i++) { + shirq_blocks[i]->base = base; + shirq_blocks[i]->irq_base = irq_find_mapping(shirq_domain, + hwirq); + shirq_blocks[i]->irq = irq_of_parse_and_map(np, i); + + spear_shirq_register(shirq_blocks[i]); + hwirq += shirq_blocks[i]->irq_nr; + } + return 0; + +err_free_desc: + irq_free_descs(irq_base, irq_nr); +err_unmap: + iounmap(base); + return -ENXIO; +} + +int __init spear300_shirq_of_init(struct device_node *np, + struct device_node *parent) +{ + return shirq_init(spear300_shirq_blocks, + ARRAY_SIZE(spear300_shirq_blocks), np); +} + +int __init spear310_shirq_of_init(struct device_node *np, + struct device_node *parent) +{ + return shirq_init(spear310_shirq_blocks, + ARRAY_SIZE(spear310_shirq_blocks), np); +} + +int __init spear320_shirq_of_init(struct device_node *np, + struct device_node *parent) +{ + return shirq_init(spear320_shirq_blocks, + ARRAY_SIZE(spear320_shirq_blocks), np); } From 86edd7b8ac2791ddf42ab082799ddb843813c3bc Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Fri, 3 Aug 2012 16:00:18 +0530 Subject: [PATCH 63/65] ARM: SPEAr3xx: DT: add shirq node for interrupt multiplexor shirq layer has been adapted to DT, add corresponding nodes in all SPEAr3xx variants. Signed-off-by: Shiraz Hashim Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/spear300.dtsi | 12 ++++++++++++ arch/arm/boot/dts/spear310.dtsi | 18 ++++++++++++++++++ arch/arm/boot/dts/spear320.dtsi | 24 ++++++++++++++++++++++-- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/spear300.dtsi b/arch/arm/boot/dts/spear300.dtsi index fdac8713367a..090adc656015 100644 --- a/arch/arm/boot/dts/spear300.dtsi +++ b/arch/arm/boot/dts/spear300.dtsi @@ -52,6 +52,14 @@ status = "disabled"; }; + shirq: interrupt-controller@0x50000000 { + compatible = "st,spear300-shirq"; + reg = <0x50000000 0x1000>; + interrupts = <28>; + #interrupt-cells = <1>; + interrupt-controller; + }; + apb { #address-cells = <1>; #size-cells = <1>; @@ -64,12 +72,16 @@ compatible = "arm,pl061", "arm,primecell"; gpio-controller; reg = <0xa9000000 0x1000>; + interrupts = <8>; + interrupt-parent = <&shirq>; status = "disabled"; }; kbd@a0000000 { compatible = "st,spear300-kbd"; reg = <0xa0000000 0x1000>; + interrupts = <7>; + interrupt-parent = <&shirq>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/spear310.dtsi b/arch/arm/boot/dts/spear310.dtsi index 930303e48df9..e814e5e97083 100644 --- a/arch/arm/boot/dts/spear310.dtsi +++ b/arch/arm/boot/dts/spear310.dtsi @@ -40,6 +40,14 @@ status = "disabled"; }; + shirq: interrupt-controller@0xb4000000 { + compatible = "st,spear310-shirq"; + reg = <0xb4000000 0x1000>; + interrupts = <28 29 30 1>; + #interrupt-cells = <1>; + interrupt-controller; + }; + apb { #address-cells = <1>; #size-cells = <1>; @@ -50,30 +58,40 @@ serial@b2000000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xb2000000 0x1000>; + interrupts = <8>; + interrupt-parent = <&shirq>; status = "disabled"; }; serial@b2080000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xb2080000 0x1000>; + interrupts = <9>; + interrupt-parent = <&shirq>; status = "disabled"; }; serial@b2100000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xb2100000 0x1000>; + interrupts = <10>; + interrupt-parent = <&shirq>; status = "disabled"; }; serial@b2180000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xb2180000 0x1000>; + interrupts = <11>; + interrupt-parent = <&shirq>; status = "disabled"; }; serial@b2200000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xb2200000 0x1000>; + interrupts = <12>; + interrupt-parent = <&shirq>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi index 6ff0d1e0e461..c056a84deabf 100644 --- a/arch/arm/boot/dts/spear320.dtsi +++ b/arch/arm/boot/dts/spear320.dtsi @@ -30,7 +30,8 @@ clcd@90000000 { compatible = "arm,pl110", "arm,primecell"; reg = <0x90000000 0x1000>; - interrupts = <33>; + interrupts = <8>; + interrupt-parent = <&shirq>; status = "disabled"; }; @@ -49,13 +50,24 @@ sdhci@70000000 { compatible = "st,sdhci-spear"; reg = <0x70000000 0x100>; - interrupts = <29>; + interrupts = <10>; + interrupt-parent = <&shirq>; status = "disabled"; }; + shirq: interrupt-controller@0xb3000000 { + compatible = "st,spear320-shirq"; + reg = <0xb3000000 0x1000>; + interrupts = <30 28 29 1>; + #interrupt-cells = <1>; + interrupt-controller; + }; + spi1: spi@a5000000 { compatible = "arm,pl022", "arm,primecell"; reg = <0xa5000000 0x1000>; + interrupts = <15>; + interrupt-parent = <&shirq>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -64,6 +76,8 @@ spi2: spi@a6000000 { compatible = "arm,pl022", "arm,primecell"; reg = <0xa6000000 0x1000>; + interrupts = <16>; + interrupt-parent = <&shirq>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -88,18 +102,24 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xa7000000 0x1000>; + interrupts = <21>; + interrupt-parent = <&shirq>; status = "disabled"; }; serial@a3000000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xa3000000 0x1000>; + interrupts = <13>; + interrupt-parent = <&shirq>; status = "disabled"; }; serial@a4000000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xa4000000 0x1000>; + interrupts = <14>; + interrupt-parent = <&shirq>; status = "disabled"; }; From e2eb69183ec4156eb814e67672e492bf902bbcd2 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Thu, 9 Aug 2012 04:50:11 +0530 Subject: [PATCH 64/65] ARM: SPEAr320: DT: Add SPEAr 320 HMI board support This adds support for SPEAr320-HMI board. Signed-off-by: Shiraz Hashim Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/spear320-hmi.dts | 305 +++++++++++++++++++++++++++++ arch/arm/mach-spear3xx/spear320.c | 1 + 3 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/spear320-hmi.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index f37cf9fa5fa0..07e6cfaaa319 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -82,7 +82,8 @@ dtb-$(CONFIG_ARCH_SPEAR13XX) += spear1310-evb.dtb \ spear1340-evb.dtb dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \ spear310-evb.dtb \ - spear320-evb.dtb + spear320-evb.dtb \ + spear320-hmi.dtb dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ tegra20-medcom-wide.dtb \ diff --git a/arch/arm/boot/dts/spear320-hmi.dts b/arch/arm/boot/dts/spear320-hmi.dts new file mode 100644 index 000000000000..3075d2d3a8be --- /dev/null +++ b/arch/arm/boot/dts/spear320-hmi.dts @@ -0,0 +1,305 @@ +/* + * DTS file for SPEAr320 Evaluation Baord + * + * Copyright 2012 Shiraz Hashim + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "spear320.dtsi" + +/ { + model = "ST SPEAr320 HMI Board"; + compatible = "st,spear320-hmi", "st,spear320"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + reg = <0 0x40000000>; + }; + + ahb { + pinmux@b3000000 { + st,pinmux-mode = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + i2c0 { + st,pins = "i2c0_grp"; + st,function = "i2c0"; + }; + ssp0 { + st,pins = "ssp0_grp"; + st,function = "ssp0"; + }; + uart0 { + st,pins = "uart0_grp"; + st,function = "uart0"; + }; + clcd { + st,pins = "clcd_grp"; + st,function = "clcd"; + }; + fsmc { + st,pins = "fsmc_8bit_grp"; + st,function = "fsmc"; + }; + sdhci { + st,pins = "sdhci_cd_12_grp"; + st,function = "sdhci"; + }; + i2s { + st,pins = "i2s_grp"; + st,function = "i2s"; + }; + uart1 { + st,pins = "uart1_grp"; + st,function = "uart1"; + }; + uart2 { + st,pins = "uart2_grp"; + st,function = "uart2"; + }; + can0 { + st,pins = "can0_grp"; + st,function = "can0"; + }; + can1 { + st,pins = "can1_grp"; + st,function = "can1"; + }; + mii0_1 { + st,pins = "rmii0_1_grp"; + st,function = "mii0_1"; + }; + pwm0_1 { + st,pins = "pwm0_1_pin_37_38_grp"; + st,function = "pwm0_1"; + }; + pwm2 { + st,pins = "pwm2_pin_34_grp"; + st,function = "pwm2"; + }; + }; + }; + + clcd@90000000 { + status = "okay"; + }; + + dma@fc400000 { + status = "okay"; + }; + + ehci@e1800000 { + status = "okay"; + }; + + fsmc: flash@4c000000 { + status = "okay"; + + partition@0 { + label = "xloader"; + reg = <0x0 0x80000>; + }; + partition@80000 { + label = "u-boot"; + reg = <0x80000 0x140000>; + }; + partition@1C0000 { + label = "environment"; + reg = <0x1C0000 0x40000>; + }; + partition@200000 { + label = "dtb"; + reg = <0x200000 0x40000>; + }; + partition@240000 { + label = "linux"; + reg = <0x240000 0xC00000>; + }; + partition@E40000 { + label = "rootfs"; + reg = <0xE40000 0x0>; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@1 { + label = "user button 1"; + linux,code = <0x100>; + gpios = <&stmpegpio 3 0x4>; + debounce-interval = <20>; + gpio-key,wakeup = <1>; + }; + + button@2 { + label = "user button 2"; + linux,code = <0x200>; + gpios = <&stmpegpio 2 0x4>; + debounce-interval = <20>; + gpio-key,wakeup = <1>; + }; + }; + + ohci@e1900000 { + status = "okay"; + }; + + ohci@e2100000 { + status = "okay"; + }; + + pwm: pwm@a8000000 { + status = "okay"; + }; + + sdhci@70000000 { + power-gpio = <&gpiopinctrl 50 1>; + power_always_enb; + status = "okay"; + }; + + smi: flash@fc000000 { + status = "okay"; + clock-rate=<50000000>; + + flash@f8000000 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xf8000000 0x800000>; + st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x50000>; + }; + partition@60000 { + label = "environment"; + reg = <0x60000 0x10000>; + }; + partition@70000 { + label = "dtb"; + reg = <0x70000 0x10000>; + }; + partition@80000 { + label = "linux"; + reg = <0x80000 0x310000>; + }; + partition@390000 { + label = "rootfs"; + reg = <0x390000 0x0>; + }; + }; + }; + + spi0: spi@d0100000 { + status = "okay"; + }; + + spi1: spi@a5000000 { + status = "okay"; + }; + + spi2: spi@a6000000 { + status = "okay"; + }; + + usbd@e1100000 { + status = "okay"; + }; + + apb { + gpio0: gpio@fc980000 { + status = "okay"; + }; + + gpio@b3000000 { + status = "okay"; + }; + + i2c0: i2c@d0180000 { + status = "okay"; + + stmpe811@41 { + compatible = "st,stmpe811"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x41>; + irq-over-gpio; + irq-gpios = <&gpiopinctrl 29 0x4>; + id = <0>; + blocks = <0x5>; + irq-trigger = <0x1>; + + stmpegpio: stmpe-gpio { + compatible = "stmpe,gpio"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + gpio,norequest-mask = <0xF3>; + }; + + stmpe610-ts { + compatible = "stmpe,ts"; + reg = <0>; + ts,sample-time = <4>; + ts,mod-12b = <1>; + ts,ref-sel = <0>; + ts,adc-freq = <1>; + ts,ave-ctrl = <1>; + ts,touch-det-delay = <3>; + ts,settling = <4>; + ts,fraction-z = <7>; + ts,i-drive = <1>; + }; + }; + }; + + i2c1: i2c@a7000000 { + status = "okay"; + }; + + rtc@fc900000 { + status = "okay"; + }; + + serial@d0000000 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + }; + + serial@a3000000 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + }; + + serial@a4000000 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <>; + }; + + wdt@fc880000 { + status = "okay"; + }; + }; + }; +}; diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c index 707504b84e0e..66e3a0c33e75 100644 --- a/arch/arm/mach-spear3xx/spear320.c +++ b/arch/arm/mach-spear3xx/spear320.c @@ -247,6 +247,7 @@ static void __init spear320_dt_init(void) static const char * const spear320_dt_board_compat[] = { "st,spear320", "st,spear320-evb", + "st,spear320-hmi", NULL, }; From df1590d9ae5e37e07e7cf91107e4c2c946ce8bf4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 12 Nov 2012 22:56:03 +0530 Subject: [PATCH 65/65] ARM: SPEAr3xx: Shirq: Move shirq controller out of plat/ This patch moves shirq interrupt controllers driver and header file out of plat-spear directory. It is moved to drivers/irqchip/ directory. Signed-off-by: Viresh Kumar --- arch/arm/mach-spear3xx/spear3xx.c | 2 +- arch/arm/plat-spear/Makefile | 2 +- drivers/irqchip/Makefile | 3 ++- .../shirq.c => drivers/irqchip/spear-shirq.c | 9 +++++---- .../shirq.h => include/linux/irqchip/spear-shirq.h | 10 ++++------ 5 files changed, 13 insertions(+), 13 deletions(-) rename arch/arm/plat-spear/shirq.c => drivers/irqchip/spear-shirq.c (97%) rename arch/arm/plat-spear/include/plat/shirq.h => include/linux/irqchip/spear-shirq.h (90%) diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c index f1aaf5b168b2..38fe95db31a7 100644 --- a/arch/arm/mach-spear3xx/spear3xx.c +++ b/arch/arm/mach-spear3xx/spear3xx.c @@ -15,12 +15,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile index 2607bd05c525..01e88532a5db 100644 --- a/arch/arm/plat-spear/Makefile +++ b/arch/arm/plat-spear/Makefile @@ -5,5 +5,5 @@ # Common support obj-y := restart.o time.o -obj-$(CONFIG_ARCH_SPEAR3XX) += pl080.o shirq.o +obj-$(CONFIG_ARCH_SPEAR3XX) += pl080.o obj-$(CONFIG_ARCH_SPEAR6XX) += pl080.o diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 054321db4350..bf7b43696cdb 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -1 +1,2 @@ -obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o +obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o +obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o diff --git a/arch/arm/plat-spear/shirq.c b/drivers/irqchip/spear-shirq.c similarity index 97% rename from arch/arm/plat-spear/shirq.c rename to drivers/irqchip/spear-shirq.c index 955c7249a5c1..80e1d2fd9d4c 100644 --- a/arch/arm/plat-spear/shirq.c +++ b/drivers/irqchip/spear-shirq.c @@ -1,11 +1,12 @@ /* - * arch/arm/plat-spear/shirq.c - * * SPEAr platform shared irq layer source file * - * Copyright (C) 2009 ST Microelectronics + * Copyright (C) 2009-2012 ST Microelectronics * Viresh Kumar * + * Copyright (C) 2012 ST Microelectronics + * Shiraz Hashim + * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. @@ -18,11 +19,11 @@ #include #include #include +#include #include #include #include #include -#include static DEFINE_SPINLOCK(lock); diff --git a/arch/arm/plat-spear/include/plat/shirq.h b/include/linux/irqchip/spear-shirq.h similarity index 90% rename from arch/arm/plat-spear/include/plat/shirq.h rename to include/linux/irqchip/spear-shirq.h index c51b355f00de..c8be16d213a3 100644 --- a/arch/arm/plat-spear/include/plat/shirq.h +++ b/include/linux/irqchip/spear-shirq.h @@ -1,9 +1,7 @@ /* - * arch/arm/plat-spear/include/plat/shirq.h - * * SPEAr platform shared irq layer header file * - * Copyright (C) 2009 ST Microelectronics + * Copyright (C) 2009-2012 ST Microelectronics * Viresh Kumar * * This file is licensed under the terms of the GNU General Public @@ -11,8 +9,8 @@ * warranty of any kind, whether express or implied. */ -#ifndef __PLAT_SHIRQ_H -#define __PLAT_SHIRQ_H +#ifndef __SPEAR_SHIRQ_H +#define __SPEAR_SHIRQ_H #include #include @@ -63,4 +61,4 @@ int __init spear310_shirq_of_init(struct device_node *np, int __init spear320_shirq_of_init(struct device_node *np, struct device_node *parent); -#endif /* __PLAT_SHIRQ_H */ +#endif /* __SPEAR_SHIRQ_H */