2011-05-10 20:34:45

by Margarita Olaya

[permalink] [raw]
Subject: [PATCH 2/4] tps65912: gpio: add gpio driver

TPS65912 has five GPIOs that can be configured for different
purposes.

Signed-off-by: Margarita Olaya Cabrera <[email protected]>
---
drivers/mfd/Makefile | 2 +-
drivers/mfd/tps65912-gpio.c | 94 ++++++++++++++++++++++++++++++++++++++++++
drivers/mfd/tps65912.c | 14 ++++++
include/linux/mfd/tps65912.h | 3 +
4 files changed, 112 insertions(+), 1 deletions(-)
create mode 100644 drivers/mfd/tps65912-gpio.c

diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 9d60cfd..687bd2a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -31,7 +31,7 @@ wm8350-objs += wm8350-irq.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o
-obj-$(CONFIG_MFD_TPS65912) += tps65912.o
+obj-$(CONFIG_MFD_TPS65912) += tps65912.o tps65912-gpio.o

obj-$(CONFIG_TPS6105X) += tps6105x.o
obj-$(CONFIG_TPS65010) += tps65010.o
diff --git a/drivers/mfd/tps65912-gpio.c b/drivers/mfd/tps65912-gpio.c
new file mode 100644
index 0000000..fa94674
--- /dev/null
+++ b/drivers/mfd/tps65912-gpio.c
@@ -0,0 +1,94 @@
+/*
+ * tps65912-gpio.c -- TI TPS6591x
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya <[email protected]>
+ *
+ * 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/module.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/tps65912.h>
+
+static int tps6591x_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+ struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+ uint8_t val;
+
+ tps65912->read(tps65912, TPS65912_GPIO1 + offset, 1, &val);
+
+ if (val & GPIO_STS_MASK)
+ return 1;
+
+ return 0;
+}
+
+static void tps6591x_gpio_set(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+
+ if (value)
+ tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
+ GPIO_SET_MASK);
+ else
+ tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
+ ~GPIO_SET_MASK);
+}
+
+static int tps6591x_gpio_output(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+
+ /* Set the initial value */
+ tps6591x_gpio_set(gc, offset, value);
+
+ return tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
+ GPIO_CFG_MASK);
+}
+
+static int tps6591x_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+
+ return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
+ ~GPIO_CFG_MASK);
+
+}
+
+void tps65912_gpio_init(struct tps65912 *tps65912, int gpio_base)
+{
+ int ret;
+
+ if (!gpio_base)
+ return;
+
+ tps65912->gpio.owner = THIS_MODULE;
+ /* FIXME: should we use compilation macro for SPI */
+ tps65912->gpio.label = tps65912->i2c_client->name;
+ tps65912->gpio.dev = tps65912->dev;
+ tps65912->gpio.base = gpio_base;
+ tps65912->gpio.ngpio = 5;
+ tps65912->gpio.can_sleep = 1;
+
+ tps65912->gpio.direction_input = tps6591x_gpio_input;
+ tps65912->gpio.direction_output = tps6591x_gpio_output;
+ tps65912->gpio.set = tps6591x_gpio_set;
+ tps65912->gpio.get = tps6591x_gpio_get;
+
+ ret = gpiochip_add(&tps65912->gpio);
+
+ if (ret)
+ dev_warn(tps65912->dev, "GPIO registration failed: %d\n", ret);
+}
+
diff --git a/drivers/mfd/tps65912.c b/drivers/mfd/tps65912.c
index a6d5fce..83dbc3a 100644
--- a/drivers/mfd/tps65912.c
+++ b/drivers/mfd/tps65912.c
@@ -88,8 +88,13 @@ static int tps65912_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tps65912 *tps65912;
+ struct tps65912_board *pmic_plat_data;
int ret = 0;

+ pmic_plat_data = dev_get_platdata(&i2c->dev);
+ if (!pmic_plat_data)
+ return -EINVAL;
+
tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
if (tps65912 == NULL)
return -ENOMEM;
@@ -107,6 +112,8 @@ static int tps65912_i2c_probe(struct i2c_client *i2c,
if (ret < 0)
goto err;

+ tps65912_gpio_init(tps65912, pmic_plat_data->gpio_base);
+
return ret;

err:
@@ -207,9 +214,14 @@ static int tps65912_spi_read(struct tps65912
*tps65912, u8 addr,
static int __devinit tps65912_spi_probe(struct spi_device *spi)
{
struct tps65912 *tps65912;
+ struct tps65912_board *pmic_plat_data;
struct tps65912_platform_data *init_data;
int dcdc_avs, value, ret = 0;

+ pmic_plat_data = dev_get_platdata(&spi->dev);
+ if (!pmic_plat_data)
+ return -ENODEV;
+
init_data = kzalloc(sizeof(struct tps65912_platform_data),
GFP_KERNEL);
if (init_data == NULL)
@@ -241,6 +253,8 @@ static int __devinit tps65912_spi_probe(struct
spi_device *spi)
if (ret < 0)
goto err;

+ tps65912_gpio_init(tps65912, pmic_plat_data->gpio_base);
+
return ret;

err:
diff --git a/include/linux/mfd/tps65912.h b/include/linux/mfd/tps65912.h
index 1d0aab8..bcfdc0d 100644
--- a/include/linux/mfd/tps65912.h
+++ b/include/linux/mfd/tps65912.h
@@ -405,6 +405,7 @@
* Board platform dat may be used to initialize regulators.
*/
struct tps65912_board {
+ int gpio_base;
struct regulator_init_data *tps65912_pmic_init_data;
};

@@ -453,5 +454,7 @@ unsigned int tps_chip(void);

int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask);
int tps65912_clear_bits(struct tps65912 *tps65912, u8 reg, u8 mask);
+void tps65912_gpio_init(struct tps65912 *tps65912, int gpio_base);
+
#endif /* __LINUX_MFD_TPS65912_H */

--
1.7.0.4


2011-05-10 20:39:29

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 2/4] tps65912: gpio: add gpio driver

On Tue, May 10, 2011 at 03:25:35PM -0500, Margarita Olaya wrote:

> drivers/mfd/Makefile | 2 +-
> drivers/mfd/tps65912-gpio.c | 94 ++++++++++++++++++++++++++++++++++++++++++

We're mostly moving GPIO drivers to drivers/gpio these days - there's a
push to move drivers into the appropriate subsystems (particularly
focused on arch/arm but still).

> +static void tps6591x_gpio_set(struct gpio_chip *gc, unsigned offset,
> + int value)
> +{
> + struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
> +
> + if (value)
> + tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
> + GPIO_SET_MASK);
> + else
> + tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
> + ~GPIO_SET_MASK);

Should one of those be clear_bits() given that there's such a function?

> + tps65912->gpio.owner = THIS_MODULE;
> + /* FIXME: should we use compilation macro for SPI */
> + tps65912->gpio.label = tps65912->i2c_client->name;

I guess dev_name() would do a reasonable job?