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 int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val); 30 31 static u8 axp_get_gpio_ctrl_reg(unsigned pin) 32 { 33 switch (pin) { 34 case 0: return AXP_GPIO0_CTRL; 35 case 1: return AXP_GPIO1_CTRL; 36 #ifdef AXP_GPIO2_CTRL 37 case 2: return AXP_GPIO2_CTRL; 38 #endif 39 #ifdef AXP_GPIO3_CTRL 40 case 3: return AXP_GPIO3_CTRL; 41 #endif 42 } 43 return 0; 44 } 45 46 static int axp_gpio_direction_input(struct udevice *dev, unsigned pin) 47 { 48 u8 reg; 49 50 switch (pin) { 51 #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 52 case SUNXI_GPIO_AXP0_VBUS_DETECT: 53 return 0; 54 #endif 55 default: 56 reg = axp_get_gpio_ctrl_reg(pin); 57 if (reg == 0) 58 return -EINVAL; 59 60 return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT); 61 } 62 } 63 64 static int axp_gpio_direction_output(struct udevice *dev, unsigned pin, 65 int val) 66 { 67 __maybe_unused int ret; 68 u8 reg; 69 70 switch (pin) { 71 #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 72 case SUNXI_GPIO_AXP0_VBUS_ENABLE: 73 ret = pmic_bus_clrbits(AXP221_MISC_CTRL, 74 AXP221_MISC_CTRL_N_VBUSEN_FUNC); 75 if (ret) 76 return ret; 77 78 return axp_gpio_set_value(dev, pin, val); 79 #endif 80 default: 81 reg = axp_get_gpio_ctrl_reg(pin); 82 if (reg == 0) 83 return -EINVAL; 84 85 return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 86 AXP_GPIO_CTRL_OUTPUT_LOW); 87 } 88 } 89 90 static int axp_gpio_get_value(struct udevice *dev, unsigned pin) 91 { 92 u8 reg, val, mask; 93 int ret; 94 95 switch (pin) { 96 #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 97 case SUNXI_GPIO_AXP0_VBUS_DETECT: 98 ret = pmic_bus_read(AXP_POWER_STATUS, &val); 99 mask = AXP_POWER_STATUS_VBUS_PRESENT; 100 break; 101 #endif 102 #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 103 case SUNXI_GPIO_AXP0_VBUS_ENABLE: 104 ret = pmic_bus_read(AXP221_VBUS_IPSOUT, &val); 105 mask = AXP221_VBUS_IPSOUT_DRIVEBUS; 106 break; 107 #endif 108 default: 109 reg = axp_get_gpio_ctrl_reg(pin); 110 if (reg == 0) 111 return -EINVAL; 112 113 ret = pmic_bus_read(AXP_GPIO_STATE, &val); 114 mask = 1 << (pin + AXP_GPIO_STATE_OFFSET); 115 } 116 if (ret) 117 return ret; 118 119 return (val & mask) ? 1 : 0; 120 } 121 122 static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val) 123 { 124 u8 reg; 125 126 switch (pin) { 127 #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 128 case SUNXI_GPIO_AXP0_VBUS_ENABLE: 129 if (val) 130 return pmic_bus_setbits(AXP221_VBUS_IPSOUT, 131 AXP221_VBUS_IPSOUT_DRIVEBUS); 132 else 133 return pmic_bus_clrbits(AXP221_VBUS_IPSOUT, 134 AXP221_VBUS_IPSOUT_DRIVEBUS); 135 #endif 136 default: 137 reg = axp_get_gpio_ctrl_reg(pin); 138 if (reg == 0) 139 return -EINVAL; 140 141 return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 142 AXP_GPIO_CTRL_OUTPUT_LOW); 143 } 144 } 145 146 static const struct dm_gpio_ops gpio_axp_ops = { 147 .direction_input = axp_gpio_direction_input, 148 .direction_output = axp_gpio_direction_output, 149 .get_value = axp_gpio_get_value, 150 .set_value = axp_gpio_set_value, 151 }; 152 153 static int gpio_axp_probe(struct udevice *dev) 154 { 155 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 156 157 /* Tell the uclass how many GPIOs we have */ 158 uc_priv->bank_name = strdup(SUNXI_GPIO_AXP0_PREFIX); 159 uc_priv->gpio_count = SUNXI_GPIO_AXP0_GPIO_COUNT; 160 161 return 0; 162 } 163 164 U_BOOT_DRIVER(gpio_axp) = { 165 .name = "gpio_axp", 166 .id = UCLASS_GPIO, 167 .ops = &gpio_axp_ops, 168 .probe = gpio_axp_probe, 169 }; 170 171 int axp_gpio_init(void) 172 { 173 struct udevice *dev; 174 int ret; 175 176 ret = pmic_bus_init(); 177 if (ret) 178 return ret; 179 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 185 return 0; 186 } 187