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