12fcf033dSHans de Goede /* 22fcf033dSHans de Goede * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com> 32fcf033dSHans de Goede * 42fcf033dSHans de Goede * X-Powers AXP Power Management ICs gpio driver 52fcf033dSHans de Goede * 62fcf033dSHans de Goede * SPDX-License-Identifier: GPL-2.0+ 72fcf033dSHans de Goede */ 82fcf033dSHans de Goede 92fcf033dSHans de Goede #include <common.h> 102fcf033dSHans de Goede #include <asm/arch/gpio.h> 112fcf033dSHans de Goede #include <asm/arch/pmic_bus.h> 12f9b7a04bSHans de Goede #include <asm/gpio.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 192fcf033dSHans de Goede #ifdef CONFIG_AXP152_POWER 202fcf033dSHans de Goede #include <axp152.h> 212fcf033dSHans de Goede #elif defined CONFIG_AXP209_POWER 222fcf033dSHans de Goede #include <axp209.h> 232fcf033dSHans de Goede #elif defined CONFIG_AXP221_POWER 242fcf033dSHans de Goede #include <axp221.h> 252fcf033dSHans de Goede #else 262fcf033dSHans de Goede #error Unknown AXP model 272fcf033dSHans de Goede #endif 282fcf033dSHans de Goede 29*421b32b8SHans de Goede static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val); 30*421b32b8SHans de Goede 312fcf033dSHans de Goede static u8 axp_get_gpio_ctrl_reg(unsigned pin) 322fcf033dSHans de Goede { 332fcf033dSHans de Goede switch (pin) { 342fcf033dSHans de Goede case 0: return AXP_GPIO0_CTRL; 352fcf033dSHans de Goede case 1: return AXP_GPIO1_CTRL; 362fcf033dSHans de Goede #ifdef AXP_GPIO2_CTRL 372fcf033dSHans de Goede case 2: return AXP_GPIO2_CTRL; 382fcf033dSHans de Goede #endif 392fcf033dSHans de Goede #ifdef AXP_GPIO3_CTRL 402fcf033dSHans de Goede case 3: return AXP_GPIO3_CTRL; 412fcf033dSHans de Goede #endif 422fcf033dSHans de Goede } 432fcf033dSHans de Goede return 0; 442fcf033dSHans de Goede } 452fcf033dSHans de Goede 46*421b32b8SHans de Goede static int axp_gpio_direction_input(struct udevice *dev, unsigned pin) 472fcf033dSHans de Goede { 482fcf033dSHans de Goede u8 reg; 492fcf033dSHans de Goede 502fcf033dSHans de Goede switch (pin) { 512fcf033dSHans de Goede #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 522fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_DETECT: 532fcf033dSHans de Goede return 0; 542fcf033dSHans de Goede #endif 552fcf033dSHans de Goede default: 562fcf033dSHans de Goede reg = axp_get_gpio_ctrl_reg(pin); 572fcf033dSHans de Goede if (reg == 0) 582fcf033dSHans de Goede return -EINVAL; 592fcf033dSHans de Goede 602fcf033dSHans de Goede return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT); 612fcf033dSHans de Goede } 622fcf033dSHans de Goede } 632fcf033dSHans de Goede 64*421b32b8SHans de Goede static int axp_gpio_direction_output(struct udevice *dev, unsigned pin, 65*421b32b8SHans de Goede int val) 662fcf033dSHans de Goede { 672fcf033dSHans de Goede __maybe_unused int ret; 682fcf033dSHans de Goede u8 reg; 692fcf033dSHans de Goede 702fcf033dSHans de Goede switch (pin) { 712fcf033dSHans de Goede #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 722fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_ENABLE: 732fcf033dSHans de Goede ret = pmic_bus_clrbits(AXP221_MISC_CTRL, 742fcf033dSHans de Goede AXP221_MISC_CTRL_N_VBUSEN_FUNC); 752fcf033dSHans de Goede if (ret) 762fcf033dSHans de Goede return ret; 772fcf033dSHans de Goede 782fcf033dSHans de Goede return axp_gpio_set_value(dev, pin, val); 792fcf033dSHans de Goede #endif 802fcf033dSHans de Goede default: 812fcf033dSHans de Goede reg = axp_get_gpio_ctrl_reg(pin); 822fcf033dSHans de Goede if (reg == 0) 832fcf033dSHans de Goede return -EINVAL; 842fcf033dSHans de Goede 852fcf033dSHans de Goede return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 862fcf033dSHans de Goede AXP_GPIO_CTRL_OUTPUT_LOW); 872fcf033dSHans de Goede } 882fcf033dSHans de Goede } 892fcf033dSHans de Goede 90*421b32b8SHans de Goede static int axp_gpio_get_value(struct udevice *dev, unsigned pin) 912fcf033dSHans de Goede { 922fcf033dSHans de Goede u8 reg, val, mask; 932fcf033dSHans de Goede int ret; 942fcf033dSHans de Goede 952fcf033dSHans de Goede switch (pin) { 962fcf033dSHans de Goede #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 972fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_DETECT: 982fcf033dSHans de Goede ret = pmic_bus_read(AXP_POWER_STATUS, &val); 992fcf033dSHans de Goede mask = AXP_POWER_STATUS_VBUS_PRESENT; 1002fcf033dSHans de Goede break; 1012fcf033dSHans de Goede #endif 1022fcf033dSHans de Goede #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 1032fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_ENABLE: 1042fcf033dSHans de Goede ret = pmic_bus_read(AXP221_VBUS_IPSOUT, &val); 1052fcf033dSHans de Goede mask = AXP221_VBUS_IPSOUT_DRIVEBUS; 1062fcf033dSHans de Goede break; 1072fcf033dSHans de Goede #endif 1082fcf033dSHans de Goede default: 1092fcf033dSHans de Goede reg = axp_get_gpio_ctrl_reg(pin); 1102fcf033dSHans de Goede if (reg == 0) 1112fcf033dSHans de Goede return -EINVAL; 1122fcf033dSHans de Goede 1132fcf033dSHans de Goede ret = pmic_bus_read(AXP_GPIO_STATE, &val); 1142fcf033dSHans de Goede mask = 1 << (pin + AXP_GPIO_STATE_OFFSET); 1152fcf033dSHans de Goede } 1162fcf033dSHans de Goede if (ret) 1172fcf033dSHans de Goede return ret; 1182fcf033dSHans de Goede 1192fcf033dSHans de Goede return (val & mask) ? 1 : 0; 1202fcf033dSHans de Goede } 1212fcf033dSHans de Goede 122*421b32b8SHans de Goede static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val) 1232fcf033dSHans de Goede { 1242fcf033dSHans de Goede u8 reg; 1252fcf033dSHans de Goede 1262fcf033dSHans de Goede switch (pin) { 1272fcf033dSHans de Goede #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 1282fcf033dSHans de Goede case SUNXI_GPIO_AXP0_VBUS_ENABLE: 1292fcf033dSHans de Goede if (val) 1302fcf033dSHans de Goede return pmic_bus_setbits(AXP221_VBUS_IPSOUT, 1312fcf033dSHans de Goede AXP221_VBUS_IPSOUT_DRIVEBUS); 1322fcf033dSHans de Goede else 1332fcf033dSHans de Goede return pmic_bus_clrbits(AXP221_VBUS_IPSOUT, 1342fcf033dSHans de Goede AXP221_VBUS_IPSOUT_DRIVEBUS); 1352fcf033dSHans de Goede #endif 1362fcf033dSHans de Goede default: 1372fcf033dSHans de Goede reg = axp_get_gpio_ctrl_reg(pin); 1382fcf033dSHans de Goede if (reg == 0) 1392fcf033dSHans de Goede return -EINVAL; 1402fcf033dSHans de Goede 1412fcf033dSHans de Goede return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 1422fcf033dSHans de Goede AXP_GPIO_CTRL_OUTPUT_LOW); 1432fcf033dSHans de Goede } 1442fcf033dSHans de Goede } 1452fcf033dSHans de Goede 146f9b7a04bSHans de Goede static const struct dm_gpio_ops gpio_axp_ops = { 147f9b7a04bSHans de Goede .direction_input = axp_gpio_direction_input, 148f9b7a04bSHans de Goede .direction_output = axp_gpio_direction_output, 149f9b7a04bSHans de Goede .get_value = axp_gpio_get_value, 150f9b7a04bSHans de Goede .set_value = axp_gpio_set_value, 151f9b7a04bSHans de Goede }; 152f9b7a04bSHans de Goede 153f9b7a04bSHans de Goede static int gpio_axp_probe(struct udevice *dev) 154f9b7a04bSHans de Goede { 155f9b7a04bSHans de Goede struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 156f9b7a04bSHans de Goede 157f9b7a04bSHans de Goede /* Tell the uclass how many GPIOs we have */ 158f9b7a04bSHans de Goede uc_priv->bank_name = strdup(SUNXI_GPIO_AXP0_PREFIX); 159f9b7a04bSHans de Goede uc_priv->gpio_count = SUNXI_GPIO_AXP0_GPIO_COUNT; 160f9b7a04bSHans de Goede 161f9b7a04bSHans de Goede return 0; 162f9b7a04bSHans de Goede } 163f9b7a04bSHans de Goede 164f9b7a04bSHans de Goede U_BOOT_DRIVER(gpio_axp) = { 165f9b7a04bSHans de Goede .name = "gpio_axp", 166f9b7a04bSHans de Goede .id = UCLASS_GPIO, 167f9b7a04bSHans de Goede .ops = &gpio_axp_ops, 168f9b7a04bSHans de Goede .probe = gpio_axp_probe, 169f9b7a04bSHans de Goede }; 170f9b7a04bSHans de Goede 1712fcf033dSHans de Goede int axp_gpio_init(void) 1722fcf033dSHans de Goede { 173*421b32b8SHans de Goede struct udevice *dev; 1742fcf033dSHans de Goede int ret; 1752fcf033dSHans de Goede 1762fcf033dSHans de Goede ret = pmic_bus_init(); 1772fcf033dSHans de Goede if (ret) 1782fcf033dSHans de Goede return ret; 1792fcf033dSHans de Goede 180f9b7a04bSHans de Goede /* There is no devicetree support for the axp yet, so bind directly */ 181f9b7a04bSHans de Goede ret = device_bind_driver(dm_root(), "gpio_axp", "AXP-gpio", &dev); 182f9b7a04bSHans de Goede if (ret) 183f9b7a04bSHans de Goede return ret; 184f9b7a04bSHans de Goede 1852fcf033dSHans de Goede return 0; 1862fcf033dSHans de Goede } 187