From 52b6bbf162cb88b2c26fe5567eb32e027081407a Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Fri, 21 Jul 2023 10:50:15 +0300 Subject: [PATCH] drivers: gpio: implement PALMAS GPIO cell Add gpio driver for TI Palmas series PMIC. This has 8 gpio which can work as input/output. Signed-off-by: Svyatoslav Ryhel --- 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..15039351dd --- /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 + */ + +#include +#include +#include +#include + +#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, +}; 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