]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
drivers: gpio: implement MAX77663 GPIO cell
authorSvyatoslav Ryhel <clamor95@gmail.com>
Sat, 15 Jul 2023 19:25:03 +0000 (22:25 +0300)
committerSvyatoslav Ryhel <clamor95@gmail.com>
Tue, 19 Dec 2023 18:53:53 +0000 (20:53 +0200)
MAXIM Semiconductor's PMIC, MAX77663 has 8 GPIO pins and 3 GPIO-like
pins. It also supports interrupts from these pins.

Add GPIO driver for these pins to control via GPIO APIs.

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

index ba42b0768e122ad83d43023e7247452a5ab18eac..250f1ebbb31db33820a574ccf4c076a03807886a 100644 (file)
@@ -238,6 +238,15 @@ config MAX7320_GPIO
         original maxim device has 8 push/pull outputs,
         some clones offers 16bit.
 
+config MAX77663_GPIO
+       bool "MAX77663 GPIO cell of PMIC driver"
+       depends on DM_GPIO && DM_PMIC_MAX77663
+       help
+         GPIO driver for MAX77663 PMIC from Maxim Semiconductor.
+         MAX77663 PMIC has 8 pins that can be configured as GPIOs
+         and 3 GPIO-like pins dedicated for power/reset buttons
+         and LID sensor.
+
 config MCP230XX_GPIO
        bool "MCP230XX GPIO driver"
        depends on DM
index c8b3fd78141a8f01ca032e9b252bc87664ec5f75..dab3eb93a3b2e8bc5698a883cecbae4fb36b4ad0 100644 (file)
@@ -68,6 +68,7 @@ obj-$(CONFIG_NX_GPIO)         += nx_gpio.o
 obj-$(CONFIG_SIFIVE_GPIO)      += sifive-gpio.o
 obj-$(CONFIG_NOMADIK_GPIO)     += nmk_gpio.o
 obj-$(CONFIG_MAX7320_GPIO)     += max7320_gpio.o
+obj-$(CONFIG_$(SPL_)MAX77663_GPIO)     += max77663_gpio.o
 obj-$(CONFIG_SL28CPLD_GPIO)    += sl28cpld-gpio.o
 obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN)      += zynqmp_gpio_modepin.o
 obj-$(CONFIG_SLG7XL45106_I2C_GPO)      += gpio_slg7xl45106.o
diff --git a/drivers/gpio/max77663_gpio.c b/drivers/gpio/max77663_gpio.c
new file mode 100644 (file)
index 0000000..ecb6047
--- /dev/null
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <asm/gpio.h>
+#include <power/max77663.h>
+#include <power/pmic.h>
+
+#define NUM_ENTRIES                            11 /* 8 GPIOs + 3 KEYs  */
+#define NUM_GPIOS                              8
+
+#define MAX77663_CNFG1_GPIO                    0x36
+#define GPIO_REG_ADDR(offset)                  (MAX77663_CNFG1_GPIO + (offset))
+
+#define MAX77663_CNFG_GPIO_DIR_MASK            BIT(1)
+#define MAX77663_CNFG_GPIO_DIR_INPUT           BIT(1)
+#define MAX77663_CNFG_GPIO_DIR_OUTPUT          0
+#define MAX77663_CNFG_GPIO_INPUT_VAL_MASK      BIT(2)
+#define MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK     BIT(3)
+#define MAX77663_CNFG_GPIO_OUTPUT_VAL_HIGH     BIT(3)
+#define MAX77663_CNFG_GPIO_OUTPUT_VAL_LOW      0
+#define MAX77663_CNFG_IRQ                      GENMASK(5, 4)
+
+#define MAX77663_ONOFFSTAT_REG                 0x15
+#define   EN0                                  BIT(2) /* KEY 2 */
+#define   ACOK                                 BIT(1) /* KEY 1 */
+#define   LID                                  BIT(0) /* KEY 0 */
+
+static int max77663_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+       int ret;
+
+       if (offset >= NUM_GPIOS)
+               return 0;
+
+       ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset),
+                             MAX77663_CNFG_GPIO_DIR_MASK,
+                             MAX77663_CNFG_GPIO_DIR_INPUT);
+       if (ret < 0)
+               log_debug("%s: CNFG_GPIOx dir update failed: %d\n", __func__, ret);
+
+       return ret;
+}
+
+static int max77663_gpio_direction_output(struct udevice *dev, unsigned int offset,
+                                         int value)
+{
+       u8 val;
+       int ret;
+
+       if (offset >= NUM_GPIOS)
+               return -EINVAL;
+
+       val = (value) ? MAX77663_CNFG_GPIO_OUTPUT_VAL_HIGH :
+                               MAX77663_CNFG_GPIO_OUTPUT_VAL_LOW;
+
+       ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset),
+                             MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK, val);
+       if (ret < 0) {
+               log_debug("%s: CNFG_GPIOx val update failed: %d\n", __func__, ret);
+               return ret;
+       }
+
+       ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset),
+                             MAX77663_CNFG_GPIO_DIR_MASK,
+                             MAX77663_CNFG_GPIO_DIR_OUTPUT);
+       if (ret < 0)
+               log_debug("%s: CNFG_GPIOx dir update failed: %d\n", __func__, ret);
+
+       return ret;
+}
+
+static int max77663_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+       int ret;
+
+       if (offset >= NUM_GPIOS) {
+               ret = pmic_reg_read(dev->parent, MAX77663_ONOFFSTAT_REG);
+               if (ret < 0) {
+                       log_debug("%s: ONOFFSTAT_REG read failed: %d\n", __func__, ret);
+                       return ret;
+               }
+
+               return !!(ret & BIT(offset - NUM_GPIOS));
+       }
+
+       ret = pmic_reg_read(dev->parent, GPIO_REG_ADDR(offset));
+       if (ret < 0) {
+               log_debug("%s: CNFG_GPIOx read failed: %d\n", __func__, ret);
+               return ret;
+       }
+
+       if (ret & MAX77663_CNFG_GPIO_DIR_MASK)
+               return !!(ret & MAX77663_CNFG_GPIO_INPUT_VAL_MASK);
+       else
+               return !!(ret & MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK);
+}
+
+static int max77663_gpio_set_value(struct udevice *dev, unsigned int offset,
+                                  int value)
+{
+       u8 val;
+       int ret;
+
+       if (offset >= NUM_GPIOS)
+               return -EINVAL;
+
+       val = (value) ? MAX77663_CNFG_GPIO_OUTPUT_VAL_HIGH :
+                               MAX77663_CNFG_GPIO_OUTPUT_VAL_LOW;
+
+       ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset),
+                             MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK, val);
+       if (ret < 0)
+               log_debug("%s: CNFG_GPIO_OUT update failed: %d\n", __func__, ret);
+
+       return ret;
+}
+
+static int max77663_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+       int ret;
+
+       if (offset >= NUM_GPIOS)
+               return GPIOF_INPUT;
+
+       ret = pmic_reg_read(dev->parent, GPIO_REG_ADDR(offset));
+       if (ret < 0) {
+               log_debug("%s: CNFG_GPIOx read failed: %d\n", __func__, ret);
+               return ret;
+       }
+
+       if (ret & MAX77663_CNFG_GPIO_DIR_MASK)
+               return GPIOF_INPUT;
+       else
+               return GPIOF_OUTPUT;
+}
+
+static const struct dm_gpio_ops max77663_gpio_ops = {
+       .direction_input        = max77663_gpio_direction_input,
+       .direction_output       = max77663_gpio_direction_output,
+       .get_value              = max77663_gpio_get_value,
+       .set_value              = max77663_gpio_set_value,
+       .get_function           = max77663_gpio_get_function,
+};
+
+static int max77663_gpio_probe(struct udevice *dev)
+{
+       struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+       int i, ret;
+
+       uc_priv->gpio_count = NUM_ENTRIES;
+       uc_priv->bank_name = "GPIO";
+
+       /*
+        * GPIO interrupts may be left ON after bootloader, hence let's
+        * pre-initialize hardware to the expected state by disabling all
+        * the interrupts.
+        */
+       for (i = 0; i < NUM_GPIOS; i++) {
+               ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(i),
+                                     MAX77663_CNFG_IRQ, 0);
+               if (ret < 0) {
+                       log_debug("%s: failed to disable interrupt: %d\n", __func__, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+U_BOOT_DRIVER(max77663_gpio) = {
+       .name   = MAX77663_GPIO_DRIVER,
+       .id     = UCLASS_GPIO,
+       .probe  = max77663_gpio_probe,
+       .ops    = &max77663_gpio_ops,
+};
index 68c3cbbc646967912a4b43f343387717d97c2ac2..cf08b6a7e1df9059bd8eb02d60fb8de0a5303369 100644 (file)
@@ -55,6 +55,15 @@ static int max77663_bind(struct udevice *dev)
                }
        }
 
+       if (IS_ENABLED(CONFIG_MAX77663_GPIO)) {
+               ret = device_bind_driver(dev, MAX77663_GPIO_DRIVER,
+                                        "gpio", NULL);
+               if (ret) {
+                       log_err("cannot bind GPIOs (ret = %d)\n", ret);
+                       return ret;
+               }
+       }
+
        regulators_node = dev_read_subnode(dev, "regulators");
        if (!ofnode_valid(regulators_node)) {
                log_err("%s regulators subnode not found!\n", dev->name);
diff --git a/include/dt-bindings/pmic/max77663.h b/include/dt-bindings/pmic/max77663.h
new file mode 100644 (file)
index 0000000..ee169a8
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ *  Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#ifndef _DT_BINDINGS_MAX77663_H_
+#define _DT_BINDINGS_MAX77663_H_
+
+/*
+ * MAX77663 has 8 GPIO (0 to 7) and 3 KEYS
+ * KEYS are appended after GPIOs
+ */
+
+#define EN0    10
+#define ACOK   9
+#define LID    8
+
+#endif
index b3ae3dabf462066e5b7c692edb1548623c0b38d2..fcb5916f27efa4412b25b7bf1aa557057ab14039 100644 (file)
@@ -13,6 +13,7 @@
 #define MAX77663_LDO_DRIVER            "max77663_ldo"
 #define MAX77663_SD_DRIVER             "max77663_sd"
 #define MAX77663_RST_DRIVER            "max77663_rst"
+#define MAX77663_GPIO_DRIVER           "max77663_gpio"
 
 /* Step-Down (SD) Regulator calculations */
 #define SD_STATUS_MASK                 0x30