diff options
author | Lee Jones <lee.jones@linaro.org> | 2012-01-05 14:07:30 +0000 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2012-01-05 14:07:30 +0000 |
commit | 819ce4853d4af0d82b7090989616304974d397a0 (patch) | |
tree | 85d8073b3cdd42893894e9bfe4a7abd5c177e181 /drivers | |
parent | 09863046a3019b480188a795e641296c86e7148c (diff) | |
parent | 071e79feac368ace3271cfcba076092b8a23a431 (diff) |
Merge branch 'tracking-igloo_kernel-gpio' into merge-integration-linux-ux500
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-ab8500.c | 164 | ||||
-rw-r--r-- | drivers/gpio/gpio-nomadik.c | 108 |
3 files changed, 221 insertions, 53 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8482a23887d..892f8e75c26 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..a0253ad14df 100644 --- a/drivers/gpio/gpio-ab8500.c +++ b/drivers/gpio/gpio-ab8500.c @@ -60,7 +60,7 @@ #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 AB8500_GPIO_ALTFUN_REG 0x50 #define ALTFUN_REG_INDEX 6 #define AB8500_NUM_GPIO 42 #define AB8500_NUM_VIR_GPIO_IRQ 16 @@ -115,7 +115,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 +132,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__); } @@ -174,9 +174,9 @@ static int ab8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) int start; int end; } clusters[] = { - {.start = 6, .end = 13}, - {.start = 24, .end = 25}, - {.start = 36, .end = 41}, + {.start = 5, .end = 12}, /* GPIO numbers start from 1 */ + {.start = 23, .end = 24}, + {.start = 35, .end = 40}, }; struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); int base = ab8500_gpio->irq_base; @@ -207,7 +207,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 +216,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 +261,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); @@ -316,21 +317,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 +346,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 +376,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,8 +399,8 @@ 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); } } @@ -443,6 +445,18 @@ static int __devinit ab8500_gpio_probe(struct platform_device *pdev) 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, @@ -493,6 +507,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 08fd87766e0..7a4fd81a195 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, @@ -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; |