diff options
author | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-04-06 11:11:16 +0200 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-04-06 11:11:16 +0200 |
commit | cc0477d1ff54e53b7d2b15bc52e33ef38921a295 (patch) | |
tree | 47177b997291911df68dab553fd6ed36d5a19721 | |
parent | 1f1573eb976d678f587b6254b5257ee7edf6ffb3 (diff) | |
parent | 1133af78634d3bcfaf3af12eb208d906af36efb5 (diff) |
Merge topic branch 'gpio' into integration-linux-ux500-3.3
-rw-r--r-- | Documentation/DocBook/gpio.tmpl | 112 | ||||
-rw-r--r-- | arch/arm/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/gpio.h | 24 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-ab8500.c | 287 | ||||
-rw-r--r-- | drivers/gpio/gpio-nomadik.c | 110 | ||||
-rw-r--r-- | drivers/gpio/gpio-stmpe.c | 41 | ||||
-rw-r--r-- | include/linux/gpio/nomadik.h (renamed from arch/arm/plat-nomadik/include/plat/gpio-nomadik.h) | 1 | ||||
-rw-r--r-- | include/linux/mfd/abx500/ab8500-gpio.h | 82 |
9 files changed, 566 insertions, 95 deletions
diff --git a/Documentation/DocBook/gpio.tmpl b/Documentation/DocBook/gpio.tmpl new file mode 100644 index 00000000000..b69c2770210 --- /dev/null +++ b/Documentation/DocBook/gpio.tmpl @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> + +<book id="GPIO"> + <bookinfo> + <title>GPIO1B</title> + + <authorgroup> + <author> + <firstname>Alessandro</firstname> + <surname>Rubini</surname> + <affiliation> + <address> + <email>rubini@unipv.it</email> + </address> + </affiliation> + </author> + <author> + <firstname>Prafulla</firstname> + <surname>WADASKAR</surname> + <affiliation> + <address> + <email>prafulla.wadaskar@st.com</email> + </address> + </affiliation> + </author> + </authorgroup> + + <copyright> + <year>2008-2010</year> + <holder>ST-Ericsson</holder> + </copyright> + + <subjectset> + <subject> + <subjectterm>Linux standard functions</subjectterm> + </subject> + </subjectset> + + <legalnotice> + <!-- Do NOT remove the legal notice below --> + + <para> + This documentation 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. + </para> + + <para> + 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. + </para> + + <para> + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para> + + <para> + For more details see the file COPYING in the source + distribution of Linux. + </para> + </legalnotice> + </bookinfo> + +<toc></toc> + <chapter id="intro"> + <title>Introduction</title> + <para> + This Documentation describes the API's provided by the GPIO controller Driver. + </para> + <para> + Only the API specific to the Ux500 platform is listed here. For the generic GPIO + API, see <filename>Documentation/gpio.txt</filename> in the kernel source tree. + </para> + </chapter> + + <chapter id="bugs"> + <title>Known Bugs And Assumptions</title> + <para> + <variablelist> + <varlistentry> + <term>None</term> + <listitem> + <para> + None. + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + </chapter> + + <chapter id="pubfunctions"> + <title> Public Interface </title> + <para> + This Section lists the API's provided by the GPIO controller driver to client drivers. + </para> + <para> + Only the API specific to the Ux500 platform is listed here. For the generic GPIO + API, see <filename>Documentation/gpio.txt</filename> in the kernel source tree. + </para> +!Earch/arm/plat-nomadik/gpio.c + </chapter> +</book> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 46ad3ebd89b..9a4b9d580ab 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1583,7 +1583,7 @@ config LOCAL_TIMERS config ARCH_NR_GPIO int default 1024 if ARCH_SHMOBILE || ARCH_TEGRA - default 355 if ARCH_U8500 + default 366 if ARCH_U8500 default 0 help Maximum number of GPIOs in the system. diff --git a/arch/arm/mach-ux500/include/mach/gpio.h b/arch/arm/mach-ux500/include/mach/gpio.h index c01ef66537f..e0d903af605 100644 --- a/arch/arm/mach-ux500/include/mach/gpio.h +++ b/arch/arm/mach-ux500/include/mach/gpio.h @@ -1,5 +1,29 @@ #ifndef __ASM_ARCH_GPIO_H #define __ASM_ARCH_GPIO_H +/* + * 288 (#267 is the highest one actually hooked up) onchip GPIOs, plus enough + * room for a couple of GPIO expanders. + */ + +#if CONFIG_ARCH_NR_GPIO > 0 +#define ARCH_NR_GPIOS CONFIG_ARCH_NR_GPIO +#else +#define ARCH_NR_GPIOS 366 +#endif + +#define NOMADIK_NR_GPIO 288 + +#include <asm-generic/gpio.h> + +/* Invoke gpiolibs gpio_chip abstraction */ +#define gpio_get_value __gpio_get_value +#define gpio_set_value __gpio_set_value +#define gpio_cansleep __gpio_cansleep +#define gpio_to_irq __gpio_to_irq + +#define MOP500_EGPIO(x) (NOMADIK_NR_GPIO + (x)) +#define MOP500_EGPIO_END MOP500_EGPIO(24) +#define AB8500_GPIO_BASE MOP500_EGPIO_END #endif /* __ASM_ARCH_GPIO_H */ diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d0c41188d4e..5e073f74baa 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -479,7 +479,7 @@ config GPIO_JANZ_TTL config GPIO_AB8500 bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions" - depends on AB8500_CORE && BROKEN + depends on AB8500_CORE help Select this to enable the AB8500 IC GPIO driver diff --git a/drivers/gpio/gpio-ab8500.c b/drivers/gpio/gpio-ab8500.c index 050c05d9189..ef75984486c 100644 --- a/drivers/gpio/gpio-ab8500.c +++ b/drivers/gpio/gpio-ab8500.c @@ -18,9 +18,16 @@ #include <linux/gpio.h> #include <linux/irq.h> #include <linux/interrupt.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500/gpio.h> +#include <linux/mfd/abx500/ab8500-gpio.h> + + +/* + * The AB9540 GPIO support is an extended version of the + * AB8500 GPIO support. The AB9540 supports an additional + * (7th) register so that more GPIO may be configured and + * used. + */ /* * GPIO registers offset @@ -32,6 +39,7 @@ #define AB8500_GPIO_SEL4_REG 0x03 #define AB8500_GPIO_SEL5_REG 0x04 #define AB8500_GPIO_SEL6_REG 0x05 +#define AB9540_GPIO_SEL7_REG 0x06 #define AB8500_GPIO_DIR1_REG 0x10 #define AB8500_GPIO_DIR2_REG 0x11 @@ -39,6 +47,7 @@ #define AB8500_GPIO_DIR4_REG 0x13 #define AB8500_GPIO_DIR5_REG 0x14 #define AB8500_GPIO_DIR6_REG 0x15 +#define AB9540_GPIO_DIR7_REG 0x16 #define AB8500_GPIO_OUT1_REG 0x20 #define AB8500_GPIO_OUT2_REG 0x21 @@ -46,6 +55,7 @@ #define AB8500_GPIO_OUT4_REG 0x23 #define AB8500_GPIO_OUT5_REG 0x24 #define AB8500_GPIO_OUT6_REG 0x25 +#define AB9540_GPIO_OUT7_REG 0x26 #define AB8500_GPIO_PUD1_REG 0x30 #define AB8500_GPIO_PUD2_REG 0x31 @@ -53,6 +63,7 @@ #define AB8500_GPIO_PUD4_REG 0x33 #define AB8500_GPIO_PUD5_REG 0x34 #define AB8500_GPIO_PUD6_REG 0x35 +#define AB9540_GPIO_PUD7_REG 0x36 #define AB8500_GPIO_IN1_REG 0x40 #define AB8500_GPIO_IN2_REG 0x41 @@ -60,9 +71,13 @@ #define AB8500_GPIO_IN4_REG 0x43 #define AB8500_GPIO_IN5_REG 0x44 #define AB8500_GPIO_IN6_REG 0x45 -#define AB8500_GPIO_ALTFUN_REG 0x45 -#define ALTFUN_REG_INDEX 6 +#define AB9540_GPIO_IN7_REG 0x46 +#define AB8500_GPIO_ALTFUN_REG 0x50 +#define AB8500_ALTFUN_REG_INDEX 6 +#define AB9540_ALTFUN_REG_INDEX 7 #define AB8500_NUM_GPIO 42 +#define AB9540_NUM_GPIO 54 +#define AB8505_NUM_GPIO 53 #define AB8500_NUM_VIR_GPIO_IRQ 16 enum ab8500_gpio_action { @@ -73,6 +88,11 @@ enum ab8500_gpio_action { UNMASK }; +struct ab8500_gpio_irq_cluster { + int start; + int end; +}; + struct ab8500_gpio { struct gpio_chip chip; struct ab8500 *parent; @@ -82,7 +102,50 @@ struct ab8500_gpio { enum ab8500_gpio_action irq_action; u16 rising; u16 falling; + struct ab8500_gpio_irq_cluster *irq_cluster; + int irq_cluster_size; +}; + +/* + * Only some GPIOs are interrupt capable, and they are + * organized in discontiguous clusters: + * + * GPIO6 to GPIO13 + * GPIO24 and GPIO25 + * GPIO36 to GPIO41 + * GPIO50 to GPIO54 (AB9540 only) + */ +static struct ab8500_gpio_irq_cluster ab8500_irq_clusters[] = { + {.start = 5, .end = 12}, /* GPIO numbers start from 1 */ + {.start = 23, .end = 24}, + {.start = 35, .end = 40}, +}; + +static struct ab8500_gpio_irq_cluster ab9540_irq_clusters[] = { + {.start = 5, .end = 12}, /* GPIO numbers start from 1 */ + {.start = 23, .end = 24}, + {.start = 35, .end = 40}, + {.start = 49, .end = 53}, +}; + +/* + * For AB8505 Only some GPIOs are interrupt capable, and they are + * organized in discontiguous clusters: + * + * GPIO10 to GPIO11 + * GPIO13 + * GPIO40 and GPIO41 + * GPIO50 + * GPIO52 to GPIO53 + */ +static struct ab8500_gpio_irq_cluster ab8505_irq_clusters[] = { + {.start = 9, .end = 10}, /* GPIO numbers start from 1 */ + {.start = 12, .end = 12}, + {.start = 39, .end = 40}, + {.start = 49, .end = 49}, + {.start = 51, .end = 52}, }; + /** * to_ab8500_gpio() - get the pointer to ab8500_gpio * @chip: Member of the structure ab8500_gpio @@ -115,7 +178,7 @@ static int ab8500_gpio_get(struct gpio_chip *chip, unsigned offset) { struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); u8 mask = 1 << (offset % 8); - u8 reg = AB8500_GPIO_OUT1_REG + (offset / 8); + u8 reg = AB8500_GPIO_IN1_REG + (offset / 8); int ret; u8 data; ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC, @@ -132,7 +195,7 @@ static void ab8500_gpio_set(struct gpio_chip *chip, unsigned offset, int val) struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); int ret; /* Write the data */ - ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, 1); + ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val); if (ret < 0) dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); } @@ -162,28 +225,13 @@ static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int ab8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - /* - * Only some GPIOs are interrupt capable, and they are - * organized in discontiguous clusters: - * - * GPIO6 to GPIO13 - * GPIO24 and GPIO25 - * GPIO36 to GPIO41 - */ - static struct ab8500_gpio_irq_cluster { - int start; - int end; - } clusters[] = { - {.start = 6, .end = 13}, - {.start = 24, .end = 25}, - {.start = 36, .end = 41}, - }; struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); int base = ab8500_gpio->irq_base; int i; - for (i = 0; i < ARRAY_SIZE(clusters); i++) { - struct ab8500_gpio_irq_cluster *cluster = &clusters[i]; + for (i = 0; i < ab8500_gpio->irq_cluster_size; i++) { + struct ab8500_gpio_irq_cluster *cluster = + &ab8500_gpio->irq_cluster[i]; if (offset >= cluster->start && offset <= cluster->end) return base + offset - cluster->start; @@ -207,7 +255,7 @@ static struct gpio_chip ab8500gpio_chip = { static unsigned int irq_to_rising(unsigned int irq) { - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + struct ab8500_gpio *ab8500_gpio = irq_get_chip_data(irq); int offset = irq - ab8500_gpio->irq_base; int new_irq = offset + AB8500_INT_GPIO6R + ab8500_gpio->parent->irq_base; @@ -216,7 +264,7 @@ static unsigned int irq_to_rising(unsigned int irq) static unsigned int irq_to_falling(unsigned int irq) { - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + struct ab8500_gpio *ab8500_gpio = irq_get_chip_data(irq); int offset = irq - ab8500_gpio->irq_base; int new_irq = offset + AB8500_INT_GPIO6F + ab8500_gpio->parent->irq_base; @@ -261,15 +309,16 @@ static irqreturn_t handle_falling(int irq, void *dev) return IRQ_HANDLED; } -static void ab8500_gpio_irq_lock(unsigned int irq) +static void ab8500_gpio_irq_lock(struct irq_data *data) { - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + struct ab8500_gpio *ab8500_gpio = irq_data_get_irq_chip_data(data); mutex_lock(&ab8500_gpio->lock); } -static void ab8500_gpio_irq_sync_unlock(unsigned int irq) +static void ab8500_gpio_irq_sync_unlock(struct irq_data *data) { - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + struct ab8500_gpio *ab8500_gpio = irq_data_get_irq_chip_data(data); + unsigned int irq = data->irq; int offset = irq - ab8500_gpio->irq_base; bool rising = ab8500_gpio->rising & BIT(offset); bool falling = ab8500_gpio->falling & BIT(offset); @@ -280,12 +329,12 @@ static void ab8500_gpio_irq_sync_unlock(unsigned int irq) if (rising) ret = request_threaded_irq(irq_to_rising(irq), NULL, handle_rising, - IRQF_TRIGGER_RISING, + IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, "ab8500-gpio-r", ab8500_gpio); if (falling) ret = request_threaded_irq(irq_to_falling(irq), NULL, handle_falling, - IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND, "ab8500-gpio-f", ab8500_gpio); break; case SHUTDOWN: @@ -316,21 +365,22 @@ static void ab8500_gpio_irq_sync_unlock(unsigned int irq) } -static void ab8500_gpio_irq_mask(unsigned int irq) +static void ab8500_gpio_irq_mask(struct irq_data *data) { - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + struct ab8500_gpio *ab8500_gpio = irq_data_get_irq_chip_data(data); ab8500_gpio->irq_action = MASK; } -static void ab8500_gpio_irq_unmask(unsigned int irq) +static void ab8500_gpio_irq_unmask(struct irq_data *data) { - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + struct ab8500_gpio *ab8500_gpio = irq_data_get_irq_chip_data(data); ab8500_gpio->irq_action = UNMASK; } -static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type) +static int ab8500_gpio_irq_set_type(struct irq_data *data, unsigned int type) { - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + struct ab8500_gpio *ab8500_gpio = irq_data_get_irq_chip_data(data); + unsigned int irq = data->irq; int offset = irq - ab8500_gpio->irq_base; if (type == IRQ_TYPE_EDGE_BOTH) { @@ -344,28 +394,28 @@ static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type) return 0; } -unsigned int ab8500_gpio_irq_startup(unsigned int irq) +unsigned int ab8500_gpio_irq_startup(struct irq_data *data) { - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + struct ab8500_gpio *ab8500_gpio = irq_data_get_irq_chip_data(data); ab8500_gpio->irq_action = STARTUP; return 0; } -void ab8500_gpio_irq_shutdown(unsigned int irq) +void ab8500_gpio_irq_shutdown(struct irq_data *data) { - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + struct ab8500_gpio *ab8500_gpio = irq_data_get_irq_chip_data(data); ab8500_gpio->irq_action = SHUTDOWN; } static struct irq_chip ab8500_gpio_irq_chip = { .name = "ab8500-gpio", - .startup = ab8500_gpio_irq_startup, - .shutdown = ab8500_gpio_irq_shutdown, - .bus_lock = ab8500_gpio_irq_lock, - .bus_sync_unlock = ab8500_gpio_irq_sync_unlock, - .mask = ab8500_gpio_irq_mask, - .unmask = ab8500_gpio_irq_unmask, - .set_type = ab8500_gpio_irq_set_type, + .irq_startup = ab8500_gpio_irq_startup, + .irq_shutdown = ab8500_gpio_irq_shutdown, + .irq_bus_lock = ab8500_gpio_irq_lock, + .irq_bus_sync_unlock = ab8500_gpio_irq_sync_unlock, + .irq_mask = ab8500_gpio_irq_mask, + .irq_unmask = ab8500_gpio_irq_unmask, + .irq_set_type = ab8500_gpio_irq_set_type, }; static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio) @@ -374,14 +424,14 @@ static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio) int irq; for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) { - set_irq_chip_data(irq, ab8500_gpio); - set_irq_chip_and_handler(irq, &ab8500_gpio_irq_chip, + irq_set_chip_data(irq, ab8500_gpio); + irq_set_chip_and_handler(irq, &ab8500_gpio_irq_chip, handle_simple_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -397,19 +447,22 @@ static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio) #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } } static int __devinit ab8500_gpio_probe(struct platform_device *pdev) { + struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent); struct ab8500_platform_data *ab8500_pdata = dev_get_platdata(pdev->dev.parent); struct ab8500_gpio_platform_data *pdata; struct ab8500_gpio *ab8500_gpio; int ret; int i; + int last_gpio_sel_reg; + int altfun_reg_index; pdata = ab8500_pdata->gpio; if (!pdata) { @@ -425,10 +478,36 @@ static int __devinit ab8500_gpio_probe(struct platform_device *pdev) ab8500_gpio->dev = &pdev->dev; ab8500_gpio->parent = dev_get_drvdata(pdev->dev.parent); ab8500_gpio->chip = ab8500gpio_chip; - ab8500_gpio->chip.ngpio = AB8500_NUM_GPIO; ab8500_gpio->chip.dev = &pdev->dev; ab8500_gpio->chip.base = pdata->gpio_base; ab8500_gpio->irq_base = pdata->irq_base; + + /* Configure GPIO Settings for specific AB devices */ + if (cpu_is_u9540()) { + ab8500_gpio->chip.ngpio = AB9540_NUM_GPIO; + ab8500_gpio->irq_cluster = ab9540_irq_clusters; + ab8500_gpio->irq_cluster_size = + ARRAY_SIZE(ab9540_irq_clusters); + last_gpio_sel_reg = AB9540_GPIO_SEL7_REG; + altfun_reg_index = AB9540_ALTFUN_REG_INDEX; + } else { + if (is_ab8505(parent)) { + ab8500_gpio->chip.ngpio = AB8505_NUM_GPIO; + ab8500_gpio->irq_cluster = ab8505_irq_clusters; + ab8500_gpio->irq_cluster_size = + ARRAY_SIZE(ab8505_irq_clusters); + last_gpio_sel_reg = AB9540_GPIO_SEL7_REG; + altfun_reg_index = AB9540_ALTFUN_REG_INDEX; + } else { + ab8500_gpio->chip.ngpio = AB8500_NUM_GPIO; + ab8500_gpio->irq_cluster = ab8500_irq_clusters; + ab8500_gpio->irq_cluster_size = + ARRAY_SIZE(ab8500_irq_clusters); + last_gpio_sel_reg = AB8500_GPIO_SEL6_REG; + altfun_reg_index = AB8500_ALTFUN_REG_INDEX; + } + } + /* initialize the lock */ mutex_init(&ab8500_gpio->lock); /* @@ -437,16 +516,28 @@ static int __devinit ab8500_gpio_probe(struct platform_device *pdev) * These values are for selecting the PINs as * GPIO or alternate function */ - for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_REG; i++) { + for (i = AB8500_GPIO_SEL1_REG; i <= last_gpio_sel_reg; i++) { ret = abx500_set_register_interruptible(ab8500_gpio->dev, AB8500_MISC, i, pdata->config_reg[i]); if (ret < 0) goto out_free; + + ret = abx500_set_register_interruptible(ab8500_gpio->dev, + AB8500_MISC, i + AB8500_GPIO_DIR1_REG, + pdata->config_direction[i]); + if (ret < 0) + goto out_free; + + ret = abx500_set_register_interruptible(ab8500_gpio->dev, + AB8500_MISC, i + AB8500_GPIO_PUD1_REG, + pdata->config_pullups[i]); + if (ret < 0) + goto out_free; } ret = abx500_set_register_interruptible(ab8500_gpio->dev, AB8500_MISC, AB8500_GPIO_ALTFUN_REG, - pdata->config_reg[ALTFUN_REG_INDEX]); + pdata->config_reg[altfun_reg_index]); if (ret < 0) goto out_free; @@ -493,6 +584,86 @@ static int __devexit ab8500_gpio_remove(struct platform_device *pdev) return 0; } +int ab8500_config_pulldown(struct device *dev, + enum ab8500_pin gpio, bool enable) +{ + u8 offset = gpio - AB8500_PIN_GPIO1; + u8 pos = offset % 8; + u8 val = enable ? 0 : 1; + u8 reg = AB8500_GPIO_PUD1_REG + (offset / 8); + int ret; + + ret = abx500_mask_and_set_register_interruptible(dev, + AB8500_MISC, reg, 1 << pos, val << pos); + if (ret < 0) + dev_err(dev, "%s write failed\n", __func__); + return ret; +} +EXPORT_SYMBOL(ab8500_config_pulldown); + +/* + * ab8500_gpio_config_select() + * + * Configure functionality of pin, either specific use or GPIO. + * @dev: device pointer + * @gpio: gpio number + * @gpio_select: true if the pin should be used as GPIO + */ +int ab8500_gpio_config_select(struct device *dev, + enum ab8500_pin gpio, bool gpio_select) +{ + u8 offset = gpio - AB8500_PIN_GPIO1; + u8 reg = AB8500_GPIO_SEL1_REG + (offset / 8); + u8 pos = offset % 8; + u8 val = gpio_select ? 1 : 0; + int ret; + + ret = abx500_mask_and_set_register_interruptible(dev, + AB8500_MISC, reg, 1 << pos, val << pos); + if (ret < 0) + dev_err(dev, "%s write failed\n", __func__); + + dev_vdbg(dev, "%s (bank, addr, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + __func__, AB8500_MISC, reg, 1 << pos, val << pos); + + return ret; +} + +/* + * ab8500_gpio_config_get_select() + * + * Read currently configured functionality, either specific use or GPIO. + * @dev: device pointer + * @gpio: gpio number + * @gpio_select: pointer to pin selection status + */ +int ab8500_gpio_config_get_select(struct device *dev, + enum ab8500_pin gpio, bool *gpio_select) +{ + u8 offset = gpio - AB8500_PIN_GPIO1; + u8 reg = AB8500_GPIO_SEL1_REG + (offset / 8); + u8 pos = offset % 8; + u8 val; + int ret; + + ret = abx500_get_register_interruptible(dev, + AB8500_MISC, reg, &val); + if (ret < 0) { + dev_err(dev, "%s read failed\n", __func__); + return ret; + } + + if (val & (1 << pos)) + *gpio_select = true; + else + *gpio_select = false; + + dev_vdbg(dev, "%s (bank, addr, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + __func__, AB8500_MISC, reg, 1 << pos, val); + + return 0; +} + static struct platform_driver ab8500_gpio_driver = { .driver = { .name = "ab8500-gpio", diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/gpio/gpio-nomadik.c index d350c8d7d2d..c101825235a 100644 --- a/drivers/gpio/gpio-nomadik.c +++ b/drivers/gpio/gpio-nomadik.c @@ -23,11 +23,11 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/slab.h> +#include <linux/gpio/nomadik.h> #include <asm/mach/irq.h> #include <plat/pincfg.h> -#include <plat/gpio-nomadik.h> #include <mach/hardware.h> #include <asm/gpio.h> @@ -58,8 +58,11 @@ struct nmk_gpio_chip { u32 real_wake; u32 rwimsc; u32 fwimsc; + u32 rimsc; + u32 fimsc; u32 slpm; u32 pull_up; + u32 lowemi; }; static struct nmk_gpio_chip * @@ -124,6 +127,24 @@ static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip, } } +static void __nmk_gpio_set_lowemi(struct nmk_gpio_chip *nmk_chip, + unsigned offset, bool lowemi) +{ + u32 bit = BIT(offset); + bool enabled = nmk_chip->lowemi & bit; + + if (lowemi == enabled) + return; + + if (lowemi) + nmk_chip->lowemi |= bit; + else + nmk_chip->lowemi &= ~bit; + + writel_relaxed(nmk_chip->lowemi, + nmk_chip->addr + NMK_GPIO_LOWEMI); +} + static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip, unsigned offset) { @@ -150,8 +171,8 @@ static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip, unsigned offset, int gpio_mode, bool glitch) { - u32 rwimsc = readl(nmk_chip->addr + NMK_GPIO_RWIMSC); - u32 fwimsc = readl(nmk_chip->addr + NMK_GPIO_FWIMSC); + u32 rwimsc = nmk_chip->rwimsc; + u32 fwimsc = nmk_chip->fwimsc; if (glitch && nmk_chip->set_ioforce) { u32 bit = BIT(offset); @@ -173,6 +194,36 @@ static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip, } } +static void +nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) +{ + u32 falling = nmk_chip->fimsc & BIT(offset); + u32 rising = nmk_chip->rimsc & BIT(offset); + int gpio = nmk_chip->chip.base + offset; + int irq = NOMADIK_GPIO_TO_IRQ(gpio); + struct irq_data *d = irq_get_irq_data(irq); + + if (!rising && !falling) + return; + + if (!d || !irqd_irq_disabled(d)) + return; + + if (rising) { + nmk_chip->rimsc &= ~BIT(offset); + writel_relaxed(nmk_chip->rimsc, + nmk_chip->addr + NMK_GPIO_RIMSC); + } + + if (falling) { + nmk_chip->fimsc &= ~BIT(offset); + writel_relaxed(nmk_chip->fimsc, + nmk_chip->addr + NMK_GPIO_FIMSC); + } + + dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio); +} + static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, pin_cfg_t cfg, bool sleep, unsigned int *slpmregs) { @@ -238,6 +289,17 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, __nmk_gpio_set_pull(nmk_chip, offset, pull); } + __nmk_gpio_set_lowemi(nmk_chip, offset, PIN_LOWEMI(cfg)); + + /* + * If the pin is switching to altfunc, and there was an interrupt + * installed on it which has been lazy disabled, actually mask the + * interrupt to prevent spurious interrupts that would occur while the + * pin is under control of the peripheral. Only SKE does this. + */ + if (af != NMK_GPIO_ALT_GPIO) + nmk_gpio_disable_lazy_irq(nmk_chip, offset); + /* * If we've backed up the SLPM registers (glitch workaround), modify * the backups since they will be restored. @@ -556,27 +618,38 @@ static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip, int gpio, enum nmk_gpio_irq_type which, bool enable) { - u32 rimsc = which == WAKE ? NMK_GPIO_RWIMSC : NMK_GPIO_RIMSC; - u32 fimsc = which == WAKE ? NMK_GPIO_FWIMSC : NMK_GPIO_FIMSC; u32 bitmask = nmk_gpio_get_bitmask(gpio); - u32 reg; + u32 *rimscval; + u32 *fimscval; + u32 rimscreg; + u32 fimscreg; + + if (which == NORMAL) { + rimscreg = NMK_GPIO_RIMSC; + fimscreg = NMK_GPIO_FIMSC; + rimscval = &nmk_chip->rimsc; + fimscval = &nmk_chip->fimsc; + } else { + rimscreg = NMK_GPIO_RWIMSC; + fimscreg = NMK_GPIO_FWIMSC; + rimscval = &nmk_chip->rwimsc; + fimscval = &nmk_chip->fwimsc; + } /* we must individually set/clear the two edges */ if (nmk_chip->edge_rising & bitmask) { - reg = readl(nmk_chip->addr + rimsc); if (enable) - reg |= bitmask; + *rimscval |= bitmask; else - reg &= ~bitmask; - writel(reg, nmk_chip->addr + rimsc); + *rimscval &= ~bitmask; + writel(*rimscval, nmk_chip->addr + rimscreg); } if (nmk_chip->edge_falling & bitmask) { - reg = readl(nmk_chip->addr + fimsc); if (enable) - reg |= bitmask; + *fimscval |= bitmask; else - reg &= ~bitmask; - writel(reg, nmk_chip->addr + fimsc); + *fimscval &= ~bitmask; + writel(*fimscval, nmk_chip->addr + fimscreg); } } @@ -1008,9 +1081,6 @@ void nmk_gpio_wakeups_suspend(void) clk_enable(chip->clk); - chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC); - chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC); - writel(chip->rwimsc & chip->real_wake, chip->addr + NMK_GPIO_RWIMSC); writel(chip->fwimsc & chip->real_wake, @@ -1123,7 +1193,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) */ nmk_chip->bank = dev->id; nmk_chip->clk = clk; - nmk_chip->addr = io_p2v(res->start); + nmk_chip->addr = __io(IO_ADDRESS(res->start)); nmk_chip->chip = nmk_gpio_template; nmk_chip->parent_irq = irq; nmk_chip->secondary_parent_irq = secondary_irq; @@ -1139,6 +1209,10 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) chip->dev = &dev->dev; chip->owner = THIS_MODULE; + clk_enable(nmk_chip->clk); + nmk_chip->lowemi = readl_relaxed(nmk_chip->addr + NMK_GPIO_LOWEMI); + clk_disable(nmk_chip->clk); + ret = gpiochip_add(&nmk_chip->chip); if (ret) goto out_free; diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 87a68a896ab..094c5c4fd7f 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); diff --git a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h b/include/linux/gpio/nomadik.h index 9605bf227df..3e8b7f16fb7 100644 --- a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h +++ b/include/linux/gpio/nomadik.h @@ -29,6 +29,7 @@ #define NMK_GPIO_SLPC 0x1c #define NMK_GPIO_AFSLA 0x20 #define NMK_GPIO_AFSLB 0x24 +#define NMK_GPIO_LOWEMI 0x28 #define NMK_GPIO_RIMSC 0x40 #define NMK_GPIO_FIMSC 0x44 diff --git a/include/linux/mfd/abx500/ab8500-gpio.h b/include/linux/mfd/abx500/ab8500-gpio.h index 488a8c920a2..67ac32c1dcb 100644 --- a/include/linux/mfd/abx500/ab8500-gpio.h +++ b/include/linux/mfd/abx500/ab8500-gpio.h @@ -8,14 +8,94 @@ #ifndef _AB8500_GPIO_H #define _AB8500_GPIO_H +#include <mach/gpio.h> + /* * Platform data to register a block: only the initial gpio/irq number. + * Array sizes are large enough to contain all AB8500 and AB9540 GPIO + * registers. */ struct ab8500_gpio_platform_data { int gpio_base; u32 irq_base; - u8 config_reg[7]; + u8 config_reg[8]; + u8 config_direction[7]; + u8 config_pullups[7]; +}; + +enum ab8500_pin { + AB8500_PIN_GPIO1 = AB8500_GPIO_BASE, + AB8500_PIN_GPIO2, + AB8500_PIN_GPIO3, + AB8500_PIN_GPIO4, + AB8500_PIN_GPIO5, + AB8500_PIN_GPIO6, + AB8500_PIN_GPIO7, + AB8500_PIN_GPIO8, + AB8500_PIN_GPIO9, + AB8500_PIN_GPIO10, + AB8500_PIN_GPIO11, + AB8500_PIN_GPIO12, + AB8500_PIN_GPIO13, + AB8500_PIN_GPIO14, + AB8500_PIN_GPIO15, + AB8500_PIN_GPIO16, + AB8500_PIN_GPIO17, + AB8500_PIN_GPIO18, + AB8500_PIN_GPIO19, + AB8500_PIN_GPIO20, + AB8500_PIN_GPIO21, + AB8500_PIN_GPIO22, + AB8500_PIN_GPIO23, + AB8500_PIN_GPIO24, + AB8500_PIN_GPIO25, + AB8500_PIN_GPIO26, + AB8500_PIN_GPIO27, + AB8500_PIN_GPIO28, + AB8500_PIN_GPIO29, + AB8500_PIN_GPIO30, + AB8500_PIN_GPIO31, + AB8500_PIN_GPIO32, + AB8500_PIN_GPIO33, + AB8500_PIN_GPIO34, + AB8500_PIN_GPIO35, + AB8500_PIN_GPIO36, + AB8500_PIN_GPIO37, + AB8500_PIN_GPIO38, + AB8500_PIN_GPIO39, + AB8500_PIN_GPIO40, + AB8500_PIN_GPIO41, + AB8500_PIN_GPIO42, + /* AB9540 GPIO extends support provided by AB8500 */ + AB9540_PIN_GPIO43, + AB9540_PIN_GPIO44, + AB9540_PIN_GPIO45, + AB9540_PIN_GPIO46, + AB9540_PIN_GPIO47, + AB9540_PIN_GPIO48, + AB9540_PIN_GPIO49, + AB9540_PIN_GPIO50, + AB9540_PIN_GPIO51, + AB9540_PIN_GPIO52, + AB9540_PIN_GPIO53, + /* + * AB9540_PIN_GPIO60 is configured, in the AB9540 GPIO registers, where + * AB9540_PIN_GPIO54 would be expected. AB9540_PIN_GPIO54 to + * AB9540_PIN_GPIO59 do not exist and no reserved space has been left + * for them in the registers. Therefore the enum goes directly from + * AB9540_PIN_GPIO53 to AB9540_PIN_GPIO60. + */ + AB9540_PIN_GPIO60, }; +int ab8500_config_pulldown(struct device *dev, + enum ab8500_pin gpio, bool enable); + +int ab8500_gpio_config_select(struct device *dev, + enum ab8500_pin gpio, bool gpio_select); + +int ab8500_gpio_config_get_select(struct device *dev, + enum ab8500_pin gpio, bool *gpio_select); + #endif /* _AB8500_GPIO_H */ |