Message ID | 1358242975-5084-1-git-send-email-linus.walleij@stericsson.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, 15 Jan 2013 10:42:55 +0100, Linus Walleij <linus.walleij@stericsson.com> wrote: > From: Linus Walleij <linus.walleij@linaro.org> > > The AB8500 GPIO driver has been marked BROKEN for ages, and we > have something better in store: a shiny new pinctrl driver. So > let use delete this old driver as the first step. > > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Grant Likely <grant.likely@secretlab.ca> I'm assuming you'll put this into your for-next branch. g. > --- > drivers/gpio/Kconfig | 6 - > drivers/gpio/Makefile | 1 - > drivers/gpio/gpio-ab8500.c | 520 --------------------------------------------- > 3 files changed, 527 deletions(-) > delete mode 100644 drivers/gpio/gpio-ab8500.c > > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index 682de75..e5116fa 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -657,12 +657,6 @@ config GPIO_JANZ_TTL > This driver provides support for driving the pins in output > mode only. Input mode is not supported. > > -config GPIO_AB8500 > - bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions" > - depends on AB8500_CORE && BROKEN > - help > - Select this to enable the AB8500 IC GPIO driver > - > config GPIO_TPS6586X > bool "TPS6586X GPIO" > depends on MFD_TPS6586X > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > index c5aebd0..45a388c 100644 > --- a/drivers/gpio/Makefile > +++ b/drivers/gpio/Makefile > @@ -10,7 +10,6 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o > obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o > > obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o > -obj-$(CONFIG_GPIO_AB8500) += gpio-ab8500.o > obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o > obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o > obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o > diff --git a/drivers/gpio/gpio-ab8500.c b/drivers/gpio/gpio-ab8500.c > deleted file mode 100644 > index 983ad42..0000000 > --- a/drivers/gpio/gpio-ab8500.c > +++ /dev/null > @@ -1,520 +0,0 @@ > -/* > - * Copyright (C) ST-Ericsson SA 2011 > - * > - * Author: BIBEK BASU <bibek.basu@stericsson.com> > - * License terms: GNU General Public License (GPL) version 2 > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License version 2 as > - * published by the Free Software Foundation. > - */ > -#include <linux/kernel.h> > -#include <linux/types.h> > -#include <linux/slab.h> > -#include <linux/init.h> > -#include <linux/module.h> > -#include <linux/err.h> > -#include <linux/platform_device.h> > -#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> > - > -/* > - * GPIO registers offset > - * Bank: 0x10 > - */ > -#define AB8500_GPIO_SEL1_REG 0x00 > -#define AB8500_GPIO_SEL2_REG 0x01 > -#define AB8500_GPIO_SEL3_REG 0x02 > -#define AB8500_GPIO_SEL4_REG 0x03 > -#define AB8500_GPIO_SEL5_REG 0x04 > -#define AB8500_GPIO_SEL6_REG 0x05 > - > -#define AB8500_GPIO_DIR1_REG 0x10 > -#define AB8500_GPIO_DIR2_REG 0x11 > -#define AB8500_GPIO_DIR3_REG 0x12 > -#define AB8500_GPIO_DIR4_REG 0x13 > -#define AB8500_GPIO_DIR5_REG 0x14 > -#define AB8500_GPIO_DIR6_REG 0x15 > - > -#define AB8500_GPIO_OUT1_REG 0x20 > -#define AB8500_GPIO_OUT2_REG 0x21 > -#define AB8500_GPIO_OUT3_REG 0x22 > -#define AB8500_GPIO_OUT4_REG 0x23 > -#define AB8500_GPIO_OUT5_REG 0x24 > -#define AB8500_GPIO_OUT6_REG 0x25 > - > -#define AB8500_GPIO_PUD1_REG 0x30 > -#define AB8500_GPIO_PUD2_REG 0x31 > -#define AB8500_GPIO_PUD3_REG 0x32 > -#define AB8500_GPIO_PUD4_REG 0x33 > -#define AB8500_GPIO_PUD5_REG 0x34 > -#define AB8500_GPIO_PUD6_REG 0x35 > - > -#define AB8500_GPIO_IN1_REG 0x40 > -#define AB8500_GPIO_IN2_REG 0x41 > -#define AB8500_GPIO_IN3_REG 0x42 > -#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 AB8500_NUM_GPIO 42 > -#define AB8500_NUM_VIR_GPIO_IRQ 16 > - > -enum ab8500_gpio_action { > - NONE, > - STARTUP, > - SHUTDOWN, > - MASK, > - UNMASK > -}; > - > -struct ab8500_gpio { > - struct gpio_chip chip; > - struct ab8500 *parent; > - struct device *dev; > - struct mutex lock; > - u32 irq_base; > - enum ab8500_gpio_action irq_action; > - u16 rising; > - u16 falling; > -}; > -/** > - * to_ab8500_gpio() - get the pointer to ab8500_gpio > - * @chip: Member of the structure ab8500_gpio > - */ > -static inline struct ab8500_gpio *to_ab8500_gpio(struct gpio_chip *chip) > -{ > - return container_of(chip, struct ab8500_gpio, chip); > -} > - > -static int ab8500_gpio_set_bits(struct gpio_chip *chip, u8 reg, > - unsigned offset, int val) > -{ > - struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); > - u8 pos = offset % 8; > - int ret; > - > - reg = reg + (offset / 8); > - ret = abx500_mask_and_set_register_interruptible(ab8500_gpio->dev, > - AB8500_MISC, reg, 1 << pos, val << pos); > - if (ret < 0) > - dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); > - return ret; > -} > -/** > - * ab8500_gpio_get() - Get the particular GPIO value > - * @chip: Gpio device > - * @offset: GPIO number to read > - */ > -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); > - int ret; > - u8 data; > - ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC, > - reg, &data); > - if (ret < 0) { > - dev_err(ab8500_gpio->dev, "%s read failed\n", __func__); > - return ret; > - } > - return (data & mask) >> (offset % 8); > -} > - > -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); > - if (ret < 0) > - dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); > -} > - > -static int ab8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, > - int val) > -{ > - int ret; > - /* set direction as output */ > - ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1); > - if (ret < 0) > - return ret; > - /* disable pull down */ > - ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1); > - if (ret < 0) > - return ret; > - /* set the output as 1 or 0 */ > - return ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val); > - > -} > - > -static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) > -{ > - /* set the register as input */ > - return ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0); > -} > - > -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]; > - > - if (offset >= cluster->start && offset <= cluster->end) > - return base + offset - cluster->start; > - > - /* Advance by the number of gpios in this cluster */ > - base += cluster->end - cluster->start + 1; > - } > - > - return -EINVAL; > -} > - > -static struct gpio_chip ab8500gpio_chip = { > - .label = "ab8500_gpio", > - .owner = THIS_MODULE, > - .direction_input = ab8500_gpio_direction_input, > - .get = ab8500_gpio_get, > - .direction_output = ab8500_gpio_direction_output, > - .set = ab8500_gpio_set, > - .to_irq = ab8500_gpio_to_irq, > -}; > - > -static unsigned int irq_to_rising(unsigned int irq) > -{ > - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); > - int offset = irq - ab8500_gpio->irq_base; > - int new_irq = offset + AB8500_INT_GPIO6R > - + ab8500_gpio->parent->irq_base; > - return new_irq; > -} > - > -static unsigned int irq_to_falling(unsigned int irq) > -{ > - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); > - int offset = irq - ab8500_gpio->irq_base; > - int new_irq = offset + AB8500_INT_GPIO6F > - + ab8500_gpio->parent->irq_base; > - return new_irq; > - > -} > - > -static unsigned int rising_to_irq(unsigned int irq, void *dev) > -{ > - struct ab8500_gpio *ab8500_gpio = dev; > - int offset = irq - AB8500_INT_GPIO6R > - - ab8500_gpio->parent->irq_base ; > - int new_irq = offset + ab8500_gpio->irq_base; > - return new_irq; > -} > - > -static unsigned int falling_to_irq(unsigned int irq, void *dev) > -{ > - struct ab8500_gpio *ab8500_gpio = dev; > - int offset = irq - AB8500_INT_GPIO6F > - - ab8500_gpio->parent->irq_base ; > - int new_irq = offset + ab8500_gpio->irq_base; > - return new_irq; > - > -} > - > -/* > - * IRQ handler > - */ > - > -static irqreturn_t handle_rising(int irq, void *dev) > -{ > - > - handle_nested_irq(rising_to_irq(irq , dev)); > - return IRQ_HANDLED; > -} > - > -static irqreturn_t handle_falling(int irq, void *dev) > -{ > - > - handle_nested_irq(falling_to_irq(irq, dev)); > - return IRQ_HANDLED; > -} > - > -static void ab8500_gpio_irq_lock(unsigned int irq) > -{ > - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); > - mutex_lock(&ab8500_gpio->lock); > -} > - > -static void ab8500_gpio_irq_sync_unlock(unsigned int irq) > -{ > - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); > - int offset = irq - ab8500_gpio->irq_base; > - bool rising = ab8500_gpio->rising & BIT(offset); > - bool falling = ab8500_gpio->falling & BIT(offset); > - int ret; > - > - switch (ab8500_gpio->irq_action) { > - case STARTUP: > - if (rising) > - ret = request_threaded_irq(irq_to_rising(irq), > - NULL, handle_rising, > - IRQF_TRIGGER_RISING, > - "ab8500-gpio-r", ab8500_gpio); > - if (falling) > - ret = request_threaded_irq(irq_to_falling(irq), > - NULL, handle_falling, > - IRQF_TRIGGER_FALLING, > - "ab8500-gpio-f", ab8500_gpio); > - break; > - case SHUTDOWN: > - if (rising) > - free_irq(irq_to_rising(irq), ab8500_gpio); > - if (falling) > - free_irq(irq_to_falling(irq), ab8500_gpio); > - break; > - case MASK: > - if (rising) > - disable_irq(irq_to_rising(irq)); > - if (falling) > - disable_irq(irq_to_falling(irq)); > - break; > - case UNMASK: > - if (rising) > - enable_irq(irq_to_rising(irq)); > - if (falling) > - enable_irq(irq_to_falling(irq)); > - break; > - case NONE: > - break; > - } > - ab8500_gpio->irq_action = NONE; > - ab8500_gpio->rising &= ~(BIT(offset)); > - ab8500_gpio->falling &= ~(BIT(offset)); > - mutex_unlock(&ab8500_gpio->lock); > -} > - > - > -static void ab8500_gpio_irq_mask(unsigned int irq) > -{ > - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); > - ab8500_gpio->irq_action = MASK; > -} > - > -static void ab8500_gpio_irq_unmask(unsigned int irq) > -{ > - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); > - ab8500_gpio->irq_action = UNMASK; > -} > - > -static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type) > -{ > - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); > - int offset = irq - ab8500_gpio->irq_base; > - > - if (type == IRQ_TYPE_EDGE_BOTH) { > - ab8500_gpio->rising = BIT(offset); > - ab8500_gpio->falling = BIT(offset); > - } else if (type == IRQ_TYPE_EDGE_RISING) { > - ab8500_gpio->rising = BIT(offset); > - } else { > - ab8500_gpio->falling = BIT(offset); > - } > - return 0; > -} > - > -unsigned int ab8500_gpio_irq_startup(unsigned int irq) > -{ > - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); > - ab8500_gpio->irq_action = STARTUP; > - return 0; > -} > - > -void ab8500_gpio_irq_shutdown(unsigned int irq) > -{ > - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); > - 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, > -}; > - > -static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio) > -{ > - u32 base = ab8500_gpio->irq_base; > - 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, > - handle_simple_irq); > - set_irq_nested_thread(irq, 1); > -#ifdef CONFIG_ARM > - set_irq_flags(irq, IRQF_VALID); > -#else > - set_irq_noprobe(irq); > -#endif > - } > - > - return 0; > -} > - > -static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio) > -{ > - int base = ab8500_gpio->irq_base; > - int irq; > - > - for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) { > -#ifdef CONFIG_ARM > - set_irq_flags(irq, 0); > -#endif > - set_irq_chip_and_handler(irq, NULL, NULL); > - set_irq_chip_data(irq, NULL); > - } > -} > - > -static int ab8500_gpio_probe(struct platform_device *pdev) > -{ > - 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; > - > - pdata = ab8500_pdata->gpio; > - if (!pdata) { > - dev_err(&pdev->dev, "gpio platform data missing\n"); > - return -ENODEV; > - } > - > - ab8500_gpio = kzalloc(sizeof(struct ab8500_gpio), GFP_KERNEL); > - if (ab8500_gpio == NULL) { > - dev_err(&pdev->dev, "failed to allocate memory\n"); > - return -ENOMEM; > - } > - 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; > - /* initialize the lock */ > - mutex_init(&ab8500_gpio->lock); > - /* > - * AB8500 core will handle and clear the IRQ > - * configre GPIO based on config-reg value. > - * These values are for selecting the PINs as > - * GPIO or alternate function > - */ > - for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_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, > - AB8500_GPIO_ALTFUN_REG, > - pdata->config_reg[ALTFUN_REG_INDEX]); > - if (ret < 0) > - goto out_free; > - > - ret = ab8500_gpio_irq_init(ab8500_gpio); > - if (ret) > - goto out_free; > - ret = gpiochip_add(&ab8500_gpio->chip); > - if (ret) { > - dev_err(&pdev->dev, "unable to add gpiochip: %d\n", > - ret); > - goto out_rem_irq; > - } > - platform_set_drvdata(pdev, ab8500_gpio); > - return 0; > - > -out_rem_irq: > - ab8500_gpio_irq_remove(ab8500_gpio); > -out_free: > - mutex_destroy(&ab8500_gpio->lock); > - kfree(ab8500_gpio); > - return ret; > -} > - > -/* > - * ab8500_gpio_remove() - remove Ab8500-gpio driver > - * @pdev : Platform device registered > - */ > -static int ab8500_gpio_remove(struct platform_device *pdev) > -{ > - struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev); > - int ret; > - > - ret = gpiochip_remove(&ab8500_gpio->chip); > - if (ret < 0) { > - dev_err(ab8500_gpio->dev, "unable to remove gpiochip: %d\n", > - ret); > - return ret; > - } > - > - platform_set_drvdata(pdev, NULL); > - mutex_destroy(&ab8500_gpio->lock); > - kfree(ab8500_gpio); > - > - return 0; > -} > - > -static struct platform_driver ab8500_gpio_driver = { > - .driver = { > - .name = "ab8500-gpio", > - .owner = THIS_MODULE, > - }, > - .probe = ab8500_gpio_probe, > - .remove = ab8500_gpio_remove, > -}; > - > -static int __init ab8500_gpio_init(void) > -{ > - return platform_driver_register(&ab8500_gpio_driver); > -} > -arch_initcall(ab8500_gpio_init); > - > -static void __exit ab8500_gpio_exit(void) > -{ > - platform_driver_unregister(&ab8500_gpio_driver); > -} > -module_exit(ab8500_gpio_exit); > - > -MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>"); > -MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins to be used as GPIO"); > -MODULE_ALIAS("platform:ab8500-gpio"); > -MODULE_LICENSE("GPL v2"); > -- > 1.7.11.3 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 682de75..e5116fa 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -657,12 +657,6 @@ config GPIO_JANZ_TTL This driver provides support for driving the pins in output mode only. Input mode is not supported. -config GPIO_AB8500 - bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions" - depends on AB8500_CORE && BROKEN - help - Select this to enable the AB8500 IC GPIO driver - config GPIO_TPS6586X bool "TPS6586X GPIO" depends on MFD_TPS6586X diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c5aebd0..45a388c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o -obj-$(CONFIG_GPIO_AB8500) += gpio-ab8500.o obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o diff --git a/drivers/gpio/gpio-ab8500.c b/drivers/gpio/gpio-ab8500.c deleted file mode 100644 index 983ad42..0000000 --- a/drivers/gpio/gpio-ab8500.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * Author: BIBEK BASU <bibek.basu@stericsson.com> - * License terms: GNU General Public License (GPL) version 2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/err.h> -#include <linux/platform_device.h> -#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> - -/* - * GPIO registers offset - * Bank: 0x10 - */ -#define AB8500_GPIO_SEL1_REG 0x00 -#define AB8500_GPIO_SEL2_REG 0x01 -#define AB8500_GPIO_SEL3_REG 0x02 -#define AB8500_GPIO_SEL4_REG 0x03 -#define AB8500_GPIO_SEL5_REG 0x04 -#define AB8500_GPIO_SEL6_REG 0x05 - -#define AB8500_GPIO_DIR1_REG 0x10 -#define AB8500_GPIO_DIR2_REG 0x11 -#define AB8500_GPIO_DIR3_REG 0x12 -#define AB8500_GPIO_DIR4_REG 0x13 -#define AB8500_GPIO_DIR5_REG 0x14 -#define AB8500_GPIO_DIR6_REG 0x15 - -#define AB8500_GPIO_OUT1_REG 0x20 -#define AB8500_GPIO_OUT2_REG 0x21 -#define AB8500_GPIO_OUT3_REG 0x22 -#define AB8500_GPIO_OUT4_REG 0x23 -#define AB8500_GPIO_OUT5_REG 0x24 -#define AB8500_GPIO_OUT6_REG 0x25 - -#define AB8500_GPIO_PUD1_REG 0x30 -#define AB8500_GPIO_PUD2_REG 0x31 -#define AB8500_GPIO_PUD3_REG 0x32 -#define AB8500_GPIO_PUD4_REG 0x33 -#define AB8500_GPIO_PUD5_REG 0x34 -#define AB8500_GPIO_PUD6_REG 0x35 - -#define AB8500_GPIO_IN1_REG 0x40 -#define AB8500_GPIO_IN2_REG 0x41 -#define AB8500_GPIO_IN3_REG 0x42 -#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 AB8500_NUM_GPIO 42 -#define AB8500_NUM_VIR_GPIO_IRQ 16 - -enum ab8500_gpio_action { - NONE, - STARTUP, - SHUTDOWN, - MASK, - UNMASK -}; - -struct ab8500_gpio { - struct gpio_chip chip; - struct ab8500 *parent; - struct device *dev; - struct mutex lock; - u32 irq_base; - enum ab8500_gpio_action irq_action; - u16 rising; - u16 falling; -}; -/** - * to_ab8500_gpio() - get the pointer to ab8500_gpio - * @chip: Member of the structure ab8500_gpio - */ -static inline struct ab8500_gpio *to_ab8500_gpio(struct gpio_chip *chip) -{ - return container_of(chip, struct ab8500_gpio, chip); -} - -static int ab8500_gpio_set_bits(struct gpio_chip *chip, u8 reg, - unsigned offset, int val) -{ - struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); - u8 pos = offset % 8; - int ret; - - reg = reg + (offset / 8); - ret = abx500_mask_and_set_register_interruptible(ab8500_gpio->dev, - AB8500_MISC, reg, 1 << pos, val << pos); - if (ret < 0) - dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); - return ret; -} -/** - * ab8500_gpio_get() - Get the particular GPIO value - * @chip: Gpio device - * @offset: GPIO number to read - */ -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); - int ret; - u8 data; - ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC, - reg, &data); - if (ret < 0) { - dev_err(ab8500_gpio->dev, "%s read failed\n", __func__); - return ret; - } - return (data & mask) >> (offset % 8); -} - -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); - if (ret < 0) - dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); -} - -static int ab8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int val) -{ - int ret; - /* set direction as output */ - ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1); - if (ret < 0) - return ret; - /* disable pull down */ - ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1); - if (ret < 0) - return ret; - /* set the output as 1 or 0 */ - return ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val); - -} - -static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - /* set the register as input */ - return ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0); -} - -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]; - - if (offset >= cluster->start && offset <= cluster->end) - return base + offset - cluster->start; - - /* Advance by the number of gpios in this cluster */ - base += cluster->end - cluster->start + 1; - } - - return -EINVAL; -} - -static struct gpio_chip ab8500gpio_chip = { - .label = "ab8500_gpio", - .owner = THIS_MODULE, - .direction_input = ab8500_gpio_direction_input, - .get = ab8500_gpio_get, - .direction_output = ab8500_gpio_direction_output, - .set = ab8500_gpio_set, - .to_irq = ab8500_gpio_to_irq, -}; - -static unsigned int irq_to_rising(unsigned int irq) -{ - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); - int offset = irq - ab8500_gpio->irq_base; - int new_irq = offset + AB8500_INT_GPIO6R - + ab8500_gpio->parent->irq_base; - return new_irq; -} - -static unsigned int irq_to_falling(unsigned int irq) -{ - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); - int offset = irq - ab8500_gpio->irq_base; - int new_irq = offset + AB8500_INT_GPIO6F - + ab8500_gpio->parent->irq_base; - return new_irq; - -} - -static unsigned int rising_to_irq(unsigned int irq, void *dev) -{ - struct ab8500_gpio *ab8500_gpio = dev; - int offset = irq - AB8500_INT_GPIO6R - - ab8500_gpio->parent->irq_base ; - int new_irq = offset + ab8500_gpio->irq_base; - return new_irq; -} - -static unsigned int falling_to_irq(unsigned int irq, void *dev) -{ - struct ab8500_gpio *ab8500_gpio = dev; - int offset = irq - AB8500_INT_GPIO6F - - ab8500_gpio->parent->irq_base ; - int new_irq = offset + ab8500_gpio->irq_base; - return new_irq; - -} - -/* - * IRQ handler - */ - -static irqreturn_t handle_rising(int irq, void *dev) -{ - - handle_nested_irq(rising_to_irq(irq , dev)); - return IRQ_HANDLED; -} - -static irqreturn_t handle_falling(int irq, void *dev) -{ - - handle_nested_irq(falling_to_irq(irq, dev)); - return IRQ_HANDLED; -} - -static void ab8500_gpio_irq_lock(unsigned int irq) -{ - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); - mutex_lock(&ab8500_gpio->lock); -} - -static void ab8500_gpio_irq_sync_unlock(unsigned int irq) -{ - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); - int offset = irq - ab8500_gpio->irq_base; - bool rising = ab8500_gpio->rising & BIT(offset); - bool falling = ab8500_gpio->falling & BIT(offset); - int ret; - - switch (ab8500_gpio->irq_action) { - case STARTUP: - if (rising) - ret = request_threaded_irq(irq_to_rising(irq), - NULL, handle_rising, - IRQF_TRIGGER_RISING, - "ab8500-gpio-r", ab8500_gpio); - if (falling) - ret = request_threaded_irq(irq_to_falling(irq), - NULL, handle_falling, - IRQF_TRIGGER_FALLING, - "ab8500-gpio-f", ab8500_gpio); - break; - case SHUTDOWN: - if (rising) - free_irq(irq_to_rising(irq), ab8500_gpio); - if (falling) - free_irq(irq_to_falling(irq), ab8500_gpio); - break; - case MASK: - if (rising) - disable_irq(irq_to_rising(irq)); - if (falling) - disable_irq(irq_to_falling(irq)); - break; - case UNMASK: - if (rising) - enable_irq(irq_to_rising(irq)); - if (falling) - enable_irq(irq_to_falling(irq)); - break; - case NONE: - break; - } - ab8500_gpio->irq_action = NONE; - ab8500_gpio->rising &= ~(BIT(offset)); - ab8500_gpio->falling &= ~(BIT(offset)); - mutex_unlock(&ab8500_gpio->lock); -} - - -static void ab8500_gpio_irq_mask(unsigned int irq) -{ - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); - ab8500_gpio->irq_action = MASK; -} - -static void ab8500_gpio_irq_unmask(unsigned int irq) -{ - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); - ab8500_gpio->irq_action = UNMASK; -} - -static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type) -{ - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); - int offset = irq - ab8500_gpio->irq_base; - - if (type == IRQ_TYPE_EDGE_BOTH) { - ab8500_gpio->rising = BIT(offset); - ab8500_gpio->falling = BIT(offset); - } else if (type == IRQ_TYPE_EDGE_RISING) { - ab8500_gpio->rising = BIT(offset); - } else { - ab8500_gpio->falling = BIT(offset); - } - return 0; -} - -unsigned int ab8500_gpio_irq_startup(unsigned int irq) -{ - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); - ab8500_gpio->irq_action = STARTUP; - return 0; -} - -void ab8500_gpio_irq_shutdown(unsigned int irq) -{ - struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); - 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, -}; - -static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio) -{ - u32 base = ab8500_gpio->irq_base; - 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, - handle_simple_irq); - set_irq_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - set_irq_noprobe(irq); -#endif - } - - return 0; -} - -static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio) -{ - int base = ab8500_gpio->irq_base; - int irq; - - for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) { -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); - } -} - -static int ab8500_gpio_probe(struct platform_device *pdev) -{ - 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; - - pdata = ab8500_pdata->gpio; - if (!pdata) { - dev_err(&pdev->dev, "gpio platform data missing\n"); - return -ENODEV; - } - - ab8500_gpio = kzalloc(sizeof(struct ab8500_gpio), GFP_KERNEL); - if (ab8500_gpio == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); - return -ENOMEM; - } - 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; - /* initialize the lock */ - mutex_init(&ab8500_gpio->lock); - /* - * AB8500 core will handle and clear the IRQ - * configre GPIO based on config-reg value. - * These values are for selecting the PINs as - * GPIO or alternate function - */ - for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_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, - AB8500_GPIO_ALTFUN_REG, - pdata->config_reg[ALTFUN_REG_INDEX]); - if (ret < 0) - goto out_free; - - ret = ab8500_gpio_irq_init(ab8500_gpio); - if (ret) - goto out_free; - ret = gpiochip_add(&ab8500_gpio->chip); - if (ret) { - dev_err(&pdev->dev, "unable to add gpiochip: %d\n", - ret); - goto out_rem_irq; - } - platform_set_drvdata(pdev, ab8500_gpio); - return 0; - -out_rem_irq: - ab8500_gpio_irq_remove(ab8500_gpio); -out_free: - mutex_destroy(&ab8500_gpio->lock); - kfree(ab8500_gpio); - return ret; -} - -/* - * ab8500_gpio_remove() - remove Ab8500-gpio driver - * @pdev : Platform device registered - */ -static int ab8500_gpio_remove(struct platform_device *pdev) -{ - struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev); - int ret; - - ret = gpiochip_remove(&ab8500_gpio->chip); - if (ret < 0) { - dev_err(ab8500_gpio->dev, "unable to remove gpiochip: %d\n", - ret); - return ret; - } - - platform_set_drvdata(pdev, NULL); - mutex_destroy(&ab8500_gpio->lock); - kfree(ab8500_gpio); - - return 0; -} - -static struct platform_driver ab8500_gpio_driver = { - .driver = { - .name = "ab8500-gpio", - .owner = THIS_MODULE, - }, - .probe = ab8500_gpio_probe, - .remove = ab8500_gpio_remove, -}; - -static int __init ab8500_gpio_init(void) -{ - return platform_driver_register(&ab8500_gpio_driver); -} -arch_initcall(ab8500_gpio_init); - -static void __exit ab8500_gpio_exit(void) -{ - platform_driver_unregister(&ab8500_gpio_driver); -} -module_exit(ab8500_gpio_exit); - -MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>"); -MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins to be used as GPIO"); -MODULE_ALIAS("platform:ab8500-gpio"); -MODULE_LICENSE("GPL v2");