xref: /openbmc/u-boot/drivers/gpio/axp_gpio.c (revision 9d1b2987)
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