diff options
author | Graeme Gregory <gg@slimlogic.co.uk> | 2011-10-21 15:10:43 +0100 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-08-02 16:40:11 -0700 |
commit | d1b803e40b9b42c9113a7aba5cf345b67f8e3a3d (patch) | |
tree | 9a7709f69e018e24bf08064c551b8bcb4a103a34 /drivers/gpio | |
parent | 755c4d57c0ab85e610f43771433d10554112c839 (diff) |
GPIO: Add Palmas GPIO support
Palmas has a maximum of 8 GPIO available but depending on the package and
OTP programming of the chip they may not all be exposed to pins on the
chip
Signed-off-by: Graeme Gregory <gg@slimlogic.co.uk>
(cherry picked from commit 0f9c01bcec3f032de5bf04213ee7055b068e5d06)
Bug 978821
Change-Id: Ic4bb7f6762535fd77e4b0b507dbc6873270ed33b
Reviewed-on: http://git-master/r/119988
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Tested-by: Pradeep Goudagunta <pgoudagunta@nvidia.com>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 7 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-palmas.c | 228 |
3 files changed, 236 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4e1bd9efe7f4..8c2a23aa209f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -523,4 +523,11 @@ config GPIO_TPS65910 help Select this option to enable GPIO driver for the TPS65910 chip family. + +config GPIO_PALMAS + bool "PALMAS GPIO" + depends on MFD_PALMAS + help + Select this option to enable GPIO driver for the Palmas + chip familly. endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a27bf53aecea..3b7579647446 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o +obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c new file mode 100644 index 000000000000..1956ff183b02 --- /dev/null +++ b/drivers/gpio/gpio-palmas.c @@ -0,0 +1,228 @@ +/* + * gpiolib support for Palmas Series PMICS + * + * Copyright 2011 Texas Instruments + * + * Author: Graeme Gregory <gg@slimlogic.co.uk> + * + * Based on gpio-wm831x.c + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/mfd/core.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> + +#include <linux/mfd/palmas.h> + +struct palmas_gpio { + struct palmas *palmas; + struct gpio_chip gpio_chip; +}; + +static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct palmas_gpio, gpio_chip); +} + +static int palmas_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct palmas_gpio *palmas_gpio = to_palmas_gpio(chip); + struct palmas *palmas = palmas_gpio->palmas; + int ret; + u8 reg = 0; + + if (!((1 << offset) & palmas->gpio_muxed)) + return -EINVAL; + + ret = palmas_gpio_read(palmas, PALMAS_GPIO_DATA_DIR, ®); + if (ret) + return ret; + + reg &= ~(1 << offset); + + return palmas_gpio_write(palmas, PALMAS_GPIO_DATA_DIR, reg); +} + +static int palmas_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct palmas_gpio *palmas_gpio = to_palmas_gpio(chip); + struct palmas *palmas = palmas_gpio->palmas; + u8 reg = 0; + + if (!((1 << offset) & palmas->gpio_muxed)) + return 0; + + palmas_gpio_read(palmas, PALMAS_GPIO_DATA_IN, ®); + + return !!(reg & (1 << offset)); +} + +static void palmas_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct palmas_gpio *palmas_gpio = to_palmas_gpio(chip); + struct palmas *palmas = palmas_gpio->palmas; + u8 reg; + + if (!((1 << offset) & palmas->gpio_muxed)) + return; + + palmas_gpio_read(palmas, PALMAS_GPIO_DATA_OUT, ®); + + reg &= ~(1 << offset); + reg |= value << offset; + + palmas_gpio_write(palmas, PALMAS_GPIO_DATA_OUT, reg); +} + +static int palmas_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct palmas_gpio *palmas_gpio = to_palmas_gpio(chip); + struct palmas *palmas = palmas_gpio->palmas; + int ret; + u8 reg; + + if (!((1 << offset) & palmas->gpio_muxed)) + return -EINVAL; + + ret = palmas_gpio_read(palmas, PALMAS_GPIO_DATA_DIR, ®); + if (ret) + return ret; + + reg |= 1 << offset; + + return palmas_gpio_write(palmas, PALMAS_GPIO_DATA_DIR, reg); +} + +static int palmas_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct palmas_gpio *palmas_gpio = to_palmas_gpio(chip); + struct palmas *palmas = palmas_gpio->palmas; + + if (!palmas->irq_base) + return -EINVAL; + + return palmas->irq_base + PALMAS_GPIO_0_IRQ + offset; +} + +static int palmas_gpio_set_debounce(struct gpio_chip *chip, unsigned offset, + unsigned debounce) +{ + struct palmas_gpio *palmas_gpio = to_palmas_gpio(chip); + struct palmas *palmas = palmas_gpio->palmas; + int ret; + u8 reg; + + if (!((1 << offset) & palmas->gpio_muxed)) + return -EINVAL; + + ret = palmas_gpio_read(palmas, PALMAS_GPIO_DATA_DIR, ®); + if (ret) + return ret; + + if (debounce) + reg |= 1 << offset; + else + reg &= ~(1 << offset); + + return palmas_gpio_write(palmas, PALMAS_GPIO_DATA_DIR, reg); +} + +static struct gpio_chip template_chip = { + .label = "palmas", + .owner = THIS_MODULE, + .direction_input = palmas_gpio_direction_in, + .get = palmas_gpio_get, + .direction_output = palmas_gpio_direction_out, + .set = palmas_gpio_set, + .to_irq = palmas_gpio_to_irq, + .set_debounce = palmas_gpio_set_debounce, + .can_sleep = 1, + .ngpio = 8, +}; + +static int __devinit palmas_gpio_probe(struct platform_device *pdev) +{ + struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); + struct palmas_platform_data *pdata = palmas->dev->platform_data; + struct palmas_gpio *gpio; + int ret; + + gpio = kzalloc(sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + gpio->palmas = palmas; + gpio->gpio_chip = template_chip; + gpio->gpio_chip.dev = &pdev->dev; + + if (pdata && pdata->gpio_base) + gpio->gpio_chip.base = pdata->gpio_base; + else + gpio->gpio_chip.base = -1; + + ret = gpiochip_add(&gpio->gpio_chip); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", + ret); + goto err; + } + + platform_set_drvdata(pdev, gpio); + + return ret; + +err: + kfree(gpio); + return ret; +} + +static int __devexit palmas_gpio_remove(struct platform_device *pdev) +{ + struct palmas_gpio *gpio = platform_get_drvdata(pdev); + int ret; + + ret = gpiochip_remove(&gpio->gpio_chip); + if (ret == 0) + kfree(gpio); + + return ret; +} + +static struct platform_driver palmas_gpio_driver = { + .driver.name = "palmas-gpio", + .driver.owner = THIS_MODULE, + .probe = palmas_gpio_probe, + .remove = __devexit_p(palmas_gpio_remove), +}; + +static int __init palmas_gpio_init(void) +{ + return platform_driver_register(&palmas_gpio_driver); +} +subsys_initcall(palmas_gpio_init); + +static void __exit palmas_gpio_exit(void) +{ + platform_driver_unregister(&palmas_gpio_driver); +} +module_exit(palmas_gpio_exit); + +MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); +MODULE_DESCRIPTION("GPIO interface for the Palmas series chips"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:palmas-gpio"); |