1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 22fcf033dSHans de Goede /* 32fcf033dSHans de Goede * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com> 42fcf033dSHans de Goede * 52fcf033dSHans de Goede * X-Powers AXP Power Management ICs gpio driver 62fcf033dSHans de Goede */ 72fcf033dSHans de Goede 82fcf033dSHans de Goede #include <common.h> 92fcf033dSHans de Goede #include <asm/arch/gpio.h> 102fcf033dSHans de Goede #include <asm/arch/pmic_bus.h> 11f9b7a04bSHans de Goede #include <asm/gpio.h> 126944aff1SHans de Goede #include <axp_pmic.h> 13f9b7a04bSHans de Goede #include <dm.h> 14f9b7a04bSHans de Goede #include <dm/device-internal.h> 15f9b7a04bSHans de Goede #include <dm/lists.h> 16f9b7a04bSHans de Goede #include <dm/root.h> 172fcf033dSHans de Goede #include <errno.h> 182fcf033dSHans de Goede 19421b32b8SHans de Goede static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val); 20421b32b8SHans de Goede 212fcf033dSHans de Goede static u8 axp_get_gpio_ctrl_reg(unsigned pin) 222fcf033dSHans de Goede { 232fcf033dSHans de Goede switch (pin) { 242fcf033dSHans de Goede case 0: return AXP_GPIO0_CTRL; 252fcf033dSHans de Goede case 1: return AXP_GPIO1_CTRL; 262fcf033dSHans de Goede #ifdef AXP_GPIO2_CTRL 272fcf033dSHans de Goede case 2: return AXP_GPIO2_CTRL; 282fcf033dSHans de Goede #endif 292fcf033dSHans de Goede #ifdef AXP_GPIO3_CTRL 302fcf033dSHans de Goede case 3: return AXP_GPIO3_CTRL; 312fcf033dSHans de Goede #endif 322fcf033dSHans de Goede } 332fcf033dSHans de Goede return 0; 342fcf033dSHans de Goede } 352fcf033dSHans de Goede 36421b32b8SHans de Goede static int axp_gpio_direction_input(struct udevice *dev, unsigned pin) 372fcf033dSHans de Goede { 382fcf033dSHans de Goede u8 reg; 392fcf033dSHans de Goede 402fcf033dSHans de Goede switch (pin) { 412fcf033dSHans de Goede #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 422fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_DETECT: 432fcf033dSHans de Goede return 0; 442fcf033dSHans de Goede #endif 452fcf033dSHans de Goede default: 462fcf033dSHans de Goede reg = axp_get_gpio_ctrl_reg(pin); 472fcf033dSHans de Goede if (reg == 0) 482fcf033dSHans de Goede return -EINVAL; 492fcf033dSHans de Goede 502fcf033dSHans de Goede return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT); 512fcf033dSHans de Goede } 522fcf033dSHans de Goede } 532fcf033dSHans de Goede 54421b32b8SHans de Goede static int axp_gpio_direction_output(struct udevice *dev, unsigned pin, 55421b32b8SHans de Goede int val) 562fcf033dSHans de Goede { 572fcf033dSHans de Goede __maybe_unused int ret; 582fcf033dSHans de Goede u8 reg; 592fcf033dSHans de Goede 602fcf033dSHans de Goede switch (pin) { 6181a8aa3aSChen-Yu Tsai #ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC 6281a8aa3aSChen-Yu Tsai /* Only available on later PMICs */ 632fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_ENABLE: 6481a8aa3aSChen-Yu Tsai ret = pmic_bus_clrbits(AXP_MISC_CTRL, 6581a8aa3aSChen-Yu Tsai AXP_MISC_CTRL_N_VBUSEN_FUNC); 662fcf033dSHans de Goede if (ret) 672fcf033dSHans de Goede return ret; 682fcf033dSHans de Goede 692fcf033dSHans de Goede return axp_gpio_set_value(dev, pin, val); 702fcf033dSHans de Goede #endif 712fcf033dSHans de Goede default: 722fcf033dSHans de Goede reg = axp_get_gpio_ctrl_reg(pin); 732fcf033dSHans de Goede if (reg == 0) 742fcf033dSHans de Goede return -EINVAL; 752fcf033dSHans de Goede 762fcf033dSHans de Goede return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 772fcf033dSHans de Goede AXP_GPIO_CTRL_OUTPUT_LOW); 782fcf033dSHans de Goede } 792fcf033dSHans de Goede } 802fcf033dSHans de Goede 81421b32b8SHans de Goede static int axp_gpio_get_value(struct udevice *dev, unsigned pin) 822fcf033dSHans de Goede { 832fcf033dSHans de Goede u8 reg, val, mask; 842fcf033dSHans de Goede int ret; 852fcf033dSHans de Goede 862fcf033dSHans de Goede switch (pin) { 872fcf033dSHans de Goede #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 882fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_DETECT: 892fcf033dSHans de Goede ret = pmic_bus_read(AXP_POWER_STATUS, &val); 902fcf033dSHans de Goede mask = AXP_POWER_STATUS_VBUS_PRESENT; 912fcf033dSHans de Goede break; 922fcf033dSHans de Goede #endif 9381a8aa3aSChen-Yu Tsai #ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC 9481a8aa3aSChen-Yu Tsai /* Only available on later PMICs */ 952fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_ENABLE: 9681a8aa3aSChen-Yu Tsai ret = pmic_bus_read(AXP_VBUS_IPSOUT, &val); 9781a8aa3aSChen-Yu Tsai mask = AXP_VBUS_IPSOUT_DRIVEBUS; 982fcf033dSHans de Goede break; 992fcf033dSHans de Goede #endif 1002fcf033dSHans de Goede default: 1012fcf033dSHans de Goede reg = axp_get_gpio_ctrl_reg(pin); 1022fcf033dSHans de Goede if (reg == 0) 1032fcf033dSHans de Goede return -EINVAL; 1042fcf033dSHans de Goede 1052fcf033dSHans de Goede ret = pmic_bus_read(AXP_GPIO_STATE, &val); 1062fcf033dSHans de Goede mask = 1 << (pin + AXP_GPIO_STATE_OFFSET); 1072fcf033dSHans de Goede } 1082fcf033dSHans de Goede if (ret) 1092fcf033dSHans de Goede return ret; 1102fcf033dSHans de Goede 1112fcf033dSHans de Goede return (val & mask) ? 1 : 0; 1122fcf033dSHans de Goede } 1132fcf033dSHans de Goede 114421b32b8SHans de Goede static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val) 1152fcf033dSHans de Goede { 1162fcf033dSHans de Goede u8 reg; 1172fcf033dSHans de Goede 1182fcf033dSHans de Goede switch (pin) { 11981a8aa3aSChen-Yu Tsai #ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC 12081a8aa3aSChen-Yu Tsai /* Only available on later PMICs */ 1212fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_ENABLE: 1222fcf033dSHans de Goede if (val) 12381a8aa3aSChen-Yu Tsai return pmic_bus_setbits(AXP_VBUS_IPSOUT, 12481a8aa3aSChen-Yu Tsai AXP_VBUS_IPSOUT_DRIVEBUS); 1252fcf033dSHans de Goede else 12681a8aa3aSChen-Yu Tsai return pmic_bus_clrbits(AXP_VBUS_IPSOUT, 12781a8aa3aSChen-Yu Tsai AXP_VBUS_IPSOUT_DRIVEBUS); 1282fcf033dSHans de Goede #endif 1292fcf033dSHans de Goede default: 1302fcf033dSHans de Goede reg = axp_get_gpio_ctrl_reg(pin); 1312fcf033dSHans de Goede if (reg == 0) 1322fcf033dSHans de Goede return -EINVAL; 1332fcf033dSHans de Goede 1342fcf033dSHans de Goede return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 1352fcf033dSHans de Goede AXP_GPIO_CTRL_OUTPUT_LOW); 1362fcf033dSHans de Goede } 1372fcf033dSHans de Goede } 1382fcf033dSHans de Goede 139f9b7a04bSHans de Goede static const struct dm_gpio_ops gpio_axp_ops = { 140f9b7a04bSHans de Goede .direction_input = axp_gpio_direction_input, 141f9b7a04bSHans de Goede .direction_output = axp_gpio_direction_output, 142f9b7a04bSHans de Goede .get_value = axp_gpio_get_value, 143f9b7a04bSHans de Goede .set_value = axp_gpio_set_value, 144f9b7a04bSHans de Goede }; 145f9b7a04bSHans de Goede 146f9b7a04bSHans de Goede static int gpio_axp_probe(struct udevice *dev) 147f9b7a04bSHans de Goede { 148f9b7a04bSHans de Goede struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 149f9b7a04bSHans de Goede 150f9b7a04bSHans de Goede /* Tell the uclass how many GPIOs we have */ 151f9b7a04bSHans de Goede uc_priv->bank_name = strdup(SUNXI_GPIO_AXP0_PREFIX); 152f9b7a04bSHans de Goede uc_priv->gpio_count = SUNXI_GPIO_AXP0_GPIO_COUNT; 153f9b7a04bSHans de Goede 154f9b7a04bSHans de Goede return 0; 155f9b7a04bSHans de Goede } 156f9b7a04bSHans de Goede 157f9b7a04bSHans de Goede U_BOOT_DRIVER(gpio_axp) = { 158f9b7a04bSHans de Goede .name = "gpio_axp", 159f9b7a04bSHans de Goede .id = UCLASS_GPIO, 160f9b7a04bSHans de Goede .ops = &gpio_axp_ops, 161f9b7a04bSHans de Goede .probe = gpio_axp_probe, 162f9b7a04bSHans de Goede }; 163f9b7a04bSHans de Goede 1642fcf033dSHans de Goede int axp_gpio_init(void) 1652fcf033dSHans de Goede { 166421b32b8SHans de Goede struct udevice *dev; 1672fcf033dSHans de Goede int ret; 1682fcf033dSHans de Goede 1692fcf033dSHans de Goede ret = pmic_bus_init(); 1702fcf033dSHans de Goede if (ret) 1712fcf033dSHans de Goede return ret; 1722fcf033dSHans de Goede 173f9b7a04bSHans de Goede /* There is no devicetree support for the axp yet, so bind directly */ 174f9b7a04bSHans de Goede ret = device_bind_driver(dm_root(), "gpio_axp", "AXP-gpio", &dev); 175f9b7a04bSHans de Goede if (ret) 176f9b7a04bSHans de Goede return ret; 177f9b7a04bSHans de Goede 1782fcf033dSHans de Goede return 0; 1792fcf033dSHans de Goede } 180