]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
drivers: gpio: implement PALMAS GPIO cell
authorSvyatoslav Ryhel <clamor95@gmail.com>
Fri, 21 Jul 2023 07:50:15 +0000 (10:50 +0300)
committerSvyatoslav Ryhel <clamor95@gmail.com>
Tue, 19 Dec 2023 18:53:53 +0000 (20:53 +0200)
Add gpio driver for TI Palmas series PMIC. This has 8 gpio which can
work as input/output.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/palmas_gpio.c [new file with mode: 0644]
drivers/power/pmic/palmas.c
include/power/palmas.h

index 250f1ebbb31db33820a574ccf4c076a03807886a..63e62e1acd29a4f97ca7856ae563a9b17249a480 100644 (file)
@@ -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
index dab3eb93a3b2e8bc5698a883cecbae4fb36b4ad0..da3da5da2b3758732d3064c0f0870c847062a85c 100644 (file)
@@ -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 (file)
index 0000000..1503935
--- /dev/null
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Based on mainline Linux palmas GPIO driver
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@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_debug("%s: Reg 0x%02x write failed, %d\n", __func__, 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_debug("%s: GPIO_DATA_DIR read failed, %d\n", __func__, 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_debug("%s: Reg 0x%02x read failed, %d\n", __func__, 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_debug("%s: GPIO_DATA_DIR val update failed: %d\n", __func__, 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_debug("%s: GPIO_DATA_DIR val update failed: %d\n", __func__, 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_debug("%s: GPIO_DATA_DIR read failed, %d\n", __func__, 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,
+};
index 32f2a938b285e3f9ef21c9282e6431590397284d..e340a32279fbf35445fd60ee38b78836307d434f 100644 (file)
@@ -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;
index 0a612052f01531924d374b25333d3cb01cbbffb4..94c99dd41136609c0d69939093294fd06cc2c33a 100644 (file)
@@ -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