From feefe73fcbb4dfc952d4185d80435fb8e053e2a7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 3 Jan 2012 15:52:42 -0600 Subject: gpio: pxa: explicitly include mach/irqs.h In preparation to make mach/irqs.h optional and remove from asm/irq.h, directly include mach/irq.h to get MMP_GPIO_TO_IRQ and PXA_GPIO_TO_IRQ. Signed-off-by: Rob Herring --- drivers/gpio/gpio-pxa.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index b2d3ee1d183a..5689ce62fd81 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -22,6 +22,8 @@ #include #include +#include + /* * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with * one set of registers. The register offsets are organized below: -- cgit From 608589b15f02e59e8c40df7ef861064f1b6fa504 Mon Sep 17 00:00:00 2001 From: wu guoxing Date: Mon, 30 Jan 2012 14:31:20 +0800 Subject: ARM/mx35/3ds: gpio: add mc9s08dz60 gpio function we only use the gpio function of mc9s08dz60 mcu chip, so just add the gpio driver, as this mcu will never be used in other board. Signed-off-by: Wu Guoxing Reviewed-by: Sascha Hauer Acked-by: Marc Kleine-Budde Signed-off-by: Grant Likely --- drivers/gpio/Kconfig | 6 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-mc9s08dz60.c | 161 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 drivers/gpio/gpio-mc9s08dz60.c (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d0c41188d4e5..eaa7d3828e70 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -225,6 +225,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 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fa10df604c01..8863a7f2dece 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -26,6 +26,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 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 + * + * 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 +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("mc9s08dz60 gpio function on mx35 3ds board"); +MODULE_LICENSE("GPL v2"); -- cgit From b43ab901d671e3e3cad425ea5e9a3c74e266dcdd Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 27 Jun 2011 09:26:23 +0200 Subject: gpio: Add a driver for Sodaville GPIO controller Sodaville has GPIO controller behind the PCI bus. To my suprissed it is not the same as on PXA. The interrupt & gpio chip can be referenced from the device tree like from any other driver. Unfortunately the driver which uses the gpio interrupt has to use irq_of_parse_and_map() instead of platform_get_irq(). The problem is that the platform device (which is created from the device tree) is most likely created before the interrupt chip is registered and therefore irq_of_parse_and_map() fails. In theory the driver works as module. In reality most of the irq functions are not exported to modules and it is possible that _this_ module is unloaded while the provided irqs are still in use. Signed-off-by: Hans J. Koch [torbenh@linutronix.de: make it work after the irq namespace cleanup, add some device tree entries.] Signed-off-by: Torben Hohn [bigeasy@linutronix.de: convert to generic irq & gpio chip] Signed-off-by: Sebastian Andrzej Siewior [grant.likely@secretlab.ca: depend on x86 to avoid irq_domain breakage] Signed-off-by: Grant Likely --- drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-sodaville.c | 302 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 drivers/gpio/gpio-sodaville.c (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index eaa7d3828e70..dbb1909ca0a2 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -417,6 +417,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 + 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 8863a7f2dece..593bdcd1976e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -46,6 +46,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-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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs"); +MODULE_LICENSE("GPL v2"); -- cgit From 9467d298e92455e6fd411d7ef1f367ced940587c Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 1 Feb 2012 12:09:04 +0530 Subject: gpio: tps65910: Add sleep control support The device tps65910/tps65911 supports the sleep functionality in some of gpios. If gpio is configured in output mode and sleep is enabled then during device sleep state, the output of gpio becomes LOW regardless of non-sleep output value. Such gpio can be used to control regulator switch such that output of regulator is off in device sleep state. Signed-off-by: Laxman Dewangan Signed-off-by: Grant Likely Acked-by: Linus Walleij --- drivers/gpio/gpio-tps65910.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') 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) -- cgit From 03e128ca35e5da22e9e65ec8ab158ec0e905fdea Mon Sep 17 00:00:00 2001 From: Charulatha V Date: Thu, 5 May 2011 19:58:01 +0530 Subject: gpio/omap: remove dependency on gpio_bank_count The gpio_bank_count is the count of number of GPIO devices in a SoC. Remove this dependency from the driver by using list. Also remove the dependency on array of pointers to gpio_bank struct of all GPIO devices. Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 163 +++++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 83 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0b0562979171..6ea7390e7801 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -28,7 +28,10 @@ #include #include +static LIST_HEAD(omap_gpio_list); + struct gpio_bank { + struct list_head node; unsigned long pbase; void __iomem *base; u16 irq; @@ -55,6 +58,7 @@ struct gpio_bank { bool dbck_flag; int stride; u32 width; + u16 id; void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable); @@ -78,15 +82,6 @@ struct omap3_gpio_regs { 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)) @@ -869,9 +864,8 @@ 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) @@ -879,13 +873,13 @@ static inline void mpuio_init(void) } #else -static inline void mpuio_init(void) {} +static inline void mpuio_init(struct gpio_bank *bank) {} #endif /* 16xx */ #else #define bank_is_mpuio(bank) 0 -static inline void mpuio_init(void) {} +static inline void mpuio_init(struct gpio_bank *bank) {} #endif @@ -1007,20 +1001,8 @@ 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) -{ - /* 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; -} - /* TODO: Cleanup cpu_is_* checks */ -static void omap_gpio_mod_init(struct gpio_bank *bank, int id) +static void omap_gpio_mod_init(struct gpio_bank *bank) { if (cpu_class_is_omap2()) { if (cpu_is_omap44xx()) { @@ -1044,13 +1026,16 @@ static void omap_gpio_mod_init(struct gpio_bank *bank, int id) static const u32 non_wakeup_gpios[] = { 0xe203ffc0, 0x08700040 }; - if (id < ARRAY_SIZE(non_wakeup_gpios)) - bank->non_wakeup_gpios = non_wakeup_gpios[id]; + if (bank->id < ARRAY_SIZE(non_wakeup_gpios)) + bank->non_wakeup_gpios = + non_wakeup_gpios[bank->id]; } } else if (cpu_class_is_omap1()) { - if (bank_is_mpuio(bank)) + if (bank_is_mpuio(bank)) { __raw_writew(0xffff, bank->base + OMAP_MPUIO_GPIO_MASKIT / bank->stride); + mpuio_init(bank); + } if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) { __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK); @@ -1161,35 +1146,35 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) static int __devinit omap_gpio_probe(struct platform_device *pdev) { - static int gpio_init_done; 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; - - if (!gpio_init_done) { - int ret; - - ret = init_gpio_info(pdev); - if (ret) - return ret; + if (!pdev->dev.platform_data) { + ret = -EINVAL; + goto err_exit; } - id = pdev->id; - bank = &gpio_bank[id]; + bank = kzalloc(sizeof(struct gpio_bank), GFP_KERNEL); + if (!bank) { + dev_err(&pdev->dev, "Memory alloc failed for gpio_bank\n"); + ret = -ENOMEM; + goto err_exit; + } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (unlikely(!res)) { - dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", id); - return -ENODEV; + dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", + pdev->id); + ret = -ENODEV; + goto err_free; } bank->irq = res->start; + bank->id = pdev->id; + + pdata = pdev->dev.platform_data; bank->virtual_irq_start = pdata->virtual_irq_start; bank->method = pdata->bank_type; bank->dev = &pdev->dev; @@ -1209,39 +1194,46 @@ 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); - return -ENODEV; + dev_err(&pdev->dev, "GPIO Bank %i Invalid mem resource\n", + pdev->id); + ret = -ENODEV; + goto err_free; } bank->base = ioremap(res->start, resource_size(res)); if (!bank->base) { - dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", id); - return -ENOMEM; + dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", + pdev->id); + ret = -ENOMEM; + goto err_free; } pm_runtime_enable(bank->dev); pm_runtime_get_sync(bank->dev); - omap_gpio_mod_init(bank, id); + omap_gpio_mod_init(bank); omap_gpio_chip_init(bank); omap_gpio_show_rev(bank); - if (!gpio_init_done) - gpio_init_done = 1; + list_add_tail(&bank->node, &omap_gpio_list); - return 0; + return ret; + +err_free: + kfree(bank); +err_exit: + return ret; } #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) static int omap_gpio_suspend(void) { - int i; + struct gpio_bank *bank; if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) return 0; - for (i = 0; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; + list_for_each_entry(bank, &omap_gpio_list, node) { void __iomem *wake_status; void __iomem *wake_clear; void __iomem *wake_set; @@ -1285,13 +1277,12 @@ static int omap_gpio_suspend(void) static void omap_gpio_resume(void) { - int i; + struct gpio_bank *bank; if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) return; - for (i = 0; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; + list_for_each_entry(bank, &omap_gpio_list, node) { void __iomem *wake_clear; void __iomem *wake_set; unsigned long flags; @@ -1339,17 +1330,17 @@ static int workaround_enabled; void omap2_gpio_prepare_for_idle(int off_mode) { - int i, c = 0; - int min = 0; - - if (cpu_is_omap34xx()) - min = 1; + int c = 0; + struct gpio_bank *bank; - for (i = min; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; + list_for_each_entry(bank, &omap_gpio_list, node) { u32 l1 = 0, l2 = 0; int j; + /* TODO: Do not use cpu_is_omap34xx */ + if ((cpu_is_omap34xx()) && (bank->id == 0)) + continue; + for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) clk_disable(bank->dbck); @@ -1408,16 +1399,16 @@ void omap2_gpio_prepare_for_idle(int off_mode) void omap2_gpio_resume_after_idle(void) { - int i; - int min = 0; + struct gpio_bank *bank; - if (cpu_is_omap34xx()) - min = 1; - for (i = min; i < gpio_bank_count; i++) { - struct gpio_bank *bank = &gpio_bank[i]; + list_for_each_entry(bank, &omap_gpio_list, node) { u32 l = 0, gen, gen0, gen1; int j; + /* TODO: Do not use cpu_is_omap34xx */ + if ((cpu_is_omap34xx()) && (bank->id == 0)) + continue; + for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) clk_enable(bank->dbck); @@ -1506,14 +1497,17 @@ void omap2_gpio_resume_after_idle(void) #endif #ifdef CONFIG_ARCH_OMAP3 -/* save the registers of bank 2-6 */ void omap_gpio_save_context(void) { - int i; + struct gpio_bank *bank; + int i = 0; + + list_for_each_entry(bank, &omap_gpio_list, node) { + i++; + + if (bank->id == 0) + continue; - /* 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 = @@ -1537,13 +1531,17 @@ void omap_gpio_save_context(void) } } -/* restore the required registers of bank 2-6 */ void omap_gpio_restore_context(void) { - int i; + struct gpio_bank *bank; + int i = 0; + + list_for_each_entry(bank, &omap_gpio_list, node) { + i++; + + if (bank->id == 0) + continue; - 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, @@ -1588,7 +1586,6 @@ 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()) -- cgit From 0cde8d03dd297fa8e7e88cedeb498d0ed5b7776d Mon Sep 17 00:00:00 2001 From: Charulatha V Date: Thu, 5 May 2011 20:15:16 +0530 Subject: gpio/omap: use flag to identify wakeup domain In omap3, save/restore context is implemented for GPIO banks 2-6 as GPIO bank1 is in wakeup domain. Instead of identifying bank's power domain by bank id, use 'loses_context' flag which is filled by pwrdm_can_ever_lose_context() during dev_init. For getting the powerdomain pointer, omap_hwmod_get_pwrdm() is used. omap_device_get_pwrdm() could not be used as the pwrdm information needs to be filled in pdata, whereas omap_device_get_pwrdm() could be used only after omap_device_build() call. Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 6ea7390e7801..07efa15c3549 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -56,6 +56,7 @@ struct gpio_bank { u32 dbck_enable_mask; struct device *dev; bool dbck_flag; + bool loses_context; int stride; u32 width; u16 id; @@ -1181,7 +1182,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; - + bank->loses_context = pdata->loses_context; bank->regs = pdata->regs; if (bank->regs->set_dataout && bank->regs->clr_dataout) @@ -1337,8 +1338,7 @@ void omap2_gpio_prepare_for_idle(int off_mode) u32 l1 = 0, l2 = 0; int j; - /* TODO: Do not use cpu_is_omap34xx */ - if ((cpu_is_omap34xx()) && (bank->id == 0)) + if (!bank->loses_context) continue; for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) @@ -1405,8 +1405,7 @@ void omap2_gpio_resume_after_idle(void) u32 l = 0, gen, gen0, gen1; int j; - /* TODO: Do not use cpu_is_omap34xx */ - if ((cpu_is_omap34xx()) && (bank->id == 0)) + if (!bank->loses_context) continue; for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) @@ -1505,7 +1504,7 @@ void omap_gpio_save_context(void) list_for_each_entry(bank, &omap_gpio_list, node) { i++; - if (bank->id == 0) + if (!bank->loses_context) continue; gpio_context[i].irqenable1 = @@ -1539,7 +1538,7 @@ void omap_gpio_restore_context(void) list_for_each_entry(bank, &omap_gpio_list, node) { i++; - if (bank->id == 0) + if (!bank->loses_context) continue; __raw_writel(gpio_context[i].irqenable1, -- cgit From 6d62e216b2ccbb8176dca73b6899b12a417bb22d Mon Sep 17 00:00:00 2001 From: Charulatha V Date: Mon, 18 Apr 2011 15:06:51 +0000 Subject: gpio/omap: make gpio_context part of gpio_bank structure Currently gpio_context array used to save gpio bank's context, is used only for OMAP3 architecture. Move gpio_context as part of gpio_bank structure so that it can be specific to each gpio bank and can be used for any OMAP architecture Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 76 ++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 42 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 07efa15c3549..6788c8a2a770 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -30,6 +30,19 @@ 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; +}; + struct gpio_bank { struct list_head node; unsigned long pbase; @@ -43,7 +56,7 @@ struct gpio_bank { #endif u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; - + struct gpio_regs context; u32 saved_datain; u32 saved_fallingdetect; u32 saved_risingdetect; @@ -66,23 +79,6 @@ struct gpio_bank { 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 - #define GPIO_INDEX(bank, gpio) (gpio % bank->width) #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio)) @@ -1499,33 +1495,31 @@ void omap2_gpio_resume_after_idle(void) void omap_gpio_save_context(void) { struct gpio_bank *bank; - int i = 0; list_for_each_entry(bank, &omap_gpio_list, node) { - i++; if (!bank->loses_context) continue; - gpio_context[i].irqenable1 = + bank->context.irqenable1 = __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1); - gpio_context[i].irqenable2 = + bank->context.irqenable2 = __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2); - gpio_context[i].wake_en = + bank->context.wake_en = __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN); - gpio_context[i].ctrl = + bank->context.ctrl = __raw_readl(bank->base + OMAP24XX_GPIO_CTRL); - gpio_context[i].oe = + bank->context.oe = __raw_readl(bank->base + OMAP24XX_GPIO_OE); - gpio_context[i].leveldetect0 = + bank->context.leveldetect0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); - gpio_context[i].leveldetect1 = + bank->context.leveldetect1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); - gpio_context[i].risingdetect = + bank->context.risingdetect = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); - gpio_context[i].fallingdetect = + bank->context.fallingdetect = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); - gpio_context[i].dataout = + bank->context.dataout = __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT); } } @@ -1533,33 +1527,31 @@ void omap_gpio_save_context(void) void omap_gpio_restore_context(void) { struct gpio_bank *bank; - int i = 0; list_for_each_entry(bank, &omap_gpio_list, node) { - i++; if (!bank->loses_context) continue; - __raw_writel(gpio_context[i].irqenable1, + __raw_writel(bank->context.irqenable1, bank->base + OMAP24XX_GPIO_IRQENABLE1); - __raw_writel(gpio_context[i].irqenable2, + __raw_writel(bank->context.irqenable2, bank->base + OMAP24XX_GPIO_IRQENABLE2); - __raw_writel(gpio_context[i].wake_en, + __raw_writel(bank->context.wake_en, bank->base + OMAP24XX_GPIO_WAKE_EN); - __raw_writel(gpio_context[i].ctrl, + __raw_writel(bank->context.ctrl, bank->base + OMAP24XX_GPIO_CTRL); - __raw_writel(gpio_context[i].oe, + __raw_writel(bank->context.oe, bank->base + OMAP24XX_GPIO_OE); - __raw_writel(gpio_context[i].leveldetect0, + __raw_writel(bank->context.leveldetect0, bank->base + OMAP24XX_GPIO_LEVELDETECT0); - __raw_writel(gpio_context[i].leveldetect1, + __raw_writel(bank->context.leveldetect1, bank->base + OMAP24XX_GPIO_LEVELDETECT1); - __raw_writel(gpio_context[i].risingdetect, + __raw_writel(bank->context.risingdetect, bank->base + OMAP24XX_GPIO_RISINGDETECT); - __raw_writel(gpio_context[i].fallingdetect, + __raw_writel(bank->context.fallingdetect, bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(gpio_context[i].dataout, + __raw_writel(bank->context.dataout, bank->base + OMAP24XX_GPIO_DATAOUT); } } -- cgit From 60a3437dc9a61c7f4b199c2bac3dcc7b611b1178 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Thu, 29 Sep 2011 04:47:25 +0530 Subject: gpio/omap: handle save/restore context in GPIO driver Modify omap_gpio_prepare_for_idle() & omap_gpio_resume_after_idle() functions to handle save context & restore context respectively in the OMAP GPIO driver itself instead of calling these functions from pm specific files. For this, in gpio_prepare_for_idle(), call *_get_context_loss_count() and in gpio_resume_after_idle() call it again. If the count is different, do restore context. Signed-off-by: Charulatha V Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 131 +++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 73 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 6788c8a2a770..a1a3b9dca178 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -72,9 +72,11 @@ struct gpio_bank { bool loses_context; int stride; u32 width; + int context_loss_count; u16 id; 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; }; @@ -1179,6 +1181,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; bank->loses_context = pdata->loses_context; + bank->get_context_loss_count = pdata->get_context_loss_count; bank->regs = pdata->regs; if (bank->regs->set_dataout && bank->regs->clr_dataout) @@ -1323,11 +1326,11 @@ static struct syscore_ops omap_gpio_syscore_ops = { #ifdef CONFIG_ARCH_OMAP2PLUS -static int workaround_enabled; +static void omap_gpio_save_context(struct gpio_bank *bank); +static void omap_gpio_restore_context(struct gpio_bank *bank); void omap2_gpio_prepare_for_idle(int off_mode) { - int c = 0; struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { @@ -1347,7 +1350,7 @@ void omap2_gpio_prepare_for_idle(int off_mode) * non-wakeup GPIOs. Otherwise spurious IRQs will be * generated. See OMAP2420 Errata item 1.101. */ if (!(bank->enabled_non_wakeup_gpios)) - continue; + goto save_gpio_context; if (cpu_is_omap24xx() || cpu_is_omap34xx()) { bank->saved_datain = __raw_readl(bank->base + @@ -1384,13 +1387,13 @@ void omap2_gpio_prepare_for_idle(int off_mode) __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT); } - c++; - } - if (!c) { - workaround_enabled = 0; - return; +save_gpio_context: + if (bank->get_context_loss_count) + bank->context_loss_count = + bank->get_context_loss_count(bank->dev); + + omap_gpio_save_context(bank); } - workaround_enabled = 1; } void omap2_gpio_resume_after_idle(void) @@ -1398,6 +1401,7 @@ void omap2_gpio_resume_after_idle(void) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { + int context_lost_cnt_after; u32 l = 0, gen, gen0, gen1; int j; @@ -1407,8 +1411,13 @@ void omap2_gpio_resume_after_idle(void) for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) clk_enable(bank->dbck); - if (!workaround_enabled) - continue; + 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); + } if (!(bank->enabled_non_wakeup_gpios)) continue; @@ -1486,74 +1495,50 @@ void omap2_gpio_resume_after_idle(void) } } } - } -#endif - -#ifdef CONFIG_ARCH_OMAP3 -void omap_gpio_save_context(void) +static void omap_gpio_save_context(struct gpio_bank *bank) { - struct gpio_bank *bank; - - list_for_each_entry(bank, &omap_gpio_list, node) { - - if (!bank->loses_context) - continue; - - bank->context.irqenable1 = - __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1); - bank->context.irqenable2 = - __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2); - bank->context.wake_en = - __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN); - bank->context.ctrl = - __raw_readl(bank->base + OMAP24XX_GPIO_CTRL); - bank->context.oe = - __raw_readl(bank->base + OMAP24XX_GPIO_OE); - bank->context.leveldetect0 = - __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); - bank->context.leveldetect1 = - __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); - bank->context.risingdetect = - __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); - bank->context.fallingdetect = - __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); - bank->context.dataout = - __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT); - } + bank->context.irqenable1 = + __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1); + bank->context.irqenable2 = + __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2); + bank->context.wake_en = + __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN); + bank->context.ctrl = __raw_readl(bank->base + OMAP24XX_GPIO_CTRL); + bank->context.oe = __raw_readl(bank->base + OMAP24XX_GPIO_OE); + bank->context.leveldetect0 = + __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); + bank->context.leveldetect1 = + __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); + bank->context.risingdetect = + __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); + bank->context.fallingdetect = + __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); + bank->context.dataout = + __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT); } -void omap_gpio_restore_context(void) +static void omap_gpio_restore_context(struct gpio_bank *bank) { - struct gpio_bank *bank; - - list_for_each_entry(bank, &omap_gpio_list, node) { - - if (!bank->loses_context) - continue; - - __raw_writel(bank->context.irqenable1, - bank->base + OMAP24XX_GPIO_IRQENABLE1); - __raw_writel(bank->context.irqenable2, - bank->base + OMAP24XX_GPIO_IRQENABLE2); - __raw_writel(bank->context.wake_en, - bank->base + OMAP24XX_GPIO_WAKE_EN); - __raw_writel(bank->context.ctrl, - bank->base + OMAP24XX_GPIO_CTRL); - __raw_writel(bank->context.oe, - bank->base + OMAP24XX_GPIO_OE); - __raw_writel(bank->context.leveldetect0, - bank->base + OMAP24XX_GPIO_LEVELDETECT0); - __raw_writel(bank->context.leveldetect1, - bank->base + OMAP24XX_GPIO_LEVELDETECT1); - __raw_writel(bank->context.risingdetect, - bank->base + OMAP24XX_GPIO_RISINGDETECT); - __raw_writel(bank->context.fallingdetect, - bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(bank->context.dataout, - bank->base + OMAP24XX_GPIO_DATAOUT); - } + __raw_writel(bank->context.irqenable1, + bank->base + OMAP24XX_GPIO_IRQENABLE1); + __raw_writel(bank->context.irqenable2, + bank->base + OMAP24XX_GPIO_IRQENABLE2); + __raw_writel(bank->context.wake_en, + bank->base + OMAP24XX_GPIO_WAKE_EN); + __raw_writel(bank->context.ctrl, bank->base + OMAP24XX_GPIO_CTRL); + __raw_writel(bank->context.oe, bank->base + OMAP24XX_GPIO_OE); + __raw_writel(bank->context.leveldetect0, + bank->base + OMAP24XX_GPIO_LEVELDETECT0); + __raw_writel(bank->context.leveldetect1, + bank->base + OMAP24XX_GPIO_LEVELDETECT1); + __raw_writel(bank->context.risingdetect, + bank->base + OMAP24XX_GPIO_RISINGDETECT); + __raw_writel(bank->context.fallingdetect, + bank->base + OMAP24XX_GPIO_FALLINGDETECT); + __raw_writel(bank->context.dataout, + bank->base + OMAP24XX_GPIO_DATAOUT); } #endif -- cgit From 803a24343f94c3eaeed35e69efa12a576258ca70 Mon Sep 17 00:00:00 2001 From: Charulatha V Date: Thu, 5 May 2011 17:04:12 +0530 Subject: gpio/omap: make non-wakeup GPIO part of pdata Non-wakeup GPIOs are available only in OMAP2. Avoid cpu_is checks by making non_wakeup_gpios as part of pdata. Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index a1a3b9dca178..2eed159d964e 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1021,13 +1021,6 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) /* 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 (bank->id < ARRAY_SIZE(non_wakeup_gpios)) - bank->non_wakeup_gpios = - non_wakeup_gpios[bank->id]; } } else if (cpu_class_is_omap1()) { if (bank_is_mpuio(bank)) { @@ -1180,6 +1173,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; + 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; -- cgit From c8eef65a2fc311f8edca47f2e4ac2cccb70eb192 Mon Sep 17 00:00:00 2001 From: Charulatha V Date: Mon, 2 May 2011 15:21:42 +0530 Subject: gpio/omap: avoid cpu checks during module ena/disable Remove cpu-is checks while enabling/disabling OMAP GPIO module during a gpio request/free. Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 53 +++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 2eed159d964e..5cc2c04cd0a6 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -83,6 +83,7 @@ struct gpio_bank { #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 void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) { @@ -577,22 +578,18 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) __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->mod_usage |= 1 << offset; + spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -625,22 +622,18 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) __raw_writel(1 << offset, reg); } #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); } + _reset_gpio(bank, bank->chip.base + offset); spin_unlock_irqrestore(&bank->lock, flags); } -- cgit From 6ed87c5b66ca81996fae2dae6d1e702d66b9832b Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Tue, 13 Sep 2011 14:41:44 +0530 Subject: gpio/omap: further cleanup using wkup_en register Wakeup enable register offset initialized according to OMAP versions during device registration. Use this to avoid version checks. Starting with OMAP4, legacy registers should not be used in combination with the updated regsiters. Use wkup_en register consistently for all SoCs wherever applicable. Signed-off-by: Tarun Kanti DebBarma Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 110 +++++++++-------------------------------------- 1 file changed, 21 insertions(+), 89 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 5cc2c04cd0a6..3daedffbd707 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -51,9 +51,7 @@ struct gpio_bank { u16 virtual_irq_start; int method; 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; @@ -598,30 +596,15 @@ 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); - } -#endif + _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0); + bank->mod_usage &= ~(1 << offset); if (bank->regs->ctrl && !bank->mod_usage) { @@ -1071,8 +1054,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; @@ -1101,7 +1084,8 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) if (bank_is_mpuio(bank)) { bank->chip.label = "mpuio"; #ifdef CONFIG_ARCH_OMAP16XX - bank->chip.dev = &omap_mpuio_device.dev; + if (bank->regs->wkup_en) + bank->chip.dev = &omap_mpuio_device.dev; #endif bank->chip.base = OMAP_MPUIO(0); } else { @@ -1212,50 +1196,24 @@ err_exit: return ret; } -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) static int omap_gpio_suspend(void) { struct gpio_bank *bank; - if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) - return 0; - list_for_each_entry(bank, &omap_gpio_list, node) { + void __iomem *base = bank->base; 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) + return 0; + + wake_status = bank->base + bank->regs->wkup_en; 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); + _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); } @@ -1266,40 +1224,16 @@ static void omap_gpio_resume(void) { struct gpio_bank *bank; - if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) - return; - list_for_each_entry(bank, &omap_gpio_list, node) { - void __iomem *wake_clear; - void __iomem *wake_set; + void __iomem *base = bank->base; 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) + return; spin_lock_irqsave(&bank->lock, flags); - __raw_writel(0xffffffff, wake_clear); - __raw_writel(bank->saved_wakeup, wake_set); + _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); } } @@ -1309,8 +1243,6 @@ static struct syscore_ops omap_gpio_syscore_ops = { .resume = omap_gpio_resume, }; -#endif - #ifdef CONFIG_ARCH_OMAP2PLUS static void omap_gpio_save_context(struct gpio_bank *bank); -- cgit From 9ea14d8cbbf1c8fc941e8e8a12aa0a3edc5c336e Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Tue, 30 Aug 2011 15:05:44 +0530 Subject: gpio/omap: use level/edge detect reg offsets By adding level and edge detection register offsets and then initializing them correctly according to OMAP versions during device registrations we can now remove lot of revision checks in these functions. Signed-off-by: Tarun Kanti DebBarma Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 114 +++++++++++++---------------------------------- 1 file changed, 32 insertions(+), 82 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 3daedffbd707..991dd39f6eda 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -257,15 +257,9 @@ 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); - } + bank->level_mask = + __raw_readl(bank->base + bank->regs->leveldetect0) | + __raw_readl(bank->base + bank->regs->leveldetect1); } #endif @@ -405,12 +399,12 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) 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))) + bank = irq_data_get_irq_chip_data(d); + + 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); @@ -658,9 +652,8 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) 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 @@ -1271,40 +1264,18 @@ void omap2_gpio_prepare_for_idle(int off_mode) if (!(bank->enabled_non_wakeup_gpios)) goto save_gpio_context; - 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); - } - - 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); - } + 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); bank->saved_fallingdetect = l1; bank->saved_risingdetect = l2; l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; - if (cpu_is_omap24xx() || cpu_is_omap34xx()) { - __raw_writel(l1, bank->base + - OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(l2, bank->base + - OMAP24XX_GPIO_RISINGDETECT); - } - - if (cpu_is_omap44xx()) { - __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT); - __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT); - } + __raw_writel(l1, bank->base + bank->regs->fallingdetect); + __raw_writel(l2, bank->base + bank->regs->risingdetect); save_gpio_context: if (bank->get_context_loss_count) @@ -1341,21 +1312,11 @@ void omap2_gpio_resume_after_idle(void) if (!(bank->enabled_non_wakeup_gpios)) continue; - 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); - } - - 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); - } + __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); /* Check if any of the non-wakeup interrupt GPIOs have changed * state. If so, generate an IRQ by software. This is @@ -1383,35 +1344,24 @@ void omap2_gpio_resume_after_idle(void) 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()) { - 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); + old0 |= gen; + old1 |= gen; } 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); + old0 |= l; + old1 |= l; } + __raw_writel(old0, bank->base + + bank->regs->leveldetect0); + __raw_writel(old1, bank->base + + bank->regs->leveldetect1); } } } -- cgit From ae10f2336b9c0c8da73da2878eba684ab876eb8f Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Tue, 30 Aug 2011 15:24:27 +0530 Subject: gpio/omap: remove hardcoded offsets in context save/restore It is not required to use hard-coded offsets any more in context save and restore functions and instead use the generic offsets which have been correctly initialized during device registration. Signed-off-by: Tarun Kanti DebBarma Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 991dd39f6eda..ceb9edf16dab 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1369,45 +1369,43 @@ void omap2_gpio_resume_after_idle(void) static void omap_gpio_save_context(struct gpio_bank *bank) { bank->context.irqenable1 = - __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1); + __raw_readl(bank->base + bank->regs->irqenable); bank->context.irqenable2 = - __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2); + __raw_readl(bank->base + bank->regs->irqenable2); bank->context.wake_en = - __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN); - bank->context.ctrl = __raw_readl(bank->base + OMAP24XX_GPIO_CTRL); - bank->context.oe = __raw_readl(bank->base + OMAP24XX_GPIO_OE); + __raw_readl(bank->base + bank->regs->wkup_en); + bank->context.ctrl = __raw_readl(bank->base + bank->regs->ctrl); + bank->context.oe = __raw_readl(bank->base + bank->regs->direction); bank->context.leveldetect0 = - __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); + __raw_readl(bank->base + bank->regs->leveldetect0); bank->context.leveldetect1 = - __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); + __raw_readl(bank->base + bank->regs->leveldetect1); bank->context.risingdetect = - __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); + __raw_readl(bank->base + bank->regs->risingdetect); bank->context.fallingdetect = - __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); - bank->context.dataout = - __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT); + __raw_readl(bank->base + bank->regs->fallingdetect); + bank->context.dataout = __raw_readl(bank->base + bank->regs->dataout); } static void omap_gpio_restore_context(struct gpio_bank *bank) { __raw_writel(bank->context.irqenable1, - bank->base + OMAP24XX_GPIO_IRQENABLE1); + bank->base + bank->regs->irqenable); __raw_writel(bank->context.irqenable2, - bank->base + OMAP24XX_GPIO_IRQENABLE2); + bank->base + bank->regs->irqenable2); __raw_writel(bank->context.wake_en, - bank->base + OMAP24XX_GPIO_WAKE_EN); - __raw_writel(bank->context.ctrl, bank->base + OMAP24XX_GPIO_CTRL); - __raw_writel(bank->context.oe, bank->base + OMAP24XX_GPIO_OE); + bank->base + bank->regs->wkup_en); + __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl); + __raw_writel(bank->context.oe, bank->base + bank->regs->direction); __raw_writel(bank->context.leveldetect0, - bank->base + OMAP24XX_GPIO_LEVELDETECT0); + bank->base + bank->regs->leveldetect0); __raw_writel(bank->context.leveldetect1, - bank->base + OMAP24XX_GPIO_LEVELDETECT1); + bank->base + bank->regs->leveldetect1); __raw_writel(bank->context.risingdetect, - bank->base + OMAP24XX_GPIO_RISINGDETECT); + bank->base + bank->regs->risingdetect); __raw_writel(bank->context.fallingdetect, - bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(bank->context.dataout, - bank->base + OMAP24XX_GPIO_DATAOUT); + bank->base + bank->regs->fallingdetect); + __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout); } #endif -- cgit From 5e571f38f6a44ef541fac0821631509d787ef0cd Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Tue, 13 Sep 2011 15:02:14 +0530 Subject: gpio/omap: cleanup set_gpio_triggering function Getting rid of ifdefs within the function by adding register offset intctrl and associating OMAPXXXX_GPIO_INT_CONTROL in respective SoC specific files. Also, use wkup_status register consistently instead of referring to wakeup clear and wakeup set register offsets. Get rid of cpu_is_xxxx checks in set_gpio_trigger() using irqctrl. Signed-off-by: Charulatha V Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 157 +++++++++++++---------------------------------- 1 file changed, 43 insertions(+), 114 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index ceb9edf16dab..f39d9e4967b2 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -199,52 +199,32 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, __raw_writel(val, reg); } -#ifdef CONFIG_ARCH_OMAP2PLUS -static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, +static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, int 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); - } - 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->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); + + if (likely(!(bank->non_wakeup_gpios & gpio_bit))) + _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); + /* 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 @@ -257,11 +237,11 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, bank->enabled_non_wakeup_gpios &= ~gpio_bit; } +exit: bank->level_mask = __raw_readl(bank->base + bank->regs->leveldetect0) | __raw_readl(bank->base + bank->regs->leveldetect1); } -#endif #ifdef CONFIG_ARCH_OMAP1 /* @@ -273,23 +253,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) @@ -299,31 +266,21 @@ 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) { 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; @@ -332,15 +289,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)); @@ -348,40 +305,12 @@ 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); + __raw_writel(l, reg); } - __raw_writel(l, reg); return 0; -bad: - return -EINVAL; } static int gpio_irq_type(struct irq_data *d, unsigned type) -- cgit From ab985f0f7c2c0ef90b7c832f0c04f470dda0593d Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Tue, 13 Sep 2011 15:12:05 +0530 Subject: gpio/omap: cleanup omap_gpio_mod_init function With register offsets now defined for respective OMAP versions we can get rid of cpu_class_* checks. This function now has common initialization code for all OMAP versions. Initialization specific to OMAP16xx has been moved within omap16xx_gpio_init(). Signed-off-by: Tarun Kanti DebBarma Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 77 +++++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 54 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f39d9e4967b2..a948351ad6c4 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -610,7 +610,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (!(isr & 1)) continue; -#ifdef CONFIG_ARCH_OMAP1 /* * Some chips can't respond to both rising and falling * at the same time. If this irq was requested with @@ -620,7 +619,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); } @@ -898,62 +896,30 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank) */ static struct lock_class_key gpio_lock_class; -/* TODO: Cleanup cpu_is_* checks */ static void omap_gpio_mod_init(struct gpio_bank *bank) { - 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_class_is_omap1()) { - if (bank_is_mpuio(bank)) { - __raw_writew(0xffff, bank->base + - OMAP_MPUIO_GPIO_MASKIT / bank->stride); - mpuio_init(bank); - } - 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); + void __iomem *base = bank->base; + u32 l = 0xffffffff; - /* - * 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->width == 16) + l = 0xffff; + + if (bank_is_mpuio(bank)) { + __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); + + /* Initialize interface clk ungated, module enabled */ + if (bank->regs->ctrl) + _gpio_rmw(base, bank->regs->ctrl, 0, 1); } static __init void @@ -1104,6 +1070,9 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) pm_runtime_enable(bank->dev); pm_runtime_get_sync(bank->dev); + if (bank_is_mpuio(bank)) + mpuio_init(bank); + omap_gpio_mod_init(bank); omap_gpio_chip_init(bank); omap_gpio_show_rev(bank); -- cgit From fad96ea825e7a8ee0c5b77292b470e4978157ee7 Mon Sep 17 00:00:00 2001 From: Charulatha V Date: Wed, 25 May 2011 11:23:50 +0530 Subject: gpio/omap: use pinctrl offset instead of macro Use regs->pinctrl field instead of using the macro OMAP1510_GPIO_PIN_CONTROL Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index a948351ad6c4..485b6b207ef9 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -490,15 +490,13 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) */ _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 (bank->regs->ctrl && !bank->mod_usage) { void __iomem *reg = bank->base + bank->regs->ctrl; u32 ctrl; -- cgit From d3901eaf1fc289e8175faa8c7c460d542b6eb7dd Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Tue, 27 Sep 2011 05:38:09 +0530 Subject: gpio/omap: remove unnecessary bit-masking for read access Remove un-necessary bit masking. Since the register are 4 byte aligned and readl would work as is. The 'enabled' mask is already taking care to mask for bank width. Signed-off-by: Charulatha V Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 485b6b207ef9..38beccc9e655 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -576,9 +576,6 @@ 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 (bank->level_mask) level_mask = bank->level_mask & enabled; -- cgit From d0d665a896c5b9a0aa60e8bac15c270cb59aa9e7 Mon Sep 17 00:00:00 2001 From: Charulatha V Date: Wed, 31 Aug 2011 00:02:21 +0530 Subject: gpio/omap: remove bank->method & METHOD_* macros The only bank->type (method) used in the OMAP GPIO driver is MPUIO type as they need to be handled separately. Identify the same using a flag and remove all METHOD_* macros. mpuio_init() function is defined under #ifdefs. It is required only in case of MPUIO bank type and only when PM operations are supported by it. This is applicable only in case of OMAP16xx SoC's MPUIO GPIO bank type. For all the other cases it is a dummy function. Hence clean up the same and remove all the OMAP SoC specific #ifdefs. Signed-off-by: Charulatha V Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 38beccc9e655..951d78435812 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -49,7 +49,6 @@ struct gpio_bank { void __iomem *base; u16 irq; u16 virtual_irq_start; - int method; u32 suspend_wakeup; u32 saved_wakeup; u32 non_wakeup_gpios; @@ -66,6 +65,7 @@ struct gpio_bank { u32 mod_usage; u32 dbck_enable_mask; struct device *dev; + bool is_mpuio; bool dbck_flag; bool loses_context; int stride; @@ -693,14 +693,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 - static int omap_mpuio_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -762,23 +754,8 @@ static inline void mpuio_init(struct gpio_bank *bank) (void) platform_device_register(&omap_mpuio_device); } -#else -static inline void mpuio_init(struct gpio_bank *bank) {} -#endif /* 16xx */ - -#else - -#define bank_is_mpuio(bank) 0 -static inline void mpuio_init(struct gpio_bank *bank) {} - -#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; @@ -899,7 +876,7 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) if (bank->width == 16) l = 0xffff; - if (bank_is_mpuio(bank)) { + if (bank->is_mpuio) { __raw_writel(l, bank->base + bank->regs->irqenable); return; } @@ -951,7 +928,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 @@ -964,12 +940,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 if (bank->regs->wkup_en) bank->chip.dev = &omap_mpuio_device.dev; -#endif bank->chip.base = OMAP_MPUIO(0); } else { bank->chip.label = "gpio"; @@ -984,7 +958,7 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) j < bank->virtual_irq_start + 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); @@ -1028,11 +1002,11 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; bank->virtual_irq_start = pdata->virtual_irq_start; - bank->method = pdata->bank_type; bank->dev = &pdev->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; @@ -1065,7 +1039,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) pm_runtime_enable(bank->dev); pm_runtime_get_sync(bank->dev); - if (bank_is_mpuio(bank)) + if (bank->is_mpuio) mpuio_init(bank); omap_gpio_mod_init(bank); -- cgit From 55b93c32520dc7ff0097db81db9b1e6b735951a9 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Thu, 29 Sep 2011 07:23:22 +0530 Subject: gpio/omap: use pm-runtime framework Call runtime pm APIs pm_runtime_get_sync() and pm_runtime_put() for enabling/disabling clocks appropriately. Remove syscore_ops and instead use SET_RUNTIME_PM_OPS macro. There is no more need to call omap_device_disable_idle_on_suspend since driver is PM runtime adapted now. Signed-off-by: Charulatha V Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 68 +++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 24 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 951d78435812..7e1e50c23f93 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -483,8 +484,14 @@ 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(). */ @@ -540,6 +547,13 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) _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); } /* @@ -565,6 +579,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; @@ -625,6 +640,7 @@ 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) @@ -1037,6 +1053,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) } pm_runtime_enable(bank->dev); + pm_runtime_irq_safe(bank->dev); pm_runtime_get_sync(bank->dev); if (bank->is_mpuio) @@ -1046,6 +1063,8 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) omap_gpio_chip_init(bank); omap_gpio_show_rev(bank); + pm_runtime_put(bank->dev); + list_add_tail(&bank->node, &omap_gpio_list); return ret; @@ -1056,7 +1075,10 @@ err_exit: return ret; } -static int omap_gpio_suspend(void) +#ifdef CONFIG_ARCH_OMAP2PLUS + +#if defined(CONFIG_PM_SLEEP) +static int omap_gpio_suspend(struct device *dev) { struct gpio_bank *bank; @@ -1080,7 +1102,7 @@ static int omap_gpio_suspend(void) return 0; } -static void omap_gpio_resume(void) +static int omap_gpio_resume(struct device *dev) { struct gpio_bank *bank; @@ -1089,21 +1111,17 @@ static void omap_gpio_resume(void) unsigned long flags; if (!bank->regs->wkup_en) - return; + return 0; 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); } -} - -static struct syscore_ops omap_gpio_syscore_ops = { - .suspend = omap_gpio_suspend, - .resume = omap_gpio_resume, -}; -#ifdef CONFIG_ARCH_OMAP2PLUS + return 0; +} +#endif /* CONFIG_PM_SLEEP */ static void omap_gpio_save_context(struct gpio_bank *bank); static void omap_gpio_restore_context(struct gpio_bank *bank); @@ -1145,11 +1163,15 @@ void omap2_gpio_prepare_for_idle(int off_mode) __raw_writel(l2, bank->base + bank->regs->risingdetect); save_gpio_context: + if (bank->get_context_loss_count) bank->context_loss_count = bank->get_context_loss_count(bank->dev); omap_gpio_save_context(bank); + + if (!pm_runtime_suspended(bank->dev)) + pm_runtime_put(bank->dev); } } @@ -1168,6 +1190,9 @@ void omap2_gpio_resume_after_idle(void) for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) clk_enable(bank->dbck); + if (pm_runtime_suspended(bank->dev)) + pm_runtime_get_sync(bank->dev); + if (bank->get_context_loss_count) { context_lost_cnt_after = bank->get_context_loss_count(bank->dev); @@ -1274,12 +1299,20 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) bank->base + bank->regs->fallingdetect); __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout); } +#else +#define omap_gpio_suspend NULL +#define omap_gpio_resume NULL #endif +static const struct dev_pm_ops gpio_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) +}; + static struct platform_driver omap_gpio_driver = { .probe = omap_gpio_probe, .driver = { .name = "omap_gpio", + .pm = &gpio_pm_ops, }, }; @@ -1293,16 +1326,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) -{ - -#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); -- cgit From 065cd795d2721f8d2d1f2967ee6ed0aec07a4202 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Thu, 24 Nov 2011 01:48:52 +0530 Subject: gpio/omap: optimize suspend and resume functions There is no need to operate on all the banks every time the function is called. Just operate on the current bank passed by the framework. Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 54 ++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 7e1e50c23f93..e9a30fa8715b 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1052,6 +1052,8 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) goto err_free; } + platform_set_drvdata(pdev, bank); + pm_runtime_enable(bank->dev); pm_runtime_irq_safe(bank->dev); pm_runtime_get_sync(bank->dev); @@ -1080,44 +1082,46 @@ err_exit: #if defined(CONFIG_PM_SLEEP) static int omap_gpio_suspend(struct device *dev) { - struct gpio_bank *bank; + 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; - list_for_each_entry(bank, &omap_gpio_list, node) { - void __iomem *base = bank->base; - void __iomem *wake_status; - unsigned long flags; + if (!bank->mod_usage || !bank->loses_context) + return 0; - if (!bank->regs->wkup_en) - return 0; + if (!bank->regs->wkup_en || !bank->suspend_wakeup) + return 0; - wake_status = bank->base + bank->regs->wkup_en; + wakeup_enable = bank->base + bank->regs->wkup_en; - spin_lock_irqsave(&bank->lock, flags); - bank->saved_wakeup = __raw_readl(wake_status); - _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); - } + 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 int omap_gpio_resume(struct device *dev) { - struct gpio_bank *bank; + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = platform_get_drvdata(pdev); + void __iomem *base = bank->base; + unsigned long flags; - list_for_each_entry(bank, &omap_gpio_list, node) { - void __iomem *base = bank->base; - unsigned long flags; + if (!bank->mod_usage || !bank->loses_context) + return 0; - if (!bank->regs->wkup_en) - return 0; + if (!bank->regs->wkup_en || !bank->saved_wakeup) + return 0; - 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); - } + 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; } -- cgit From 2dc983c565e03f6f6f96c5fe7449b65d86af4dee Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Thu, 24 Nov 2011 02:44:29 +0530 Subject: gpio/omap: cleanup prepare_for_idle and resume_after_idle Since *_prepare_for_idle() and *_resume_after_idle() are called with interrupts disabled they should be kept as simple as possible. So, moving most of the stuff to *_runtime_suspend/resume() callbacks. To avoid invalid context restore happening in *_runtime_resume() callback as a result of *_get_sync() call in *_gpio_probe(), update bank->context_loss_count. This would make context restore condition check false in the callback and skip restore until further initialization take place. The workaround_enabled static variable is now a member of struct gpio_bank. Unlike most GPIO registers the OE has 0xffffffff as the default value. To make sure invalid context is not restored, updating the OE context with default value. Signed-off-by: Tarun Kanti DebBarma Signed-off-by: Charulatha V Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 245 ++++++++++++++++++++++++++++------------------- 1 file changed, 147 insertions(+), 98 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index e9a30fa8715b..d483cc9f0c63 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -29,6 +29,8 @@ #include #include +#define OFF_MODE 1 + static LIST_HEAD(omap_gpio_list); struct gpio_regs { @@ -73,6 +75,8 @@ struct gpio_bank { u32 width; int context_loss_count; u16 id; + 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); @@ -905,6 +909,8 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) 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); @@ -1127,141 +1133,179 @@ static int omap_gpio_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ +#if defined(CONFIG_PM_RUNTIME) static void omap_gpio_save_context(struct gpio_bank *bank); static void omap_gpio_restore_context(struct gpio_bank *bank); -void omap2_gpio_prepare_for_idle(int off_mode) +static int omap_gpio_runtime_suspend(struct device *dev) { - struct gpio_bank *bank; - - list_for_each_entry(bank, &omap_gpio_list, node) { - u32 l1 = 0, l2 = 0; - int j; - - if (!bank->loses_context) - continue; - - for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) - clk_disable(bank->dbck); + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = platform_get_drvdata(pdev); + u32 l1 = 0, l2 = 0; + unsigned long flags; - if (!off_mode) - continue; + spin_lock_irqsave(&bank->lock, flags); + if (bank->power_mode != OFF_MODE) { + bank->power_mode = 0; + goto save_gpio_context; + } + /* + * 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)) + goto save_gpio_context; - /* 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)) - goto save_gpio_context; + 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); - 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); + bank->saved_fallingdetect = l1; + bank->saved_risingdetect = l2; + l1 &= ~bank->enabled_non_wakeup_gpios; + l2 &= ~bank->enabled_non_wakeup_gpios; - bank->saved_fallingdetect = l1; - bank->saved_risingdetect = l2; - l1 &= ~bank->enabled_non_wakeup_gpios; - l2 &= ~bank->enabled_non_wakeup_gpios; + __raw_writel(l1, bank->base + bank->regs->fallingdetect); + __raw_writel(l2, bank->base + bank->regs->risingdetect); - __raw_writel(l1, bank->base + bank->regs->fallingdetect); - __raw_writel(l2, bank->base + bank->regs->risingdetect); + bank->workaround_enabled = true; save_gpio_context: - - if (bank->get_context_loss_count) - bank->context_loss_count = + if (bank->get_context_loss_count) + bank->context_loss_count = bank->get_context_loss_count(bank->dev); - omap_gpio_save_context(bank); + omap_gpio_save_context(bank); + spin_unlock_irqrestore(&bank->lock, flags); - if (!pm_runtime_suspended(bank->dev)) - pm_runtime_put(bank->dev); - } + return 0; } -void omap2_gpio_resume_after_idle(void) +static int omap_gpio_runtime_resume(struct device *dev) { - struct gpio_bank *bank; - - list_for_each_entry(bank, &omap_gpio_list, node) { - int context_lost_cnt_after; - u32 l = 0, gen, gen0, gen1; - int j; - - if (!bank->loses_context) - continue; - - for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) - clk_enable(bank->dbck); + 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 (pm_runtime_suspended(bank->dev)) - pm_runtime_get_sync(bank->dev); + spin_lock_irqsave(&bank->lock, flags); + if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) { + spin_unlock_irqrestore(&bank->lock, flags); + return 0; + } - 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); + 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; } + } - if (!(bank->enabled_non_wakeup_gpios)) - continue; + __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); - __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); + /* + * 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; - /* 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; - /* - * 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); - 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; - /* 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 (gen) { - u32 old0, old1; + old0 = __raw_readl(bank->base + bank->regs->leveldetect0); + old1 = __raw_readl(bank->base + bank->regs->leveldetect1); - old0 = __raw_readl(bank->base + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + __raw_writel(old0 | gen, bank->base + bank->regs->leveldetect0); - old1 = __raw_readl(bank->base + + __raw_writel(old1 | gen, bank->base + bank->regs->leveldetect1); + } - if (cpu_is_omap24xx() || cpu_is_omap34xx()) { - old0 |= gen; - old1 |= gen; - } - - if (cpu_is_omap44xx()) { - old0 |= l; - old1 |= l; - } - __raw_writel(old0, bank->base + + if (cpu_is_omap44xx()) { + __raw_writel(old0 | l, bank->base + bank->regs->leveldetect0); - __raw_writel(old1, bank->base + + __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 */ + +void omap2_gpio_prepare_for_idle(int pwr_mode) +{ + struct gpio_bank *bank; + + list_for_each_entry(bank, &omap_gpio_list, node) { + int j; + + if (!bank->mod_usage || !bank->loses_context) + continue; + + bank->power_mode = pwr_mode; + + for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) + clk_disable(bank->dbck); + + pm_runtime_put_sync_suspend(bank->dev); + } +} + +void omap2_gpio_resume_after_idle(void) +{ + struct gpio_bank *bank; + + list_for_each_entry(bank, &omap_gpio_list, node) { + int j; + + if (!bank->mod_usage || !bank->loses_context) + continue; + + for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) + clk_enable(bank->dbck); + + pm_runtime_get_sync(bank->dev); } } +#if defined(CONFIG_PM_RUNTIME) static void omap_gpio_save_context(struct gpio_bank *bank) { bank->context.irqenable1 = @@ -1303,13 +1347,18 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) bank->base + bank->regs->fallingdetect); __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout); } +#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) }; static struct platform_driver omap_gpio_driver = { -- cgit From 72f83af99838bb663f85b65386db5b875748f379 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Thu, 24 Nov 2011 03:03:28 +0530 Subject: gpio/omap: fix debounce clock handling The dbck_enable_mask indicates which all GPIOs within a bank have debounce enabled and dbck is enabled/disabled based upon this. But there is no mechanism to track the dbck state. In order to manage the dbck state we need additional flag and logic so that turning off/on dbck is synchronized with pm_runtime_put/get_sync calls. Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index d483cc9f0c63..69e61aecab71 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -67,6 +67,7 @@ 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; @@ -158,6 +159,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 @@ -1178,6 +1195,7 @@ save_gpio_context: bank->get_context_loss_count(bank->dev); omap_gpio_save_context(bank); + _gpio_dbck_disable(bank); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -1192,6 +1210,7 @@ static int omap_gpio_runtime_resume(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); + _gpio_dbck_enable(bank); if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) { spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -1274,16 +1293,11 @@ void omap2_gpio_prepare_for_idle(int pwr_mode) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { - int j; - if (!bank->mod_usage || !bank->loses_context) continue; bank->power_mode = pwr_mode; - for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) - clk_disable(bank->dbck); - pm_runtime_put_sync_suspend(bank->dev); } } @@ -1293,14 +1307,9 @@ void omap2_gpio_resume_after_idle(void) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { - int j; - if (!bank->mod_usage || !bank->loses_context) continue; - for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) - clk_enable(bank->dbck); - pm_runtime_get_sync(bank->dev); } } -- cgit From 6fd9c421649961a9d6d30b149e0128dde1b806b4 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Thu, 24 Nov 2011 03:58:54 +0530 Subject: gpio/omap: fix incorrect access of debounce module Enable debounce clock before writing/reading debounce registers. Disable the clock at the end so that it is synchronized with the pm_runtime_get/put_sync calls. 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. Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 69e61aecab71..8aeb8dd4342b 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -203,22 +203,30 @@ 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); } static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, -- cgit From 41d87cbd660fd5793a6c70f9c93d9dcc8964179d Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Tue, 15 Nov 2011 12:52:38 +0530 Subject: gpio/omap: remove omap_gpio_save_context overhead Context is now saved dynamically in respective functions whenever and whichever registers are modified. This avoid overhead of saving all registers context in the runtime suspend callback. Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 56 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 8aeb8dd4342b..62c49e0f7f29 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -101,6 +101,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; } @@ -131,6 +132,7 @@ 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) @@ -244,8 +246,20 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, _gpio_rmw(base, bank->regs->fallingdetect, gpio_bit, trigger & IRQ_TYPE_EDGE_FALLING); - if (likely(!(bank->non_wakeup_gpios & gpio_bit))) + 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))) { _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 (!bank->regs->irqctrl) { @@ -338,6 +352,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) /* 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); } return 0; @@ -430,6 +446,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) } __raw_writel(l, reg); + bank->context.irqenable1 = l; } static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) @@ -450,6 +467,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) } __raw_writel(l, reg); + bank->context.irqenable1 = l; } static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) @@ -541,6 +559,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) /* 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; @@ -558,9 +577,12 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&bank->lock, flags); - if (bank->regs->wkup_en) + if (bank->regs->wkup_en) { /* Disable wake-up during idle for dynamic tick */ _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0); + bank->context.wake_en = + __raw_readl(bank->base + bank->regs->wkup_en); + } bank->mod_usage &= ~(1 << offset); @@ -572,6 +594,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) /* 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); @@ -1159,7 +1182,6 @@ static int omap_gpio_resume(struct device *dev) #endif /* CONFIG_PM_SLEEP */ #if defined(CONFIG_PM_RUNTIME) -static void omap_gpio_save_context(struct gpio_bank *bank); static void omap_gpio_restore_context(struct gpio_bank *bank); static int omap_gpio_runtime_suspend(struct device *dev) @@ -1172,7 +1194,7 @@ static int omap_gpio_runtime_suspend(struct device *dev) spin_lock_irqsave(&bank->lock, flags); if (bank->power_mode != OFF_MODE) { bank->power_mode = 0; - goto save_gpio_context; + goto update_gpio_context_count; } /* * If going to OFF, remove triggering for all @@ -1180,7 +1202,7 @@ static int omap_gpio_runtime_suspend(struct device *dev) * generated. See OMAP2420 Errata item 1.101. */ if (!(bank->enabled_non_wakeup_gpios)) - goto save_gpio_context; + goto update_gpio_context_count; bank->saved_datain = __raw_readl(bank->base + bank->regs->datain); @@ -1197,12 +1219,11 @@ static int omap_gpio_runtime_suspend(struct device *dev) bank->workaround_enabled = true; -save_gpio_context: +update_gpio_context_count: if (bank->get_context_loss_count) bank->context_loss_count = bank->get_context_loss_count(bank->dev); - omap_gpio_save_context(bank); _gpio_dbck_disable(bank); spin_unlock_irqrestore(&bank->lock, flags); @@ -1323,27 +1344,6 @@ void omap2_gpio_resume_after_idle(void) } #if defined(CONFIG_PM_RUNTIME) -static void omap_gpio_save_context(struct gpio_bank *bank) -{ - bank->context.irqenable1 = - __raw_readl(bank->base + bank->regs->irqenable); - bank->context.irqenable2 = - __raw_readl(bank->base + bank->regs->irqenable2); - bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); - bank->context.ctrl = __raw_readl(bank->base + bank->regs->ctrl); - bank->context.oe = __raw_readl(bank->base + bank->regs->direction); - 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); - bank->context.dataout = __raw_readl(bank->base + bank->regs->dataout); -} - static void omap_gpio_restore_context(struct gpio_bank *bank) { __raw_writel(bank->context.irqenable1, -- cgit From ae547354a8ed59f19b57f7e1de9c7816edfc3537 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 9 Sep 2011 19:08:58 +0530 Subject: gpio/omap: save and restore debounce registers GPIO debounce registers need to be saved and restored for proper functioning of driver. Signed-off-by: Nishanth Menon tarun.kanti@ti.com: Debounce context save is moved to _set_gpio_debounce() as part of dynamic context save to remove overhead. Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 62c49e0f7f29..f6b2c51b2935 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -44,6 +44,8 @@ struct gpio_regs { u32 risingdetect; u32 fallingdetect; u32 dataout; + u32 debounce; + u32 debounce_en; }; struct gpio_bank { @@ -229,6 +231,10 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, * 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; + } } static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, @@ -1363,6 +1369,12 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) __raw_writel(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout); + 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); + } } #endif /* CONFIG_PM_RUNTIME */ #else -- cgit From ba805be53cb9112917631d368f859af5e20d695f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Aug 2011 18:41:08 +0530 Subject: gpio/omap: enable irq at the end of all configuration in restore Setup the interrupt enable registers only after we have configured the required edge and required configurations, not before, to prevent spurious events as part of restore routine. Signed-off-by: Nishanth Menon Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f6b2c51b2935..41265e823b23 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1352,10 +1352,6 @@ void omap2_gpio_resume_after_idle(void) #if defined(CONFIG_PM_RUNTIME) static void omap_gpio_restore_context(struct gpio_bank *bank) { - __raw_writel(bank->context.irqenable1, - bank->base + bank->regs->irqenable); - __raw_writel(bank->context.irqenable2, - bank->base + bank->regs->irqenable2); __raw_writel(bank->context.wake_en, bank->base + bank->regs->wkup_en); __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl); @@ -1375,6 +1371,11 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) __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 -- cgit From 6d13eaaf33436e20d1a41122f28434bcc37999dc Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Aug 2011 18:54:50 +0530 Subject: gpio/omap: restore OE only after setting the output level Setup the dataout register before restoring OE. This is to make sure that we have valid data in dataout register which would be made available in output pins as soon as OE is enabled. Else, there is risk of unknown data getting out into gpio pins. Signed-off-by: Nishanth Menon Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 41265e823b23..e0fd2e4b2b9c 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1355,7 +1355,6 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) __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.oe, bank->base + bank->regs->direction); __raw_writel(bank->context.leveldetect0, bank->base + bank->regs->leveldetect0); __raw_writel(bank->context.leveldetect1, @@ -1365,6 +1364,8 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) __raw_writel(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); __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); -- cgit From f86bcc302a8c570dd0f5a50097a6af96a0e717c2 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 9 Sep 2011 19:14:08 +0530 Subject: gpio/omap: handle set_dataout reg capable IP on restore GPIO IP revisions such as those used in OMAP4 have a set_dataout while the previous revisions used a single dataout register. Depending on what is available restore the dataout settings to the right register. Signed-off-by: Nishanth Menon Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index e0fd2e4b2b9c..f49bd6f47a50 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1363,7 +1363,12 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) bank->base + bank->regs->risingdetect); __raw_writel(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); - __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout); + 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) { -- cgit From 6f74dc9bc8de41f3de474a7269a70921e773c40f Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Jan 2012 08:39:37 +0000 Subject: gpio: tegra: Dynamically allocate IRQ base, and support DT Enhance the driver to dynamically allocate the base IRQ number, and create an IRQ domain for itself. The use of an IRQ domain ensures that any device tree node interrupts properties are correctly parsed. Describe interrupt-related properties in the device tree binding docs, and the contents of "child" node interrupts property. Update tegra*.dtsi to specify the required interrupt-related properties. Finally, remove the definition of TEGRA_GPIO_TO_IRQ; this macro no longer gives correct results since the IRQ numbers for GPIOs are dynamically allocated. Signed-off-by: Stephen Warren Acked-by: Grant Likely Signed-off-by: Olof Johansson --- drivers/gpio/gpio-tegra.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index bdc293791590..bc923c7acce9 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -74,7 +75,7 @@ struct tegra_gpio_bank { #endif }; - +static struct irq_domain irq_domain; static void __iomem *regs; static struct tegra_gpio_bank tegra_gpio_banks[7]; @@ -139,7 +140,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_domain_to_irq(&irq_domain, offset); } static struct gpio_chip tegra_gpio_chip = { @@ -155,28 +156,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; @@ -343,6 +344,16 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) int i; int j; + irq_domain.irq_base = irq_alloc_descs(-1, 0, TEGRA_NR_GPIOS, 0); + if (irq_domain.irq_base < 0) { + dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } + irq_domain.nr_irq = TEGRA_NR_GPIOS; + irq_domain.ops = &irq_domain_simple_ops; + irq_domain.of_node = pdev->dev.of_node; + irq_domain_add(&irq_domain); + for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { @@ -381,7 +392,7 @@ 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); + int irq = irq_domain_to_irq(&irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; -- cgit From 3391811c4294da42e412ec5f83a251caf05869a4 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 19 Jan 2012 08:16:35 +0000 Subject: gpio: tegra: Parameterize the number of banks Tegra20's GPIO controller has 7 banks, and Tegra30's controller has 8 banks. Allow the number of banks to be configured at run-time by the device tree. Signed-off-by: Stephen Warren Acked-by: Grant Likely Signed-off-by: Olof Johansson --- drivers/gpio/gpio-tegra.c | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index bc923c7acce9..98f3980dab7c 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -77,7 +77,8 @@ struct tegra_gpio_bank { 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) { @@ -274,7 +275,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++) { @@ -297,7 +298,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++) { @@ -338,23 +339,46 @@ 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; - irq_domain.irq_base = irq_alloc_descs(-1, 0, TEGRA_NR_GPIOS, 0); - if (irq_domain.irq_base < 0) { + 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.nr_irq = TEGRA_NR_GPIOS; + irq_domain.irq_base = irq_base; + irq_domain.nr_irq = tegra_gpio_chip.ngpio; irq_domain.ops = &irq_domain_simple_ops; irq_domain.of_node = pdev->dev.of_node; irq_domain_add(&irq_domain); - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + 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"); @@ -391,7 +415,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); - for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) { + for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { int irq = irq_domain_to_irq(&irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ @@ -404,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); -- cgit From 864533ceb6db336dead389577c102a8b792a121a Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 13 Feb 2012 22:53:20 +0800 Subject: Fix circular locking dependency (3.3-rc2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hi, On Wed, Feb 8, 2012 at 8:41 PM, Felipe Balbi wrote: > Hi guys, > > I have just triggered the folllowing: > > [   84.860321] ====================================================== > [   84.860321] [ INFO: possible circular locking dependency detected ] > [   84.860321] 3.3.0-rc2-00026-ge4e8a39 #474 Not tainted > [   84.860321] ------------------------------------------------------- > [   84.860321] bash/949 is trying to acquire lock: > [   84.860321]  (sysfs_lock){+.+.+.}, at: [] gpio_value_store+0x24/0xcc > [   84.860321] > [   84.860321] but task is already holding lock: > [   84.860321]  (s_active#22){++++.+}, at: [] sysfs_write_file+0xdc/0x184 > [   84.911468] > [   84.911468] which lock already depends on the new lock. > [   84.911468] > [   84.920043] > [   84.920043] the existing dependency chain (in reverse order) is: > [   84.920043] > [   84.927886] -> #1 (s_active#22){++++.+}: > [   84.927886]        [] check_prevs_add+0xdc/0x150 > [   84.927886]        [] validate_chain.clone.24+0x564/0x694 > [   84.927886]        [] __lock_acquire+0x49c/0x980 > [   84.951660]        [] lock_acquire+0x98/0x100 > [   84.951660]        [] sysfs_deactivate+0xb0/0x100 > [   84.962982]        [] sysfs_addrm_finish+0x2c/0x6c > [   84.962982]        [] sysfs_remove_dir+0x84/0x98 > [   84.962982]        [] kobject_del+0x10/0x78 > [   84.974670]        [] device_del+0x140/0x170 > [   84.974670]        [] device_unregister+0xc/0x18 > [   84.985382]        [] gpio_unexport+0xbc/0xdc > [   84.985382]        [] gpio_free+0x14/0xfc > [   85.001708]        [] unexport_store+0x78/0x8c > [   85.001708]        [] class_attr_store+0x18/0x24 > [   85.007293]        [] sysfs_write_file+0x100/0x184 > [   85.018981]        [] vfs_write+0xb4/0x148 > [   85.018981]        [] sys_write+0x40/0x70 > [   85.018981]        [] ret_fast_syscall+0x0/0x3c > [   85.035003] > [   85.035003] -> #0 (sysfs_lock){+.+.+.}: > [   85.035003]        [] check_prev_add+0x680/0x698 > [   85.035003]        [] check_prevs_add+0xdc/0x150 > [   85.052093]        [] validate_chain.clone.24+0x564/0x694 > [   85.052093]        [] __lock_acquire+0x49c/0x980 > [   85.052093]        [] lock_acquire+0x98/0x100 > [   85.069885]        [] mutex_lock_nested+0x3c/0x2f4 > [   85.069885]        [] gpio_value_store+0x24/0xcc > [   85.069885]        [] dev_attr_store+0x18/0x24 > [   85.087158]        [] sysfs_write_file+0x100/0x184 > [   85.087158]        [] vfs_write+0xb4/0x148 > [   85.098297]        [] sys_write+0x40/0x70 > [   85.098297]        [] ret_fast_syscall+0x0/0x3c > [   85.109069] > [   85.109069] other info that might help us debug this: > [   85.109069] > [   85.117462]  Possible unsafe locking scenario: > [   85.117462] > [   85.117462]        CPU0                    CPU1 > [   85.128417]        ----                    ---- > [   85.128417]   lock(s_active#22); > [   85.128417]                                lock(sysfs_lock); > [   85.128417]                                lock(s_active#22); > [   85.142486]   lock(sysfs_lock); > [   85.151794] > [   85.151794]  *** DEADLOCK *** > [   85.151794] > [   85.151794] 2 locks held by bash/949: > [   85.158020]  #0:  (&buffer->mutex){+.+.+.}, at: [] sysfs_write_file+0x28/0x184 > [   85.170349]  #1:  (s_active#22){++++.+}, at: [] sysfs_write_file+0xdc/0x184 > [   85.170349] > [   85.178588] stack backtrace: > [   85.178588] [] (unwind_backtrace+0x0/0xf0) from [] (print_circular_bug+0x100/0x114) > [   85.193023] [] (print_circular_bug+0x100/0x114) from [] (check_prev_add+0x680/0x698) > [   85.193023] [] (check_prev_add+0x680/0x698) from [] (check_prevs_add+0xdc/0x150) > [   85.212524] [] (check_prevs_add+0xdc/0x150) from [] (validate_chain.clone.24+0x564/0x694) > [   85.212524] [] (validate_chain.clone.24+0x564/0x694) from [] (__lock_acquire+0x49c/0x980) > [   85.233306] [] (__lock_acquire+0x49c/0x980) from [] (lock_acquire+0x98/0x100) > [   85.233306] [] (lock_acquire+0x98/0x100) from [] (mutex_lock_nested+0x3c/0x2f4) > [   85.242614] [] (mutex_lock_nested+0x3c/0x2f4) from [] (gpio_value_store+0x24/0xcc) > [   85.261840] [] (gpio_value_store+0x24/0xcc) from [] (dev_attr_store+0x18/0x24) > [   85.261840] [] (dev_attr_store+0x18/0x24) from [] (sysfs_write_file+0x100/0x184) > [   85.271240] [] (sysfs_write_file+0x100/0x184) from [] (vfs_write+0xb4/0x148) > [   85.290008] [] (vfs_write+0xb4/0x148) from [] (sys_write+0x40/0x70) > [   85.298400] [] (sys_write+0x40/0x70) from [] (ret_fast_syscall+0x0/0x3c) > -bash: echo: write error: Operation not permitted > > the way to trigger is: > > root@legolas:~# cd /sys/class/gpio/ > root@legolas:/sys/class/gpio# echo 2 > export > root@legolas:/sys/class/gpio# echo 2 > unexport > root@legolas:/sys/class/gpio# echo 2 > export > root@legolas:/sys/class/gpio# cd gpio2/ > root@legolas:/sys/class/gpio/gpio2# echo 1 > value Looks 'sysfs_lock' needn't to be held for unregister, so the patch below may fix the problem. Acked-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 17fdf4b6af93..d77354068b90 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -873,6 +873,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 +885,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); -- cgit From 6e33aceda2d82126e9d08a39e21a15be0dd00a6c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 11 Jan 2012 15:25:20 +0530 Subject: gpio/gpio-pl061: No need of thaw and poweroff routines for hibernate pl061 uses same routines for suspend/freeze/poweroff and resume/thaw/restore. We are only saving and restoring register values on these routines. During hibernation, in freeze() we take a snapshot of gpio registers. In thaw() we don't actually need to restore these registers, as power was never shut down till now. Similarly, in poweroff() we don't need to take snapshot of these registers again, as it was done during freeze() and by now the image is already saved on disk. This patch passes poweroff() and thaw() routines as NULL to avoid this extra work done. Signed-off-by: Viresh Kumar Signed-off-by: Grant Likely --- drivers/gpio/gpio-pl061.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') 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[] = { -- cgit From 63325ff235deeed5a5fc25705e292239115c76cd Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 24 Feb 2012 10:34:33 -0800 Subject: ARM: OMAP1: Move 16xx GPIO system clock to platform init code This way we can remove omap_read/write call from the GPIO driver and remove include to linux/io.h. Cc: Grant Likely Signed-off-by: Tony Lindgren --- drivers/gpio/gpio-omap.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0b0562979171..5b7b164e08ad 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1064,13 +1064,6 @@ static void omap_gpio_mod_init(struct gpio_bank *bank, int id) + OMAP1610_GPIO_IRQSTATUS1); __raw_writew(0x0014, bank->base + OMAP1610_GPIO_SYSCONFIG); - - /* - * 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 -- cgit From bdc93a77da75ee421125896ce4bbd91afff63809 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 13 Feb 2012 16:21:15 -0700 Subject: gpio: tegra: Fix build issue due to irq_domain rework. Commit 7da5a66 "irq_domain: Remove 'new' irq_domain in favour of the ppc one" changed the set of available irq domain APIs. Update the Tegra GPIO driver to account for those changes, to solve a build break. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson --- drivers/gpio/gpio-tegra.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 98f3980dab7c..6f17671260e1 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -75,7 +75,7 @@ struct tegra_gpio_bank { #endif }; -static struct irq_domain irq_domain; +static struct irq_domain *irq_domain; static void __iomem *regs; static u32 tegra_gpio_bank_count; static struct tegra_gpio_bank *tegra_gpio_banks; @@ -141,7 +141,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 irq_domain_to_irq(&irq_domain, offset); + return irq_find_mapping(irq_domain, offset); } static struct gpio_chip tegra_gpio_chip = { @@ -372,11 +372,9 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); return -ENODEV; } - irq_domain.irq_base = irq_base; - irq_domain.nr_irq = tegra_gpio_chip.ngpio; - irq_domain.ops = &irq_domain_simple_ops; - irq_domain.of_node = pdev->dev.of_node; - irq_domain_add(&irq_domain); + 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); @@ -416,7 +414,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { - int irq = irq_domain_to_irq(&irq_domain, 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)]; -- cgit From 6e2cf6514066cdd5a0844b34760029a5a4870318 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 2 Mar 2012 15:56:03 -0700 Subject: gpio: constify the data parameter to gpiochip_find() Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d77354068b90..e633a2afbe90 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1152,8 +1152,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; -- cgit From aca5ce14eb773a75e5d935968b2e390dc5bd29c3 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 17 Feb 2012 20:26:21 +0530 Subject: gpio: gpiolib: Support for open drain/collector gpios Adding support for the open drain gpio on which client can specify the open drain property through GPIO flag GPIOF_OPEN_DRAIN at the time of gpio request. The open drain pins are normally pulled high and it cannot be driven to output with value of 1 and so when client request for setting the pin to HIGH, the gpio will be set to input direction to make pin in tristate and hence PULL-UP on pins will make the state to HIGH. The open drain pin can be driven to LOW by setting output with value of 0. Signed-off-by: Laxman Dewangan Reviwed-by: Mark Brown Acked-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e633a2afbe90..5d25a33d5359 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -58,6 +58,7 @@ 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 ID_SHIFT 16 /* add new flags before this one */ @@ -1264,6 +1265,7 @@ 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); } else WARN_ON(extra_checks); @@ -1285,6 +1287,9 @@ 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_DIR_IN) err = gpio_direction_input(gpio); else @@ -1434,6 +1439,10 @@ 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); + spin_lock_irqsave(&gpio_lock, flags); if (!gpio_is_valid(gpio)) @@ -1570,6 +1579,31 @@ 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_value() - assign a gpio's value * @gpio: gpio whose value will be assigned @@ -1586,7 +1620,10 @@ void __gpio_set_value(unsigned gpio, int value) chip = gpio_to_chip(gpio); 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 + chip->set(chip, gpio - chip->base, value); } EXPORT_SYMBOL_GPL(__gpio_set_value); @@ -1653,7 +1690,10 @@ 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 + chip->set(chip, gpio - chip->base, value); } EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); -- cgit From 25553ff0756c59b617af6bdd280c94e943164184 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 17 Feb 2012 20:26:22 +0530 Subject: gpio: gpiolib: Support for open source/emitter gpios Adding support for the open source gpio on which client can specify the open source property through GPIO flag GPIOF_OPEN_SOURCE at the time of gpio request. The open source pins are normally pulled low and it cannot be driven to output with value of 0 and so when client request for setting the pin to LOW, the gpio will be set to input direction to make pin in tristate and hence PULL-DOWN on pins will make the state to LOW. The open source pin can be driven to HIGH by setting output with value of 1. Signed-off-by: Laxman Dewangan Reviwed-by: Mark Brown Acked-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5d25a33d5359..58f40dfc5265 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -59,6 +59,7 @@ struct gpio_desc { #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 */ @@ -1266,6 +1267,7 @@ void gpio_free(unsigned gpio) 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); @@ -1290,6 +1292,9 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) 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 @@ -1443,6 +1448,10 @@ int gpio_direction_output(unsigned gpio, int value) 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)) @@ -1604,6 +1613,32 @@ static void _gpio_set_open_drain_value(unsigned gpio, __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 @@ -1622,6 +1657,8 @@ void __gpio_set_value(unsigned gpio, int value) trace_gpio_value(gpio, 0, 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); } @@ -1692,6 +1729,8 @@ void gpio_set_value_cansleep(unsigned gpio, int value) trace_gpio_value(gpio, 0, 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); } -- cgit From e4e449e82871c53ef3b22bd3a50fceabc0638926 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 17 Feb 2012 10:46:00 -0800 Subject: gpiolib: Add comments explaining the _cansleep() WARN_ON()s I've seen users getting very confused by the WARN_ON()s for can_sleep GPIOs in the atomic-safe paths, the discoverability of the non-atomic version of the API seems to be hampered by the fact that it's defined in a header file not the .c file where the warnings are. Add a couple of comments next to the warnings to help people on their way. Signed-off-by: Mark Brown Reviwed-by: Mark Brown Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 58f40dfc5265..5a75510d66bb 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1581,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); @@ -1653,6 +1654,7 @@ 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); if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) -- cgit From 862ff64011e606582cec80cc3fa4fcd3e585d76f Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 1 Feb 2012 15:58:56 +0100 Subject: gpio/omap: Remove bank->id information and misc cleanup The driver does not need anymore any id to identify the GPIO instance. Remove every occurence of the bank->id inside the driver. Remove two trailing spaces. Add a dev variable for better readability in probe. Remove unused variable bank->pbase. Signed-off-by: Benoit Cousson Acked-by: Tarun Kanti DebBarma --- drivers/gpio/gpio-omap.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f49bd6f47a50..a0c3e03a1d1e 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -50,7 +50,6 @@ struct gpio_regs { struct gpio_bank { struct list_head node; - unsigned long pbase; void __iomem *base; u16 irq; u16 virtual_irq_start; @@ -77,7 +76,6 @@ struct gpio_bank { int stride; u32 width; int context_loss_count; - u16 id; int power_mode; bool workaround_enabled; @@ -155,7 +153,7 @@ 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; @@ -495,7 +493,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; } @@ -1048,37 +1046,36 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) static int __devinit omap_gpio_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct omap_gpio_platform_data *pdata; struct resource *res; struct gpio_bank *bank; int ret = 0; - if (!pdev->dev.platform_data) { + if (!dev->platform_data) { ret = -EINVAL; goto err_exit; } bank = kzalloc(sizeof(struct gpio_bank), GFP_KERNEL); if (!bank) { - dev_err(&pdev->dev, "Memory alloc failed for gpio_bank\n"); + dev_err(dev, "Memory alloc failed\n"); ret = -ENOMEM; goto err_exit; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (unlikely(!res)) { - dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", - pdev->id); + dev_err(dev, "Invalid IRQ resource\n"); ret = -ENODEV; goto err_free; } bank->irq = res->start; - bank->id = pdev->id; pdata = pdev->dev.platform_data; bank->virtual_irq_start = pdata->virtual_irq_start; - bank->dev = &pdev->dev; + bank->dev = dev; bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; @@ -1098,16 +1095,14 @@ 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", - pdev->id); + dev_err(dev, "Invalid mem resource\n"); ret = -ENODEV; goto err_free; } bank->base = ioremap(res->start, resource_size(res)); if (!bank->base) { - dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", - pdev->id); + dev_err(dev, "Could not ioremap\n"); ret = -ENOMEM; goto err_free; } -- cgit From 96751fcbe5438e95514b025e9cee7a6d38038f40 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 1 Feb 2012 16:01:39 +0100 Subject: gpio/omap: Use devm_ API and add request_mem_region Replace the regular kzalloc and ioremap with the devm_ equivalent to simplify error handling. Add the missing devm_request_mem_region to reserve the region used by the driver. Signed-off-by: Benoit Cousson Cc: Tarun Kanti DebBarma --- drivers/gpio/gpio-omap.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index a0c3e03a1d1e..c3a9dc8fe732 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -1052,23 +1052,19 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) struct gpio_bank *bank; int ret = 0; - if (!dev->platform_data) { - ret = -EINVAL; - goto err_exit; - } + if (!dev->platform_data) + return -EINVAL; - bank = kzalloc(sizeof(struct gpio_bank), GFP_KERNEL); + bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL); if (!bank) { dev_err(dev, "Memory alloc failed\n"); - ret = -ENOMEM; - goto err_exit; + return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (unlikely(!res)) { dev_err(dev, "Invalid IRQ resource\n"); - ret = -ENODEV; - goto err_free; + return -ENODEV; } bank->irq = res->start; @@ -1096,15 +1092,19 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!res)) { dev_err(dev, "Invalid mem resource\n"); - ret = -ENODEV; - goto err_free; + return -ENODEV; + } + + if (!devm_request_mem_region(dev, res->start, resource_size(res), + pdev->name)) { + dev_err(dev, "Region already claimed\n"); + return -EBUSY; } - bank->base = ioremap(res->start, resource_size(res)); + bank->base = devm_ioremap(dev, res->start, resource_size(res)); if (!bank->base) { dev_err(dev, "Could not ioremap\n"); - ret = -ENOMEM; - goto err_free; + return -ENOMEM; } platform_set_drvdata(pdev, bank); @@ -1125,11 +1125,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) list_add_tail(&bank->node, &omap_gpio_list); return ret; - -err_free: - kfree(bank); -err_exit: - return ret; } #ifdef CONFIG_ARCH_OMAP2PLUS -- cgit From 384ebe1c2849160d040df3e68634ec506f13d9ff Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 16 Aug 2011 11:53:02 +0200 Subject: gpio/omap: Add DT support to GPIO driver Adapt the GPIO driver to retrieve information from a DT file. Allocate the irq_base dynamically and rename bank->virtual_irq_start to bank->irq_base. Change irq_base type to int instead of u16 to match irq_alloc_descs output. Add documentation for GPIO properties specific to OMAP. Signed-off-by: Benoit Cousson Cc: Tarun Kanti DebBarma Acked-by: Rob Herring --- drivers/gpio/gpio-omap.c | 121 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 112 insertions(+), 9 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index c3a9dc8fe732..bc2bd698ff2a 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include #include @@ -52,7 +55,8 @@ struct gpio_bank { struct list_head node; void __iomem *base; u16 irq; - u16 virtual_irq_start; + int irq_base; + struct irq_domain *domain; u32 suspend_wakeup; u32 saved_wakeup; u32 non_wakeup_gpios; @@ -669,7 +673,7 @@ 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)); @@ -915,7 +919,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; } /*---------------------------------------------------------------------*/ @@ -1028,8 +1032,7 @@ 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) { @@ -1044,15 +1047,22 @@ 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) { 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; struct gpio_bank *bank; int ret = 0; - if (!dev->platform_data) + match = of_match_device(of_match_ptr(omap_gpio_match), dev); + + pdata = match ? match->data : dev->platform_data; + if (!pdata) return -EINVAL; bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL); @@ -1068,9 +1078,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) } bank->irq = res->start; - - pdata = pdev->dev.platform_data; - bank->virtual_irq_start = pdata->virtual_irq_start; bank->dev = dev; bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; @@ -1080,6 +1087,18 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) 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; @@ -1387,11 +1406,95 @@ static const struct dev_pm_ops gpio_pm_ops = { 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), }, }; -- cgit From 25db711df3258d125dc1209800317e5c0ef3c870 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Thu, 23 Feb 2012 21:50:10 +0100 Subject: gpio/omap: Fix IRQ handling for SPARSE_IRQ The driver is still relying on internal OMAP IRQ defines that are not relevant anymore if OMAP is built with SPARSE_IRQ. Replace the defines with the proper IRQ base number. Clean some comment style issue. Remove some hidden and ugly cpu_class_is_omap1() inside the gpio header. Signed-off-by: Benoit Cousson Tested-by: Tarun Kanti DebBarma --- drivers/gpio/gpio-omap.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index bc2bd698ff2a..afef0f7c8adf 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -93,6 +93,11 @@ struct gpio_bank { #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) { void __iomem *reg = bank->base; @@ -369,7 +374,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) 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; @@ -377,13 +382,11 @@ 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; - bank = irq_data_get_irq_chip_data(d); - if (!bank->regs->leveldetect0 && (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) return -EINVAL; @@ -524,14 +527,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) @@ -675,11 +674,13 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) 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; + 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 @@ -705,8 +706,8 @@ exit: 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); @@ -716,16 +717,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); @@ -736,8 +737,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; -- cgit From 38040c858cbd4c06080e7d1e79e9ff4c74c33d2c Mon Sep 17 00:00:00 2001 From: Chris Blair Date: Thu, 26 Jan 2012 22:17:15 +0100 Subject: gpio: Support no-irq stmpe mode Adds support for boards which have an STMPE GPIO device without the interrupt pin connected. This means that no interrupt can be received but the GPIO pins can still be driven and read. Cc: Grant Likely Acked-by: Viresh Kumar Tested-by: Michel Jaouen Signed-off-by: Chris Blair Acked-by: Viresh Kumar Signed-off-by: Samuel Ortiz --- drivers/gpio/gpio-stmpe.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 87a68a896abf..094c5c4fd7f2 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -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); -- cgit From 68942edb09f69b6e09522d1d346665eb3aadde49 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Mon, 5 Mar 2012 15:10:04 -0800 Subject: gpio/omap: fix wakeups on level-triggered GPIOs While both level- and edge-triggered GPIOs are capable of generating interrupts, only edge-triggered GPIOs are capable of generating a module-level wakeup to the PRCM (c.f. 34xx NDA TRM section 25.5.3.2.) In order to ensure that devices using level-triggered GPIOs as interrupts can also cause wakeups (e.g. from idle), this patch enables edge-triggering for wakeup-enabled, level-triggered GPIOs when a GPIO bank is runtime-suspended (which also happens during idle.) This fixes a problem found in GPMC-connected network cards with GPIO interrupts (e.g. smsc911x on Zoom3, Overo, ...) where network booting with NFSroot was very slow since the GPIO IRQs used by the NIC were not generating PRCM wakeups, and thus not waking the system from idle. NOTE: until v3.3, this boot-time problem was somewhat masked because the UART init prevented WFI during boot until the full serial driver was available. Preventing WFI allowed regular GPIO interrupts to fire and this problem was not seen. After the UART runtime PM cleanups, we no longer avoid WFI during boot, so GPIO IRQs that were not causing wakeups resulted in very slow IRQ response times. Tested on platforms using level-triggered GPIOs for network IRQs using the SMSC911x NIC: 3530/Overo and 3630/Zoom3. Reported-by: Tony Lindgren Tested-by: Tarun Kanti DebBarma Tested-by: Tony Lindgren Signed-off-by: Kevin Hilman Signed-off-by: Grant Likely --- drivers/gpio/gpio-omap.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index afef0f7c8adf..c48de8ffe9ef 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1206,8 +1206,30 @@ static int omap_gpio_runtime_suspend(struct device *dev) struct gpio_bank *bank = platform_get_drvdata(pdev); u32 l1 = 0, l2 = 0; unsigned long flags; + u32 wake_low, wake_hi; spin_lock_irqsave(&bank->lock, flags); + + /* + * 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; @@ -1256,6 +1278,18 @@ static int omap_gpio_runtime_resume(struct device *dev) spin_lock_irqsave(&bank->lock, flags); _gpio_dbck_enable(bank); + + /* + * 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 (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) { spin_unlock_irqrestore(&bank->lock, flags); return 0; -- cgit From 8e5fb37b9873eacb2381f2931d252b6db6e2cb16 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 5 Mar 2012 23:01:10 +0100 Subject: GPIO: LPC32xx: Fix missing bit selection mask Add missing mask to pin bit selection in gpio-lpc32xx.c (#define GPIO3_PIN_IN_SEL) Signed-off-by: Roland Stigge Acked-by: Arnd Bergmann Signed-off-by: Grant Likely --- drivers/gpio/gpio-lpc32xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index ddfacc5ce56d..14a2f297a0b4 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -59,7 +59,7 @@ #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) -- cgit From 46158aad96b0a90b52fd345f89951a50b3d1a81f Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 5 Mar 2012 23:01:11 +0100 Subject: GPIO: LPC32xx: Add output reading to GPO P3 The chip offers the function to detect the current state of output of the GPO P3 pins. Useful for reading GPIO output state in Linux' GPIO API, e.g. via sysfs. Please note that this only reads back the currently programmed output state, not the actual electrical level in terms of a GPI function. Finally, GPO3 is still just an output. Signed-off-by: Roland Stigge Acked-by: Arnd Bergmann Signed-off-by: Grant Likely --- drivers/gpio/gpio-lpc32xx.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 14a2f297a0b4..61c2d08d37b6 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -62,9 +62,11 @@ #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, -- cgit From 7535b8bef067b71070ed5bdcf3606402f1e99618 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Mon, 27 Feb 2012 11:19:43 +0530 Subject: gpio/gpio-stmpe: Fix the value returned by _get_value routine The present _get_value routine returns the contents of the GPIO Monitor Pin Status Register(GPMR) starting from the bit whose value is requested to BIT 0 (irrelevant bits are replace by 0). For e.g. if we request the value of GPIO 6 in the earlier implementation the value returned is: BIT6 followed by 6 0's whereas it should just return BIT6. This patch addresses the same. Signed-off-by: Bhupesh Sharma Reviewed-by: Viresh Kumar Signed-off-by: Grant Likely --- drivers/gpio/gpio-stmpe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 87a68a896abf..8abf4e9e2300 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) -- cgit From 691e06c0ff2cd0cfe79db5c52baac4fe18ca55af Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Mar 2012 17:32:24 -0500 Subject: ARM: tegra: export tegra_gpio_{en,dis}able These two functions are used in drivers that can be modules, so they need to be exported. Signed-off-by: Arnd Bergmann Signed-off-by: Alan Ott Acked-by: Olof Johansson Signed-off-by: Grant Likely --- drivers/gpio/gpio-tegra.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index bdc293791590..96662cc05ff9 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -107,11 +107,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) { -- cgit From 8805f410e4fb88a56552c1af42d61b38837a38fd Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 5 Mar 2012 15:32:38 -0800 Subject: gpio/omap: Fix section warning for omap_mpuio_alloc_gc() Make omap_mpuio_alloc_gc() __devinit as omap_gpio_chip_init() is __devinit. Otherwise we get: WARNING: vmlinux.o(.devinit.text+0xa10): Section mismatch in reference from the function omap_gpio_chip_init() to the function .init.text:omap_mpuio_alloc_gc() The function __devinit omap_gpio_chip_init() references a function __init omap_mpuio_alloc_gc(). If omap_mpuio_alloc_gc is only used by omap_gpio_chip_init then annotate omap_mpuio_alloc_gc with a matching annotation. Signed-off-by: Tony Lindgren Acked-by: Kevin Hilman Signed-off-by: Grant Likely --- drivers/gpio/gpio-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index c48de8ffe9ef..7cbad8569268 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -973,7 +973,7 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) _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) { -- cgit From ab2dde9924dd1ddb791fa8b14aa52e1df681e20c Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Sun, 11 Mar 2012 18:16:11 +0530 Subject: gpio/davinci: fix oops on unbanked gpio irq request Unbanked GPIO irq setup code was overwriting chip_data leading to the following oops on request_irq() Unable to handle kernel paging request at virtual address febfffff pgd = c22dc000 [febfffff] *pgd=00000000 Internal error: Oops: 801 [#1] PREEMPT Modules linked in: mcu(+) edmak irqk cmemk CPU: 0 Not tainted (3.0.0-rc7+ #93) PC is at irq_gc_mask_set_bit+0x68/0x7c LR is at vprintk+0x22c/0x484 pc : [] lr : [] psr: 60000093 sp : c33e3ba0 ip : c33e3af0 fp : c33e3bc4 r10: c04555bc r9 : c33d4340 r8 : 60000013 r7 : 0000002d r6 : c04555bc r5 : fec67010 r4 : 00000000 r3 : c04734c8 r2 : fec00000 r1 : ffffffff r0 : 00000026 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 0005317f Table: 822dc000 DAC: 00000015 Process modprobe (pid: 526, stack limit = 0xc33e2270) Stack: (0xc33e3ba0 to 0xc33e4000) 3ba0: 00000000 c007d3d4 c33e3bcc c04555bc c04555bc c33d4340 c33e3bdc c33e3bc8 3bc0: c007f5f8 c0080bb4 00000000 c04555bc c33e3bf4 c33e3be0 c007f654 c007f5c0 3be0: 00000000 c04555bc c33e3c24 c33e3bf8 c007e6e8 c007f618 c01f2284 c0350af8 3c00: c0405214 bf016c98 00000001 00000000 c33dc008 0000002d c33e3c54 c33e3c28 3c20: c007e888 c007e408 00000001 c23ef880 c33dc000 00000000 c33dc080 c25caa00 3c40: c0487498 bf017078 c33e3c94 c33e3c58 bf016b44 c007e7d4 bf017078 c33dc008 3c60: c25caa08 c33dc008 c33e3c84 bf017484 c25caa00 c25caa00 c01f5f48 c25caa08 3c80: c0496d60 bf017484 c33e3ca4 c33e3c98 c022a698 bf01692c c33e3cd4 c33e3ca8 3ca0: c01f5d88 c022a688 00000000 bf017484 c25caa00 c25caa00 c01f5f48 c25caa08 3cc0: c0496d60 00000000 c33e3cec c33e3cd8 c01f5f8c c01f5d10 00000000 c33e3cf0 3ce0: c33e3d14 c33e3cf0 c01f5210 c01f5f58 c303cb48 c25ecf94 c25caa00 c25caa00 3d00: c25caa34 c33e3dd8 c33e3d34 c33e3d18 c01f6044 c01f51b8 c0496d3c c25caa00 3d20: c044e918 c33e3dd8 c33e3d44 c33e3d38 c01f4ff4 c01f5fcc c33e3d94 c33e3d48 3d40: c01f3d10 c01f4fd8 00000000 c044e918 00000000 00000000 c01f52c0 c034d570 3d60: c33e3d84 c33e3d70 c022bf84 c25caa00 00000000 c044e918 c33e3dd8 c25c2e00 3d80: c0496d60 bf01763c c33e3db4 c33e3d98 c022b1a0 c01f384c c25caa00 c33e3dd8 3da0: 00000000 c33e3dd8 c33e3dd4 c33e3db8 c022b27c c022b0e8 00000000 bf01763c 3dc0: c0451c80 c33e3dd8 c33e3e34 c33e3dd8 bf016f60 c022b210 5f75636d 746e6f63 3de0: 006c6f72 00000000 00000000 00000000 00000000 00000000 00000000 bf0174bc 3e00: 00000000 00989680 00000000 00000020 c0451c80 c0451c80 bf0174dc c01f5eb0 3e20: c33f0f00 bf0174dc c33e3e44 c33e3e38 c01f72f4 bf016e2c c33e3e74 c33e3e48 3e40: c01f5d88 c01f72e4 00000000 c0451c80 c0451cb4 bf0174dc c01f5eb0 c33f0f00 3e60: c0473100 00000000 c33e3e94 c33e3e78 c01f5f44 c01f5d10 00000000 c33e3e98 3e80: bf0174dc c01f5eb0 c33e3ebc c33e3e98 c01f5534 c01f5ec0 c303c038 c3061c30 3ea0: 00003cd8 00098258 bf0174dc c0462ac8 c33e3ecc c33e3ec0 c01f5bec c01f54dc 3ec0: c33e3efc c33e3ed0 c01f4d30 c01f5bdc bf0173a0 c33e2000 00003cd8 00098258 3ee0: bf0174dc c33e2000 c00301a4 bf019000 c33e3f1c c33e3f00 c01f6588 c01f4c8c 3f00: 00003cd8 00098258 00000000 c33e2000 c33e3f2c c33e3f20 c01f777c c01f6524 3f20: c33e3f3c c33e3f30 bf019014 c01f7740 c33e3f7c c33e3f40 c002f3ec bf019010 3f40: 00000000 00003cd8 00098258 bf017518 00000000 00003cd8 00098258 bf017518 3f60: 00000000 c00301a4 c33e2000 00000000 c33e3fa4 c33e3f80 c007b934 c002f3c4 3f80: c00b307c c00b2f48 00003cd8 00000000 00000003 00000080 00000000 c33e3fa8 3fa0: c0030020 c007b8b8 00003cd8 00000000 00098288 00003cd8 00098258 00098240 3fc0: 00003cd8 00000000 00000003 00000080 00098008 00098028 00098288 00000001 3fe0: be892998 be892988 00013d7c 40178740 60000010 00098288 09089041 00200845 Backtrace: [] (irq_gc_mask_set_bit+0x0/0x7c) from [] (irq_enable+0x48/0x58) r6:c33d4340 r5:c04555bc r4:c04555bc [] (irq_enable+0x0/0x58) from [] (irq_startup+0x4c/0x54) r5:c04555bc r4:00000000 [] (irq_startup+0x0/0x54) from [] (__setup_irq+0x2f0/0x3cc) r5:c04555bc r4:00000000 [] (__setup_irq+0x0/0x3cc) from [] (request_threaded_irq+0xc4/0x110) r8:0000002d r7:c33dc008 r6:00000000 r5:00000001 r4:bf016c98 [] (request_threaded_irq+0x0/0x110) from [] (mcu_spi_probe+0x228/0x37c [mcu]) [] (mcu_spi_probe+0x0/0x37c [mcu]) from [] (spi_drv_probe+0x20/0x24) [] (spi_drv_probe+0x0/0x24) from [] (driver_probe_device+0x88/0x1b0) [] (driver_probe_device+0x0/0x1b0) from [] (__device_attach+0x44/0x48) [] (__device_attach+0x0/0x48) from [] (bus_for_each_drv+0x68/0x94) r5:c33e3cf0 r4:00000000 [] (bus_for_each_drv+0x0/0x94) from [] (device_attach+0x88/0xa0) r7:c33e3dd8 r6:c25caa34 r5:c25caa00 r4:c25caa00 [] (device_attach+0x0/0xa0) from [] (bus_probe_device+0x2c/0x4c) r7:c33e3dd8 r6:c044e918 r5:c25caa00 r4:c0496d3c [] (bus_probe_device+0x0/0x4c) from [] (device_add+0x4d4/0x648) [] (device_add+0x0/0x648) from [] (spi_add_device+0xc8/0x128) [] (spi_add_device+0x0/0x128) from [] (spi_new_device+0x7c/0xb4) r7:c33e3dd8 r6:00000000 r5:c33e3dd8 r4:c25caa00 [] (spi_new_device+0x0/0xb4) from [] (mcu_probe+0x144/0x224 [mcu]) r7:c33e3dd8 r6:c0451c80 r5:bf01763c r4:00000000 [] (mcu_probe+0x0/0x224 [mcu]) from [] (platform_drv_probe+0x20/0x24) [] (platform_drv_probe+0x0/0x24) from [] (driver_probe_device+0x88/0x1b0) [] (driver_probe_device+0x0/0x1b0) from [] (__driver_attach+0x94/0x98) [] (__driver_attach+0x0/0x98) from [] (bus_for_each_dev+0x68/0x94) r7:c01f5eb0 r6:bf0174dc r5:c33e3e98 r4:00000000 [] (bus_for_each_dev+0x0/0x94) from [] (driver_attach+0x20/0x28) r7:c0462ac8 r6:bf0174dc r5:00098258 r4:00003cd8 [] (driver_attach+0x0/0x28) from [] (bus_add_driver+0xb4/0x258) [] (bus_add_driver+0x0/0x258) from [] (driver_register+0x74/0x158) [] (driver_register+0x0/0x158) from [] (platform_driver_register+0x4c/0x60) r7:c33e2000 r6:00000000 r5:00098258 r4:00003cd8 [] (platform_driver_register+0x0/0x60) from [] (mcu_init+0x14/0x20 [mcu]) [] (mcu_init+0x0/0x20 [mcu]) from [] (do_one_initcall+0x38/0x170) [] (do_one_initcall+0x0/0x170) from [] (sys_init_module+0x8c/0x1a4) [] (sys_init_module+0x0/0x1a4) from [] (ret_fast_syscall+0x0/0x2c) r7:00000080 r6:00000003 r5:00000000 r4:00003cd8 Code: e1844003 e585400c e596300c e5932064 (e7814002) Fix the issue. Cc: # v3.0.x+ Reported-by: Jon Povey Signed-off-by: Sekhar Nori Signed-off-by: Grant Likely --- drivers/gpio/gpio-davinci.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index df0d59570a84..a6777e5e0ced 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; @@ -400,8 +406,7 @@ 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_handler_data(irq, &chips[gpio / 32]); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } -- cgit From 81b279d80a63628e580c71a31d30a8c3b3047ad4 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Sun, 11 Mar 2012 18:16:12 +0530 Subject: gpio/davinci: fix enabling unbanked GPIO IRQs Unbanked GPIO IRQ handling code made a copy of just the irq_chip structure for GPIO IRQ lines which caused problems after the generic IRQ chip conversion because there was no valid irq_chip_type structure with the right "regs" populated. irq_gc_mask_set_bit() was therefore accessing random addresses. Fix it by making a copy of irq_chip_type structure instead. This will ensure sane register offsets. Cc: # v3.0.x+ Reported-by: Jon Povey Tested-by: Jon Povey Signed-off-by: Sekhar Nori Signed-off-by: Grant Likely --- drivers/gpio/gpio-davinci.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index a6777e5e0ced..3d000169285d 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -386,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; @@ -394,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); @@ -405,7 +406,7 @@ 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_chip(irq, &gpio_unbanked.chip); irq_set_handler_data(irq, &chips[gpio / 32]); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } -- cgit From 08932d81961b1c57870949d069ce2dad235da443 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Wed, 11 Jan 2012 09:58:30 +1100 Subject: ep93xx: Configure GPIO ports in core code Move the pinmux setting of the EP93xx GPIOs to the core code. This removes the need for the GPIO driver to have access to the system controller registers. Signed-off-by: Ryan Mallon Cc: Grant Likely Reviewed-by: Mika Westerberg Acked-by: Hartley Sweeten --- drivers/gpio/gpio-ep93xx.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 1c0fc3756cb1..4ca5642e9776 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -378,13 +378,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]; -- cgit From a9696d840ed503da6458335bdcd4defbeb480ea7 Mon Sep 17 00:00:00 2001 From: Sangsu Park Date: Mon, 12 Mar 2012 16:23:33 -0700 Subject: gpio/samsung: add support GPIOlib for EXYNOS5250 This patch adds gpio_chips for EXYNOS5250 and replaces exynos4_xxx() with exynos_xxx() and variables to support exynos4 and exynos5 together. In addition, use ioreamp() for base address of gpios. Signed-off-by: Sangsu Park Acked-by: Grant Likely Signed-off-by: Kukjin Kim --- drivers/gpio/gpio-samsung.c | 439 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 411 insertions(+), 28 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 0a79a1167a25..d6cfdee7f8b7 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 @@ -2386,8 +2386,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 +2685,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 +2701,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)); @@ -2524,11 +2797,11 @@ static __init int samsung_gpiolib_init(void) 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 } @@ -2540,11 +2813,11 @@ static __init int samsung_gpiolib_init(void) 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 } @@ -2556,11 +2829,11 @@ static __init int samsung_gpiolib_init(void) 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 } @@ -2570,12 +2843,122 @@ static __init int samsung_gpiolib_init(void) 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 + } 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); -- cgit From d39c815278bef7ce896100d8b385c81ed5cac015 Mon Sep 17 00:00:00 2001 From: Sangsu Park Date: Mon, 12 Mar 2012 16:23:33 -0700 Subject: gpio/samsung: use ioremap() for EXYNOS4 GPIOlib This patch changes to use ioremap() for EXYNOS4210 so that we can drop the static mapping for EXYNOS SoCs. Note: Will be updated for all of Samsung GPIOlibs to use ioremap() next time. Signed-off-by: Sangsu Park Acked-by: Grant Likely Signed-off-by: Kukjin Kim --- drivers/gpio/gpio-samsung.c | 48 ++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index d6cfdee7f8b7..46277877b7ec 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -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 = { @@ -2789,9 +2785,16 @@ 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); @@ -2800,14 +2803,25 @@ static __init int samsung_gpiolib_init(void) chip->config = &exynos_gpio_cfg; chip->group = group++; } -#ifdef CONFIG_CPU_EXYNOS4210 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); @@ -2816,14 +2830,19 @@ static __init int samsung_gpiolib_init(void) chip->config = &exynos_gpio_cfg; chip->group = group++; } -#ifdef CONFIG_CPU_EXYNOS4210 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); @@ -2832,17 +2851,18 @@ static __init int samsung_gpiolib_init(void) chip->config = &exynos_gpio_cfg; chip->group = group++; } -#ifdef CONFIG_CPU_EXYNOS4210 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; -- cgit From b0092f2665be3dd04f923d09a6a0deeddb4e96ec Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 19 Mar 2012 11:36:00 -0600 Subject: gpio: tegra: tegra_gpio_config shouldn't be __init This function is called from non-__init context, just like tegra_gpio_enable()/disable(). Remove the __init annotation to avoid section mismatch warnings during compile. Signed-off-by: Stephen Warren Signed-off-by: Grant Likely --- drivers/gpio/gpio-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 96662cc05ff9..ceb1fd081b85 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -428,7 +428,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; -- cgit From 381a752f291763bd6971521fa44c76ad9e937f7b Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Wed, 29 Feb 2012 21:49:21 +0530 Subject: gpio/omap: fix wakeup_en register update in _set_gpio_wakeup() There are two ways through which wakeup_en register can be programmed using gpiolib APIs as shown below. It is seen that in the second case in _set_gpio_wakeup(), even though bank->suspend_wakeup is updated correctly, its value is not programmed in wakeup_en register. Fix this. irq_set_type()->gpio_irq_type()->_set_gpio_triggering()->set_gpio_trigger() irq_set_wake()->gpio_wake_enable()->_set_gpio_wakeup() Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 7cbad8569268..1a144ac3b34e 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -511,6 +511,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; -- cgit From 00ece7e4826e631565eae089d3c813120c6535ef Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Fri, 25 Nov 2011 15:41:06 +0530 Subject: gpio/omap: fix trigger type to unsigned The GPIO trigger parameter is of type unsigned. enum { IRQ_TYPE_NONE = 0x00000000, IRQ_TYPE_EDGE_RISING = 0x00000001, IRQ_TYPE_EDGE_FALLING = 0x00000002, IRQ_TYPE_EDGE_BOTH = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING), IRQ_TYPE_LEVEL_HIGH = 0x00000004, IRQ_TYPE_LEVEL_LOW = 0x00000008, IRQ_TYPE_LEVEL_MASK = (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH), IRQ_TYPE_SENSE_MASK = 0x0000000f, IRQ_TYPE_PROBE = 0x00000010, ... }; Even though gpio_irq_type(struct irq_data *d, unsigned type) has the right type of parameter, the subsequent called functions set_gpio_triggering() and set_gpio_trigger() wrongly makes it signed integer. Fix this. Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Acked-by: Felipe Balbi Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 1a144ac3b34e..2042857a3663 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -245,7 +245,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, } static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, - int trigger) + unsigned trigger) { void __iomem *base = bank->base; u32 gpio_bit = 1 << gpio; @@ -327,7 +327,8 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) 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; -- cgit From 8276536cec38bc6bde30d0aa67716f22b9b9705a Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Fri, 25 Nov 2011 15:27:37 +0530 Subject: gpio/omap: fix _set_gpio_irqenable implementation This function should be capable of both enabling and disabling interrupts based upon the *enable* parameter. Right now the function only enables the interrupt and *enable* is not used at all. So add the interrupt disable capability also using the parameter. Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Acked-by: Felipe Balbi Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 2042857a3663..8901d576cb7d 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -484,7 +484,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)); } /* -- cgit From 2c836f7ea5e7b5eec2a798e02b1d76ea791fa094 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Fri, 2 Mar 2012 12:52:52 +0530 Subject: gpio/omap: fix missing dataout context save in _set_gpio_dataout_reg There are two functions, _set_gpio_dataout_reg() and _set_gpio_dataout_mask() which writes to dataout register and the dataout context must be saved. It is missing in the first function, _set_gpio_dataout_reg(). Fix this. Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 8901d576cb7d..bbe964899017 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -120,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); } -- cgit From 960edffe29dfd845ee532ee51398592cba96d701 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Mon, 5 Mar 2012 16:00:54 +0530 Subject: gpio/omap: fix incorrect context restore logic in omap_gpio_runtime_* In omap_gpio_runtime_suspend/resume() the context save/restore should be independent of bank->enabled_non_wakeup_gpios. This was preventing context restore of GPIO lines which are not wakeup enabled. Reported-by: Govindraj Raja Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index bbe964899017..bcb1061dbd6d 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1247,9 +1247,6 @@ static int omap_gpio_runtime_suspend(struct device *dev) * non-wakeup GPIOs. Otherwise spurious IRQs will be * generated. See OMAP2420 Errata item 1.101. */ - if (!(bank->enabled_non_wakeup_gpios)) - goto update_gpio_context_count; - bank->saved_datain = __raw_readl(bank->base + bank->regs->datain); l1 = __raw_readl(bank->base + bank->regs->fallingdetect); @@ -1298,7 +1295,7 @@ static int omap_gpio_runtime_resume(struct device *dev) __raw_writel(bank->context.risingdetect, bank->base + bank->regs->risingdetect); - if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) { + if (!bank->workaround_enabled) { spin_unlock_irqrestore(&bank->lock, flags); return 0; } -- cgit From 2a900eb74c123a21054836ab2c63d6ff46f854c6 Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Tue, 6 Mar 2012 12:08:16 +0530 Subject: gpio/omap: fix incorrect update to context.irqenable1 In _enable_gpio_irqbank() when bank->regs->set_irqenable is TRUE, gpio_mask can be directly set by writing to set_irqenable register without overwriting current value. In order to ensure the same is stored in context.irqenable1, we must avoid overwriting it with gpio_mask at the end of the function. Instead, update irqenable1 appropriately by OR'ing with gpio_mask. For the case where bank->regs->set_irqenable is FALSE, irqenable1 can be directly overwritten with 'l' which holds correct computed value. if (bank->regs->set_irqenable) { reg += bank->regs->set_irqenable; l = gpio_mask; } else { reg += bank->regs->irqenable; l = __raw_readl(reg); if (bank->regs->irqenable_inv) l &= ~gpio_mask; else l |= gpio_mask; } Make similar change for _disable_gpio_irqbank(). Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index bcb1061dbd6d..6c17e5812312 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -451,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); @@ -458,10 +459,10 @@ 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); - bank->context.irqenable1 = l; } static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) @@ -472,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); @@ -479,10 +481,10 @@ 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); - bank->context.irqenable1 = l; } static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) -- cgit From 7fcca715de3438b8fc3c8a144702f3a95c8ff63c Mon Sep 17 00:00:00 2001 From: Tarun Kanti DebBarma Date: Mon, 27 Feb 2012 11:46:09 +0530 Subject: gpio/omap: fix redundant decoding of gpio offset In gpio_get(), _get_gpio_datain() and _get_gpio_dataout() get rid of un-necessary operation to compute gpio mask. The gpio offset passed to gpio_get() is sufficient to do that. Here is Russell's original comment: Can someone explain to me this: static int _get_gpio_datain(struct gpio_bank *bank, int gpio) { void __iomem *reg = bank->base + bank->regs->datain; return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0; } static int gpio_get(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); void __iomem *reg = bank->base; int gpio = chip->base + offset; u32 mask = GPIO_BIT(bank, gpio); if (gpio_is_input(bank, mask)) return _get_gpio_datain(bank, gpio); else return _get_gpio_dataout(bank, gpio); } Given that bank->width on OMAP is either 32 or 16, and GPIO numbers for any GPIO chip are always aligned to 32 or 16, why does this code bother adding the chips base gpio number and then modulo the width? Surely this means if - for argument sake - you registered a GPIO chip with 8 lines followed by one with 16 lines, GPIO0..7 would be chip 0 bit 0..7, GPIO8..15 would be chip 1 bit 8..15, GPIO16..23 would be chip 1 bit 0..7. However, if you registered a GPIO chip with 16 lines first, it would mean GPIO0..15 would be chip 0 bit 0..15, and GPIO16..31 would be chip 1 bit 0..15. Surely this kind of behaviour is not intended? Is there a reason why the bitmask can't just be (1 << offset) where offset is passed into these functions as GPIO number - chip->base ? Reported-by: Russell King - ARM Linux Signed-off-by: Tarun Kanti DebBarma Reviewed-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 6c17e5812312..1adc2ec1e383 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -147,18 +147,18 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable) 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) @@ -865,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) -- cgit From f01b1f90bf46ddaf2a68215a9489364c974e5689 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 29 Feb 2012 22:38:06 +0100 Subject: mfd: Make twl4030 SIH SPARSE_IRQ capable twl4030 is using a two level irq controllers infrastruture. So far, only the first level was using dynamic irq_desc allocation to be able to have irq_domain support for device tree. There is a need to allocate separate irq_descs for the SIH too to avoid hacking the first level with interrupts from the second level. Add an irq_base parameter to allow the caller to provide the base from pdata or from dynamic allocation. Affect TWL4030_NR_IRQS to the twl-core IRQs only. Moreover that will allow the extraction of the of_node pointer for further Device Tree conversion. Signed-off-by: Felipe Balbi Signed-off-by: Benoit Cousson Signed-off-by: Samuel Ortiz --- drivers/gpio/gpio-twl4030.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index b8b4f228757c..697396c74627 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -404,7 +404,8 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev) "can't dispatch IRQs from modules\n"); goto no_irqs; } - ret = twl4030_sih_setup(TWL4030_MODULE_GPIO); + ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, + pdata->irq_base); if (ret < 0) return ret; WARN_ON(ret != pdata->irq_base); -- cgit From 2d9dd99b4470a2ef05509435465e055f50456330 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 29 Feb 2012 22:48:32 +0100 Subject: gpio/twl: Allocate irq_desc dynamically for SPARSE_IRQ support Do not use the board pdata for irq_base, but allocate them dynamically to allow a proper support of SPARSE_IRQ. Fix an unneeded line wrap. Signed-off-by: Benoit Cousson Acked-by: Felipe Balbi Acked-by: Grant Likely Signed-off-by: Samuel Ortiz --- drivers/gpio/gpio-twl4030.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 697396c74627..49e5c6eb403a 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -395,23 +395,26 @@ 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; + 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(&pdev->dev, TWL4030_MODULE_GPIO, - pdata->irq_base); - 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; } + 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 @@ -443,9 +446,7 @@ no_irqs: 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) { -- cgit From b8589e2a8065b8e7773742b60ae96b63b757bb69 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 29 Feb 2012 22:51:32 +0100 Subject: gpio/twl: Add DT support to gpio-twl4030 driver Add the DT support for the I2C GPIO expander inside the twl4030. Note: The pdata parameters still have to be properly adapted using dedicated bindings. Signed-off-by: Benoit Cousson Acked-by: Felipe Balbi Acked-by: Grant Likely Signed-off-by: Samuel Ortiz --- drivers/gpio/gpio-twl4030.c | 79 ++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 29 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 49e5c6eb403a..94256fe7bf36 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include @@ -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,6 +398,7 @@ 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; + struct device_node *node = pdev->dev.of_node; int ret, irq_base; /* maybe setup IRQs */ @@ -409,6 +413,9 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev) 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; @@ -416,40 +423,45 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev) 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); twl_gpiochip.ngpio = 0; gpio_twl4030_remove(pdev); - } else if (pdata->setup) { + } else if (pdata && pdata->setup) { int status; status = pdata->setup(&pdev->dev, @@ -467,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) { @@ -488,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, }; -- cgit From 8194c7c4d5ea14d819bb2eab6a23b07331b734d8 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 23 Mar 2012 08:56:10 +0000 Subject: gpio/sodaville: Mark broken due to core irqdomain migration The sodaville driver doesn't build anymore due to the transition to common irq_domain in the core code. It needs to be reworked, but the rework isn't trivial. Since this is a new driver anyway for v3.4, mark it as broken now and a fixup patch can re-enable it when the rework change has been tested. Signed-off-by: Grant Likely --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index dbb1909ca0a2..dfea1d84655d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -419,7 +419,7 @@ config GPIO_ML_IOH config GPIO_SODAVILLE bool "Intel Sodaville GPIO support" - depends on X86 && PCI && OF + depends on X86 && PCI && OF && BROKEN select GPIO_GENERIC select GENERIC_IRQ_CHIP help -- cgit From f314f33be77d6a48ae19748e3dc4a6657042b525 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 24 Feb 2012 00:06:51 +0100 Subject: ARM: 7342/2: sa1100: prepare for sparse irq conversion In preparation to convert SA1100 to sparse irq, set .nr_irqs for each machine and explicitly include mach/irqs.h as needed. Signed-off-by: Rob Herring Signed-off-by: Russell King --- drivers/gpio/gpio-sa1100.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') 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 #include +#include static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset) { -- cgit From c77c8a6fd3d57b586ff5ecb5ab5b32ca4f54fe75 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 21 Mar 2012 11:13:27 -0700 Subject: gpio/ep93xx: Remove unused inline function and useless pr_err message Minor removal of an unused inline function and a useless pr_err message. Signed-off-by: H Hartley Sweeten Signed-off-by: Grant Likely --- drivers/gpio/gpio-ep93xx.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 1c0fc3756cb1..6a89683fdc91 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 #include #include @@ -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; } -- cgit From 5c1e2c9dc684f26fcc78ff4ef15dc97ed0244303 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 16 Mar 2012 17:35:08 -0600 Subject: gpio: tegra: fix register address calculations for Tegra30 Tegra20 and Tegra30 share the same register layout within registers, but the addresses of the registers is a little different. Fix the driver to cope with this. Signed-off-by: Stephen Warren Acked-by: Olof Johansson --- drivers/gpio/gpio-tegra.c | 55 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 13 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 32de6707e3c4..7d05a345776f 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -37,7 +37,8 @@ #define GPIO_PORT(x) (((x) >> 3) & 0x3) #define GPIO_BIT(x) ((x) & 0x7) -#define GPIO_REG(x) (GPIO_BANK(x) * 0x80 + GPIO_PORT(x) * 4) +#define GPIO_REG(x) (GPIO_BANK(x) * tegra_gpio_bank_stride + \ + GPIO_PORT(x) * 4) #define GPIO_CNF(x) (GPIO_REG(x) + 0x00) #define GPIO_OE(x) (GPIO_REG(x) + 0x10) @@ -48,12 +49,12 @@ #define GPIO_INT_LVL(x) (GPIO_REG(x) + 0x60) #define GPIO_INT_CLR(x) (GPIO_REG(x) + 0x70) -#define GPIO_MSK_CNF(x) (GPIO_REG(x) + 0x800) -#define GPIO_MSK_OE(x) (GPIO_REG(x) + 0x810) -#define GPIO_MSK_OUT(x) (GPIO_REG(x) + 0X820) -#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + 0x840) -#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + 0x850) -#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + 0x860) +#define GPIO_MSK_CNF(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x00) +#define GPIO_MSK_OE(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x10) +#define GPIO_MSK_OUT(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0X20) +#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x40) +#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x50) +#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x60) #define GPIO_INT_LVL_MASK 0x010101 #define GPIO_INT_LVL_EDGE_RISING 0x000101 @@ -78,6 +79,8 @@ struct tegra_gpio_bank { static struct irq_domain *irq_domain; static void __iomem *regs; static u32 tegra_gpio_bank_count; +static u32 tegra_gpio_bank_stride; +static u32 tegra_gpio_upper_offset; static struct tegra_gpio_bank *tegra_gpio_banks; static inline void tegra_gpio_writel(u32 val, u32 reg) @@ -333,6 +336,26 @@ static struct irq_chip tegra_gpio_irq_chip = { #endif }; +struct tegra_gpio_soc_config { + u32 bank_stride; + u32 upper_offset; +}; + +static struct tegra_gpio_soc_config tegra20_gpio_config = { + .bank_stride = 0x80, + .upper_offset = 0x800, +}; + +static struct tegra_gpio_soc_config tegra30_gpio_config = { + .bank_stride = 0x100, + .upper_offset = 0x80, +}; + +static struct of_device_id tegra_gpio_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, + { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, + { }, +}; /* This lock class tells lockdep that GPIO irqs are in a different * category than their parents, so it won't report false recursion. @@ -341,6 +364,8 @@ static struct lock_class_key gpio_lock_class; static int __devinit tegra_gpio_probe(struct platform_device *pdev) { + const struct of_device_id *match; + struct tegra_gpio_soc_config *config; int irq_base; struct resource *res; struct tegra_gpio_bank *bank; @@ -348,6 +373,15 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) int i; int j; + match = of_match_device(tegra_gpio_of_match, &pdev->dev); + if (match) + config = (struct tegra_gpio_soc_config *)match->data; + else + config = &tegra20_gpio_config; + + tegra_gpio_bank_stride = config->bank_stride; + tegra_gpio_upper_offset = config->upper_offset; + for (;;) { res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count); if (!res) @@ -441,11 +475,6 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return 0; } -static struct of_device_id tegra_gpio_of_match[] __devinitdata = { - { .compatible = "nvidia,tegra20-gpio", }, - { }, -}; - static struct platform_driver tegra_gpio_driver = { .driver = { .name = "tegra-gpio", -- cgit From 4a3398ee9d7d8008ee9bfc8a600b734a1b22af23 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 16 Mar 2012 17:37:24 -0600 Subject: gpio: tegra: Iterate over the correct number of banks When Tegra30 support was added to the Tegra GPIO driver, a few places which iterated over all banks were not converted to use the variable tegra_gpio_bank_count rather than hard-coding the bank count. Fix this. Signed-off-by: Stephen Warren Acked-by: Olof Johansson --- drivers/gpio/gpio-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 7d05a345776f..12f349b3830d 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -436,7 +436,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return -ENODEV; } - for (i = 0; i < 7; i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio)); @@ -514,7 +514,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) int i; int j; - for (i = 0; i < 7; i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); seq_printf(s, -- cgit