]>
Commit | Line | Data |
---|---|---|
60445cb5 HCE |
1 | /* |
2 | * Copyright (C) 2007 Atmel Corporation | |
3 | * | |
1a459660 | 4 | * SPDX-License-Identifier: GPL-2.0+ |
60445cb5 HCE |
5 | */ |
6 | #include <common.h> | |
0eafd4b7 WY |
7 | #include <clk.h> |
8 | #include <dm.h> | |
9 | #include <fdtdec.h> | |
60445cb5 HCE |
10 | #include <spi.h> |
11 | #include <malloc.h> | |
0eafd4b7 | 12 | #include <wait_bit.h> |
60445cb5 HCE |
13 | |
14 | #include <asm/io.h> | |
15 | ||
16 | #include <asm/arch/clk.h> | |
329f0f52 | 17 | #include <asm/arch/hardware.h> |
0eafd4b7 WY |
18 | #ifdef CONFIG_DM_SPI |
19 | #include <asm/arch/at91_spi.h> | |
20 | #endif | |
21 | #ifdef CONFIG_DM_GPIO | |
22 | #include <asm/gpio.h> | |
23 | #endif | |
60445cb5 HCE |
24 | |
25 | #include "atmel_spi.h" | |
26 | ||
0eafd4b7 WY |
27 | DECLARE_GLOBAL_DATA_PTR; |
28 | ||
29 | #ifndef CONFIG_DM_SPI | |
30 | ||
e0d2d3bd BS |
31 | static int spi_has_wdrbt(struct atmel_spi_slave *slave) |
32 | { | |
33 | unsigned int ver; | |
34 | ||
35 | ver = spi_readl(slave, VERSION); | |
36 | ||
37 | return (ATMEL_SPI_VERSION_REV(ver) >= 0x210); | |
38 | } | |
39 | ||
60445cb5 HCE |
40 | void spi_init() |
41 | { | |
42 | ||
43 | } | |
44 | ||
45 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
46 | unsigned int max_hz, unsigned int mode) | |
47 | { | |
48 | struct atmel_spi_slave *as; | |
49 | unsigned int scbr; | |
50 | u32 csrx; | |
51 | void *regs; | |
52 | ||
f09d3b28 | 53 | if (!spi_cs_is_valid(bus, cs)) |
60445cb5 HCE |
54 | return NULL; |
55 | ||
56 | switch (bus) { | |
57 | case 0: | |
329f0f52 | 58 | regs = (void *)ATMEL_BASE_SPI0; |
60445cb5 | 59 | break; |
329f0f52 | 60 | #ifdef ATMEL_BASE_SPI1 |
60445cb5 | 61 | case 1: |
329f0f52 | 62 | regs = (void *)ATMEL_BASE_SPI1; |
60445cb5 HCE |
63 | break; |
64 | #endif | |
329f0f52 | 65 | #ifdef ATMEL_BASE_SPI2 |
60445cb5 | 66 | case 2: |
329f0f52 | 67 | regs = (void *)ATMEL_BASE_SPI2; |
60445cb5 HCE |
68 | break; |
69 | #endif | |
329f0f52 | 70 | #ifdef ATMEL_BASE_SPI3 |
60445cb5 | 71 | case 3: |
329f0f52 | 72 | regs = (void *)ATMEL_BASE_SPI3; |
60445cb5 HCE |
73 | break; |
74 | #endif | |
75 | default: | |
76 | return NULL; | |
77 | } | |
78 | ||
79 | ||
80 | scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz; | |
81 | if (scbr > ATMEL_SPI_CSRx_SCBR_MAX) | |
82 | /* Too low max SCK rate */ | |
83 | return NULL; | |
84 | if (scbr < 1) | |
85 | scbr = 1; | |
86 | ||
87 | csrx = ATMEL_SPI_CSRx_SCBR(scbr); | |
88 | csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8); | |
89 | if (!(mode & SPI_CPHA)) | |
90 | csrx |= ATMEL_SPI_CSRx_NCPHA; | |
91 | if (mode & SPI_CPOL) | |
92 | csrx |= ATMEL_SPI_CSRx_CPOL; | |
93 | ||
d3504fee | 94 | as = spi_alloc_slave(struct atmel_spi_slave, bus, cs); |
60445cb5 HCE |
95 | if (!as) |
96 | return NULL; | |
97 | ||
60445cb5 HCE |
98 | as->regs = regs; |
99 | as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS | |
100 | | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf); | |
e0d2d3bd BS |
101 | if (spi_has_wdrbt(as)) |
102 | as->mr |= ATMEL_SPI_MR_WDRBT; | |
103 | ||
60445cb5 HCE |
104 | spi_writel(as, CSR(cs), csrx); |
105 | ||
106 | return &as->slave; | |
107 | } | |
108 | ||
109 | void spi_free_slave(struct spi_slave *slave) | |
110 | { | |
111 | struct atmel_spi_slave *as = to_atmel_spi(slave); | |
112 | ||
113 | free(as); | |
114 | } | |
115 | ||
116 | int spi_claim_bus(struct spi_slave *slave) | |
117 | { | |
118 | struct atmel_spi_slave *as = to_atmel_spi(slave); | |
119 | ||
120 | /* Enable the SPI hardware */ | |
121 | spi_writel(as, CR, ATMEL_SPI_CR_SPIEN); | |
122 | ||
123 | /* | |
124 | * Select the slave. This should set SCK to the correct | |
125 | * initial state, etc. | |
126 | */ | |
127 | spi_writel(as, MR, as->mr); | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
132 | void spi_release_bus(struct spi_slave *slave) | |
133 | { | |
134 | struct atmel_spi_slave *as = to_atmel_spi(slave); | |
135 | ||
136 | /* Disable the SPI hardware */ | |
137 | spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS); | |
138 | } | |
139 | ||
140 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
141 | const void *dout, void *din, unsigned long flags) | |
142 | { | |
143 | struct atmel_spi_slave *as = to_atmel_spi(slave); | |
144 | unsigned int len_tx; | |
145 | unsigned int len_rx; | |
146 | unsigned int len; | |
60445cb5 HCE |
147 | u32 status; |
148 | const u8 *txp = dout; | |
149 | u8 *rxp = din; | |
150 | u8 value; | |
151 | ||
60445cb5 HCE |
152 | if (bitlen == 0) |
153 | /* Finish any previously submitted transfers */ | |
154 | goto out; | |
155 | ||
156 | /* | |
157 | * TODO: The controller can do non-multiple-of-8 bit | |
158 | * transfers, but this driver currently doesn't support it. | |
159 | * | |
160 | * It's also not clear how such transfers are supposed to be | |
161 | * represented as a stream of bytes...this is a limitation of | |
162 | * the current SPI interface. | |
163 | */ | |
164 | if (bitlen % 8) { | |
165 | /* Errors always terminate an ongoing transfer */ | |
166 | flags |= SPI_XFER_END; | |
167 | goto out; | |
168 | } | |
169 | ||
170 | len = bitlen / 8; | |
171 | ||
172 | /* | |
173 | * The controller can do automatic CS control, but it is | |
174 | * somewhat quirky, and it doesn't really buy us much anyway | |
175 | * in the context of U-Boot. | |
176 | */ | |
f09d3b28 | 177 | if (flags & SPI_XFER_BEGIN) { |
60445cb5 | 178 | spi_cs_activate(slave); |
f09d3b28 RM |
179 | /* |
180 | * sometimes the RDR is not empty when we get here, | |
181 | * in theory that should not happen, but it DOES happen. | |
182 | * Read it here to be on the safe side. | |
183 | * That also clears the OVRES flag. Required if the | |
184 | * following loop exits due to OVRES! | |
185 | */ | |
186 | spi_readl(as, RDR); | |
187 | } | |
60445cb5 HCE |
188 | |
189 | for (len_tx = 0, len_rx = 0; len_rx < len; ) { | |
190 | status = spi_readl(as, SR); | |
191 | ||
192 | if (status & ATMEL_SPI_SR_OVRES) | |
193 | return -1; | |
194 | ||
195 | if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) { | |
196 | if (txp) | |
197 | value = *txp++; | |
198 | else | |
199 | value = 0; | |
200 | spi_writel(as, TDR, value); | |
201 | len_tx++; | |
202 | } | |
203 | if (status & ATMEL_SPI_SR_RDRF) { | |
204 | value = spi_readl(as, RDR); | |
205 | if (rxp) | |
206 | *rxp++ = value; | |
207 | len_rx++; | |
208 | } | |
209 | } | |
210 | ||
211 | out: | |
212 | if (flags & SPI_XFER_END) { | |
213 | /* | |
214 | * Wait until the transfer is completely done before | |
215 | * we deactivate CS. | |
216 | */ | |
217 | do { | |
218 | status = spi_readl(as, SR); | |
219 | } while (!(status & ATMEL_SPI_SR_TXEMPTY)); | |
220 | ||
221 | spi_cs_deactivate(slave); | |
222 | } | |
223 | ||
224 | return 0; | |
225 | } | |
0eafd4b7 WY |
226 | |
227 | #else | |
228 | ||
229 | #define MAX_CS_COUNT 4 | |
230 | ||
231 | struct atmel_spi_platdata { | |
232 | struct at91_spi *regs; | |
233 | }; | |
234 | ||
235 | struct atmel_spi_priv { | |
236 | unsigned int freq; /* Default frequency */ | |
237 | unsigned int mode; | |
238 | ulong bus_clk_rate; | |
239 | struct gpio_desc cs_gpios[MAX_CS_COUNT]; | |
240 | }; | |
241 | ||
242 | static int atmel_spi_claim_bus(struct udevice *dev) | |
243 | { | |
244 | struct udevice *bus = dev_get_parent(dev); | |
245 | struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); | |
246 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
247 | struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); | |
248 | struct at91_spi *reg_base = bus_plat->regs; | |
249 | u32 cs = slave_plat->cs; | |
250 | u32 freq = priv->freq; | |
251 | u32 scbr, csrx, mode; | |
252 | ||
253 | scbr = (priv->bus_clk_rate + freq - 1) / freq; | |
254 | if (scbr > ATMEL_SPI_CSRx_SCBR_MAX) | |
255 | return -EINVAL; | |
256 | ||
257 | if (scbr < 1) | |
258 | scbr = 1; | |
259 | ||
260 | csrx = ATMEL_SPI_CSRx_SCBR(scbr); | |
261 | csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8); | |
262 | ||
263 | if (!(priv->mode & SPI_CPHA)) | |
264 | csrx |= ATMEL_SPI_CSRx_NCPHA; | |
265 | if (priv->mode & SPI_CPOL) | |
266 | csrx |= ATMEL_SPI_CSRx_CPOL; | |
267 | ||
268 | writel(csrx, ®_base->csr[cs]); | |
269 | ||
270 | mode = ATMEL_SPI_MR_MSTR | | |
271 | ATMEL_SPI_MR_MODFDIS | | |
272 | ATMEL_SPI_MR_WDRBT | | |
273 | ATMEL_SPI_MR_PCS(~(1 << cs)); | |
274 | ||
275 | writel(mode, ®_base->mr); | |
276 | ||
277 | writel(ATMEL_SPI_CR_SPIEN, ®_base->cr); | |
278 | ||
279 | return 0; | |
280 | } | |
281 | ||
282 | static int atmel_spi_release_bus(struct udevice *dev) | |
283 | { | |
284 | struct udevice *bus = dev_get_parent(dev); | |
285 | struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); | |
286 | ||
287 | writel(ATMEL_SPI_CR_SPIDIS, &bus_plat->regs->cr); | |
288 | ||
289 | return 0; | |
290 | } | |
291 | ||
292 | static void atmel_spi_cs_activate(struct udevice *dev) | |
293 | { | |
294 | struct udevice *bus = dev_get_parent(dev); | |
295 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
296 | struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); | |
297 | u32 cs = slave_plat->cs; | |
298 | ||
61a77ce1 WY |
299 | if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) |
300 | return; | |
301 | ||
0eafd4b7 WY |
302 | dm_gpio_set_value(&priv->cs_gpios[cs], 0); |
303 | } | |
304 | ||
305 | static void atmel_spi_cs_deactivate(struct udevice *dev) | |
306 | { | |
307 | struct udevice *bus = dev_get_parent(dev); | |
308 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
309 | struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); | |
310 | u32 cs = slave_plat->cs; | |
311 | ||
61a77ce1 WY |
312 | if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) |
313 | return; | |
314 | ||
0eafd4b7 WY |
315 | dm_gpio_set_value(&priv->cs_gpios[cs], 1); |
316 | } | |
317 | ||
318 | static int atmel_spi_xfer(struct udevice *dev, unsigned int bitlen, | |
319 | const void *dout, void *din, unsigned long flags) | |
320 | { | |
321 | struct udevice *bus = dev_get_parent(dev); | |
322 | struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); | |
323 | struct at91_spi *reg_base = bus_plat->regs; | |
324 | ||
325 | u32 len_tx, len_rx, len; | |
326 | u32 status; | |
327 | const u8 *txp = dout; | |
328 | u8 *rxp = din; | |
329 | u8 value; | |
330 | ||
331 | if (bitlen == 0) | |
332 | goto out; | |
333 | ||
334 | /* | |
335 | * The controller can do non-multiple-of-8 bit | |
336 | * transfers, but this driver currently doesn't support it. | |
337 | * | |
338 | * It's also not clear how such transfers are supposed to be | |
339 | * represented as a stream of bytes...this is a limitation of | |
340 | * the current SPI interface. | |
341 | */ | |
342 | if (bitlen % 8) { | |
343 | /* Errors always terminate an ongoing transfer */ | |
344 | flags |= SPI_XFER_END; | |
345 | goto out; | |
346 | } | |
347 | ||
348 | len = bitlen / 8; | |
349 | ||
350 | /* | |
351 | * The controller can do automatic CS control, but it is | |
352 | * somewhat quirky, and it doesn't really buy us much anyway | |
353 | * in the context of U-Boot. | |
354 | */ | |
355 | if (flags & SPI_XFER_BEGIN) { | |
356 | atmel_spi_cs_activate(dev); | |
357 | ||
358 | /* | |
359 | * sometimes the RDR is not empty when we get here, | |
360 | * in theory that should not happen, but it DOES happen. | |
361 | * Read it here to be on the safe side. | |
362 | * That also clears the OVRES flag. Required if the | |
363 | * following loop exits due to OVRES! | |
364 | */ | |
365 | readl(®_base->rdr); | |
366 | } | |
367 | ||
368 | for (len_tx = 0, len_rx = 0; len_rx < len; ) { | |
369 | status = readl(®_base->sr); | |
370 | ||
371 | if (status & ATMEL_SPI_SR_OVRES) | |
372 | return -1; | |
373 | ||
374 | if ((len_tx < len) && (status & ATMEL_SPI_SR_TDRE)) { | |
375 | if (txp) | |
376 | value = *txp++; | |
377 | else | |
378 | value = 0; | |
379 | writel(value, ®_base->tdr); | |
380 | len_tx++; | |
381 | } | |
382 | ||
383 | if (status & ATMEL_SPI_SR_RDRF) { | |
384 | value = readl(®_base->rdr); | |
385 | if (rxp) | |
386 | *rxp++ = value; | |
387 | len_rx++; | |
388 | } | |
389 | } | |
390 | ||
391 | out: | |
392 | if (flags & SPI_XFER_END) { | |
393 | /* | |
394 | * Wait until the transfer is completely done before | |
395 | * we deactivate CS. | |
396 | */ | |
397 | wait_for_bit(__func__, ®_base->sr, | |
398 | ATMEL_SPI_SR_TXEMPTY, true, 1000, false); | |
399 | ||
400 | atmel_spi_cs_deactivate(dev); | |
401 | } | |
402 | ||
403 | return 0; | |
404 | } | |
405 | ||
406 | static int atmel_spi_set_speed(struct udevice *bus, uint speed) | |
407 | { | |
408 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
409 | ||
410 | priv->freq = speed; | |
411 | ||
412 | return 0; | |
413 | } | |
414 | ||
415 | static int atmel_spi_set_mode(struct udevice *bus, uint mode) | |
416 | { | |
417 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
418 | ||
419 | priv->mode = mode; | |
420 | ||
421 | return 0; | |
422 | } | |
423 | ||
424 | static const struct dm_spi_ops atmel_spi_ops = { | |
425 | .claim_bus = atmel_spi_claim_bus, | |
426 | .release_bus = atmel_spi_release_bus, | |
427 | .xfer = atmel_spi_xfer, | |
428 | .set_speed = atmel_spi_set_speed, | |
429 | .set_mode = atmel_spi_set_mode, | |
430 | /* | |
431 | * cs_info is not needed, since we require all chip selects to be | |
432 | * in the device tree explicitly | |
433 | */ | |
434 | }; | |
435 | ||
436 | static int atmel_spi_enable_clk(struct udevice *bus) | |
437 | { | |
438 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
439 | struct clk clk; | |
440 | ulong clk_rate; | |
441 | int ret; | |
442 | ||
443 | ret = clk_get_by_index(bus, 0, &clk); | |
444 | if (ret) | |
445 | return -EINVAL; | |
446 | ||
447 | ret = clk_enable(&clk); | |
448 | if (ret) | |
449 | return ret; | |
450 | ||
451 | clk_rate = clk_get_rate(&clk); | |
452 | if (!clk_rate) | |
453 | return -EINVAL; | |
454 | ||
455 | priv->bus_clk_rate = clk_rate; | |
456 | ||
457 | clk_free(&clk); | |
458 | ||
459 | return 0; | |
460 | } | |
461 | ||
462 | static int atmel_spi_probe(struct udevice *bus) | |
463 | { | |
464 | struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); | |
465 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
466 | int i, ret; | |
467 | ||
468 | ret = atmel_spi_enable_clk(bus); | |
469 | if (ret) | |
470 | return ret; | |
471 | ||
a821c4af | 472 | bus_plat->regs = (struct at91_spi *)devfdt_get_addr(bus); |
0eafd4b7 WY |
473 | |
474 | ret = gpio_request_list_by_name(bus, "cs-gpios", priv->cs_gpios, | |
475 | ARRAY_SIZE(priv->cs_gpios), 0); | |
476 | if (ret < 0) { | |
477 | error("Can't get %s gpios! Error: %d", bus->name, ret); | |
478 | return ret; | |
479 | } | |
480 | ||
481 | for(i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { | |
61a77ce1 WY |
482 | if (!dm_gpio_is_valid(&priv->cs_gpios[i])) |
483 | continue; | |
484 | ||
0eafd4b7 WY |
485 | dm_gpio_set_dir_flags(&priv->cs_gpios[i], |
486 | GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); | |
487 | } | |
488 | ||
489 | writel(ATMEL_SPI_CR_SWRST, &bus_plat->regs->cr); | |
490 | ||
491 | return 0; | |
492 | } | |
493 | ||
494 | static const struct udevice_id atmel_spi_ids[] = { | |
495 | { .compatible = "atmel,at91rm9200-spi" }, | |
496 | { } | |
497 | }; | |
498 | ||
499 | U_BOOT_DRIVER(atmel_spi) = { | |
500 | .name = "atmel_spi", | |
501 | .id = UCLASS_SPI, | |
502 | .of_match = atmel_spi_ids, | |
503 | .ops = &atmel_spi_ops, | |
504 | .platdata_auto_alloc_size = sizeof(struct atmel_spi_platdata), | |
505 | .priv_auto_alloc_size = sizeof(struct atmel_spi_priv), | |
506 | .probe = atmel_spi_probe, | |
507 | }; | |
508 | #endif |