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 <errno.h> 13 14 #ifdef CONFIG_AXP152_POWER 15 #include <axp152.h> 16 #elif defined CONFIG_AXP209_POWER 17 #include <axp209.h> 18 #elif defined CONFIG_AXP221_POWER 19 #include <axp221.h> 20 #else 21 #error Unknown AXP model 22 #endif 23 24 static u8 axp_get_gpio_ctrl_reg(unsigned pin) 25 { 26 switch (pin) { 27 case 0: return AXP_GPIO0_CTRL; 28 case 1: return AXP_GPIO1_CTRL; 29 #ifdef AXP_GPIO2_CTRL 30 case 2: return AXP_GPIO2_CTRL; 31 #endif 32 #ifdef AXP_GPIO3_CTRL 33 case 3: return AXP_GPIO3_CTRL; 34 #endif 35 } 36 return 0; 37 } 38 39 int axp_gpio_direction_input(struct udevice *dev, unsigned pin) 40 { 41 u8 reg; 42 43 switch (pin) { 44 #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 45 case SUNXI_GPIO_AXP0_VBUS_DETECT: 46 return 0; 47 #endif 48 default: 49 reg = axp_get_gpio_ctrl_reg(pin); 50 if (reg == 0) 51 return -EINVAL; 52 53 return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT); 54 } 55 } 56 57 int axp_gpio_direction_output(struct udevice *dev, unsigned pin, int val) 58 { 59 __maybe_unused int ret; 60 u8 reg; 61 62 switch (pin) { 63 #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 64 case SUNXI_GPIO_AXP0_VBUS_ENABLE: 65 ret = pmic_bus_clrbits(AXP221_MISC_CTRL, 66 AXP221_MISC_CTRL_N_VBUSEN_FUNC); 67 if (ret) 68 return ret; 69 70 return axp_gpio_set_value(dev, pin, val); 71 #endif 72 default: 73 reg = axp_get_gpio_ctrl_reg(pin); 74 if (reg == 0) 75 return -EINVAL; 76 77 return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 78 AXP_GPIO_CTRL_OUTPUT_LOW); 79 } 80 } 81 82 int axp_gpio_get_value(struct udevice *dev, unsigned pin) 83 { 84 u8 reg, val, mask; 85 int ret; 86 87 switch (pin) { 88 #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ 89 case SUNXI_GPIO_AXP0_VBUS_DETECT: 90 ret = pmic_bus_read(AXP_POWER_STATUS, &val); 91 mask = AXP_POWER_STATUS_VBUS_PRESENT; 92 break; 93 #endif 94 #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 95 case SUNXI_GPIO_AXP0_VBUS_ENABLE: 96 ret = pmic_bus_read(AXP221_VBUS_IPSOUT, &val); 97 mask = AXP221_VBUS_IPSOUT_DRIVEBUS; 98 break; 99 #endif 100 default: 101 reg = axp_get_gpio_ctrl_reg(pin); 102 if (reg == 0) 103 return -EINVAL; 104 105 ret = pmic_bus_read(AXP_GPIO_STATE, &val); 106 mask = 1 << (pin + AXP_GPIO_STATE_OFFSET); 107 } 108 if (ret) 109 return ret; 110 111 return (val & mask) ? 1 : 0; 112 } 113 114 int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val) 115 { 116 u8 reg; 117 118 switch (pin) { 119 #ifdef CONFIG_AXP221_POWER /* Only available on axp221/axp223 */ 120 case SUNXI_GPIO_AXP0_VBUS_ENABLE: 121 if (val) 122 return pmic_bus_setbits(AXP221_VBUS_IPSOUT, 123 AXP221_VBUS_IPSOUT_DRIVEBUS); 124 else 125 return pmic_bus_clrbits(AXP221_VBUS_IPSOUT, 126 AXP221_VBUS_IPSOUT_DRIVEBUS); 127 #endif 128 default: 129 reg = axp_get_gpio_ctrl_reg(pin); 130 if (reg == 0) 131 return -EINVAL; 132 133 return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : 134 AXP_GPIO_CTRL_OUTPUT_LOW); 135 } 136 } 137 138 int axp_gpio_init(void) 139 { 140 int ret; 141 142 ret = pmic_bus_init(); 143 if (ret) 144 return ret; 145 146 return 0; 147 } 148