1 /* 2 * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com> 3 * 4 * X-Powers AXP Power Management ICs gpio driver 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <asm/arch/gpio.h> 11 #include <asm/arch/pmic_bus.h> 12 #include <asm/gpio.h> 13 #include <dm.h> 14 #include <dm/device-internal.h> 15 #include <dm/lists.h> 16 #include <dm/root.h> 17 #include <errno.h> 18 19 #ifdef CONFIG_AXP152_POWER 20 #include <axp152.h> 21 #elif defined CONFIG_AXP209_POWER 22 #include <axp209.h> 23 #elif defined CONFIG_AXP221_POWER 24 #include <axp221.h> 25 #else 26 #error Unknown AXP model 27 #endif 28 29 static u8 axp_get_gpio_ctrl_reg(unsigned pin) 30 { 31 switch (pin) { 32 case 0: return AXP_GPIO0_CTRL; 33 case 1: return AXP_GPIO1_CTRL; 34 #ifdef AXP_GPIO2_CTRL 35 case 2: return AXP_GPIO2_CTRL; 36 #endif 37 #ifdef AXP_GPIO3_CTRL 38 case 3: return AXP_GPIO3_CTRL; 39 #endif 40 } 41 return 0; 42 } 43 44 int axp_gpio_direction_input(struct udevice *dev, unsigned pin) 45 { 46 u8 reg; 47 48 switch (pin) { 49 #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 50 case SUNXI_GPIO_AXP0_VBUS_DETECT: 51 return 0; 52 #endif 53 default: 54 reg = axp_get_gpio_ctrl_reg(pin); 55 if (reg == 0) 56 return -EINVAL; 57 58 return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT); 59 } 60 } 61 62 int axp_gpio_direction_output(struct udevice *dev, unsigned pin, int val) 63 { 64 __maybe_unused int ret; 65 u8 reg; 66 67 switch (pin) { 68 #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 69 case SUNXI_GPIO_AXP0_VBUS_ENABLE: 70 ret = pmic_bus_clrbits(AXP221_MISC_CTRL, 71 AXP221_MISC_CTRL_N_VBUSEN_FUNC); 72 if (ret) 73 return ret; 74 75 return axp_gpio_set_value(dev, pin, val); 76 #endif 77 default: 78 reg = axp_get_gpio_ctrl_reg(pin); 79 if (reg == 0) 80 return -EINVAL; 81 82 return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 83 AXP_GPIO_CTRL_OUTPUT_LOW); 84 } 85 } 86 87 int axp_gpio_get_value(struct udevice *dev, unsigned pin) 88 { 89 u8 reg, val, mask; 90 int ret; 91 92 switch (pin) { 93 #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 94 case SUNXI_GPIO_AXP0_VBUS_DETECT: 95 ret = pmic_bus_read(AXP_POWER_STATUS, &val); 96 mask = AXP_POWER_STATUS_VBUS_PRESENT; 97 break; 98 #endif 99 #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 100 case SUNXI_GPIO_AXP0_VBUS_ENABLE: 101 ret = pmic_bus_read(AXP221_VBUS_IPSOUT, &val); 102 mask = AXP221_VBUS_IPSOUT_DRIVEBUS; 103 break; 104 #endif 105 default: 106 reg = axp_get_gpio_ctrl_reg(pin); 107 if (reg == 0) 108 return -EINVAL; 109 110 ret = pmic_bus_read(AXP_GPIO_STATE, &val); 111 mask = 1 << (pin + AXP_GPIO_STATE_OFFSET); 112 } 113 if (ret) 114 return ret; 115 116 return (val & mask) ? 1 : 0; 117 } 118 119 int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val) 120 { 121 u8 reg; 122 123 switch (pin) { 124 #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 125 case SUNXI_GPIO_AXP0_VBUS_ENABLE: 126 if (val) 127 return pmic_bus_setbits(AXP221_VBUS_IPSOUT, 128 AXP221_VBUS_IPSOUT_DRIVEBUS); 129 else 130 return pmic_bus_clrbits(AXP221_VBUS_IPSOUT, 131 AXP221_VBUS_IPSOUT_DRIVEBUS); 132 #endif 133 default: 134 reg = axp_get_gpio_ctrl_reg(pin); 135 if (reg == 0) 136 return -EINVAL; 137 138 return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 139 AXP_GPIO_CTRL_OUTPUT_LOW); 140 } 141 } 142 143 #ifdef CONFIG_DM_GPIO 144 static const struct dm_gpio_ops gpio_axp_ops = { 145 .direction_input = axp_gpio_direction_input, 146 .direction_output = axp_gpio_direction_output, 147 .get_value = axp_gpio_get_value, 148 .set_value = axp_gpio_set_value, 149 }; 150 151 static int gpio_axp_probe(struct udevice *dev) 152 { 153 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 154 155 /* Tell the uclass how many GPIOs we have */ 156 uc_priv->bank_name = strdup(SUNXI_GPIO_AXP0_PREFIX); 157 uc_priv->gpio_count = SUNXI_GPIO_AXP0_GPIO_COUNT; 158 159 return 0; 160 } 161 162 U_BOOT_DRIVER(gpio_axp) = { 163 .name = "gpio_axp", 164 .id = UCLASS_GPIO, 165 .ops = &gpio_axp_ops, 166 .probe = gpio_axp_probe, 167 }; 168 #endif 169 170 int axp_gpio_init(void) 171 { 172 __maybe_unused struct udevice *dev; 173 int ret; 174 175 ret = pmic_bus_init(); 176 if (ret) 177 return ret; 178 179 #ifdef CONFIG_DM_GPIO 180 /* There is no devicetree support for the axp yet, so bind directly */ 181 ret = device_bind_driver(dm_root(), "gpio_axp", "AXP-gpio", &dev); 182 if (ret) 183 return ret; 184 #endif 185 186 return 0; 187 } 188