]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/gpio/axp_gpio.c
tpm: tpm_tis_i2c: Move definitions into the header file
[karo-tx-uboot.git] / drivers / gpio / axp_gpio.c
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 }