diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 25 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpio/gpio-davinci.c | 26 | ||||
-rw-r--r-- | drivers/gpio/gpio-ep93xx.c | 15 | ||||
-rw-r--r-- | drivers/gpio/gpio-ge.c | 199 | ||||
-rw-r--r-- | drivers/gpio/gpio-lpc32xx.c | 19 | ||||
-rw-r--r-- | drivers/gpio/gpio-mc9s08dz60.c | 161 | ||||
-rw-r--r-- | drivers/gpio/gpio-mpc8xxx.c | 30 | ||||
-rw-r--r-- | drivers/gpio/gpio-omap.c | 1313 | ||||
-rw-r--r-- | drivers/gpio/gpio-pl061.c | 7 | ||||
-rw-r--r-- | drivers/gpio/gpio-sa1100.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-samsung.c | 487 | ||||
-rw-r--r-- | drivers/gpio/gpio-sodaville.c | 302 | ||||
-rw-r--r-- | drivers/gpio/gpio-stmpe.c | 43 | ||||
-rw-r--r-- | drivers/gpio/gpio-tegra.c | 63 | ||||
-rw-r--r-- | drivers/gpio/gpio-tps65910.c | 20 | ||||
-rw-r--r-- | drivers/gpio/gpio-twl4030.c | 111 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 98 |
18 files changed, 2063 insertions, 860 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d0c41188d4e5..edadbdad31d0 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -190,6 +190,17 @@ config GPIO_VX855 additional drivers must be enabled in order to use the functionality of the device. +config GPIO_GE_FPGA + bool "GE FPGA based GPIO" + depends on GE_FPGA + help + Support for common GPIO functionality provided on some GE Single Board + Computers. + + This driver provides basic support (configure as input or output, read + and write pin state) for GPIO implemented in a number of GE single + board computers. + comment "I2C GPIO expanders:" config GPIO_MAX7300 @@ -225,6 +236,12 @@ config GPIO_MAX732X_IRQ Say yes here to enable the max732x to be used as an interrupt controller. It requires the driver to be built in the kernel. +config GPIO_MC9S08DZ60 + bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions" + depends on I2C && MACH_MX35_3DS + help + Select this to enable the MC9S08DZ60 GPIO driver + config GPIO_PCA953X tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports" depends on I2C @@ -411,6 +428,14 @@ config GPIO_ML_IOH Hub) which is for IVI(In-Vehicle Infotainment) use. This driver can access the IOH's GPIO device. +config GPIO_SODAVILLE + bool "Intel Sodaville GPIO support" + depends on X86 && PCI && OF && BROKEN + select GPIO_GENERIC + select GENERIC_IRQ_CHIP + help + Say Y here to support Intel Sodaville GPIO. + config GPIO_TIMBERDALE bool "Support for timberdale GPIO IP" depends on MFD_TIMBERDALE && HAS_IOMEM diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fa10df604c01..007f54bd0081 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o +obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o @@ -26,6 +27,7 @@ obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o +obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o @@ -45,6 +47,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o 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_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index df0d59570a84..3d000169285d 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -313,10 +313,16 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) return -ENODEV; } -static int gpio_irq_type_unbanked(struct irq_data *d, unsigned trigger) +static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) { - struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); - u32 mask = (u32) irq_data_get_irq_handler_data(d); + struct davinci_gpio_controller *d; + struct davinci_gpio_regs __iomem *g; + struct davinci_soc_info *soc_info = &davinci_soc_info; + u32 mask; + + d = (struct davinci_gpio_controller *)data->handler_data; + g = (struct davinci_gpio_regs __iomem *)d->regs; + mask = __gpio_mask(data->irq - soc_info->gpio_irq); if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) return -EINVAL; @@ -380,7 +386,7 @@ static int __init davinci_gpio_irq_setup(void) * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. */ if (soc_info->gpio_unbanked) { - static struct irq_chip gpio_irqchip_unbanked; + static struct irq_chip_type gpio_unbanked; /* pass "bank 0" GPIO IRQs to AINTC */ chips[0].chip.to_irq = gpio_to_irq_unbanked; @@ -388,9 +394,10 @@ static int __init davinci_gpio_irq_setup(void) /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; - gpio_irqchip_unbanked = *irq_get_chip(irq); - gpio_irqchip_unbanked.name = "GPIO-AINTC"; - gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked; + gpio_unbanked = *container_of(irq_get_chip(irq), + struct irq_chip_type, chip); + gpio_unbanked.chip.name = "GPIO-AINTC"; + gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked; /* default trigger: both edges */ g = gpio2regs(0); @@ -399,9 +406,8 @@ static int __init davinci_gpio_irq_setup(void) /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) { - irq_set_chip(irq, &gpio_irqchip_unbanked); - irq_set_handler_data(irq, (void *)__gpio_mask(gpio)); - irq_set_chip_data(irq, (__force void *)g); + irq_set_chip(irq, &gpio_unbanked.chip); + irq_set_handler_data(irq, &chips[gpio / 32]); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 1c0fc3756cb1..776b772523e5 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -12,8 +12,6 @@ * published by the Free Software Foundation. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -65,11 +63,6 @@ static void ep93xx_gpio_update_int_params(unsigned port) EP93XX_GPIO_REG(int_en_register_offset[port])); } -static inline void ep93xx_gpio_int_mask(unsigned line) -{ - gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7)); -} - static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) { int line = irq_to_gpio(irq); @@ -212,7 +205,6 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) handler = handle_edge_irq; break; default: - pr_err("failed to set irq type %d for gpio %d\n", type, gpio); return -EINVAL; } @@ -378,13 +370,6 @@ static int __devinit ep93xx_gpio_probe(struct platform_device *pdev) } ep93xx_gpio->mmio_base = mmio; - /* Default all ports to GPIO */ - ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS | - EP93XX_SYSCON_DEVCFG_GONK | - EP93XX_SYSCON_DEVCFG_EONIDE | - EP93XX_SYSCON_DEVCFG_GONIDE | - EP93XX_SYSCON_DEVCFG_HONIDE); - for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i]; struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c new file mode 100644 index 000000000000..7b95a4a8318c --- /dev/null +++ b/drivers/gpio/gpio-ge.c @@ -0,0 +1,199 @@ +/* + * Driver for GE FPGA based GPIO + * + * Author: Martyn Welch <martyn.welch@ge.com> + * + * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. + * + * 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. + */ + +/* TODO + * + * Configuration of output modes (totem-pole/open-drain) + * Interrupt configuration - interrupts are always generated the FPGA relies on + * the I/O interrupt controllers mask to stop them propergating + */ + +#include <linux/kernel.h> +#include <linux/compiler.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/module.h> + +#define GEF_GPIO_DIRECT 0x00 +#define GEF_GPIO_IN 0x04 +#define GEF_GPIO_OUT 0x08 +#define GEF_GPIO_TRIG 0x0C +#define GEF_GPIO_POLAR_A 0x10 +#define GEF_GPIO_POLAR_B 0x14 +#define GEF_GPIO_INT_STAT 0x18 +#define GEF_GPIO_OVERRUN 0x1C +#define GEF_GPIO_MODE 0x20 + +static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value) +{ + unsigned int data; + + data = ioread32be(reg); + /* value: 0=low; 1=high */ + if (value & 0x1) + data = data | (0x1 << offset); + else + data = data & ~(0x1 << offset); + + iowrite32be(data, reg); +} + + +static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) +{ + unsigned int data; + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); + data = data | (0x1 << offset); + iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); + + return 0; +} + +static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) +{ + unsigned int data; + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + /* Set direction before switching to input */ + _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); + + data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); + data = data & ~(0x1 << offset); + iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); + + return 0; +} + +static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + unsigned int data; + int state = 0; + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + data = ioread32be(mmchip->regs + GEF_GPIO_IN); + state = (int)((data >> offset) & 0x1); + + return state; +} + +static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); +} + +static int __init gef_gpio_init(void) +{ + struct device_node *np; + int retval; + struct of_mm_gpio_chip *gef_gpio_chip; + + for_each_compatible_node(np, NULL, "gef,sbc610-gpio") { + + pr_debug("%s: Initialising GEF GPIO\n", np->full_name); + + /* Allocate chip structure */ + gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); + if (!gef_gpio_chip) { + pr_err("%s: Unable to allocate structure\n", + np->full_name); + continue; + } + + /* Setup pointers to chip functions */ + gef_gpio_chip->gc.of_gpio_n_cells = 2; + gef_gpio_chip->gc.ngpio = 19; + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; + gef_gpio_chip->gc.get = gef_gpio_get; + gef_gpio_chip->gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + retval = of_mm_gpiochip_add(np, gef_gpio_chip); + if (retval) { + kfree(gef_gpio_chip); + pr_err("%s: Unable to add GPIO\n", np->full_name); + } + } + + for_each_compatible_node(np, NULL, "gef,sbc310-gpio") { + + pr_debug("%s: Initialising GEF GPIO\n", np->full_name); + + /* Allocate chip structure */ + gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); + if (!gef_gpio_chip) { + pr_err("%s: Unable to allocate structure\n", + np->full_name); + continue; + } + + /* Setup pointers to chip functions */ + gef_gpio_chip->gc.of_gpio_n_cells = 2; + gef_gpio_chip->gc.ngpio = 6; + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; + gef_gpio_chip->gc.get = gef_gpio_get; + gef_gpio_chip->gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + retval = of_mm_gpiochip_add(np, gef_gpio_chip); + if (retval) { + kfree(gef_gpio_chip); + pr_err("%s: Unable to add GPIO\n", np->full_name); + } + } + + for_each_compatible_node(np, NULL, "ge,imp3a-gpio") { + + pr_debug("%s: Initialising GE GPIO\n", np->full_name); + + /* Allocate chip structure */ + gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); + if (!gef_gpio_chip) { + pr_err("%s: Unable to allocate structure\n", + np->full_name); + continue; + } + + /* Setup pointers to chip functions */ + gef_gpio_chip->gc.of_gpio_n_cells = 2; + gef_gpio_chip->gc.ngpio = 16; + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; + gef_gpio_chip->gc.get = gef_gpio_get; + gef_gpio_chip->gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + retval = of_mm_gpiochip_add(np, gef_gpio_chip); + if (retval) { + kfree(gef_gpio_chip); + pr_err("%s: Unable to add GPIO\n", np->full_name); + } + } + + return 0; +}; +arch_initcall(gef_gpio_init); + +MODULE_DESCRIPTION("GE I/O FPGA GPIO driver"); +MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index ddfacc5ce56d..61c2d08d37b6 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -59,12 +59,14 @@ #define GPO3_PIN_TO_BIT(x) (1 << (x)) #define GPIO012_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) #define GPIO3_PIN_IN_SHIFT(x) ((x) == 5 ? 24 : 10 + (x)) -#define GPIO3_PIN_IN_SEL(x, y) ((x) >> GPIO3_PIN_IN_SHIFT(y)) +#define GPIO3_PIN_IN_SEL(x, y) (((x) >> GPIO3_PIN_IN_SHIFT(y)) & 1) #define GPIO3_PIN5_IN_SEL(x) (((x) >> 24) & 1) #define GPI3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) +#define GPO3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) struct gpio_regs { void __iomem *inp_state; + void __iomem *outp_state; void __iomem *outp_set; void __iomem *outp_clr; void __iomem *dir_set; @@ -145,6 +147,7 @@ static struct gpio_regs gpio_grp_regs_p2 = { static struct gpio_regs gpio_grp_regs_p3 = { .inp_state = LPC32XX_GPIO_P3_INP_STATE, + .outp_state = LPC32XX_GPIO_P3_OUTP_STATE, .outp_set = LPC32XX_GPIO_P3_OUTP_SET, .outp_clr = LPC32XX_GPIO_P3_OUTP_CLR, .dir_set = LPC32XX_GPIO_P2_DIR_SET, @@ -240,6 +243,12 @@ static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group, return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin); } +static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group, + unsigned pin) +{ + return GPO3_PIN_IN_SEL(__raw_readl(group->gpio_grp->outp_state), pin); +} + /* * GENERIC_GPIO primitives. */ @@ -340,6 +349,13 @@ static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin, __set_gpo_level_p3(group, pin, value); } +static int lpc32xx_gpo_get_value(struct gpio_chip *chip, unsigned pin) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + return __get_gpo_state_p3(group, pin); +} + static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin) { if (pin < chip->ngpio) @@ -427,6 +443,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .label = "gpo_p3", .direction_output = lpc32xx_gpio_dir_out_always, .set = lpc32xx_gpo_set_value, + .get = lpc32xx_gpo_get_value, .request = lpc32xx_gpio_request, .base = LPC32XX_GPO_P3_GRP, .ngpio = LPC32XX_GPO_P3_MAX, diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c new file mode 100644 index 000000000000..2738cc44d636 --- /dev/null +++ b/drivers/gpio/gpio-mc9s08dz60.c @@ -0,0 +1,161 @@ +/* + * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Author: Wu Guoxing <b39297@freescale.com> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/gpio.h> + +#define GPIO_GROUP_NUM 2 +#define GPIO_NUM_PER_GROUP 8 +#define GPIO_NUM (GPIO_GROUP_NUM*GPIO_NUM_PER_GROUP) + +struct mc9s08dz60 { + struct i2c_client *client; + struct gpio_chip chip; +}; + +static inline struct mc9s08dz60 *to_mc9s08dz60(struct gpio_chip *gc) +{ + return container_of(gc, struct mc9s08dz60, chip); +} + + +static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit) +{ + *reg = 0x20 + offset / GPIO_NUM_PER_GROUP; + *bit = offset % GPIO_NUM_PER_GROUP; +} + +static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset) +{ + u8 reg, bit; + s32 value; + struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc); + + mc9s_gpio_to_reg_and_bit(offset, ®, &bit); + value = i2c_smbus_read_byte_data(mc9s->client, reg); + + return (value >= 0) ? (value >> bit) & 0x1 : 0; +} + +static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val) +{ + u8 reg, bit; + s32 value; + + mc9s_gpio_to_reg_and_bit(offset, ®, &bit); + value = i2c_smbus_read_byte_data(mc9s->client, reg); + if (value >= 0) { + if (val) + value |= 1 << bit; + else + value &= ~(1 << bit); + + return i2c_smbus_write_byte_data(mc9s->client, reg, value); + } else + return value; + +} + + +static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val) +{ + struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc); + + mc9s08dz60_set(mc9s, offset, val); +} + +static int mc9s08dz60_direction_output(struct gpio_chip *gc, + unsigned offset, int val) +{ + struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc); + + return mc9s08dz60_set(mc9s, offset, val); +} + +static int mc9s08dz60_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct mc9s08dz60 *mc9s; + + mc9s = kzalloc(sizeof(*mc9s), GFP_KERNEL); + if (!mc9s) + return -ENOMEM; + + mc9s->chip.label = client->name; + mc9s->chip.base = -1; + mc9s->chip.dev = &client->dev; + mc9s->chip.owner = THIS_MODULE; + mc9s->chip.ngpio = GPIO_NUM; + mc9s->chip.can_sleep = 1; + mc9s->chip.get = mc9s08dz60_get_value; + mc9s->chip.set = mc9s08dz60_set_value; + mc9s->chip.direction_output = mc9s08dz60_direction_output; + mc9s->client = client; + i2c_set_clientdata(client, mc9s); + + ret = gpiochip_add(&mc9s->chip); + if (ret) + goto error; + + return 0; + + error: + kfree(mc9s); + return ret; +} + +static int mc9s08dz60_remove(struct i2c_client *client) +{ + struct mc9s08dz60 *mc9s; + int ret; + + mc9s = i2c_get_clientdata(client); + + ret = gpiochip_remove(&mc9s->chip); + if (!ret) + kfree(mc9s); + + return ret; + +} + +static const struct i2c_device_id mc9s08dz60_id[] = { + {"mc9s08dz60", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, mc9s08dz60_id); + +static struct i2c_driver mc9s08dz60_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "mc9s08dz60", + }, + .probe = mc9s08dz60_probe, + .remove = mc9s08dz60_remove, + .id_table = mc9s08dz60_id, +}; + +module_i2c_driver(mc9s08dz60_i2c_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc. " + "Wu Guoxing <b39297@freescale.com>"); +MODULE_DESCRIPTION("mc9s08dz60 gpio function on mx35 3ds board"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 5cd04b65c556..e6568c19c939 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -37,7 +37,7 @@ struct mpc8xxx_gpio_chip { * open drain mode safely */ u32 data; - struct irq_host *irq; + struct irq_domain *irq; void *of_dev_id_data; }; @@ -281,7 +281,7 @@ static struct irq_chip mpc8xxx_irq_chip = { .irq_set_type = mpc8xxx_irq_set_type, }; -static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, +static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; @@ -296,24 +296,9 @@ static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, return 0; } -static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, - unsigned int *out_flags) - -{ - /* interrupt sense values coming from the device tree equal either - * EDGE_FALLING or EDGE_BOTH - */ - *out_hwirq = intspec[0]; - *out_flags = intspec[1]; - - return 0; -} - -static struct irq_host_ops mpc8xxx_gpio_irq_ops = { +static struct irq_domain_ops mpc8xxx_gpio_irq_ops = { .map = mpc8xxx_gpio_irq_map, - .xlate = mpc8xxx_gpio_irq_xlate, + .xlate = irq_domain_xlate_twocell, }; static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { @@ -364,9 +349,8 @@ static void __init mpc8xxx_add_controller(struct device_node *np) if (hwirq == NO_IRQ) goto skip_irq; - mpc8xxx_gc->irq = - irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS, - &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS); + mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS, + &mpc8xxx_gpio_irq_ops, mpc8xxx_gc); if (!mpc8xxx_gc->irq) goto skip_irq; @@ -374,8 +358,6 @@ static void __init mpc8xxx_add_controller(struct device_node *np) if (id) mpc8xxx_gc->of_dev_id_data = id->data; - mpc8xxx_gc->irq->host_data = mpc8xxx_gc; - /* ack and mask all irqs */ out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); out_be32(mm_gc->regs + GPIO_IMR, 0); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0b0562979171..1adc2ec1e383 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -19,8 +19,12 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/slab.h> +#include <linux/device.h> #include <linux/pm_runtime.h> +#include <linux/pm.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/irqdomain.h> #include <mach/hardware.h> #include <asm/irq.h> @@ -28,19 +32,36 @@ #include <asm/gpio.h> #include <asm/mach/irq.h> +#define OFF_MODE 1 + +static LIST_HEAD(omap_gpio_list); + +struct gpio_regs { + u32 irqenable1; + u32 irqenable2; + u32 wake_en; + u32 ctrl; + u32 oe; + u32 leveldetect0; + u32 leveldetect1; + u32 risingdetect; + u32 fallingdetect; + u32 dataout; + u32 debounce; + u32 debounce_en; +}; + struct gpio_bank { - unsigned long pbase; + struct list_head node; void __iomem *base; u16 irq; - u16 virtual_irq_start; - int method; + int irq_base; + struct irq_domain *domain; u32 suspend_wakeup; -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) u32 saved_wakeup; -#endif u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; - + struct gpio_regs context; u32 saved_datain; u32 saved_fallingdetect; u32 saved_risingdetect; @@ -51,44 +72,31 @@ struct gpio_bank { struct clk *dbck; u32 mod_usage; u32 dbck_enable_mask; + bool dbck_enabled; struct device *dev; + bool is_mpuio; bool dbck_flag; + bool loses_context; int stride; u32 width; + int context_loss_count; + int power_mode; + bool workaround_enabled; void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable); + int (*get_context_loss_count)(struct device *dev); struct omap_gpio_reg_offs *regs; }; -#ifdef CONFIG_ARCH_OMAP3 -struct omap3_gpio_regs { - u32 irqenable1; - u32 irqenable2; - u32 wake_en; - u32 ctrl; - u32 oe; - u32 leveldetect0; - u32 leveldetect1; - u32 risingdetect; - u32 fallingdetect; - u32 dataout; -}; - -static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS]; -#endif - -/* - * TODO: Cleanup gpio_bank usage as it is having information - * related to all instances of the device - */ -static struct gpio_bank *gpio_bank; - -/* TODO: Analyze removing gpio_bank_count usage from driver code */ -int gpio_bank_count; - #define GPIO_INDEX(bank, gpio) (gpio % bank->width) #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio)) +#define GPIO_MOD_CTRL_BIT BIT(0) + +static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) +{ + return gpio_irq - bank->irq_base + bank->chip.base; +} static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) { @@ -102,6 +110,7 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) else l &= ~(1 << gpio); __raw_writel(l, reg); + bank->context.oe = l; } @@ -111,10 +120,13 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable) void __iomem *reg = bank->base; u32 l = GPIO_BIT(bank, gpio); - if (enable) + if (enable) { reg += bank->regs->set_dataout; - else + bank->context.dataout |= l; + } else { reg += bank->regs->clr_dataout; + bank->context.dataout &= ~l; + } __raw_writel(l, reg); } @@ -132,27 +144,28 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable) else l &= ~gpio_bit; __raw_writel(l, reg); + bank->context.dataout = l; } -static int _get_gpio_datain(struct gpio_bank *bank, int gpio) +static int _get_gpio_datain(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->datain; - return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0; + return (__raw_readl(reg) & (1 << offset)) != 0; } -static int _get_gpio_dataout(struct gpio_bank *bank, int gpio) +static int _get_gpio_dataout(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->dataout; - return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0; + return (__raw_readl(reg) & (1 << offset)) != 0; } static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) { int l = __raw_readl(base + reg); - if (set) + if (set) l |= mask; else l &= ~mask; @@ -160,6 +173,22 @@ static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) __raw_writel(l, base + reg); } +static inline void _gpio_dbck_enable(struct gpio_bank *bank) +{ + if (bank->dbck_enable_mask && !bank->dbck_enabled) { + clk_enable(bank->dbck); + bank->dbck_enabled = true; + } +} + +static inline void _gpio_dbck_disable(struct gpio_bank *bank) +{ + if (bank->dbck_enable_mask && bank->dbck_enabled) { + clk_disable(bank->dbck); + bank->dbck_enabled = false; + } +} + /** * _set_gpio_debounce - low level gpio debounce time * @bank: the gpio bank we're acting upon @@ -188,70 +217,74 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, l = GPIO_BIT(bank, gpio); + clk_enable(bank->dbck); reg = bank->base + bank->regs->debounce; __raw_writel(debounce, reg); reg = bank->base + bank->regs->debounce_en; val = __raw_readl(reg); - if (debounce) { + if (debounce) val |= l; - clk_enable(bank->dbck); - } else { + else val &= ~l; - clk_disable(bank->dbck); - } bank->dbck_enable_mask = val; __raw_writel(val, reg); + clk_disable(bank->dbck); + /* + * Enable debounce clock per module. + * This call is mandatory because in omap_gpio_request() when + * *_runtime_get_sync() is called, _gpio_dbck_enable() within + * runtime callbck fails to turn on dbck because dbck_enable_mask + * used within _gpio_dbck_enable() is still not initialized at + * that point. Therefore we have to enable dbck here. + */ + _gpio_dbck_enable(bank); + if (bank->dbck_enable_mask) { + bank->context.debounce = debounce; + bank->context.debounce_en = val; + } } -#ifdef CONFIG_ARCH_OMAP2PLUS -static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, - int trigger) +static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, + unsigned trigger) { void __iomem *base = bank->base; u32 gpio_bit = 1 << gpio; - if (cpu_is_omap44xx()) { - _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT0, gpio_bit, - trigger & IRQ_TYPE_LEVEL_LOW); - _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT1, gpio_bit, - trigger & IRQ_TYPE_LEVEL_HIGH); - _gpio_rmw(base, OMAP4_GPIO_RISINGDETECT, gpio_bit, - trigger & IRQ_TYPE_EDGE_RISING); - _gpio_rmw(base, OMAP4_GPIO_FALLINGDETECT, gpio_bit, - trigger & IRQ_TYPE_EDGE_FALLING); - } else { - _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, - trigger & IRQ_TYPE_LEVEL_LOW); - _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, - trigger & IRQ_TYPE_LEVEL_HIGH); - _gpio_rmw(base, OMAP24XX_GPIO_RISINGDETECT, gpio_bit, - trigger & IRQ_TYPE_EDGE_RISING); - _gpio_rmw(base, OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, - trigger & IRQ_TYPE_EDGE_FALLING); - } + _gpio_rmw(base, bank->regs->leveldetect0, gpio_bit, + trigger & IRQ_TYPE_LEVEL_LOW); + _gpio_rmw(base, bank->regs->leveldetect1, gpio_bit, + trigger & IRQ_TYPE_LEVEL_HIGH); + _gpio_rmw(base, bank->regs->risingdetect, gpio_bit, + trigger & IRQ_TYPE_EDGE_RISING); + _gpio_rmw(base, bank->regs->fallingdetect, gpio_bit, + trigger & IRQ_TYPE_EDGE_FALLING); + + bank->context.leveldetect0 = + __raw_readl(bank->base + bank->regs->leveldetect0); + bank->context.leveldetect1 = + __raw_readl(bank->base + bank->regs->leveldetect1); + bank->context.risingdetect = + __raw_readl(bank->base + bank->regs->risingdetect); + bank->context.fallingdetect = + __raw_readl(bank->base + bank->regs->fallingdetect); + if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { - if (cpu_is_omap44xx()) { - _gpio_rmw(base, OMAP4_GPIO_IRQWAKEN0, gpio_bit, - trigger != 0); - } else { - /* - * GPIO wakeup request can only be generated on edge - * transitions - */ - if (trigger & IRQ_TYPE_EDGE_BOTH) - __raw_writel(1 << gpio, bank->base - + OMAP24XX_GPIO_SETWKUENA); - else - __raw_writel(1 << gpio, bank->base - + OMAP24XX_GPIO_CLEARWKUENA); - } + _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); + bank->context.wake_en = + __raw_readl(bank->base + bank->regs->wkup_en); } + /* This part needs to be executed always for OMAP{34xx, 44xx} */ - if (cpu_is_omap34xx() || cpu_is_omap44xx() || - (bank->non_wakeup_gpios & gpio_bit)) { + if (!bank->regs->irqctrl) { + /* On omap24xx proceed only when valid GPIO bit is set */ + if (bank->non_wakeup_gpios) { + if (!(bank->non_wakeup_gpios & gpio_bit)) + goto exit; + } + /* * Log the edge gpio and manually trigger the IRQ * after resume if the input level changes @@ -264,17 +297,11 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, bank->enabled_non_wakeup_gpios &= ~gpio_bit; } - if (cpu_is_omap44xx()) { - bank->level_mask = - __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT0) | - __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT1); - } else { - bank->level_mask = - __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) | - __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); - } +exit: + bank->level_mask = + __raw_readl(bank->base + bank->regs->leveldetect0) | + __raw_readl(bank->base + bank->regs->leveldetect1); } -#endif #ifdef CONFIG_ARCH_OMAP1 /* @@ -286,23 +313,10 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) void __iomem *reg = bank->base; u32 l = 0; - switch (bank->method) { - case METHOD_MPUIO: - reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride; - break; -#ifdef CONFIG_ARCH_OMAP15XX - case METHOD_GPIO_1510: - reg += OMAP1510_GPIO_INT_CONTROL; - break; -#endif -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) - case METHOD_GPIO_7XX: - reg += OMAP7XX_GPIO_INT_CONTROL; - break; -#endif - default: + if (!bank->regs->irqctrl) return; - } + + reg += bank->regs->irqctrl; l = __raw_readl(reg); if ((l >> gpio) & 1) @@ -312,31 +326,22 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) __raw_writel(l, reg); } +#else +static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {} #endif -static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) +static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, + unsigned trigger) { void __iomem *reg = bank->base; + void __iomem *base = bank->base; u32 l = 0; - switch (bank->method) { -#ifdef CONFIG_ARCH_OMAP1 - case METHOD_MPUIO: - reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride; - l = __raw_readl(reg); - if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) - bank->toggle_mask |= 1 << gpio; - if (trigger & IRQ_TYPE_EDGE_RISING) - l |= 1 << gpio; - else if (trigger & IRQ_TYPE_EDGE_FALLING) - l &= ~(1 << gpio); - else - goto bad; - break; -#endif -#ifdef CONFIG_ARCH_OMAP15XX - case METHOD_GPIO_1510: - reg += OMAP1510_GPIO_INT_CONTROL; + if (bank->regs->leveldetect0 && bank->regs->wkup_en) { + set_gpio_trigger(bank, gpio, trigger); + } else if (bank->regs->irqctrl) { + reg += bank->regs->irqctrl; + l = __raw_readl(reg); if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) bank->toggle_mask |= 1 << gpio; @@ -345,15 +350,15 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) else if (trigger & IRQ_TYPE_EDGE_FALLING) l &= ~(1 << gpio); else - goto bad; - break; -#endif -#ifdef CONFIG_ARCH_OMAP16XX - case METHOD_GPIO_1610: + return -EINVAL; + + __raw_writel(l, reg); + } else if (bank->regs->edgectrl1) { if (gpio & 0x08) - reg += OMAP1610_GPIO_EDGE_CTRL2; + reg += bank->regs->edgectrl2; else - reg += OMAP1610_GPIO_EDGE_CTRL1; + reg += bank->regs->edgectrl1; + gpio &= 0x07; l = __raw_readl(reg); l &= ~(3 << (gpio << 1)); @@ -361,45 +366,19 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) l |= 2 << (gpio << 1); if (trigger & IRQ_TYPE_EDGE_FALLING) l |= 1 << (gpio << 1); - if (trigger) - /* Enable wake-up during idle for dynamic tick */ - __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA); - else - __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA); - break; -#endif -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) - case METHOD_GPIO_7XX: - reg += OMAP7XX_GPIO_INT_CONTROL; - l = __raw_readl(reg); - if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) - bank->toggle_mask |= 1 << gpio; - if (trigger & IRQ_TYPE_EDGE_RISING) - l |= 1 << gpio; - else if (trigger & IRQ_TYPE_EDGE_FALLING) - l &= ~(1 << gpio); - else - goto bad; - break; -#endif -#ifdef CONFIG_ARCH_OMAP2PLUS - case METHOD_GPIO_24XX: - case METHOD_GPIO_44XX: - set_24xx_gpio_triggering(bank, gpio, trigger); - return 0; -#endif - default: - goto bad; + + /* Enable wake-up during idle for dynamic tick */ + _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger); + bank->context.wake_en = + __raw_readl(bank->base + bank->regs->wkup_en); + __raw_writel(l, reg); } - __raw_writel(l, reg); return 0; -bad: - return -EINVAL; } static int gpio_irq_type(struct irq_data *d, unsigned type) { - struct gpio_bank *bank; + struct gpio_bank *bank = irq_data_get_irq_chip_data(d); unsigned gpio; int retval; unsigned long flags; @@ -407,17 +386,15 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) if (!cpu_class_is_omap2() && d->irq > IH_MPUIO_BASE) gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE); else - gpio = d->irq - IH_GPIO_BASE; + gpio = irq_to_gpio(bank, d->irq); if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; - /* OMAP1 allows only only edge triggering */ - if (!cpu_class_is_omap2() - && (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) + if (!bank->regs->leveldetect0 && + (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) return -EINVAL; - bank = irq_data_get_irq_chip_data(d); spin_lock_irqsave(&bank->lock, flags); retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type); spin_unlock_irqrestore(&bank->lock, flags); @@ -474,6 +451,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) if (bank->regs->set_irqenable) { reg += bank->regs->set_irqenable; l = gpio_mask; + bank->context.irqenable1 |= gpio_mask; } else { reg += bank->regs->irqenable; l = __raw_readl(reg); @@ -481,6 +459,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) l &= ~gpio_mask; else l |= gpio_mask; + bank->context.irqenable1 = l; } __raw_writel(l, reg); @@ -494,6 +473,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) if (bank->regs->clr_irqenable) { reg += bank->regs->clr_irqenable; l = gpio_mask; + bank->context.irqenable1 &= ~gpio_mask; } else { reg += bank->regs->irqenable; l = __raw_readl(reg); @@ -501,6 +481,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) l |= gpio_mask; else l &= ~gpio_mask; + bank->context.irqenable1 = l; } __raw_writel(l, reg); @@ -508,7 +489,10 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) { - _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + if (enable) + _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + else + _disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); } /* @@ -525,7 +509,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) unsigned long flags; if (bank->non_wakeup_gpios & gpio_bit) { - dev_err(bank->dev, + dev_err(bank->dev, "Unable to modify wakeup on non-wakeup GPIO%d\n", gpio); return -EINVAL; } @@ -536,6 +520,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) else bank->suspend_wakeup &= ~gpio_bit; + __raw_writel(bank->suspend_wakeup, bank->base + bank->regs->wkup_en); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -552,14 +537,10 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ static int gpio_wake_enable(struct irq_data *d, unsigned int enable) { - unsigned int gpio = d->irq - IH_GPIO_BASE; - struct gpio_bank *bank; - int retval; - - bank = irq_data_get_irq_chip_data(d); - retval = _set_gpio_wakeup(bank, gpio, enable); + struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + unsigned int gpio = irq_to_gpio(bank, d->irq); - return retval; + return _set_gpio_wakeup(bank, gpio, enable); } static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -567,38 +548,39 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + /* + * If this is the first gpio_request for the bank, + * enable the bank module. + */ + if (!bank->mod_usage) + pm_runtime_get_sync(bank->dev); + spin_lock_irqsave(&bank->lock, flags); /* Set trigger to none. You need to enable the desired trigger with * request_irq() or set_irq_type(). */ _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); -#ifdef CONFIG_ARCH_OMAP15XX - if (bank->method == METHOD_GPIO_1510) { - void __iomem *reg; + if (bank->regs->pinctrl) { + void __iomem *reg = bank->base + bank->regs->pinctrl; /* Claim the pin for MPU */ - reg = bank->base + OMAP1510_GPIO_PIN_CONTROL; __raw_writel(__raw_readl(reg) | (1 << offset), reg); } -#endif - if (!cpu_class_is_omap1()) { - if (!bank->mod_usage) { - void __iomem *reg = bank->base; - u32 ctrl; - - if (cpu_is_omap24xx() || cpu_is_omap34xx()) - reg += OMAP24XX_GPIO_CTRL; - else if (cpu_is_omap44xx()) - reg += OMAP4_GPIO_CTRL; - ctrl = __raw_readl(reg); - /* Module is enabled, clocks are not gated */ - ctrl &= 0xFFFFFFFE; - __raw_writel(ctrl, reg); - } - bank->mod_usage |= 1 << offset; + + if (bank->regs->ctrl && !bank->mod_usage) { + void __iomem *reg = bank->base + bank->regs->ctrl; + u32 ctrl; + + ctrl = __raw_readl(reg); + /* Module is enabled, clocks are not gated */ + ctrl &= ~GPIO_MOD_CTRL_BIT; + __raw_writel(ctrl, reg); + bank->context.ctrl = ctrl; } + + bank->mod_usage |= 1 << offset; + spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -607,48 +589,40 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); + void __iomem *base = bank->base; unsigned long flags; spin_lock_irqsave(&bank->lock, flags); -#ifdef CONFIG_ARCH_OMAP16XX - if (bank->method == METHOD_GPIO_1610) { - /* Disable wake-up during idle for dynamic tick */ - void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; - __raw_writel(1 << offset, reg); - } -#endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - if (bank->method == METHOD_GPIO_24XX) { - /* Disable wake-up during idle for dynamic tick */ - void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA; - __raw_writel(1 << offset, reg); - } -#endif -#ifdef CONFIG_ARCH_OMAP4 - if (bank->method == METHOD_GPIO_44XX) { + + if (bank->regs->wkup_en) { /* Disable wake-up during idle for dynamic tick */ - void __iomem *reg = bank->base + OMAP4_GPIO_IRQWAKEN0; - __raw_writel(1 << offset, reg); + _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0); + bank->context.wake_en = + __raw_readl(bank->base + bank->regs->wkup_en); } -#endif - if (!cpu_class_is_omap1()) { - bank->mod_usage &= ~(1 << offset); - if (!bank->mod_usage) { - void __iomem *reg = bank->base; - u32 ctrl; - - if (cpu_is_omap24xx() || cpu_is_omap34xx()) - reg += OMAP24XX_GPIO_CTRL; - else if (cpu_is_omap44xx()) - reg += OMAP4_GPIO_CTRL; - ctrl = __raw_readl(reg); - /* Module is disabled, clocks are gated */ - ctrl |= 1; - __raw_writel(ctrl, reg); - } + + bank->mod_usage &= ~(1 << offset); + + if (bank->regs->ctrl && !bank->mod_usage) { + void __iomem *reg = bank->base + bank->regs->ctrl; + u32 ctrl; + + ctrl = __raw_readl(reg); + /* Module is disabled, clocks are gated */ + ctrl |= GPIO_MOD_CTRL_BIT; + __raw_writel(ctrl, reg); + bank->context.ctrl = ctrl; } + _reset_gpio(bank, bank->chip.base + offset); spin_unlock_irqrestore(&bank->lock, flags); + + /* + * If this is the last gpio to be freed in the bank, + * disable the bank module. + */ + if (!bank->mod_usage) + pm_runtime_put(bank->dev); } /* @@ -674,6 +648,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) bank = irq_get_handler_data(irq); isr_reg = bank->base + bank->regs->irqstatus; + pm_runtime_get_sync(bank->dev); if (WARN_ON(!isr_reg)) goto exit; @@ -685,12 +660,8 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) enabled = _get_gpio_irqbank_mask(bank); isr_saved = isr = __raw_readl(isr_reg) & enabled; - if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) - isr &= 0x0000ffff; - - if (cpu_class_is_omap2()) { + if (bank->level_mask) level_mask = bank->level_mask & enabled; - } /* clear edge sensitive interrupts before handler(s) are called so that we don't miss any interrupt occurred while @@ -711,14 +682,15 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (!isr) break; - gpio_irq = bank->virtual_irq_start; + gpio_irq = bank->irq_base; for (; isr != 0; isr >>= 1, gpio_irq++) { - gpio_index = GPIO_INDEX(bank, irq_to_gpio(gpio_irq)); + int gpio = irq_to_gpio(bank, gpio_irq); if (!(isr & 1)) continue; -#ifdef CONFIG_ARCH_OMAP1 + gpio_index = GPIO_INDEX(bank, gpio); + /* * Some chips can't respond to both rising and falling * at the same time. If this irq was requested with @@ -728,7 +700,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) */ if (bank->toggle_mask & (1 << gpio_index)) _toggle_gpio_edge_triggering(bank, gpio_index); -#endif generic_handle_irq(gpio_irq); } @@ -740,12 +711,13 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) exit: if (!unmasked) chained_irq_exit(chip, desc); + pm_runtime_put(bank->dev); } static void gpio_irq_shutdown(struct irq_data *d) { - unsigned int gpio = d->irq - IH_GPIO_BASE; struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + unsigned int gpio = irq_to_gpio(bank, d->irq); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); @@ -755,16 +727,16 @@ static void gpio_irq_shutdown(struct irq_data *d) static void gpio_ack_irq(struct irq_data *d) { - unsigned int gpio = d->irq - IH_GPIO_BASE; struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + unsigned int gpio = irq_to_gpio(bank, d->irq); _clear_gpio_irqstatus(bank, gpio); } static void gpio_mask_irq(struct irq_data *d) { - unsigned int gpio = d->irq - IH_GPIO_BASE; struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + unsigned int gpio = irq_to_gpio(bank, d->irq); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); @@ -775,8 +747,8 @@ static void gpio_mask_irq(struct irq_data *d) static void gpio_unmask_irq(struct irq_data *d) { - unsigned int gpio = d->irq - IH_GPIO_BASE; struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + unsigned int gpio = irq_to_gpio(bank, d->irq); unsigned int irq_mask = GPIO_BIT(bank, gpio); u32 trigger = irqd_get_trigger_type(d); unsigned long flags; @@ -808,14 +780,6 @@ static struct irq_chip gpio_irq_chip = { /*---------------------------------------------------------------------*/ -#ifdef CONFIG_ARCH_OMAP1 - -#define bank_is_mpuio(bank) ((bank)->method == METHOD_MPUIO) - -#ifdef CONFIG_ARCH_OMAP16XX - -#include <linux/platform_device.h> - static int omap_mpuio_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -869,32 +833,16 @@ static struct platform_device omap_mpuio_device = { /* could list the /proc/iomem resources */ }; -static inline void mpuio_init(void) +static inline void mpuio_init(struct gpio_bank *bank) { - struct gpio_bank *bank = &gpio_bank[0]; platform_set_drvdata(&omap_mpuio_device, bank); if (platform_driver_register(&omap_mpuio_driver) == 0) (void) platform_device_register(&omap_mpuio_device); } -#else -static inline void mpuio_init(void) {} -#endif /* 16xx */ - -#else - -#define bank_is_mpuio(bank) 0 -static inline void mpuio_init(void) {} - -#endif - /*---------------------------------------------------------------------*/ -/* REVISIT these are stupid implementations! replace by ones that - * don't switch on METHOD_* and which mostly avoid spinlocks - */ - static int gpio_input(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; @@ -917,19 +865,15 @@ static int gpio_is_input(struct gpio_bank *bank, int mask) static int gpio_get(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; - void __iomem *reg; - int gpio; u32 mask; - gpio = chip->base + offset; bank = container_of(chip, struct gpio_bank, chip); - reg = bank->base; - mask = GPIO_BIT(bank, gpio); + mask = (1 << offset); if (gpio_is_input(bank, mask)) - return _get_gpio_datain(bank, gpio); + return _get_gpio_datain(bank, offset); else - return _get_gpio_dataout(bank, gpio); + return _get_gpio_dataout(bank, offset); } static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) @@ -982,7 +926,7 @@ static int gpio_2irq(struct gpio_chip *chip, unsigned offset) struct gpio_bank *bank; bank = container_of(chip, struct gpio_bank, chip); - return bank->virtual_irq_start + offset; + return bank->irq_base + offset; } /*---------------------------------------------------------------------*/ @@ -1007,81 +951,35 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank) */ static struct lock_class_key gpio_lock_class; -static inline int init_gpio_info(struct platform_device *pdev) +static void omap_gpio_mod_init(struct gpio_bank *bank) { - /* TODO: Analyze removing gpio_bank_count usage from driver code */ - gpio_bank = kzalloc(gpio_bank_count * sizeof(struct gpio_bank), - GFP_KERNEL); - if (!gpio_bank) { - dev_err(&pdev->dev, "Memory alloc failed for gpio_bank\n"); - return -ENOMEM; - } - return 0; -} + void __iomem *base = bank->base; + u32 l = 0xffffffff; -/* TODO: Cleanup cpu_is_* checks */ -static void omap_gpio_mod_init(struct gpio_bank *bank, int id) -{ - if (cpu_class_is_omap2()) { - if (cpu_is_omap44xx()) { - __raw_writel(0xffffffff, bank->base + - OMAP4_GPIO_IRQSTATUSCLR0); - __raw_writel(0x00000000, bank->base + - OMAP4_GPIO_DEBOUNCENABLE); - /* Initialize interface clk ungated, module enabled */ - __raw_writel(0, bank->base + OMAP4_GPIO_CTRL); - } else if (cpu_is_omap34xx()) { - __raw_writel(0x00000000, bank->base + - OMAP24XX_GPIO_IRQENABLE1); - __raw_writel(0xffffffff, bank->base + - OMAP24XX_GPIO_IRQSTATUS1); - __raw_writel(0x00000000, bank->base + - OMAP24XX_GPIO_DEBOUNCE_EN); - - /* Initialize interface clk ungated, module enabled */ - __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL); - } else if (cpu_is_omap24xx()) { - static const u32 non_wakeup_gpios[] = { - 0xe203ffc0, 0x08700040 - }; - if (id < ARRAY_SIZE(non_wakeup_gpios)) - bank->non_wakeup_gpios = non_wakeup_gpios[id]; - } - } else if (cpu_class_is_omap1()) { - if (bank_is_mpuio(bank)) - __raw_writew(0xffff, bank->base + - OMAP_MPUIO_GPIO_MASKIT / bank->stride); - if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) { - __raw_writew(0xffff, bank->base - + OMAP1510_GPIO_INT_MASK); - __raw_writew(0x0000, bank->base - + OMAP1510_GPIO_INT_STATUS); - } - if (cpu_is_omap16xx() && bank->method == METHOD_GPIO_1610) { - __raw_writew(0x0000, bank->base - + OMAP1610_GPIO_IRQENABLE1); - __raw_writew(0xffff, bank->base - + OMAP1610_GPIO_IRQSTATUS1); - __raw_writew(0x0014, bank->base - + OMAP1610_GPIO_SYSCONFIG); + if (bank->width == 16) + l = 0xffff; - /* - * Enable system clock for GPIO module. - * The CAM_CLK_CTRL *is* really the right place. - */ - omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, - ULPD_CAM_CLK_CTRL); - } - if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX) { - __raw_writel(0xffffffff, bank->base - + OMAP7XX_GPIO_INT_MASK); - __raw_writel(0x00000000, bank->base - + OMAP7XX_GPIO_INT_STATUS); - } + if (bank->is_mpuio) { + __raw_writel(l, bank->base + bank->regs->irqenable); + return; } + + _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv); + _gpio_rmw(base, bank->regs->irqstatus, l, + bank->regs->irqenable_inv == false); + _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->debounce_en != 0); + _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->ctrl != 0); + if (bank->regs->debounce_en) + _gpio_rmw(base, bank->regs->debounce_en, 0, 1); + + /* Save OE default value (0xffffffff) in the context */ + bank->context.oe = __raw_readl(bank->base + bank->regs->direction); + /* Initialize interface clk ungated, module enabled */ + if (bank->regs->ctrl) + _gpio_rmw(base, bank->regs->ctrl, 0, 1); } -static __init void +static __devinit void omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, unsigned int num) { @@ -1101,8 +999,8 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, ct->chip.irq_mask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_mask_clr_bit; ct->chip.irq_set_type = gpio_irq_type; - /* REVISIT: assuming only 16xx supports MPUIO wake events */ - if (cpu_is_omap16xx()) + + if (bank->regs->wkup_en) ct->chip.irq_set_wake = gpio_wake_enable, ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride; @@ -1115,7 +1013,6 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) int j; static int gpio; - bank->mod_usage = 0; /* * REVISIT eventually switch from OMAP-specific gpio structs * over to the generic ones @@ -1128,11 +1025,10 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) bank->chip.set_debounce = gpio_debounce; bank->chip.set = gpio_set; bank->chip.to_irq = gpio_2irq; - if (bank_is_mpuio(bank)) { + if (bank->is_mpuio) { bank->chip.label = "mpuio"; -#ifdef CONFIG_ARCH_OMAP16XX - bank->chip.dev = &omap_mpuio_device.dev; -#endif + if (bank->regs->wkup_en) + bank->chip.dev = &omap_mpuio_device.dev; bank->chip.base = OMAP_MPUIO(0); } else { bank->chip.label = "gpio"; @@ -1143,11 +1039,10 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) gpiochip_add(&bank->chip); - for (j = bank->virtual_irq_start; - j < bank->virtual_irq_start + bank->width; j++) { + for (j = bank->irq_base; j < bank->irq_base + bank->width; j++) { irq_set_lockdep_class(j, &gpio_lock_class); irq_set_chip_data(j, bank); - if (bank_is_mpuio(bank)) { + if (bank->is_mpuio) { omap_mpuio_alloc_gc(bank, j, bank->width); } else { irq_set_chip(j, &gpio_irq_chip); @@ -1159,45 +1054,58 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) irq_set_handler_data(bank->irq, bank); } +static const struct of_device_id omap_gpio_match[]; + static int __devinit omap_gpio_probe(struct platform_device *pdev) { - static int gpio_init_done; + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + const struct of_device_id *match; struct omap_gpio_platform_data *pdata; struct resource *res; - int id; struct gpio_bank *bank; + int ret = 0; - if (!pdev->dev.platform_data) - return -EINVAL; - - pdata = pdev->dev.platform_data; + match = of_match_device(of_match_ptr(omap_gpio_match), dev); - if (!gpio_init_done) { - int ret; + pdata = match ? match->data : dev->platform_data; + if (!pdata) + return -EINVAL; - ret = init_gpio_info(pdev); - if (ret) - return ret; + bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL); + if (!bank) { + dev_err(dev, "Memory alloc failed\n"); + return -ENOMEM; } - id = pdev->id; - bank = &gpio_bank[id]; - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (unlikely(!res)) { - dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", id); + dev_err(dev, "Invalid IRQ resource\n"); return -ENODEV; } bank->irq = res->start; - bank->virtual_irq_start = pdata->virtual_irq_start; - bank->method = pdata->bank_type; - bank->dev = &pdev->dev; + bank->dev = dev; bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; - + bank->is_mpuio = pdata->is_mpuio; + bank->non_wakeup_gpios = pdata->non_wakeup_gpios; + bank->loses_context = pdata->loses_context; + bank->get_context_loss_count = pdata->get_context_loss_count; bank->regs = pdata->regs; +#ifdef CONFIG_OF_GPIO + bank->chip.of_node = of_node_get(node); +#endif + + bank->irq_base = irq_alloc_descs(-1, 0, bank->width, 0); + if (bank->irq_base < 0) { + dev_err(dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } + + bank->domain = irq_domain_add_legacy(node, bank->width, bank->irq_base, + 0, &irq_domain_simple_ops, NULL); if (bank->regs->set_dataout && bank->regs->clr_dataout) bank->set_dataout = _set_gpio_dataout_reg; @@ -1209,369 +1117,422 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) /* Static mapping, never released */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!res)) { - dev_err(&pdev->dev, "GPIO Bank %i Invalid mem resource\n", id); + dev_err(dev, "Invalid mem resource\n"); return -ENODEV; } - bank->base = ioremap(res->start, resource_size(res)); + if (!devm_request_mem_region(dev, res->start, resource_size(res), + pdev->name)) { + dev_err(dev, "Region already claimed\n"); + return -EBUSY; + } + + bank->base = devm_ioremap(dev, res->start, resource_size(res)); if (!bank->base) { - dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", id); + dev_err(dev, "Could not ioremap\n"); return -ENOMEM; } + platform_set_drvdata(pdev, bank); + pm_runtime_enable(bank->dev); + pm_runtime_irq_safe(bank->dev); pm_runtime_get_sync(bank->dev); - omap_gpio_mod_init(bank, id); + if (bank->is_mpuio) + mpuio_init(bank); + + omap_gpio_mod_init(bank); omap_gpio_chip_init(bank); omap_gpio_show_rev(bank); - if (!gpio_init_done) - gpio_init_done = 1; + pm_runtime_put(bank->dev); - return 0; + list_add_tail(&bank->node, &omap_gpio_list); + + return ret; } -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) -static int omap_gpio_suspend(void) +#ifdef CONFIG_ARCH_OMAP2PLUS + +#if defined(CONFIG_PM_SLEEP) +static int omap_gpio_suspend(struct device *dev) { - int i; + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = platform_get_drvdata(pdev); + void __iomem *base = bank->base; + void __iomem *wakeup_enable; + unsigned long flags; - if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) + if (!bank->mod_usage || !bank->loses_context) return 0; - for (i = 0; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; - void __iomem *wake_status; - void __iomem *wake_clear; - void __iomem *wake_set; - unsigned long flags; - - switch (bank->method) { -#ifdef CONFIG_ARCH_OMAP16XX - case METHOD_GPIO_1610: - wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE; - wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; - wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; - break; -#endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - case METHOD_GPIO_24XX: - wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN; - wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; - wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; - break; -#endif -#ifdef CONFIG_ARCH_OMAP4 - case METHOD_GPIO_44XX: - wake_status = bank->base + OMAP4_GPIO_IRQWAKEN0; - wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0; - wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0; - break; -#endif - default: - continue; - } + if (!bank->regs->wkup_en || !bank->suspend_wakeup) + return 0; - spin_lock_irqsave(&bank->lock, flags); - bank->saved_wakeup = __raw_readl(wake_status); - __raw_writel(0xffffffff, wake_clear); - __raw_writel(bank->suspend_wakeup, wake_set); - spin_unlock_irqrestore(&bank->lock, flags); - } + wakeup_enable = bank->base + bank->regs->wkup_en; + + spin_lock_irqsave(&bank->lock, flags); + bank->saved_wakeup = __raw_readl(wakeup_enable); + _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0); + _gpio_rmw(base, bank->regs->wkup_en, bank->suspend_wakeup, 1); + spin_unlock_irqrestore(&bank->lock, flags); return 0; } -static void omap_gpio_resume(void) +static int omap_gpio_resume(struct device *dev) { - int i; + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = platform_get_drvdata(pdev); + void __iomem *base = bank->base; + unsigned long flags; - if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) - return; + if (!bank->mod_usage || !bank->loses_context) + return 0; - for (i = 0; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; - void __iomem *wake_clear; - void __iomem *wake_set; - unsigned long flags; - - switch (bank->method) { -#ifdef CONFIG_ARCH_OMAP16XX - case METHOD_GPIO_1610: - wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; - wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; - break; -#endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - case METHOD_GPIO_24XX: - wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; - wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; - break; -#endif -#ifdef CONFIG_ARCH_OMAP4 - case METHOD_GPIO_44XX: - wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0; - wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0; - break; -#endif - default: - continue; - } + if (!bank->regs->wkup_en || !bank->saved_wakeup) + return 0; - spin_lock_irqsave(&bank->lock, flags); - __raw_writel(0xffffffff, wake_clear); - __raw_writel(bank->saved_wakeup, wake_set); - spin_unlock_irqrestore(&bank->lock, flags); - } + spin_lock_irqsave(&bank->lock, flags); + _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0); + _gpio_rmw(base, bank->regs->wkup_en, bank->saved_wakeup, 1); + spin_unlock_irqrestore(&bank->lock, flags); + + return 0; } +#endif /* CONFIG_PM_SLEEP */ -static struct syscore_ops omap_gpio_syscore_ops = { - .suspend = omap_gpio_suspend, - .resume = omap_gpio_resume, -}; +#if defined(CONFIG_PM_RUNTIME) +static void omap_gpio_restore_context(struct gpio_bank *bank); -#endif +static int omap_gpio_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = platform_get_drvdata(pdev); + u32 l1 = 0, l2 = 0; + unsigned long flags; + u32 wake_low, wake_hi; -#ifdef CONFIG_ARCH_OMAP2PLUS + spin_lock_irqsave(&bank->lock, flags); -static int workaround_enabled; + /* + * Only edges can generate a wakeup event to the PRCM. + * + * Therefore, ensure any wake-up capable GPIOs have + * edge-detection enabled before going idle to ensure a wakeup + * to the PRCM is generated on a GPIO transition. (c.f. 34xx + * NDA TRM 25.5.3.1) + * + * The normal values will be restored upon ->runtime_resume() + * by writing back the values saved in bank->context. + */ + wake_low = bank->context.leveldetect0 & bank->context.wake_en; + if (wake_low) + __raw_writel(wake_low | bank->context.fallingdetect, + bank->base + bank->regs->fallingdetect); + wake_hi = bank->context.leveldetect1 & bank->context.wake_en; + if (wake_hi) + __raw_writel(wake_hi | bank->context.risingdetect, + bank->base + bank->regs->risingdetect); + + if (bank->power_mode != OFF_MODE) { + bank->power_mode = 0; + goto update_gpio_context_count; + } + /* + * If going to OFF, remove triggering for all + * non-wakeup GPIOs. Otherwise spurious IRQs will be + * generated. See OMAP2420 Errata item 1.101. + */ + bank->saved_datain = __raw_readl(bank->base + + bank->regs->datain); + l1 = __raw_readl(bank->base + bank->regs->fallingdetect); + l2 = __raw_readl(bank->base + bank->regs->risingdetect); -void omap2_gpio_prepare_for_idle(int off_mode) -{ - int i, c = 0; - int min = 0; + bank->saved_fallingdetect = l1; + bank->saved_risingdetect = l2; + l1 &= ~bank->enabled_non_wakeup_gpios; + l2 &= ~bank->enabled_non_wakeup_gpios; - if (cpu_is_omap34xx()) - min = 1; + __raw_writel(l1, bank->base + bank->regs->fallingdetect); + __raw_writel(l2, bank->base + bank->regs->risingdetect); - for (i = min; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; - u32 l1 = 0, l2 = 0; - int j; + bank->workaround_enabled = true; - for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) - clk_disable(bank->dbck); +update_gpio_context_count: + if (bank->get_context_loss_count) + bank->context_loss_count = + bank->get_context_loss_count(bank->dev); - if (!off_mode) - continue; + _gpio_dbck_disable(bank); + spin_unlock_irqrestore(&bank->lock, flags); - /* If going to OFF, remove triggering for all - * non-wakeup GPIOs. Otherwise spurious IRQs will be - * generated. See OMAP2420 Errata item 1.101. */ - if (!(bank->enabled_non_wakeup_gpios)) - continue; + return 0; +} - if (cpu_is_omap24xx() || cpu_is_omap34xx()) { - bank->saved_datain = __raw_readl(bank->base + - OMAP24XX_GPIO_DATAIN); - l1 = __raw_readl(bank->base + - OMAP24XX_GPIO_FALLINGDETECT); - l2 = __raw_readl(bank->base + - OMAP24XX_GPIO_RISINGDETECT); - } +static int omap_gpio_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = platform_get_drvdata(pdev); + int context_lost_cnt_after; + u32 l = 0, gen, gen0, gen1; + unsigned long flags; - if (cpu_is_omap44xx()) { - bank->saved_datain = __raw_readl(bank->base + - OMAP4_GPIO_DATAIN); - l1 = __raw_readl(bank->base + - OMAP4_GPIO_FALLINGDETECT); - l2 = __raw_readl(bank->base + - OMAP4_GPIO_RISINGDETECT); - } + spin_lock_irqsave(&bank->lock, flags); + _gpio_dbck_enable(bank); - bank->saved_fallingdetect = l1; - bank->saved_risingdetect = l2; - l1 &= ~bank->enabled_non_wakeup_gpios; - l2 &= ~bank->enabled_non_wakeup_gpios; + /* + * In ->runtime_suspend(), level-triggered, wakeup-enabled + * GPIOs were set to edge trigger also in order to be able to + * generate a PRCM wakeup. Here we restore the + * pre-runtime_suspend() values for edge triggering. + */ + __raw_writel(bank->context.fallingdetect, + bank->base + bank->regs->fallingdetect); + __raw_writel(bank->context.risingdetect, + bank->base + bank->regs->risingdetect); - if (cpu_is_omap24xx() || cpu_is_omap34xx()) { - __raw_writel(l1, bank->base + - OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(l2, bank->base + - OMAP24XX_GPIO_RISINGDETECT); - } + if (!bank->workaround_enabled) { + spin_unlock_irqrestore(&bank->lock, flags); + return 0; + } - if (cpu_is_omap44xx()) { - __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT); - __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT); + if (bank->get_context_loss_count) { + context_lost_cnt_after = + bank->get_context_loss_count(bank->dev); + if (context_lost_cnt_after != bank->context_loss_count || + !context_lost_cnt_after) { + omap_gpio_restore_context(bank); + } else { + spin_unlock_irqrestore(&bank->lock, flags); + return 0; } - - c++; - } - if (!c) { - workaround_enabled = 0; - return; } - workaround_enabled = 1; -} -void omap2_gpio_resume_after_idle(void) -{ - int i; - int min = 0; + __raw_writel(bank->saved_fallingdetect, + bank->base + bank->regs->fallingdetect); + __raw_writel(bank->saved_risingdetect, + bank->base + bank->regs->risingdetect); + l = __raw_readl(bank->base + bank->regs->datain); - if (cpu_is_omap34xx()) - min = 1; - for (i = min; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; - u32 l = 0, gen, gen0, gen1; - int j; + /* + * Check if any of the non-wakeup interrupt GPIOs have changed + * state. If so, generate an IRQ by software. This is + * horribly racy, but it's the best we can do to work around + * this silicon bug. + */ + l ^= bank->saved_datain; + l &= bank->enabled_non_wakeup_gpios; - for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) - clk_enable(bank->dbck); + /* + * No need to generate IRQs for the rising edge for gpio IRQs + * configured with falling edge only; and vice versa. + */ + gen0 = l & bank->saved_fallingdetect; + gen0 &= bank->saved_datain; - if (!workaround_enabled) - continue; + gen1 = l & bank->saved_risingdetect; + gen1 &= ~(bank->saved_datain); - if (!(bank->enabled_non_wakeup_gpios)) - continue; + /* FIXME: Consider GPIO IRQs with level detections properly! */ + gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect)); + /* Consider all GPIO IRQs needed to be updated */ + gen |= gen0 | gen1; + + if (gen) { + u32 old0, old1; + + old0 = __raw_readl(bank->base + bank->regs->leveldetect0); + old1 = __raw_readl(bank->base + bank->regs->leveldetect1); if (cpu_is_omap24xx() || cpu_is_omap34xx()) { - __raw_writel(bank->saved_fallingdetect, - bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(bank->saved_risingdetect, - bank->base + OMAP24XX_GPIO_RISINGDETECT); - l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); + __raw_writel(old0 | gen, bank->base + + bank->regs->leveldetect0); + __raw_writel(old1 | gen, bank->base + + bank->regs->leveldetect1); } if (cpu_is_omap44xx()) { - __raw_writel(bank->saved_fallingdetect, - bank->base + OMAP4_GPIO_FALLINGDETECT); - __raw_writel(bank->saved_risingdetect, - bank->base + OMAP4_GPIO_RISINGDETECT); - l = __raw_readl(bank->base + OMAP4_GPIO_DATAIN); - } - - /* Check if any of the non-wakeup interrupt GPIOs have changed - * state. If so, generate an IRQ by software. This is - * horribly racy, but it's the best we can do to work around - * this silicon bug. */ - l ^= bank->saved_datain; - l &= bank->enabled_non_wakeup_gpios; - - /* - * No need to generate IRQs for the rising edge for gpio IRQs - * configured with falling edge only; and vice versa. - */ - gen0 = l & bank->saved_fallingdetect; - gen0 &= bank->saved_datain; - - gen1 = l & bank->saved_risingdetect; - gen1 &= ~(bank->saved_datain); - - /* FIXME: Consider GPIO IRQs with level detections properly! */ - gen = l & (~(bank->saved_fallingdetect) & - ~(bank->saved_risingdetect)); - /* Consider all GPIO IRQs needed to be updated */ - gen |= gen0 | gen1; - - if (gen) { - u32 old0, old1; - - if (cpu_is_omap24xx() || cpu_is_omap34xx()) { - old0 = __raw_readl(bank->base + - OMAP24XX_GPIO_LEVELDETECT0); - old1 = __raw_readl(bank->base + - OMAP24XX_GPIO_LEVELDETECT1); - __raw_writel(old0 | gen, bank->base + - OMAP24XX_GPIO_LEVELDETECT0); - __raw_writel(old1 | gen, bank->base + - OMAP24XX_GPIO_LEVELDETECT1); - __raw_writel(old0, bank->base + - OMAP24XX_GPIO_LEVELDETECT0); - __raw_writel(old1, bank->base + - OMAP24XX_GPIO_LEVELDETECT1); - } - - if (cpu_is_omap44xx()) { - old0 = __raw_readl(bank->base + - OMAP4_GPIO_LEVELDETECT0); - old1 = __raw_readl(bank->base + - OMAP4_GPIO_LEVELDETECT1); - __raw_writel(old0 | l, bank->base + - OMAP4_GPIO_LEVELDETECT0); - __raw_writel(old1 | l, bank->base + - OMAP4_GPIO_LEVELDETECT1); - __raw_writel(old0, bank->base + - OMAP4_GPIO_LEVELDETECT0); - __raw_writel(old1, bank->base + - OMAP4_GPIO_LEVELDETECT1); - } + __raw_writel(old0 | l, bank->base + + bank->regs->leveldetect0); + __raw_writel(old1 | l, bank->base + + bank->regs->leveldetect1); } + __raw_writel(old0, bank->base + bank->regs->leveldetect0); + __raw_writel(old1, bank->base + bank->regs->leveldetect1); } + bank->workaround_enabled = false; + spin_unlock_irqrestore(&bank->lock, flags); + + return 0; } +#endif /* CONFIG_PM_RUNTIME */ -#endif +void omap2_gpio_prepare_for_idle(int pwr_mode) +{ + struct gpio_bank *bank; + + list_for_each_entry(bank, &omap_gpio_list, node) { + if (!bank->mod_usage || !bank->loses_context) + continue; -#ifdef CONFIG_ARCH_OMAP3 -/* save the registers of bank 2-6 */ -void omap_gpio_save_context(void) + bank->power_mode = pwr_mode; + + pm_runtime_put_sync_suspend(bank->dev); + } +} + +void omap2_gpio_resume_after_idle(void) { - int i; - - /* saving banks from 2-6 only since GPIO1 is in WKUP */ - for (i = 1; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; - gpio_context[i].irqenable1 = - __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1); - gpio_context[i].irqenable2 = - __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2); - gpio_context[i].wake_en = - __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN); - gpio_context[i].ctrl = - __raw_readl(bank->base + OMAP24XX_GPIO_CTRL); - gpio_context[i].oe = - __raw_readl(bank->base + OMAP24XX_GPIO_OE); - gpio_context[i].leveldetect0 = - __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); - gpio_context[i].leveldetect1 = - __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); - gpio_context[i].risingdetect = - __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); - gpio_context[i].fallingdetect = - __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); - gpio_context[i].dataout = - __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT); + struct gpio_bank *bank; + + list_for_each_entry(bank, &omap_gpio_list, node) { + if (!bank->mod_usage || !bank->loses_context) + continue; + + pm_runtime_get_sync(bank->dev); } } -/* restore the required registers of bank 2-6 */ -void omap_gpio_restore_context(void) +#if defined(CONFIG_PM_RUNTIME) +static void omap_gpio_restore_context(struct gpio_bank *bank) { - int i; - - for (i = 1; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; - __raw_writel(gpio_context[i].irqenable1, - bank->base + OMAP24XX_GPIO_IRQENABLE1); - __raw_writel(gpio_context[i].irqenable2, - bank->base + OMAP24XX_GPIO_IRQENABLE2); - __raw_writel(gpio_context[i].wake_en, - bank->base + OMAP24XX_GPIO_WAKE_EN); - __raw_writel(gpio_context[i].ctrl, - bank->base + OMAP24XX_GPIO_CTRL); - __raw_writel(gpio_context[i].oe, - bank->base + OMAP24XX_GPIO_OE); - __raw_writel(gpio_context[i].leveldetect0, - bank->base + OMAP24XX_GPIO_LEVELDETECT0); - __raw_writel(gpio_context[i].leveldetect1, - bank->base + OMAP24XX_GPIO_LEVELDETECT1); - __raw_writel(gpio_context[i].risingdetect, - bank->base + OMAP24XX_GPIO_RISINGDETECT); - __raw_writel(gpio_context[i].fallingdetect, - bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(gpio_context[i].dataout, - bank->base + OMAP24XX_GPIO_DATAOUT); + __raw_writel(bank->context.wake_en, + bank->base + bank->regs->wkup_en); + __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl); + __raw_writel(bank->context.leveldetect0, + bank->base + bank->regs->leveldetect0); + __raw_writel(bank->context.leveldetect1, + bank->base + bank->regs->leveldetect1); + __raw_writel(bank->context.risingdetect, + bank->base + bank->regs->risingdetect); + __raw_writel(bank->context.fallingdetect, + bank->base + bank->regs->fallingdetect); + if (bank->regs->set_dataout && bank->regs->clr_dataout) + __raw_writel(bank->context.dataout, + bank->base + bank->regs->set_dataout); + else + __raw_writel(bank->context.dataout, + bank->base + bank->regs->dataout); + __raw_writel(bank->context.oe, bank->base + bank->regs->direction); + + if (bank->dbck_enable_mask) { + __raw_writel(bank->context.debounce, bank->base + + bank->regs->debounce); + __raw_writel(bank->context.debounce_en, + bank->base + bank->regs->debounce_en); } + + __raw_writel(bank->context.irqenable1, + bank->base + bank->regs->irqenable); + __raw_writel(bank->context.irqenable2, + bank->base + bank->regs->irqenable2); } +#endif /* CONFIG_PM_RUNTIME */ +#else +#define omap_gpio_suspend NULL +#define omap_gpio_resume NULL +#define omap_gpio_runtime_suspend NULL +#define omap_gpio_runtime_resume NULL +#endif + +static const struct dev_pm_ops gpio_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) + SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, + NULL) +}; + +#if defined(CONFIG_OF) +static struct omap_gpio_reg_offs omap2_gpio_regs = { + .revision = OMAP24XX_GPIO_REVISION, + .direction = OMAP24XX_GPIO_OE, + .datain = OMAP24XX_GPIO_DATAIN, + .dataout = OMAP24XX_GPIO_DATAOUT, + .set_dataout = OMAP24XX_GPIO_SETDATAOUT, + .clr_dataout = OMAP24XX_GPIO_CLEARDATAOUT, + .irqstatus = OMAP24XX_GPIO_IRQSTATUS1, + .irqstatus2 = OMAP24XX_GPIO_IRQSTATUS2, + .irqenable = OMAP24XX_GPIO_IRQENABLE1, + .irqenable2 = OMAP24XX_GPIO_IRQENABLE2, + .set_irqenable = OMAP24XX_GPIO_SETIRQENABLE1, + .clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1, + .debounce = OMAP24XX_GPIO_DEBOUNCE_VAL, + .debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN, + .ctrl = OMAP24XX_GPIO_CTRL, + .wkup_en = OMAP24XX_GPIO_WAKE_EN, + .leveldetect0 = OMAP24XX_GPIO_LEVELDETECT0, + .leveldetect1 = OMAP24XX_GPIO_LEVELDETECT1, + .risingdetect = OMAP24XX_GPIO_RISINGDETECT, + .fallingdetect = OMAP24XX_GPIO_FALLINGDETECT, +}; + +static struct omap_gpio_reg_offs omap4_gpio_regs = { + .revision = OMAP4_GPIO_REVISION, + .direction = OMAP4_GPIO_OE, + .datain = OMAP4_GPIO_DATAIN, + .dataout = OMAP4_GPIO_DATAOUT, + .set_dataout = OMAP4_GPIO_SETDATAOUT, + .clr_dataout = OMAP4_GPIO_CLEARDATAOUT, + .irqstatus = OMAP4_GPIO_IRQSTATUS0, + .irqstatus2 = OMAP4_GPIO_IRQSTATUS1, + .irqenable = OMAP4_GPIO_IRQSTATUSSET0, + .irqenable2 = OMAP4_GPIO_IRQSTATUSSET1, + .set_irqenable = OMAP4_GPIO_IRQSTATUSSET0, + .clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0, + .debounce = OMAP4_GPIO_DEBOUNCINGTIME, + .debounce_en = OMAP4_GPIO_DEBOUNCENABLE, + .ctrl = OMAP4_GPIO_CTRL, + .wkup_en = OMAP4_GPIO_IRQWAKEN0, + .leveldetect0 = OMAP4_GPIO_LEVELDETECT0, + .leveldetect1 = OMAP4_GPIO_LEVELDETECT1, + .risingdetect = OMAP4_GPIO_RISINGDETECT, + .fallingdetect = OMAP4_GPIO_FALLINGDETECT, +}; + +static struct omap_gpio_platform_data omap2_pdata = { + .regs = &omap2_gpio_regs, + .bank_width = 32, + .dbck_flag = false, +}; + +static struct omap_gpio_platform_data omap3_pdata = { + .regs = &omap2_gpio_regs, + .bank_width = 32, + .dbck_flag = true, +}; + +static struct omap_gpio_platform_data omap4_pdata = { + .regs = &omap4_gpio_regs, + .bank_width = 32, + .dbck_flag = true, +}; + +static const struct of_device_id omap_gpio_match[] = { + { + .compatible = "ti,omap4-gpio", + .data = &omap4_pdata, + }, + { + .compatible = "ti,omap3-gpio", + .data = &omap3_pdata, + }, + { + .compatible = "ti,omap2-gpio", + .data = &omap2_pdata, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_gpio_match); #endif static struct platform_driver omap_gpio_driver = { .probe = omap_gpio_probe, .driver = { .name = "omap_gpio", + .pm = &gpio_pm_ops, + .of_match_table = of_match_ptr(omap_gpio_match), }, }; @@ -1585,17 +1546,3 @@ static int __init omap_gpio_drv_reg(void) return platform_driver_register(&omap_gpio_driver); } postcore_initcall(omap_gpio_drv_reg); - -static int __init omap_gpio_sysinit(void) -{ - mpuio_init(); - -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) - if (cpu_is_omap16xx() || cpu_class_is_omap2()) - register_syscore_ops(&omap_gpio_syscore_ops); -#endif - - return 0; -} - -arch_initcall(omap_gpio_sysinit); diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 77c9cc70fa77..b4b5da4fd2cc 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -352,7 +352,12 @@ static int pl061_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume); +static const struct dev_pm_ops pl061_dev_pm_ops = { + .suspend = pl061_suspend, + .resume = pl061_resume, + .freeze = pl061_suspend, + .restore = pl061_resume, +}; #endif static struct amba_id pl061_ids[] = { diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 7eecf69362ee..8ea3b33d4b40 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <mach/hardware.h> +#include <mach/irqs.h> static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset) { diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 0a79a1167a25..46277877b7ec 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -169,7 +169,7 @@ int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN); } -static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip, +static int exynos_gpio_setpull(struct samsung_gpio_chip *chip, unsigned int off, samsung_gpio_pull_t pull) { if (pull == S3C_GPIO_PULL_UP) @@ -178,7 +178,7 @@ static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip, return samsung_gpio_setpull_updown(chip, off, pull); } -static samsung_gpio_pull_t exynos4_gpio_getpull(struct samsung_gpio_chip *chip, +static samsung_gpio_pull_t exynos_gpio_getpull(struct samsung_gpio_chip *chip, unsigned int off) { samsung_gpio_pull_t pull; @@ -452,9 +452,9 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = { }; #endif -static struct samsung_gpio_cfg exynos4_gpio_cfg = { - .set_pull = exynos4_gpio_setpull, - .get_pull = exynos4_gpio_getpull, +static struct samsung_gpio_cfg exynos_gpio_cfg = { + .set_pull = exynos_gpio_setpull, + .get_pull = exynos_gpio_getpull, .set_config = samsung_gpio_setcfg_4bit, .get_config = samsung_gpio_getcfg_4bit, }; @@ -502,13 +502,13 @@ static struct samsung_gpio_cfg samsung_gpio_cfgs[] = { .get_config = samsung_gpio_getcfg_2bit, }, [8] = { - .set_pull = exynos4_gpio_setpull, - .get_pull = exynos4_gpio_getpull, + .set_pull = exynos_gpio_setpull, + .get_pull = exynos_gpio_getpull, }, [9] = { .cfg_eint = 0x3, - .set_pull = exynos4_gpio_setpull, - .get_pull = exynos4_gpio_getpull, + .set_pull = exynos_gpio_setpull, + .get_pull = exynos_gpio_getpull, } }; @@ -2113,10 +2113,10 @@ static struct samsung_gpio_chip s5pv210_gpios_4bit[] = { }; /* - * Followings are the gpio banks in EXYNOS4210 + * Followings are the gpio banks in EXYNOS SoCs * * The 'config' member when left to NULL, is initialized to the default - * structure samsung_gpio_cfgs[3] in the init function below. + * structure exynos_gpio_cfg in the init function below. * * The 'base' member is also initialized in the init function below. * Note: The initialization of 'base' member of samsung_gpio_chip structure @@ -2331,7 +2331,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = { .label = "GPY6", }, }, { - .base = (S5P_VA_GPIO2 + 0xC00), .config = &samsung_gpio_cfgs[9], .irq_base = IRQ_EINT(0), .chip = { @@ -2341,7 +2340,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = { .to_irq = samsung_gpiolib_to_irq, }, }, { - .base = (S5P_VA_GPIO2 + 0xC20), .config = &samsung_gpio_cfgs[9], .irq_base = IRQ_EINT(8), .chip = { @@ -2351,7 +2349,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = { .to_irq = samsung_gpiolib_to_irq, }, }, { - .base = (S5P_VA_GPIO2 + 0xC40), .config = &samsung_gpio_cfgs[9], .irq_base = IRQ_EINT(16), .chip = { @@ -2361,7 +2358,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = { .to_irq = samsung_gpiolib_to_irq, }, }, { - .base = (S5P_VA_GPIO2 + 0xC60), .config = &samsung_gpio_cfgs[9], .irq_base = IRQ_EINT(24), .chip = { @@ -2386,8 +2382,280 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = { #endif }; -#if defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) -static int exynos4_gpio_xlate(struct gpio_chip *gc, +static struct samsung_gpio_chip exynos5_gpios_1[] = { +#ifdef CONFIG_ARCH_EXYNOS5 + { + .chip = { + .base = EXYNOS5_GPA0(0), + .ngpio = EXYNOS5_GPIO_A0_NR, + .label = "GPA0", + }, + }, { + .chip = { + .base = EXYNOS5_GPA1(0), + .ngpio = EXYNOS5_GPIO_A1_NR, + .label = "GPA1", + }, + }, { + .chip = { + .base = EXYNOS5_GPA2(0), + .ngpio = EXYNOS5_GPIO_A2_NR, + .label = "GPA2", + }, + }, { + .chip = { + .base = EXYNOS5_GPB0(0), + .ngpio = EXYNOS5_GPIO_B0_NR, + .label = "GPB0", + }, + }, { + .chip = { + .base = EXYNOS5_GPB1(0), + .ngpio = EXYNOS5_GPIO_B1_NR, + .label = "GPB1", + }, + }, { + .chip = { + .base = EXYNOS5_GPB2(0), + .ngpio = EXYNOS5_GPIO_B2_NR, + .label = "GPB2", + }, + }, { + .chip = { + .base = EXYNOS5_GPB3(0), + .ngpio = EXYNOS5_GPIO_B3_NR, + .label = "GPB3", + }, + }, { + .chip = { + .base = EXYNOS5_GPC0(0), + .ngpio = EXYNOS5_GPIO_C0_NR, + .label = "GPC0", + }, + }, { + .chip = { + .base = EXYNOS5_GPC1(0), + .ngpio = EXYNOS5_GPIO_C1_NR, + .label = "GPC1", + }, + }, { + .chip = { + .base = EXYNOS5_GPC2(0), + .ngpio = EXYNOS5_GPIO_C2_NR, + .label = "GPC2", + }, + }, { + .chip = { + .base = EXYNOS5_GPC3(0), + .ngpio = EXYNOS5_GPIO_C3_NR, + .label = "GPC3", + }, + }, { + .chip = { + .base = EXYNOS5_GPD0(0), + .ngpio = EXYNOS5_GPIO_D0_NR, + .label = "GPD0", + }, + }, { + .chip = { + .base = EXYNOS5_GPD1(0), + .ngpio = EXYNOS5_GPIO_D1_NR, + .label = "GPD1", + }, + }, { + .chip = { + .base = EXYNOS5_GPY0(0), + .ngpio = EXYNOS5_GPIO_Y0_NR, + .label = "GPY0", + }, + }, { + .chip = { + .base = EXYNOS5_GPY1(0), + .ngpio = EXYNOS5_GPIO_Y1_NR, + .label = "GPY1", + }, + }, { + .chip = { + .base = EXYNOS5_GPY2(0), + .ngpio = EXYNOS5_GPIO_Y2_NR, + .label = "GPY2", + }, + }, { + .chip = { + .base = EXYNOS5_GPY3(0), + .ngpio = EXYNOS5_GPIO_Y3_NR, + .label = "GPY3", + }, + }, { + .chip = { + .base = EXYNOS5_GPY4(0), + .ngpio = EXYNOS5_GPIO_Y4_NR, + .label = "GPY4", + }, + }, { + .chip = { + .base = EXYNOS5_GPY5(0), + .ngpio = EXYNOS5_GPIO_Y5_NR, + .label = "GPY5", + }, + }, { + .chip = { + .base = EXYNOS5_GPY6(0), + .ngpio = EXYNOS5_GPIO_Y6_NR, + .label = "GPY6", + }, + }, { + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(0), + .chip = { + .base = EXYNOS5_GPX0(0), + .ngpio = EXYNOS5_GPIO_X0_NR, + .label = "GPX0", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(8), + .chip = { + .base = EXYNOS5_GPX1(0), + .ngpio = EXYNOS5_GPIO_X1_NR, + .label = "GPX1", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(16), + .chip = { + .base = EXYNOS5_GPX2(0), + .ngpio = EXYNOS5_GPIO_X2_NR, + .label = "GPX2", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(24), + .chip = { + .base = EXYNOS5_GPX3(0), + .ngpio = EXYNOS5_GPIO_X3_NR, + .label = "GPX3", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos5_gpios_2[] = { +#ifdef CONFIG_ARCH_EXYNOS5 + { + .chip = { + .base = EXYNOS5_GPE0(0), + .ngpio = EXYNOS5_GPIO_E0_NR, + .label = "GPE0", + }, + }, { + .chip = { + .base = EXYNOS5_GPE1(0), + .ngpio = EXYNOS5_GPIO_E1_NR, + .label = "GPE1", + }, + }, { + .chip = { + .base = EXYNOS5_GPF0(0), + .ngpio = EXYNOS5_GPIO_F0_NR, + .label = "GPF0", + }, + }, { + .chip = { + .base = EXYNOS5_GPF1(0), + .ngpio = EXYNOS5_GPIO_F1_NR, + .label = "GPF1", + }, + }, { + .chip = { + .base = EXYNOS5_GPG0(0), + .ngpio = EXYNOS5_GPIO_G0_NR, + .label = "GPG0", + }, + }, { + .chip = { + .base = EXYNOS5_GPG1(0), + .ngpio = EXYNOS5_GPIO_G1_NR, + .label = "GPG1", + }, + }, { + .chip = { + .base = EXYNOS5_GPG2(0), + .ngpio = EXYNOS5_GPIO_G2_NR, + .label = "GPG2", + }, + }, { + .chip = { + .base = EXYNOS5_GPH0(0), + .ngpio = EXYNOS5_GPIO_H0_NR, + .label = "GPH0", + }, + }, { + .chip = { + .base = EXYNOS5_GPH1(0), + .ngpio = EXYNOS5_GPIO_H1_NR, + .label = "GPH1", + + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos5_gpios_3[] = { +#ifdef CONFIG_ARCH_EXYNOS5 + { + .chip = { + .base = EXYNOS5_GPV0(0), + .ngpio = EXYNOS5_GPIO_V0_NR, + .label = "GPV0", + }, + }, { + .chip = { + .base = EXYNOS5_GPV1(0), + .ngpio = EXYNOS5_GPIO_V1_NR, + .label = "GPV1", + }, + }, { + .chip = { + .base = EXYNOS5_GPV2(0), + .ngpio = EXYNOS5_GPIO_V2_NR, + .label = "GPV2", + }, + }, { + .chip = { + .base = EXYNOS5_GPV3(0), + .ngpio = EXYNOS5_GPIO_V3_NR, + .label = "GPV3", + }, + }, { + .chip = { + .base = EXYNOS5_GPV4(0), + .ngpio = EXYNOS5_GPIO_V4_NR, + .label = "GPV4", + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos5_gpios_4[] = { +#ifdef CONFIG_ARCH_EXYNOS5 + { + .chip = { + .base = EXYNOS5_GPZ(0), + .ngpio = EXYNOS5_GPIO_Z_NR, + .label = "GPZ", + }, + }, +#endif +}; + + +#if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) +static int exynos_gpio_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags) { unsigned int pin; @@ -2413,13 +2681,13 @@ static int exynos4_gpio_xlate(struct gpio_chip *gc, return gpiospec->args[0]; } -static const struct of_device_id exynos4_gpio_dt_match[] __initdata = { +static const struct of_device_id exynos_gpio_dt_match[] __initdata = { { .compatible = "samsung,exynos4-gpio", }, {} }; -static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, - u64 base, u64 offset) +static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) { struct gpio_chip *gc = &chip->chip; u64 address; @@ -2429,28 +2697,29 @@ static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; gc->of_node = of_find_matching_node_by_address(NULL, - exynos4_gpio_dt_match, address); + exynos_gpio_dt_match, address); if (!gc->of_node) { pr_info("gpio: device tree node not found for gpio controller" " with base address %08llx\n", address); return; } gc->of_gpio_n_cells = 4; - gc->of_xlate = exynos4_gpio_xlate; + gc->of_xlate = exynos_gpio_xlate; } -#elif defined(CONFIG_ARCH_EXYNOS4) -static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, - u64 base, u64 offset) +#elif defined(CONFIG_ARCH_EXYNOS) +static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) { return; } -#endif /* defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) */ +#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */ /* TODO: cleanup soc_is_* */ static __init int samsung_gpiolib_init(void) { struct samsung_gpio_chip *chip; int i, nr_chips; + void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4; int group = 0; samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs)); @@ -2516,66 +2785,200 @@ static __init int samsung_gpiolib_init(void) s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); #endif } else if (soc_is_exynos4210()) { - group = 0; +#ifdef CONFIG_CPU_EXYNOS4210 + void __iomem *gpx_base; /* gpio part1 */ + gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); + if (gpio_base1 == NULL) { + pr_err("unable to ioremap for gpio_base1\n"); + goto err_ioremap1; + } + chip = exynos4_gpios_1; nr_chips = ARRAY_SIZE(exynos4_gpios_1); for (i = 0; i < nr_chips; i++, chip++) { if (!chip->config) { - chip->config = &exynos4_gpio_cfg; + chip->config = &exynos_gpio_cfg; chip->group = group++; } -#ifdef CONFIG_CPU_EXYNOS4210 - exynos4_gpiolib_attach_ofnode(chip, + exynos_gpiolib_attach_ofnode(chip, EXYNOS4_PA_GPIO1, i * 0x20); -#endif } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1); + samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, + nr_chips, gpio_base1); /* gpio part2 */ + gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K); + if (gpio_base2 == NULL) { + pr_err("unable to ioremap for gpio_base2\n"); + goto err_ioremap2; + } + + /* need to set base address for gpx */ + chip = &exynos4_gpios_2[16]; + gpx_base = gpio_base2 + 0xC00; + for (i = 0; i < 4; i++, chip++, gpx_base += 0x20) + chip->base = gpx_base; + chip = exynos4_gpios_2; nr_chips = ARRAY_SIZE(exynos4_gpios_2); for (i = 0; i < nr_chips; i++, chip++) { if (!chip->config) { - chip->config = &exynos4_gpio_cfg; + chip->config = &exynos_gpio_cfg; chip->group = group++; } -#ifdef CONFIG_CPU_EXYNOS4210 - exynos4_gpiolib_attach_ofnode(chip, + exynos_gpiolib_attach_ofnode(chip, EXYNOS4_PA_GPIO2, i * 0x20); -#endif } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2); + samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, + nr_chips, gpio_base2); /* gpio part3 */ + gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256); + if (gpio_base3 == NULL) { + pr_err("unable to ioremap for gpio_base3\n"); + goto err_ioremap3; + } + chip = exynos4_gpios_3; nr_chips = ARRAY_SIZE(exynos4_gpios_3); for (i = 0; i < nr_chips; i++, chip++) { if (!chip->config) { - chip->config = &exynos4_gpio_cfg; + chip->config = &exynos_gpio_cfg; chip->group = group++; } -#ifdef CONFIG_CPU_EXYNOS4210 - exynos4_gpiolib_attach_ofnode(chip, + exynos_gpiolib_attach_ofnode(chip, EXYNOS4_PA_GPIO3, i * 0x20); -#endif } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3); + samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, + nr_chips, gpio_base3); #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT) s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS); s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS); #endif + +#endif /* CONFIG_CPU_EXYNOS4210 */ + } else if (soc_is_exynos5250()) { +#ifdef CONFIG_SOC_EXYNOS5250 + void __iomem *gpx_base; + + /* gpio part1 */ + gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K); + if (gpio_base1 == NULL) { + pr_err("unable to ioremap for gpio_base1\n"); + goto err_ioremap1; + } + + /* need to set base address for gpx */ + chip = &exynos5_gpios_1[20]; + gpx_base = gpio_base1 + 0xC00; + for (i = 0; i < 4; i++, chip++, gpx_base += 0x20) + chip->base = gpx_base; + + chip = exynos5_gpios_1; + nr_chips = ARRAY_SIZE(exynos5_gpios_1); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS5_PA_GPIO1, i * 0x20); + } + samsung_gpiolib_add_4bit_chips(exynos5_gpios_1, + nr_chips, gpio_base1); + + /* gpio part2 */ + gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K); + if (gpio_base2 == NULL) { + pr_err("unable to ioremap for gpio_base2\n"); + goto err_ioremap2; + } + + chip = exynos5_gpios_2; + nr_chips = ARRAY_SIZE(exynos5_gpios_2); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS5_PA_GPIO2, i * 0x20); + } + samsung_gpiolib_add_4bit_chips(exynos5_gpios_2, + nr_chips, gpio_base2); + + /* gpio part3 */ + gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K); + if (gpio_base3 == NULL) { + pr_err("unable to ioremap for gpio_base3\n"); + goto err_ioremap3; + } + + /* need to set base address for gpv */ + exynos5_gpios_3[0].base = gpio_base3; + exynos5_gpios_3[1].base = gpio_base3 + 0x20; + exynos5_gpios_3[2].base = gpio_base3 + 0x60; + exynos5_gpios_3[3].base = gpio_base3 + 0x80; + exynos5_gpios_3[4].base = gpio_base3 + 0xC0; + + chip = exynos5_gpios_3; + nr_chips = ARRAY_SIZE(exynos5_gpios_3); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS5_PA_GPIO3, i * 0x20); + } + samsung_gpiolib_add_4bit_chips(exynos5_gpios_3, + nr_chips, gpio_base3); + + /* gpio part4 */ + gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K); + if (gpio_base4 == NULL) { + pr_err("unable to ioremap for gpio_base4\n"); + goto err_ioremap4; + } + + chip = exynos5_gpios_4; + nr_chips = ARRAY_SIZE(exynos5_gpios_4); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS5_PA_GPIO4, i * 0x20); + } + samsung_gpiolib_add_4bit_chips(exynos5_gpios_4, + nr_chips, gpio_base4); +#endif /* CONFIG_SOC_EXYNOS5250 */ } else { WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n"); return -ENODEV; } return 0; + +err_ioremap4: + iounmap(gpio_base3); +err_ioremap3: + iounmap(gpio_base2); +err_ioremap2: + iounmap(gpio_base1); +err_ioremap1: + return -ENOMEM; } core_initcall(samsung_gpiolib_init); diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c new file mode 100644 index 000000000000..9ba15d31d242 --- /dev/null +++ b/drivers/gpio/gpio-sodaville.c @@ -0,0 +1,302 @@ +/* + * GPIO interface for Intel Sodaville SoCs. + * + * Copyright (c) 2010, 2011 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 as published + * by the Free Software Foundation. + * + */ + +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/of_irq.h> +#include <linux/basic_mmio_gpio.h> + +#define DRV_NAME "sdv_gpio" +#define SDV_NUM_PUB_GPIOS 12 +#define PCI_DEVICE_ID_SDV_GPIO 0x2e67 +#define GPIO_BAR 0 + +#define GPOUTR 0x00 +#define GPOER 0x04 +#define GPINR 0x08 + +#define GPSTR 0x0c +#define GPIT1R0 0x10 +#define GPIO_INT 0x14 +#define GPIT1R1 0x18 + +#define GPMUXCTL 0x1c + +struct sdv_gpio_chip_data { + int irq_base; + void __iomem *gpio_pub_base; + struct irq_domain id; + struct irq_chip_generic *gc; + struct bgpio_chip bgpio; +}; + +static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct sdv_gpio_chip_data *sd = gc->private; + void __iomem *type_reg; + u32 irq_offs = d->irq - sd->irq_base; + u32 reg; + + if (irq_offs < 8) + type_reg = sd->gpio_pub_base + GPIT1R0; + else + type_reg = sd->gpio_pub_base + GPIT1R1; + + reg = readl(type_reg); + + switch (type) { + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~BIT(4 * (irq_offs % 8)); + break; + + case IRQ_TYPE_LEVEL_LOW: + reg |= BIT(4 * (irq_offs % 8)); + break; + + default: + return -EINVAL; + } + + writel(reg, type_reg); + return 0; +} + +static irqreturn_t sdv_gpio_pub_irq_handler(int irq, void *data) +{ + struct sdv_gpio_chip_data *sd = data; + u32 irq_stat = readl(sd->gpio_pub_base + GPSTR); + + irq_stat &= readl(sd->gpio_pub_base + GPIO_INT); + if (!irq_stat) + return IRQ_NONE; + + while (irq_stat) { + u32 irq_bit = __fls(irq_stat); + + irq_stat &= ~BIT(irq_bit); + generic_handle_irq(sd->irq_base + irq_bit); + } + + return IRQ_HANDLED; +} + +static int sdv_xlate(struct irq_domain *h, struct device_node *node, + const u32 *intspec, u32 intsize, irq_hw_number_t *out_hwirq, + u32 *out_type) +{ + u32 line, type; + + if (node != h->of_node) + return -EINVAL; + + if (intsize < 2) + return -EINVAL; + + line = *intspec; + *out_hwirq = line; + + intspec++; + type = *intspec; + + switch (type) { + case IRQ_TYPE_LEVEL_LOW: + case IRQ_TYPE_LEVEL_HIGH: + *out_type = type; + break; + default: + return -EINVAL; + } + return 0; +} + +static struct irq_domain_ops irq_domain_sdv_ops = { + .dt_translate = sdv_xlate, +}; + +static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, + struct pci_dev *pdev) +{ + struct irq_chip_type *ct; + int ret; + + sd->irq_base = irq_alloc_descs(-1, 0, SDV_NUM_PUB_GPIOS, -1); + if (sd->irq_base < 0) + return sd->irq_base; + + /* mask + ACK all interrupt sources */ + writel(0, sd->gpio_pub_base + GPIO_INT); + writel((1 << 11) - 1, sd->gpio_pub_base + GPSTR); + + ret = request_irq(pdev->irq, sdv_gpio_pub_irq_handler, IRQF_SHARED, + "sdv_gpio", sd); + if (ret) + goto out_free_desc; + + sd->id.irq_base = sd->irq_base; + sd->id.of_node = of_node_get(pdev->dev.of_node); + sd->id.ops = &irq_domain_sdv_ops; + + /* + * This gpio irq controller latches level irqs. Testing shows that if + * we unmask & ACK the IRQ before the source of the interrupt is gone + * then the interrupt is active again. + */ + sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base, + sd->gpio_pub_base, handle_fasteoi_irq); + if (!sd->gc) { + ret = -ENOMEM; + goto out_free_irq; + } + + sd->gc->private = sd; + ct = sd->gc->chip_types; + ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; + ct->regs.eoi = GPSTR; + ct->regs.mask = GPIO_INT; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_eoi = irq_gc_eoi; + ct->chip.irq_set_type = sdv_gpio_pub_set_type; + + irq_setup_generic_chip(sd->gc, IRQ_MSK(SDV_NUM_PUB_GPIOS), + IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, + IRQ_LEVEL | IRQ_NOPROBE); + + irq_domain_add(&sd->id); + return 0; +out_free_irq: + free_irq(pdev->irq, sd); +out_free_desc: + irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); + return ret; +} + +static int __devinit sdv_gpio_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_id) +{ + struct sdv_gpio_chip_data *sd; + unsigned long addr; + const void *prop; + int len; + int ret; + u32 mux_val; + + sd = kzalloc(sizeof(struct sdv_gpio_chip_data), GFP_KERNEL); + if (!sd) + return -ENOMEM; + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "can't enable device.\n"); + goto done; + } + + ret = pci_request_region(pdev, GPIO_BAR, DRV_NAME); + if (ret) { + dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR); + goto disable_pci; + } + + addr = pci_resource_start(pdev, GPIO_BAR); + if (!addr) + goto release_reg; + sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR)); + + prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len); + if (prop && len == 4) { + mux_val = of_read_number(prop, 1); + writel(mux_val, sd->gpio_pub_base + GPMUXCTL); + } + + ret = bgpio_init(&sd->bgpio, &pdev->dev, 4, + sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR, + NULL, sd->gpio_pub_base + GPOER, NULL, false); + if (ret) + goto unmap; + sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS; + + ret = gpiochip_add(&sd->bgpio.gc); + if (ret < 0) { + dev_err(&pdev->dev, "gpiochip_add() failed.\n"); + goto unmap; + } + + ret = sdv_register_irqsupport(sd, pdev); + if (ret) + goto unmap; + + pci_set_drvdata(pdev, sd); + dev_info(&pdev->dev, "Sodaville GPIO driver registered.\n"); + return 0; + +unmap: + iounmap(sd->gpio_pub_base); +release_reg: + pci_release_region(pdev, GPIO_BAR); +disable_pci: + pci_disable_device(pdev); +done: + kfree(sd); + return ret; +} + +static void sdv_gpio_remove(struct pci_dev *pdev) +{ + struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev); + + irq_domain_del(&sd->id); + free_irq(pdev->irq, sd); + irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); + + if (gpiochip_remove(&sd->bgpio.gc)) + dev_err(&pdev->dev, "gpiochip_remove() failed.\n"); + + pci_release_region(pdev, GPIO_BAR); + iounmap(sd->gpio_pub_base); + pci_disable_device(pdev); + kfree(sd); +} + +static struct pci_device_id sdv_gpio_pci_ids[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) }, + { 0, }, +}; + +static struct pci_driver sdv_gpio_driver = { + .name = DRV_NAME, + .id_table = sdv_gpio_pci_ids, + .probe = sdv_gpio_probe, + .remove = sdv_gpio_remove, +}; + +static int __init sdv_gpio_init(void) +{ + return pci_register_driver(&sdv_gpio_driver); +} +module_init(sdv_gpio_init); + +static void __exit sdv_gpio_exit(void) +{ + pci_unregister_driver(&sdv_gpio_driver); +} +module_exit(sdv_gpio_exit); + +MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>"); +MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 87a68a896abf..dce34727bbf8 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -54,7 +54,7 @@ static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset) if (ret < 0) return ret; - return ret & mask; + return !!(ret & mask); } static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val) @@ -307,13 +307,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) struct stmpe_gpio_platform_data *pdata; struct stmpe_gpio *stmpe_gpio; int ret; - int irq; + int irq = 0; pdata = stmpe->pdata->gpio; irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL); if (!stmpe_gpio) @@ -330,21 +328,28 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip.dev = &pdev->dev; stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1; - stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0); + if (irq >= 0) + stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0); + else + dev_info(&pdev->dev, + "device configured in no-irq mode; " + "irqs are not available\n"); ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO); if (ret) goto out_free; - ret = stmpe_gpio_irq_init(stmpe_gpio); - if (ret) - goto out_disable; + if (irq >= 0) { + ret = stmpe_gpio_irq_init(stmpe_gpio); + if (ret) + goto out_disable; - ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT, - "stmpe-gpio", stmpe_gpio); - if (ret) { - dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_removeirq; + ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, + IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio); + if (ret) { + dev_err(&pdev->dev, "unable to get irq: %d\n", ret); + goto out_removeirq; + } } ret = gpiochip_add(&stmpe_gpio->chip); @@ -361,9 +366,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) return 0; out_freeirq: - free_irq(irq, stmpe_gpio); + if (irq >= 0) + free_irq(irq, stmpe_gpio); out_removeirq: - stmpe_gpio_irq_remove(stmpe_gpio); + if (irq >= 0) + stmpe_gpio_irq_remove(stmpe_gpio); out_disable: stmpe_disable(stmpe, STMPE_BLOCK_GPIO); out_free: @@ -391,8 +398,10 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev) stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - free_irq(irq, stmpe_gpio); - stmpe_gpio_irq_remove(stmpe_gpio); + if (irq >= 0) { + free_irq(irq, stmpe_gpio); + stmpe_gpio_irq_remove(stmpe_gpio); + } platform_set_drvdata(pdev, NULL); kfree(stmpe_gpio); diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index bdc293791590..32de6707e3c4 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -25,6 +25,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/irqdomain.h> #include <asm/mach/irq.h> @@ -74,9 +75,10 @@ struct tegra_gpio_bank { #endif }; - +static struct irq_domain *irq_domain; static void __iomem *regs; -static struct tegra_gpio_bank tegra_gpio_banks[7]; +static u32 tegra_gpio_bank_count; +static struct tegra_gpio_bank *tegra_gpio_banks; static inline void tegra_gpio_writel(u32 val, u32 reg) { @@ -107,11 +109,13 @@ void tegra_gpio_enable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); } +EXPORT_SYMBOL_GPL(tegra_gpio_enable); void tegra_gpio_disable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); } +EXPORT_SYMBOL_GPL(tegra_gpio_disable); static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { @@ -139,7 +143,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - return TEGRA_GPIO_TO_IRQ(offset); + return irq_find_mapping(irq_domain, offset); } static struct gpio_chip tegra_gpio_chip = { @@ -155,28 +159,28 @@ static struct gpio_chip tegra_gpio_chip = { static void tegra_gpio_irq_ack(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); } static void tegra_gpio_irq_mask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); } static void tegra_gpio_irq_unmask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); } static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); int port = GPIO_PORT(gpio); int lvl_type; @@ -273,7 +277,7 @@ void tegra_gpio_resume(void) local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -296,7 +300,7 @@ void tegra_gpio_suspend(void) int p; local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -337,13 +341,44 @@ static struct lock_class_key gpio_lock_class; static int __devinit tegra_gpio_probe(struct platform_device *pdev) { + int irq_base; struct resource *res; struct tegra_gpio_bank *bank; int gpio; int i; int j; - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + for (;;) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count); + if (!res) + break; + tegra_gpio_bank_count++; + } + if (!tegra_gpio_bank_count) { + dev_err(&pdev->dev, "Missing IRQ resource\n"); + return -ENODEV; + } + + tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32; + + tegra_gpio_banks = devm_kzalloc(&pdev->dev, + tegra_gpio_bank_count * sizeof(*tegra_gpio_banks), + GFP_KERNEL); + if (!tegra_gpio_banks) { + dev_err(&pdev->dev, "Couldn't allocate bank structure\n"); + 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_simple_ops, NULL); + + for (i = 0; i < tegra_gpio_bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { dev_err(&pdev->dev, "Missing IRQ resource\n"); @@ -380,8 +415,8 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); - for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) { - int irq = TEGRA_GPIO_TO_IRQ(gpio); + for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { + int irq = irq_find_mapping(irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; @@ -393,7 +428,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) set_irq_flags(irq, IRQF_VALID); } - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { bank = &tegra_gpio_banks[i]; irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); @@ -426,7 +461,7 @@ static int __init tegra_gpio_init(void) } postcore_initcall(tegra_gpio_init); -void __init tegra_gpio_config(struct tegra_gpio_table *table, int num) +void tegra_gpio_config(struct tegra_gpio_table *table, int num) { int i; diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 91f45b965d1e..7eef648a3351 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -69,6 +69,7 @@ static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset) void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base) { int ret; + struct tps65910_board *board_data; if (!gpio_base) return; @@ -80,10 +81,10 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base) switch(tps65910_chip_id(tps65910)) { case TPS65910: - tps65910->gpio.ngpio = 6; + tps65910->gpio.ngpio = TPS65910_NUM_GPIO; break; case TPS65911: - tps65910->gpio.ngpio = 9; + tps65910->gpio.ngpio = TPS65911_NUM_GPIO; break; default: return; @@ -95,6 +96,21 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base) tps65910->gpio.set = tps65910_gpio_set; tps65910->gpio.get = tps65910_gpio_get; + /* Configure sleep control for gpios */ + board_data = dev_get_platdata(tps65910->dev); + if (board_data) { + int i; + for (i = 0; i < tps65910->gpio.ngpio; ++i) { + if (board_data->en_gpio_sleep[i]) { + ret = tps65910_set_bits(tps65910, + TPS65910_GPIO0 + i, GPIO_SLEEP_MASK); + if (ret < 0) + dev_warn(tps65910->dev, + "GPIO Sleep setting failed\n"); + } + } + } + ret = gpiochip_add(&tps65910->gpio); if (ret) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index b8b4f228757c..94256fe7bf36 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -32,6 +32,8 @@ #include <linux/irq.h> #include <linux/gpio.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/irqdomain.h> #include <linux/i2c/twl.h> @@ -256,7 +258,8 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) * and vMMC2 power supplies based on card presence. */ pdata = chip->dev->platform_data; - value |= pdata->mmc_cd & 0x03; + if (pdata) + value |= pdata->mmc_cd & 0x03; status = gpio_twl4030_write(REG_GPIO_CTRL, value); } @@ -395,59 +398,70 @@ static int gpio_twl4030_remove(struct platform_device *pdev); static int __devinit gpio_twl4030_probe(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; - int ret; + struct device_node *node = pdev->dev.of_node; + int ret, irq_base; /* maybe setup IRQs */ - if (pdata->irq_base) { - if (is_module()) { - dev_err(&pdev->dev, - "can't dispatch IRQs from modules\n"); - goto no_irqs; - } - ret = twl4030_sih_setup(TWL4030_MODULE_GPIO); - if (ret < 0) - return ret; - WARN_ON(ret != pdata->irq_base); - twl4030_gpio_irq_base = ret; + if (is_module()) { + dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); + goto no_irqs; + } + + irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0); + if (irq_base < 0) { + dev_err(&pdev->dev, "Failed to alloc irq_descs\n"); + return irq_base; } + irq_domain_add_legacy(node, TWL4030_GPIO_MAX, irq_base, 0, + &irq_domain_simple_ops, NULL); + + ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base); + if (ret < 0) + return ret; + + twl4030_gpio_irq_base = irq_base; + no_irqs: - /* - * NOTE: boards may waste power if they don't set pullups - * and pulldowns correctly ... default for non-ULPI pins is - * pulldown, and some other pins may have external pullups - * or pulldowns. Careful! - */ - ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); - if (ret) - dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", - pdata->pullups, pdata->pulldowns, - ret); - - ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); - if (ret) - dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", - pdata->debounce, pdata->mmc_cd, - ret); - - twl_gpiochip.base = pdata->gpio_base; + twl_gpiochip.base = -1; twl_gpiochip.ngpio = TWL4030_GPIO_MAX; twl_gpiochip.dev = &pdev->dev; - /* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, - * is (still) clear if use_leds is set. - */ - if (pdata->use_leds) - twl_gpiochip.ngpio += 2; + if (pdata) { + twl_gpiochip.base = pdata->gpio_base; + + /* + * NOTE: boards may waste power if they don't set pullups + * and pulldowns correctly ... default for non-ULPI pins is + * pulldown, and some other pins may have external pullups + * or pulldowns. Careful! + */ + ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); + if (ret) + dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", + pdata->pullups, pdata->pulldowns, + ret); + + ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); + if (ret) + dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", + pdata->debounce, pdata->mmc_cd, + ret); + + /* + * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, + * is (still) clear if use_leds is set. + */ + if (pdata->use_leds) + twl_gpiochip.ngpio += 2; + } ret = gpiochip_add(&twl_gpiochip); if (ret < 0) { - dev_err(&pdev->dev, - "could not register gpiochip, %d\n", - ret); + dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); twl_gpiochip.ngpio = 0; gpio_twl4030_remove(pdev); - } else if (pdata->setup) { + } else if (pdata && pdata->setup) { int status; status = pdata->setup(&pdev->dev, @@ -465,7 +479,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev) struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; int status; - if (pdata->teardown) { + if (pdata && pdata->teardown) { status = pdata->teardown(&pdev->dev, pdata->gpio_base, TWL4030_GPIO_MAX); if (status) { @@ -486,12 +500,21 @@ static int gpio_twl4030_remove(struct platform_device *pdev) return -EIO; } +static const struct of_device_id twl_gpio_match[] = { + { .compatible = "ti,twl4030-gpio", }, + { }, +}; +MODULE_DEVICE_TABLE(of, twl_gpio_match); + /* Note: this hardware lives inside an I2C-based multi-function device. */ MODULE_ALIAS("platform:twl4030_gpio"); static struct platform_driver gpio_twl4030_driver = { - .driver.name = "twl4030_gpio", - .driver.owner = THIS_MODULE, + .driver = { + .name = "twl4030_gpio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl_gpio_match), + }, .probe = gpio_twl4030_probe, .remove = gpio_twl4030_remove, }; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 17fdf4b6af93..5a75510d66bb 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -58,6 +58,8 @@ struct gpio_desc { #define FLAG_TRIG_FALL 5 /* trigger on falling edge */ #define FLAG_TRIG_RISE 6 /* trigger on rising edge */ #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ +#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */ +#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */ #define ID_SHIFT 16 /* add new flags before this one */ @@ -873,6 +875,7 @@ void gpio_unexport(unsigned gpio) { struct gpio_desc *desc; int status = 0; + struct device *dev = NULL; if (!gpio_is_valid(gpio)) { status = -EINVAL; @@ -884,19 +887,20 @@ void gpio_unexport(unsigned gpio) desc = &gpio_desc[gpio]; if (test_bit(FLAG_EXPORT, &desc->flags)) { - struct device *dev = NULL; dev = class_find_device(&gpio_class, NULL, desc, match_export); if (dev) { gpio_setup_irq(desc, dev, 0); clear_bit(FLAG_EXPORT, &desc->flags); - put_device(dev); - device_unregister(dev); } else status = -ENODEV; } mutex_unlock(&sysfs_lock); + if (dev) { + device_unregister(dev); + put_device(dev); + } done: if (status) pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); @@ -1150,8 +1154,9 @@ EXPORT_SYMBOL_GPL(gpiochip_remove); * non-zero, this function will return to the caller and not iterate over any * more gpio_chips. */ -struct gpio_chip *gpiochip_find(void *data, - int (*match)(struct gpio_chip *chip, void *data)) +struct gpio_chip *gpiochip_find(const void *data, + int (*match)(struct gpio_chip *chip, + const void *data)) { struct gpio_chip *chip = NULL; unsigned long flags; @@ -1261,6 +1266,8 @@ void gpio_free(unsigned gpio) module_put(desc->chip->owner); clear_bit(FLAG_ACTIVE_LOW, &desc->flags); clear_bit(FLAG_REQUESTED, &desc->flags); + clear_bit(FLAG_OPEN_DRAIN, &desc->flags); + clear_bit(FLAG_OPEN_SOURCE, &desc->flags); } else WARN_ON(extra_checks); @@ -1282,6 +1289,12 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (err) return err; + if (flags & GPIOF_OPEN_DRAIN) + set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags); + + if (flags & GPIOF_OPEN_SOURCE) + set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags); + if (flags & GPIOF_DIR_IN) err = gpio_direction_input(gpio); else @@ -1431,6 +1444,14 @@ int gpio_direction_output(unsigned gpio, int value) struct gpio_desc *desc = &gpio_desc[gpio]; int status = -EINVAL; + /* Open drain pin should not be driven to 1 */ + if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + return gpio_direction_input(gpio); + + /* Open source pin should not be driven to 0 */ + if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + return gpio_direction_input(gpio); + spin_lock_irqsave(&gpio_lock, flags); if (!gpio_is_valid(gpio)) @@ -1560,6 +1581,7 @@ int __gpio_get_value(unsigned gpio) int value; chip = gpio_to_chip(gpio); + /* Should be using gpio_get_value_cansleep() */ WARN_ON(chip->can_sleep); value = chip->get ? chip->get(chip, gpio - chip->base) : 0; trace_gpio_value(gpio, 1, value); @@ -1567,6 +1589,57 @@ int __gpio_get_value(unsigned gpio) } EXPORT_SYMBOL_GPL(__gpio_get_value); +/* + * _gpio_set_open_drain_value() - Set the open drain gpio's value. + * @gpio: Gpio whose state need to be set. + * @chip: Gpio chip. + * @value: Non-zero for setting it HIGH otherise it will set to LOW. + */ +static void _gpio_set_open_drain_value(unsigned gpio, + struct gpio_chip *chip, int value) +{ + int err = 0; + if (value) { + err = chip->direction_input(chip, gpio - chip->base); + if (!err) + clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + } else { + err = chip->direction_output(chip, gpio - chip->base, 0); + if (!err) + set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + } + trace_gpio_direction(gpio, value, err); + if (err < 0) + pr_err("%s: Error in set_value for open drain gpio%d err %d\n", + __func__, gpio, err); +} + +/* + * _gpio_set_open_source() - Set the open source gpio's value. + * @gpio: Gpio whose state need to be set. + * @chip: Gpio chip. + * @value: Non-zero for setting it HIGH otherise it will set to LOW. + */ +static void _gpio_set_open_source_value(unsigned gpio, + struct gpio_chip *chip, int value) +{ + int err = 0; + if (value) { + err = chip->direction_output(chip, gpio - chip->base, 1); + if (!err) + set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + } else { + err = chip->direction_input(chip, gpio - chip->base); + if (!err) + clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + } + trace_gpio_direction(gpio, !value, err); + if (err < 0) + pr_err("%s: Error in set_value for open source gpio%d err %d\n", + __func__, gpio, err); +} + + /** * __gpio_set_value() - assign a gpio's value * @gpio: gpio whose value will be assigned @@ -1581,9 +1654,15 @@ void __gpio_set_value(unsigned gpio, int value) struct gpio_chip *chip; chip = gpio_to_chip(gpio); + /* Should be using gpio_set_value_cansleep() */ WARN_ON(chip->can_sleep); trace_gpio_value(gpio, 0, value); - chip->set(chip, gpio - chip->base, value); + if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) + _gpio_set_open_drain_value(gpio, chip, value); + else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) + _gpio_set_open_source_value(gpio, chip, value); + else + chip->set(chip, gpio - chip->base, value); } EXPORT_SYMBOL_GPL(__gpio_set_value); @@ -1650,7 +1729,12 @@ void gpio_set_value_cansleep(unsigned gpio, int value) might_sleep_if(extra_checks); chip = gpio_to_chip(gpio); trace_gpio_value(gpio, 0, value); - chip->set(chip, gpio - chip->base, value); + if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) + _gpio_set_open_drain_value(gpio, chip, value); + else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) + _gpio_set_open_source_value(gpio, chip, value); + else + chip->set(chip, gpio - chip->base, value); } EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); |