]>
Commit | Line | Data |
---|---|---|
2c62c56a WY |
1 | /* |
2 | * Atmel PIO4 device driver | |
3 | * | |
4 | * Copyright (C) 2015 Atmel Corporation | |
5 | * Wenyou.Yang <wenyou.yang@atmel.com> | |
6 | * | |
7 | * SPDX-License-Identifier: GPL-2.0+ | |
8 | */ | |
9 | #include <common.h> | |
ee3311db | 10 | #include <clk.h> |
2c62c56a | 11 | #include <dm.h> |
ee3311db WY |
12 | #include <fdtdec.h> |
13 | #include <dm/root.h> | |
2c62c56a | 14 | #include <asm/arch/hardware.h> |
ee3311db | 15 | #include <asm/gpio.h> |
2c62c56a WY |
16 | #include <mach/gpio.h> |
17 | #include <mach/atmel_pio4.h> | |
18 | ||
ee3311db WY |
19 | DECLARE_GLOBAL_DATA_PTR; |
20 | ||
2c62c56a WY |
21 | static struct atmel_pio4_port *atmel_pio4_port_base(u32 port) |
22 | { | |
23 | struct atmel_pio4_port *base = NULL; | |
24 | ||
25 | switch (port) { | |
26 | case AT91_PIO_PORTA: | |
27 | base = (struct atmel_pio4_port *)ATMEL_BASE_PIOA; | |
28 | break; | |
29 | case AT91_PIO_PORTB: | |
30 | base = (struct atmel_pio4_port *)ATMEL_BASE_PIOB; | |
31 | break; | |
32 | case AT91_PIO_PORTC: | |
33 | base = (struct atmel_pio4_port *)ATMEL_BASE_PIOC; | |
34 | break; | |
35 | case AT91_PIO_PORTD: | |
36 | base = (struct atmel_pio4_port *)ATMEL_BASE_PIOD; | |
37 | break; | |
38 | default: | |
39 | printf("Error: Atmel PIO4: Failed to get PIO base of port#%d!\n", | |
40 | port); | |
41 | break; | |
42 | } | |
43 | ||
44 | return base; | |
45 | } | |
46 | ||
47 | static int atmel_pio4_config_io_func(u32 port, u32 pin, | |
48 | u32 func, u32 use_pullup) | |
49 | { | |
50 | struct atmel_pio4_port *port_base; | |
51 | u32 reg, mask; | |
52 | ||
46ed9381 | 53 | if (pin >= ATMEL_PIO_NPINS_PER_BANK) |
2c62c56a WY |
54 | return -ENODEV; |
55 | ||
56 | port_base = atmel_pio4_port_base(port); | |
57 | if (!port_base) | |
58 | return -ENODEV; | |
59 | ||
60 | mask = 1 << pin; | |
61 | reg = func; | |
46ed9381 | 62 | reg |= use_pullup ? ATMEL_PIO_PUEN_MASK : 0; |
2c62c56a WY |
63 | |
64 | writel(mask, &port_base->mskr); | |
65 | writel(reg, &port_base->cfgr); | |
66 | ||
67 | return 0; | |
68 | } | |
69 | ||
70 | int atmel_pio4_set_gpio(u32 port, u32 pin, u32 use_pullup) | |
71 | { | |
72 | return atmel_pio4_config_io_func(port, pin, | |
46ed9381 | 73 | ATMEL_PIO_CFGR_FUNC_GPIO, |
2c62c56a WY |
74 | use_pullup); |
75 | } | |
76 | ||
77 | int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 use_pullup) | |
78 | { | |
79 | return atmel_pio4_config_io_func(port, pin, | |
46ed9381 | 80 | ATMEL_PIO_CFGR_FUNC_PERIPH_A, |
2c62c56a WY |
81 | use_pullup); |
82 | } | |
83 | ||
84 | int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 use_pullup) | |
85 | { | |
86 | return atmel_pio4_config_io_func(port, pin, | |
46ed9381 | 87 | ATMEL_PIO_CFGR_FUNC_PERIPH_B, |
2c62c56a WY |
88 | use_pullup); |
89 | } | |
90 | ||
91 | int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 use_pullup) | |
92 | { | |
93 | return atmel_pio4_config_io_func(port, pin, | |
46ed9381 | 94 | ATMEL_PIO_CFGR_FUNC_PERIPH_C, |
2c62c56a WY |
95 | use_pullup); |
96 | } | |
97 | ||
98 | int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 use_pullup) | |
99 | { | |
100 | return atmel_pio4_config_io_func(port, pin, | |
46ed9381 | 101 | ATMEL_PIO_CFGR_FUNC_PERIPH_D, |
2c62c56a WY |
102 | use_pullup); |
103 | } | |
104 | ||
105 | int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 use_pullup) | |
106 | { | |
107 | return atmel_pio4_config_io_func(port, pin, | |
46ed9381 | 108 | ATMEL_PIO_CFGR_FUNC_PERIPH_E, |
2c62c56a WY |
109 | use_pullup); |
110 | } | |
111 | ||
112 | int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 use_pullup) | |
113 | { | |
114 | return atmel_pio4_config_io_func(port, pin, | |
46ed9381 | 115 | ATMEL_PIO_CFGR_FUNC_PERIPH_F, |
2c62c56a WY |
116 | use_pullup); |
117 | } | |
118 | ||
119 | int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 use_pullup) | |
120 | { | |
121 | return atmel_pio4_config_io_func(port, pin, | |
46ed9381 | 122 | ATMEL_PIO_CFGR_FUNC_PERIPH_G, |
2c62c56a WY |
123 | use_pullup); |
124 | } | |
125 | ||
126 | int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value) | |
127 | { | |
128 | struct atmel_pio4_port *port_base; | |
129 | u32 reg, mask; | |
130 | ||
46ed9381 | 131 | if (pin >= ATMEL_PIO_NPINS_PER_BANK) |
2c62c56a WY |
132 | return -ENODEV; |
133 | ||
134 | port_base = atmel_pio4_port_base(port); | |
135 | if (!port_base) | |
136 | return -ENODEV; | |
137 | ||
138 | mask = 0x01 << pin; | |
46ed9381 | 139 | reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK; |
2c62c56a WY |
140 | |
141 | writel(mask, &port_base->mskr); | |
142 | writel(reg, &port_base->cfgr); | |
143 | ||
144 | if (value) | |
145 | writel(mask, &port_base->sodr); | |
146 | else | |
147 | writel(mask, &port_base->codr); | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
152 | int atmel_pio4_get_pio_input(u32 port, u32 pin) | |
153 | { | |
154 | struct atmel_pio4_port *port_base; | |
155 | u32 reg, mask; | |
156 | ||
46ed9381 | 157 | if (pin >= ATMEL_PIO_NPINS_PER_BANK) |
2c62c56a WY |
158 | return -ENODEV; |
159 | ||
160 | port_base = atmel_pio4_port_base(port); | |
161 | if (!port_base) | |
162 | return -ENODEV; | |
163 | ||
164 | mask = 0x01 << pin; | |
46ed9381 | 165 | reg = ATMEL_PIO_CFGR_FUNC_GPIO; |
2c62c56a WY |
166 | |
167 | writel(mask, &port_base->mskr); | |
168 | writel(reg, &port_base->cfgr); | |
169 | ||
170 | return (readl(&port_base->pdsr) & mask) ? 1 : 0; | |
171 | } | |
172 | ||
173 | #ifdef CONFIG_DM_GPIO | |
ee3311db WY |
174 | |
175 | struct atmel_pioctrl_data { | |
176 | u32 nbanks; | |
177 | }; | |
178 | ||
179 | struct atmel_pio4_platdata { | |
180 | struct atmel_pio4_port *reg_base; | |
181 | }; | |
182 | ||
183 | static struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev, | |
184 | u32 bank) | |
185 | { | |
186 | struct atmel_pio4_platdata *plat = dev_get_platdata(dev); | |
187 | struct atmel_pio4_port *port_base = | |
188 | (struct atmel_pio4_port *)((u32)plat->reg_base + | |
189 | ATMEL_PIO_BANK_OFFSET * bank); | |
190 | ||
191 | return port_base; | |
192 | } | |
193 | ||
2c62c56a WY |
194 | static int atmel_pio4_direction_input(struct udevice *dev, unsigned offset) |
195 | { | |
ee3311db WY |
196 | u32 bank = ATMEL_PIO_BANK(offset); |
197 | u32 line = ATMEL_PIO_LINE(offset); | |
198 | struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); | |
199 | u32 mask = BIT(line); | |
2c62c56a WY |
200 | |
201 | writel(mask, &port_base->mskr); | |
ee3311db WY |
202 | |
203 | clrbits_le32(&port_base->cfgr, | |
204 | ATMEL_PIO_CFGR_FUNC_MASK | ATMEL_PIO_DIR_MASK); | |
2c62c56a WY |
205 | |
206 | return 0; | |
207 | } | |
208 | ||
209 | static int atmel_pio4_direction_output(struct udevice *dev, | |
210 | unsigned offset, int value) | |
211 | { | |
ee3311db WY |
212 | u32 bank = ATMEL_PIO_BANK(offset); |
213 | u32 line = ATMEL_PIO_LINE(offset); | |
214 | struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); | |
215 | u32 mask = BIT(line); | |
2c62c56a WY |
216 | |
217 | writel(mask, &port_base->mskr); | |
ee3311db WY |
218 | |
219 | clrsetbits_le32(&port_base->cfgr, | |
220 | ATMEL_PIO_CFGR_FUNC_MASK, ATMEL_PIO_DIR_MASK); | |
2c62c56a WY |
221 | |
222 | if (value) | |
223 | writel(mask, &port_base->sodr); | |
224 | else | |
225 | writel(mask, &port_base->codr); | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
230 | static int atmel_pio4_get_value(struct udevice *dev, unsigned offset) | |
231 | { | |
ee3311db WY |
232 | u32 bank = ATMEL_PIO_BANK(offset); |
233 | u32 line = ATMEL_PIO_LINE(offset); | |
234 | struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); | |
235 | u32 mask = BIT(line); | |
2c62c56a WY |
236 | |
237 | return (readl(&port_base->pdsr) & mask) ? 1 : 0; | |
238 | } | |
239 | ||
240 | static int atmel_pio4_set_value(struct udevice *dev, | |
241 | unsigned offset, int value) | |
242 | { | |
ee3311db WY |
243 | u32 bank = ATMEL_PIO_BANK(offset); |
244 | u32 line = ATMEL_PIO_LINE(offset); | |
245 | struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); | |
246 | u32 mask = BIT(line); | |
2c62c56a WY |
247 | |
248 | if (value) | |
249 | writel(mask, &port_base->sodr); | |
250 | else | |
251 | writel(mask, &port_base->codr); | |
252 | ||
253 | return 0; | |
254 | } | |
255 | ||
256 | static int atmel_pio4_get_function(struct udevice *dev, unsigned offset) | |
257 | { | |
ee3311db WY |
258 | u32 bank = ATMEL_PIO_BANK(offset); |
259 | u32 line = ATMEL_PIO_LINE(offset); | |
260 | struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); | |
261 | u32 mask = BIT(line); | |
2c62c56a WY |
262 | |
263 | writel(mask, &port_base->mskr); | |
264 | ||
265 | return (readl(&port_base->cfgr) & | |
46ed9381 | 266 | ATMEL_PIO_DIR_MASK) ? GPIOF_OUTPUT : GPIOF_INPUT; |
2c62c56a WY |
267 | } |
268 | ||
269 | static const struct dm_gpio_ops atmel_pio4_ops = { | |
270 | .direction_input = atmel_pio4_direction_input, | |
271 | .direction_output = atmel_pio4_direction_output, | |
272 | .get_value = atmel_pio4_get_value, | |
273 | .set_value = atmel_pio4_set_value, | |
274 | .get_function = atmel_pio4_get_function, | |
275 | }; | |
276 | ||
ee3311db WY |
277 | static int atmel_pio4_bind(struct udevice *dev) |
278 | { | |
e160f7d4 | 279 | return dm_scan_fdt_node(dev, gd->fdt_blob, dev_of_offset(dev), false); |
ee3311db WY |
280 | } |
281 | ||
2c62c56a WY |
282 | static int atmel_pio4_probe(struct udevice *dev) |
283 | { | |
ee3311db | 284 | struct atmel_pio4_platdata *plat = dev_get_platdata(dev); |
2c62c56a | 285 | struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); |
ee3311db | 286 | struct atmel_pioctrl_data *pioctrl_data; |
ee3311db WY |
287 | struct clk clk; |
288 | fdt_addr_t addr_base; | |
289 | u32 nbanks; | |
ee3311db WY |
290 | int ret; |
291 | ||
292 | ret = clk_get_by_index(dev, 0, &clk); | |
293 | if (ret) | |
294 | return ret; | |
295 | ||
ee3311db WY |
296 | ret = clk_enable(&clk); |
297 | if (ret) | |
298 | return ret; | |
299 | ||
300 | clk_free(&clk); | |
301 | ||
a821c4af | 302 | addr_base = devfdt_get_addr(dev); |
ee3311db WY |
303 | if (addr_base == FDT_ADDR_T_NONE) |
304 | return -EINVAL; | |
305 | ||
306 | plat->reg_base = (struct atmel_pio4_port *)addr_base; | |
2c62c56a | 307 | |
ee3311db WY |
308 | pioctrl_data = (struct atmel_pioctrl_data *)dev_get_driver_data(dev); |
309 | nbanks = pioctrl_data->nbanks; | |
310 | ||
e160f7d4 SG |
311 | uc_priv->bank_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), |
312 | NULL); | |
ee3311db | 313 | uc_priv->gpio_count = nbanks * ATMEL_PIO_NPINS_PER_BANK; |
2c62c56a WY |
314 | |
315 | return 0; | |
316 | } | |
317 | ||
ee3311db WY |
318 | /* |
319 | * The number of banks can be different from a SoC to another one. | |
320 | * We can have up to 16 banks. | |
321 | */ | |
322 | static const struct atmel_pioctrl_data atmel_sama5d2_pioctrl_data = { | |
323 | .nbanks = 4, | |
324 | }; | |
325 | ||
326 | static const struct udevice_id atmel_pio4_ids[] = { | |
327 | { | |
328 | .compatible = "atmel,sama5d2-gpio", | |
329 | .data = (ulong)&atmel_sama5d2_pioctrl_data, | |
330 | }, | |
331 | {} | |
332 | }; | |
333 | ||
2c62c56a WY |
334 | U_BOOT_DRIVER(gpio_atmel_pio4) = { |
335 | .name = "gpio_atmel_pio4", | |
336 | .id = UCLASS_GPIO, | |
337 | .ops = &atmel_pio4_ops, | |
338 | .probe = atmel_pio4_probe, | |
ee3311db WY |
339 | .bind = atmel_pio4_bind, |
340 | .of_match = atmel_pio4_ids, | |
341 | .platdata_auto_alloc_size = sizeof(struct atmel_pio4_platdata), | |
2c62c56a | 342 | }; |
ee3311db | 343 | |
2c62c56a | 344 | #endif |