[3/4] gpio: palmas: Add support for Palams GPIO

Submitted by Laxman Dewangan on Jan. 3, 2013, 10:46 a.m.

Details

Message ID 1357210020-19876-4-git-send-email-ldewangan@nvidia.com
State Accepted
Headers show

Commit Message

Laxman Dewangan Jan. 3, 2013, 10:46 a.m.
Add gpio driver for TI Palmas series PMIC. This has 8 gpio which can
work as input/output.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
---
 drivers/gpio/Kconfig       |    7 ++
 drivers/gpio/Makefile      |    1 +
 drivers/gpio/gpio-palmas.c |  184 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 192 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpio/gpio-palmas.c

Comments

Linus Walleij Jan. 10, 2013, 10:57 a.m.
On Thu, Jan 3, 2013 at 11:46 AM, Laxman Dewangan <ldewangan@nvidia.com> wrote:

> Add gpio driver for TI Palmas series PMIC. This has 8 gpio which can
> work as input/output.
>
> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>

This driver seems unnecessary. Can't you just use
drivers/gpio/gpio-generic.c ?

> +static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
> +{
> +       struct palmas_gpio *pg = to_palmas_gpio(gc);
> +       struct palmas *palmas = pg->palmas;
> +
> +       return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
> +}

Why are you implementing this for a driver which does not even expose
the ability to trigger IRQs? If it's supposed to support IRQs it should
register a struct irq_chip.

Yours,
Linus Walleij
Laxman Dewangan Jan. 10, 2013, 11:03 a.m.
On Thursday 10 January 2013 04:27 PM, Linus Walleij wrote:
> On Thu, Jan 3, 2013 at 11:46 AM, Laxman Dewangan <ldewangan@nvidia.com> wrote:
>
>> Add gpio driver for TI Palmas series PMIC. This has 8 gpio which can
>> work as input/output.
>>
>> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
> This driver seems unnecessary. Can't you just use
> drivers/gpio/gpio-generic.c ?
The gpio-generic driver is for the MMIO based interface. This is for the 
PMIC-Palma which is in i2c interface and so need to have register access 
through the i2c call exposed by palma mfd driver.



>
>> +static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
>> +{
>> +       struct palmas_gpio *pg = to_palmas_gpio(gc);
>> +       struct palmas *palmas = pg->palmas;
>> +
>> +       return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
>> +}
> Why are you implementing this for a driver which does not even expose
> the ability to trigger IRQs? If it's supposed to support IRQs it should
> register a struct irq_chip.

The interrupts are registered in mfd core via the regmap-irq_chip.
This api converts the gpio number to corresponding irq.
Mark Brown Jan. 10, 2013, 11:05 a.m.
On Thu, Jan 10, 2013 at 11:57:10AM +0100, Linus Walleij wrote:
> On Thu, Jan 3, 2013 at 11:46 AM, Laxman Dewangan <ldewangan@nvidia.com> wrote:

> > Add gpio driver for TI Palmas series PMIC. This has 8 gpio which can
> > work as input/output.

> > Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>

> This driver seems unnecessary. Can't you just use
> drivers/gpio/gpio-generic.c ?

This only works for memory mapped devices but this is an I2C controlled
MFD.  Someone should really do a regmap gpio-chip (or convert the
gpio-generic driver to regmap, regmap does support MMIO now but it does
add a little overhead).

> > +static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
> > +{
> > +       struct palmas_gpio *pg = to_palmas_gpio(gc);
> > +       struct palmas *palmas = pg->palmas;
> > +
> > +       return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
> > +}

> Why are you implementing this for a driver which does not even expose
> the ability to trigger IRQs? If it's supposed to support IRQs it should
> register a struct irq_chip.

The irq_chip is in the MFD core for the device.
Linus Walleij Jan. 17, 2013, 10:34 a.m.
On Thu, Jan 3, 2013 at 11:46 AM, Laxman Dewangan <ldewangan@nvidia.com> wrote:

> Add gpio driver for TI Palmas series PMIC. This has 8 gpio which can
> work as input/output.
>
> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>

OK you & Mark have convinced me that this driver is OK as it stands.

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Do you want me to apply it to my GPIO tree or does it have
dependencies so you'll take it through MFD or something?

Yours,
Linus Walleij
Mark Brown Jan. 17, 2013, 10:35 a.m.
On Thu, Jan 17, 2013 at 11:34:42AM +0100, Linus Walleij wrote:

> Do you want me to apply it to my GPIO tree or does it have
> dependencies so you'll take it through MFD or something?

The MFD has been merged for a couple of releases now.
Laxman Dewangan Jan. 17, 2013, 10:37 a.m.
On Thursday 17 January 2013 04:05 PM, Mark Brown wrote:
> On Thu, Jan 17, 2013 at 11:34:42AM +0100, Linus Walleij wrote:
>
>> Do you want me to apply it to my GPIO tree or does it have
>> dependencies so you'll take it through MFD or something?
> The MFD has been merged for a couple of releases now.
Yes, Although this driver used the new API introduced in patch 1/4 but I 
think it is fine to apply this in GPIO subsystem here as it is 
independent driver.
Linus Walleij Jan. 17, 2013, 1:58 p.m.
On Thu, Jan 17, 2013 at 11:37 AM, Laxman Dewangan <ldewangan@nvidia.com> wrote:
> On Thursday 17 January 2013 04:05 PM, Mark Brown wrote:
>>
>> On Thu, Jan 17, 2013 at 11:34:42AM +0100, Linus Walleij wrote:
>>
>>> Do you want me to apply it to my GPIO tree or does it have
>>> dependencies so you'll take it through MFD or something?
>>
>> The MFD has been merged for a couple of releases now.
>
> Yes, Although this driver used the new API introduced in patch 1/4 but I
> think it is fine to apply this in GPIO subsystem here as it is independent
> driver.

OK that's what fooled me.

Patch applied!

Yours,
Linus Walleij

Patch hide | download patch | download mbox

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 682de75..40a0ec3 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -663,6 +663,13 @@  config GPIO_AB8500
 	help
 	  Select this to enable the AB8500 IC GPIO driver
 
+config GPIO_PALMAS
+	bool "TI PALMAS series PMICs GPIO"
+	depends on MFD_PALMAS
+	help
+	  Select this option to enable GPIO driver for the TI PALMAS
+	  series chip family.
+
 config GPIO_TPS6586X
 	bool "TPS6586X GPIO"
 	depends on MFD_TPS6586X
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c5aebd0..8962c5f 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -69,6 +69,7 @@  obj-$(CONFIG_GPIO_TC3589X)	+= gpio-tc3589x.o
 obj-$(CONFIG_ARCH_TEGRA)	+= gpio-tegra.o
 obj-$(CONFIG_GPIO_TIMBERDALE)	+= gpio-timberdale.o
 obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
+obj-$(CONFIG_GPIO_PALMAS)	+= gpio-palmas.o
 obj-$(CONFIG_GPIO_TPS6586X)	+= gpio-tps6586x.o
 obj-$(CONFIG_GPIO_TPS65910)	+= gpio-tps65910.o
 obj-$(CONFIG_GPIO_TPS65912)	+= gpio-tps65912.o
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
new file mode 100644
index 0000000..e3a4e56
--- /dev/null
+++ b/drivers/gpio/gpio-palmas.c
@@ -0,0 +1,184 @@ 
+/*
+ * TI Palma series PMIC's GPIO driver.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/palmas.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct palmas_gpio {
+	struct gpio_chip gpio_chip;
+	struct palmas *palmas;
+};
+
+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_get(struct gpio_chip *gc, unsigned offset)
+{
+	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas *palmas = pg->palmas;
+	unsigned int val;
+	int ret;
+
+	ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_IN, &val);
+	if (ret < 0) {
+		dev_err(gc->dev, "GPIO_DATA_IN read failed, err = %d\n", ret);
+		return ret;
+	}
+	return !!(val & BIT(offset));
+}
+
+static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
+			int value)
+{
+	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas *palmas = pg->palmas;
+	int ret;
+
+	if (value)
+		ret = palmas_write(palmas, PALMAS_GPIO_BASE,
+				PALMAS_GPIO_SET_DATA_OUT, BIT(offset));
+	else
+		ret = palmas_write(palmas, PALMAS_GPIO_BASE,
+				PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset));
+	if (ret < 0)
+		dev_err(gc->dev, "%s write failed, err = %d\n",
+			(value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT",
+			ret);
+}
+
+static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
+				int value)
+{
+	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas *palmas = pg->palmas;
+	int ret;
+
+	/* Set the initial value */
+	palmas_gpio_set(gc, offset, value);
+
+	ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
+		PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset));
+	if (ret < 0)
+		dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
+	return ret;
+}
+
+static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas *palmas = pg->palmas;
+	int ret;
+
+	ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
+		PALMAS_GPIO_DATA_DIR, BIT(offset), 0);
+	if (ret < 0)
+		dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
+	return ret;
+}
+
+static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas *palmas = pg->palmas;
+
+	return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
+}
+
+static int palmas_gpio_probe(struct platform_device *pdev)
+{
+	struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
+	struct palmas_platform_data *palmas_pdata;
+	struct palmas_gpio *palmas_gpio;
+	int ret;
+
+	palmas_gpio = devm_kzalloc(&pdev->dev,
+				sizeof(*palmas_gpio), GFP_KERNEL);
+	if (!palmas_gpio) {
+		dev_err(&pdev->dev, "Could not allocate palmas_gpio\n");
+		return -ENOMEM;
+	}
+
+	palmas_gpio->palmas = palmas;
+	palmas_gpio->gpio_chip.owner = THIS_MODULE;
+	palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);
+	palmas_gpio->gpio_chip.ngpio = 8;
+	palmas_gpio->gpio_chip.can_sleep = 1;
+	palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;
+	palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;
+	palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
+	palmas_gpio->gpio_chip.set	= palmas_gpio_set;
+	palmas_gpio->gpio_chip.get	= palmas_gpio_get;
+	palmas_gpio->gpio_chip.dev = &pdev->dev;
+#ifdef CONFIG_OF_GPIO
+	palmas_gpio->gpio_chip.of_node = palmas->dev->of_node;
+#endif
+	palmas_pdata = dev_get_platdata(palmas->dev);
+	if (palmas_pdata && palmas_pdata->gpio_base)
+		palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base;
+	else
+		palmas_gpio->gpio_chip.base = -1;
+
+	ret = gpiochip_add(&palmas_gpio->gpio_chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, palmas_gpio);
+	return ret;
+}
+
+static int palmas_gpio_remove(struct platform_device *pdev)
+{
+	struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev);
+
+	return gpiochip_remove(&palmas_gpio->gpio_chip);
+}
+
+static struct platform_driver palmas_gpio_driver = {
+	.driver.name	= "palmas-gpio",
+	.driver.owner	= THIS_MODULE,
+	.probe		= palmas_gpio_probe,
+	.remove		= 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_ALIAS("platform:palmas-gpio");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("GPIO driver for TI Palmas series PMICs");
+MODULE_LICENSE("GPL v2");