]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
1f8f7730 SG |
2 | /* |
3 | * (C) Copyright 2015 Google, Inc | |
4 | * | |
5 | * (C) Copyright 2008-2014 Rockchip Electronics | |
6 | * Peter, Software Engineering, <[email protected]>. | |
1f8f7730 SG |
7 | */ |
8 | ||
1f8f7730 | 9 | #include <dm.h> |
48647828 | 10 | #include <syscon.h> |
1221ce45 | 11 | #include <linux/errno.h> |
1f8f7730 | 12 | #include <asm/gpio.h> |
15f09a1a | 13 | #include <asm/arch-rockchip/clock.h> |
88b962f3 | 14 | #include <asm/arch-rockchip/hardware.h> |
15f09a1a | 15 | #include <asm/arch-rockchip/gpio.h> |
48647828 | 16 | #include <dm/pinctrl.h> |
88b962f3 JK |
17 | #include <dm/read.h> |
18 | #include <dt-bindings/pinctrl/rockchip.h> | |
19 | ||
20 | #define SWPORT_DR 0x0000 | |
21 | #define SWPORT_DDR 0x0004 | |
22 | #define EXT_PORT 0x0050 | |
23 | #define SWPORT_DR_L 0x0000 | |
24 | #define SWPORT_DR_H 0x0004 | |
25 | #define SWPORT_DDR_L 0x0008 | |
26 | #define SWPORT_DDR_H 0x000C | |
27 | #define EXT_PORT_V2 0x0070 | |
28 | #define VER_ID_V2 0x0078 | |
1f8f7730 SG |
29 | |
30 | enum { | |
31 | ROCKCHIP_GPIOS_PER_BANK = 32, | |
32 | }; | |
33 | ||
1f8f7730 | 34 | struct rockchip_gpio_priv { |
88b962f3 | 35 | void __iomem *regs; |
48647828 SG |
36 | struct udevice *pinctrl; |
37 | int bank; | |
1f8f7730 | 38 | char name[2]; |
88b962f3 | 39 | u32 version; |
1f8f7730 SG |
40 | }; |
41 | ||
88b962f3 | 42 | static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset) |
1f8f7730 SG |
43 | { |
44 | struct rockchip_gpio_priv *priv = dev_get_priv(dev); | |
88b962f3 | 45 | u32 mask = BIT(offset), data; |
1f8f7730 | 46 | |
88b962f3 JK |
47 | if (priv->version) |
48 | data = readl(priv->regs + EXT_PORT_V2); | |
49 | else | |
50 | data = readl(priv->regs + EXT_PORT); | |
1f8f7730 | 51 | |
88b962f3 | 52 | return (data & mask) ? 1 : 0; |
1f8f7730 SG |
53 | } |
54 | ||
88b962f3 JK |
55 | static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset, |
56 | int value) | |
1f8f7730 SG |
57 | { |
58 | struct rockchip_gpio_priv *priv = dev_get_priv(dev); | |
88b962f3 | 59 | u32 mask = BIT(offset), data = value ? mask : 0; |
1f8f7730 | 60 | |
88b962f3 JK |
61 | if (priv->version && offset >= 16) |
62 | rk_clrsetreg(priv->regs + SWPORT_DR_H, mask >> 16, data >> 16); | |
63 | else if (priv->version) | |
64 | rk_clrsetreg(priv->regs + SWPORT_DR_L, mask, data); | |
65 | else | |
66 | clrsetbits_le32(priv->regs + SWPORT_DR, mask, data); | |
1f8f7730 SG |
67 | |
68 | return 0; | |
69 | } | |
70 | ||
88b962f3 | 71 | static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset) |
1f8f7730 SG |
72 | { |
73 | struct rockchip_gpio_priv *priv = dev_get_priv(dev); | |
88b962f3 JK |
74 | u32 mask = BIT(offset); |
75 | ||
76 | if (priv->version && offset >= 16) | |
77 | rk_clrreg(priv->regs + SWPORT_DDR_H, mask >> 16); | |
78 | else if (priv->version) | |
79 | rk_clrreg(priv->regs + SWPORT_DDR_L, mask); | |
80 | else | |
81 | clrbits_le32(priv->regs + SWPORT_DDR, mask); | |
1f8f7730 | 82 | |
88b962f3 | 83 | return 0; |
1f8f7730 SG |
84 | } |
85 | ||
88b962f3 JK |
86 | static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset, |
87 | int value) | |
1f8f7730 SG |
88 | { |
89 | struct rockchip_gpio_priv *priv = dev_get_priv(dev); | |
88b962f3 JK |
90 | u32 mask = BIT(offset); |
91 | ||
92 | rockchip_gpio_set_value(dev, offset, value); | |
1f8f7730 | 93 | |
88b962f3 JK |
94 | if (priv->version && offset >= 16) |
95 | rk_setreg(priv->regs + SWPORT_DDR_H, mask >> 16); | |
96 | else if (priv->version) | |
97 | rk_setreg(priv->regs + SWPORT_DDR_L, mask); | |
98 | else | |
99 | setbits_le32(priv->regs + SWPORT_DDR, mask); | |
1f8f7730 SG |
100 | |
101 | return 0; | |
102 | } | |
103 | ||
104 | static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset) | |
105 | { | |
48647828 | 106 | struct rockchip_gpio_priv *priv = dev_get_priv(dev); |
88b962f3 | 107 | u32 mask = BIT(offset), data; |
48647828 SG |
108 | int ret; |
109 | ||
88b962f3 JK |
110 | if (CONFIG_IS_ENABLED(PINCTRL)) { |
111 | ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset); | |
112 | if (ret < 0) | |
113 | return ret; | |
114 | else if (ret != RK_FUNC_GPIO) | |
115 | return GPIOF_FUNC; | |
116 | } | |
117 | ||
118 | if (priv->version && offset >= 16) | |
119 | data = readl(priv->regs + SWPORT_DDR_H) << 16; | |
120 | else if (priv->version) | |
121 | data = readl(priv->regs + SWPORT_DDR_L); | |
122 | else | |
123 | data = readl(priv->regs + SWPORT_DDR); | |
48647828 | 124 | |
88b962f3 | 125 | return (data & mask) ? GPIOF_OUTPUT : GPIOF_INPUT; |
1f8f7730 SG |
126 | } |
127 | ||
aa48c94c SG |
128 | /* Simple SPL interface to GPIOs */ |
129 | #ifdef CONFIG_SPL_BUILD | |
130 | ||
131 | enum { | |
132 | PULL_NONE_1V8 = 0, | |
133 | PULL_DOWN_1V8 = 1, | |
134 | PULL_UP_1V8 = 3, | |
135 | }; | |
136 | ||
137 | int spl_gpio_set_pull(void *vregs, uint gpio, int pull) | |
138 | { | |
139 | u32 *regs = vregs; | |
140 | uint val; | |
141 | ||
142 | regs += gpio >> GPIO_BANK_SHIFT; | |
143 | gpio &= GPIO_OFFSET_MASK; | |
144 | switch (pull) { | |
145 | case GPIO_PULL_UP: | |
146 | val = PULL_UP_1V8; | |
147 | break; | |
148 | case GPIO_PULL_DOWN: | |
149 | val = PULL_DOWN_1V8; | |
150 | break; | |
151 | case GPIO_PULL_NORMAL: | |
152 | default: | |
153 | val = PULL_NONE_1V8; | |
154 | break; | |
155 | } | |
156 | clrsetbits_le32(regs, 3 << (gpio * 2), val << (gpio * 2)); | |
157 | ||
158 | return 0; | |
159 | } | |
160 | ||
161 | int spl_gpio_output(void *vregs, uint gpio, int value) | |
162 | { | |
163 | struct rockchip_gpio_regs * const regs = vregs; | |
164 | ||
165 | clrsetbits_le32(®s->swport_dr, 1 << gpio, value << gpio); | |
166 | ||
167 | /* Set direction */ | |
168 | clrsetbits_le32(®s->swport_ddr, 1 << gpio, 1 << gpio); | |
169 | ||
170 | return 0; | |
171 | } | |
172 | #endif /* CONFIG_SPL_BUILD */ | |
173 | ||
1f8f7730 SG |
174 | static int rockchip_gpio_probe(struct udevice *dev) |
175 | { | |
176 | struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); | |
177 | struct rockchip_gpio_priv *priv = dev_get_priv(dev); | |
904b8700 | 178 | struct ofnode_phandle_args args; |
1f8f7730 | 179 | char *end; |
48647828 | 180 | int ret; |
1f8f7730 | 181 | |
a1d3480b | 182 | priv->regs = dev_read_addr_ptr(dev); |
88b962f3 JK |
183 | |
184 | if (CONFIG_IS_ENABLED(PINCTRL)) { | |
185 | ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl); | |
186 | if (ret) | |
187 | return ret; | |
188 | } | |
48647828 | 189 | |
904b8700 CM |
190 | /* |
191 | * If "gpio-ranges" is present in the devicetree use it to parse | |
192 | * the GPIO bank ID, otherwise use the legacy method. | |
193 | */ | |
194 | ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), | |
195 | "gpio-ranges", NULL, 3, | |
196 | 0, &args); | |
197 | if (!ret || ret != -ENOENT) { | |
198 | uc_priv->gpio_count = args.args[2]; | |
3c454977 | 199 | priv->bank = args.args[1] / ROCKCHIP_GPIOS_PER_BANK; |
904b8700 CM |
200 | } else { |
201 | uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK; | |
f41738d0 JK |
202 | ret = dev_read_alias_seq(dev, &priv->bank); |
203 | if (ret) { | |
204 | end = strrchr(dev->name, '@'); | |
205 | priv->bank = trailing_strtoln(dev->name, end); | |
206 | } | |
904b8700 CM |
207 | } |
208 | ||
48647828 | 209 | priv->name[0] = 'A' + priv->bank; |
1f8f7730 SG |
210 | uc_priv->bank_name = priv->name; |
211 | ||
88b962f3 JK |
212 | priv->version = readl(priv->regs + VER_ID_V2); |
213 | ||
1f8f7730 SG |
214 | return 0; |
215 | } | |
216 | ||
217 | static const struct dm_gpio_ops gpio_rockchip_ops = { | |
218 | .direction_input = rockchip_gpio_direction_input, | |
219 | .direction_output = rockchip_gpio_direction_output, | |
220 | .get_value = rockchip_gpio_get_value, | |
221 | .set_value = rockchip_gpio_set_value, | |
222 | .get_function = rockchip_gpio_get_function, | |
1f8f7730 SG |
223 | }; |
224 | ||
225 | static const struct udevice_id rockchip_gpio_ids[] = { | |
226 | { .compatible = "rockchip,gpio-bank" }, | |
227 | { } | |
228 | }; | |
229 | ||
e3e2470f WL |
230 | U_BOOT_DRIVER(rockchip_gpio_bank) = { |
231 | .name = "rockchip_gpio_bank", | |
1f8f7730 SG |
232 | .id = UCLASS_GPIO, |
233 | .of_match = rockchip_gpio_ids, | |
234 | .ops = &gpio_rockchip_ops, | |
41575d8e | 235 | .priv_auto = sizeof(struct rockchip_gpio_priv), |
1f8f7730 SG |
236 | .probe = rockchip_gpio_probe, |
237 | }; |