]>
Commit | Line | Data |
---|---|---|
2fcf033d HG |
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> | |
f9b7a04b | 12 | #include <asm/gpio.h> |
6944aff1 | 13 | #include <axp_pmic.h> |
f9b7a04b HG |
14 | #include <dm.h> |
15 | #include <dm/device-internal.h> | |
16 | #include <dm/lists.h> | |
17 | #include <dm/root.h> | |
2fcf033d HG |
18 | #include <errno.h> |
19 | ||
421b32b8 HG |
20 | static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val); |
21 | ||
2fcf033d HG |
22 | static u8 axp_get_gpio_ctrl_reg(unsigned pin) |
23 | { | |
24 | switch (pin) { | |
25 | case 0: return AXP_GPIO0_CTRL; | |
26 | case 1: return AXP_GPIO1_CTRL; | |
27 | #ifdef AXP_GPIO2_CTRL | |
28 | case 2: return AXP_GPIO2_CTRL; | |
29 | #endif | |
30 | #ifdef AXP_GPIO3_CTRL | |
31 | case 3: return AXP_GPIO3_CTRL; | |
32 | #endif | |
33 | } | |
34 | return 0; | |
35 | } | |
36 | ||
421b32b8 | 37 | static int axp_gpio_direction_input(struct udevice *dev, unsigned pin) |
2fcf033d HG |
38 | { |
39 | u8 reg; | |
40 | ||
41 | switch (pin) { | |
42 | #ifndef CONFIG_AXP152_POWER /* NA on axp152 */ | |
43 | case SUNXI_GPIO_AXP0_VBUS_DETECT: | |
44 | return 0; | |
45 | #endif | |
46 | default: | |
47 | reg = axp_get_gpio_ctrl_reg(pin); | |
48 | if (reg == 0) | |
49 | return -EINVAL; | |
50 | ||
51 | return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT); | |
52 | } | |
53 | } | |
54 | ||
421b32b8 HG |
55 | static int axp_gpio_direction_output(struct udevice *dev, unsigned pin, |
56 | int val) | |
2fcf033d HG |
57 | { |
58 | __maybe_unused int ret; | |
59 | u8 reg; | |
60 | ||
61 | switch (pin) { | |
81a8aa3a CYT |
62 | #ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC |
63 | /* Only available on later PMICs */ | |
2fcf033d | 64 | case SUNXI_GPIO_AXP0_VBUS_ENABLE: |
81a8aa3a CYT |
65 | ret = pmic_bus_clrbits(AXP_MISC_CTRL, |
66 | AXP_MISC_CTRL_N_VBUSEN_FUNC); | |
2fcf033d HG |
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 | ||
421b32b8 | 82 | static int axp_gpio_get_value(struct udevice *dev, unsigned pin) |
2fcf033d HG |
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 | |
81a8aa3a CYT |
94 | #ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC |
95 | /* Only available on later PMICs */ | |
2fcf033d | 96 | case SUNXI_GPIO_AXP0_VBUS_ENABLE: |
81a8aa3a CYT |
97 | ret = pmic_bus_read(AXP_VBUS_IPSOUT, &val); |
98 | mask = AXP_VBUS_IPSOUT_DRIVEBUS; | |
2fcf033d HG |
99 | break; |
100 | #endif | |
101 | default: | |
102 | reg = axp_get_gpio_ctrl_reg(pin); | |
103 | if (reg == 0) | |
104 | return -EINVAL; | |
105 | ||
106 | ret = pmic_bus_read(AXP_GPIO_STATE, &val); | |
107 | mask = 1 << (pin + AXP_GPIO_STATE_OFFSET); | |
108 | } | |
109 | if (ret) | |
110 | return ret; | |
111 | ||
112 | return (val & mask) ? 1 : 0; | |
113 | } | |
114 | ||
421b32b8 | 115 | static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val) |
2fcf033d HG |
116 | { |
117 | u8 reg; | |
118 | ||
119 | switch (pin) { | |
81a8aa3a CYT |
120 | #ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC |
121 | /* Only available on later PMICs */ | |
2fcf033d HG |
122 | case SUNXI_GPIO_AXP0_VBUS_ENABLE: |
123 | if (val) | |
81a8aa3a CYT |
124 | return pmic_bus_setbits(AXP_VBUS_IPSOUT, |
125 | AXP_VBUS_IPSOUT_DRIVEBUS); | |
2fcf033d | 126 | else |
81a8aa3a CYT |
127 | return pmic_bus_clrbits(AXP_VBUS_IPSOUT, |
128 | AXP_VBUS_IPSOUT_DRIVEBUS); | |
2fcf033d HG |
129 | #endif |
130 | default: | |
131 | reg = axp_get_gpio_ctrl_reg(pin); | |
132 | if (reg == 0) | |
133 | return -EINVAL; | |
134 | ||
135 | return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH : | |
136 | AXP_GPIO_CTRL_OUTPUT_LOW); | |
137 | } | |
138 | } | |
139 | ||
f9b7a04b HG |
140 | static const struct dm_gpio_ops gpio_axp_ops = { |
141 | .direction_input = axp_gpio_direction_input, | |
142 | .direction_output = axp_gpio_direction_output, | |
143 | .get_value = axp_gpio_get_value, | |
144 | .set_value = axp_gpio_set_value, | |
145 | }; | |
146 | ||
147 | static int gpio_axp_probe(struct udevice *dev) | |
148 | { | |
149 | struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); | |
150 | ||
151 | /* Tell the uclass how many GPIOs we have */ | |
152 | uc_priv->bank_name = strdup(SUNXI_GPIO_AXP0_PREFIX); | |
153 | uc_priv->gpio_count = SUNXI_GPIO_AXP0_GPIO_COUNT; | |
154 | ||
155 | return 0; | |
156 | } | |
157 | ||
158 | U_BOOT_DRIVER(gpio_axp) = { | |
159 | .name = "gpio_axp", | |
160 | .id = UCLASS_GPIO, | |
161 | .ops = &gpio_axp_ops, | |
162 | .probe = gpio_axp_probe, | |
163 | }; | |
f9b7a04b | 164 | |
2fcf033d HG |
165 | int axp_gpio_init(void) |
166 | { | |
421b32b8 | 167 | struct udevice *dev; |
2fcf033d HG |
168 | int ret; |
169 | ||
170 | ret = pmic_bus_init(); | |
171 | if (ret) | |
172 | return ret; | |
173 | ||
f9b7a04b HG |
174 | /* There is no devicetree support for the axp yet, so bind directly */ |
175 | ret = device_bind_driver(dm_root(), "gpio_axp", "AXP-gpio", &dev); | |
176 | if (ret) | |
177 | return ret; | |
f9b7a04b | 178 | |
2fcf033d HG |
179 | return 0; |
180 | } |