summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorGraeme Gregory <gg@slimlogic.co.uk>2011-10-21 15:10:43 +0100
committerSimone Willett <swillett@nvidia.com>2012-08-02 16:40:11 -0700
commitd1b803e40b9b42c9113a7aba5cf345b67f8e3a3d (patch)
tree9a7709f69e018e24bf08064c551b8bcb4a103a34 /drivers/gpio
parent755c4d57c0ab85e610f43771433d10554112c839 (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/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-palmas.c228
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, &reg);
+ 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, &reg);
+
+ 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);
+
+ 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, &reg);
+ 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, &reg);
+ 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");