[PATCH v2 3/3] drivers: gpio: implement PALMAS GPIO cell

Svyatoslav Ryhel clamor95 at gmail.com
Mon Nov 6 10:00:46 CET 2023


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

Signed-off-by: Svyatoslav Ryhel <clamor95 at gmail.com>
---
 drivers/gpio/Kconfig        |   7 ++
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/palmas_gpio.c  | 132 ++++++++++++++++++++++++++++++++++++
 drivers/power/pmic/palmas.c |  10 ++-
 include/power/palmas.h      |  12 ++++
 5 files changed, 161 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpio/palmas_gpio.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 250f1ebbb3..63e62e1acd 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -435,6 +435,13 @@ config VYBRID_GPIO
 	help
 	  Say yes here to support Vybrid vf610 GPIOs.
 
+config PALMAS_GPIO
+	bool "TI PALMAS series PMICs GPIO"
+	depends on DM_GPIO && PMIC_PALMAS
+	help
+	  Select this option to enable GPIO driver for the TI PALMAS
+	  series chip family.
+
 config PIC32_GPIO
 	bool "Microchip PIC32 GPIO driver"
 	depends on DM_GPIO && MACH_PIC32
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index dab3eb93a3..da3da5da2b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_VYBRID_GPIO)	+= vybrid_gpio.o
 obj-$(CONFIG_HIKEY_GPIO)	+= hi6220_gpio.o
 obj-$(CONFIG_HSDK_CREG_GPIO)	+= hsdk-creg-gpio.o
 obj-$(CONFIG_IMX_RGPIO2P)	+= imx_rgpio2p.o
+obj-$(CONFIG_$(SPL_)PALMAS_GPIO)	+= palmas_gpio.o
 obj-$(CONFIG_PIC32_GPIO)	+= pic32_gpio.o
 obj-$(CONFIG_OCTEON_GPIO)	+= octeon_gpio.o
 obj-$(CONFIG_MVEBU_GPIO)	+= mvebu_gpio.o
diff --git a/drivers/gpio/palmas_gpio.c b/drivers/gpio/palmas_gpio.c
new file mode 100644
index 0000000000..b4610cba18
--- /dev/null
+++ b/drivers/gpio/palmas_gpio.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Based on mainline Linux palmas GPIO driver
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95 at gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <asm/gpio.h>
+#include <power/palmas.h>
+
+#define NUM_GPIOS	8
+
+static int palmas_gpio_set_value(struct udevice *dev, unsigned int offset,
+				 int value)
+{
+	struct palmas_priv *priv = dev_get_priv(dev->parent);
+	u32 reg;
+	int ret;
+
+	reg = (value) ? PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT;
+
+	ret = dm_i2c_reg_write(priv->chip2, reg, BIT(offset));
+	if (ret < 0)
+		log_err("Reg 0x%02x write failed, %d\n", reg, ret);
+
+	return ret;
+}
+
+static int palmas_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+	struct palmas_priv *priv = dev_get_priv(dev->parent);
+	u32 reg;
+	int ret;
+
+	ret = dm_i2c_reg_read(priv->chip2, PALMAS_GPIO_DATA_DIR);
+	if (ret < 0) {
+		log_err("GPIO_DATA_DIR read failed, %d\n", ret);
+		return ret;
+	}
+
+	if (ret & BIT(offset))
+		reg = PALMAS_GPIO_DATA_OUT;
+	else
+		reg = PALMAS_GPIO_DATA_IN;
+
+	ret = dm_i2c_reg_read(priv->chip2, reg);
+	if (ret < 0) {
+		log_err("Reg 0x%02x read failed, %d\n", reg, ret);
+		return ret;
+	}
+
+	return !!(ret & BIT(offset));
+}
+
+static int palmas_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+	struct palmas_priv *priv = dev_get_priv(dev->parent);
+	int ret;
+
+	ret = dm_i2c_reg_clrset(priv->chip2, PALMAS_GPIO_DATA_DIR,
+				BIT(offset), 0);
+	if (ret < 0)
+		log_err("GPIO_DATA_DIR val update failed: %d\n", ret);
+
+	return ret;
+}
+
+static int palmas_gpio_direction_output(struct udevice *dev, unsigned int offset,
+					int value)
+{
+	struct palmas_priv *priv = dev_get_priv(dev->parent);
+	int ret;
+
+	/* Set the initial value */
+	palmas_gpio_set_value(dev, offset, value);
+
+	ret = dm_i2c_reg_clrset(priv->chip2, PALMAS_GPIO_DATA_DIR,
+				BIT(offset), BIT(offset));
+	if (ret < 0)
+		log_err("GPIO_DATA_DIR val update failed: %d\n", ret);
+
+	return ret;
+}
+
+static int palmas_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+	struct palmas_priv *priv = dev_get_priv(dev->parent);
+	int ret;
+
+	ret = dm_i2c_reg_read(priv->chip2, PALMAS_GPIO_DATA_DIR);
+	if (ret < 0) {
+		log_err("GPIO_DATA_DIR read failed, %d\n", ret);
+		return ret;
+	}
+
+	if (ret & BIT(offset))
+		return GPIOF_OUTPUT;
+	else
+		return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops palmas_gpio_ops = {
+	.direction_input	= palmas_gpio_direction_input,
+	.direction_output	= palmas_gpio_direction_output,
+	.get_value		= palmas_gpio_get_value,
+	.set_value		= palmas_gpio_set_value,
+	.get_function		= palmas_gpio_get_function,
+};
+
+static int palmas_gpio_probe(struct udevice *dev)
+{
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	uc_priv->gpio_count = NUM_GPIOS;
+	uc_priv->bank_name = "GPIO";
+
+	return 0;
+}
+
+static const struct udevice_id palmas_ids[] = {
+	{ .compatible = "ti,palmas-gpio" },
+	{ }
+};
+
+U_BOOT_DRIVER(palmas_gpio) = {
+	.name	= PALMAS_GPIO_DRIVER,
+	.id	= UCLASS_GPIO,
+	.of_match = palmas_ids,
+	.probe	= palmas_gpio_probe,
+	.ops	= &palmas_gpio_ops,
+};
diff --git a/drivers/power/pmic/palmas.c b/drivers/power/pmic/palmas.c
index 32f2a938b2..e340a32279 100644
--- a/drivers/power/pmic/palmas.c
+++ b/drivers/power/pmic/palmas.c
@@ -46,7 +46,7 @@ static int palmas_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
 static int palmas_bind(struct udevice *dev)
 {
 	ofnode pmic_node = ofnode_null(), regulators_node;
-	ofnode subnode;
+	ofnode subnode, gpio_node;
 	int children, ret;
 
 	if (IS_ENABLED(CONFIG_SYSRESET_PALMAS)) {
@@ -58,6 +58,14 @@ static int palmas_bind(struct udevice *dev)
 		}
 	}
 
+	gpio_node = ofnode_find_subnode(dev_ofnode(dev), "gpio");
+	if (ofnode_valid(gpio_node)) {
+		ret = device_bind_driver_to_node(dev, PALMAS_GPIO_DRIVER,
+						 "gpio", gpio_node, NULL);
+		if (ret)
+			log_err("cannot bind GPIOs (ret = %d)\n", ret);
+	}
+
 	dev_for_each_subnode(subnode, dev) {
 		const char *name;
 		char *temp;
diff --git a/include/power/palmas.h b/include/power/palmas.h
index 0a612052f0..94c99dd411 100644
--- a/include/power/palmas.h
+++ b/include/power/palmas.h
@@ -15,6 +15,7 @@ struct palmas_priv {
 #define PALMAS_LDO_DRIVER     "palmas_ldo"
 #define PALMAS_SMPS_DRIVER    "palmas_smps"
 #define PALMAS_RST_DRIVER     "palmas_rst"
+#define PALMAS_GPIO_DRIVER    "palmas_gpio"
 
 #define PALMAS_SMPS_VOLT_MASK		0x7F
 #define PALMAS_SMPS_RANGE_MASK		0x80
@@ -35,3 +36,14 @@ struct palmas_priv {
 #define   DEV_OFF			0x00
 #define PALMAS_INT3_MASK		0x1B
 #define   MASK_VBUS			BIT(7)
+
+/* second chip */
+#define PALMAS_GPIO_DATA_IN		0x80
+#define PALMAS_GPIO_DATA_DIR		0x81
+#define PALMAS_GPIO_DATA_OUT		0x82
+#define PALMAS_GPIO_DEBOUNCE_EN		0x83
+#define PALMAS_GPIO_CLEAR_DATA_OUT	0x84
+#define PALMAS_GPIO_SET_DATA_OUT	0x85
+#define PALMAS_PU_PD_GPIO_CTRL1		0x86
+#define PALMAS_PU_PD_GPIO_CTRL2		0x87
+#define PALMAS_OD_OUTPUT_GPIO_CTRL	0x88
-- 
2.40.1



More information about the U-Boot mailing list