]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
60445cb5 HCE |
2 | /* |
3 | * Copyright (C) 2007 Atmel Corporation | |
60445cb5 | 4 | */ |
d678a59d | 5 | #include <common.h> |
0eafd4b7 WY |
6 | #include <clk.h> |
7 | #include <dm.h> | |
8 | #include <fdtdec.h> | |
60445cb5 HCE |
9 | #include <spi.h> |
10 | #include <malloc.h> | |
0eafd4b7 | 11 | #include <wait_bit.h> |
60445cb5 | 12 | #include <asm/io.h> |
60445cb5 | 13 | #include <asm/arch/clk.h> |
329f0f52 | 14 | #include <asm/arch/hardware.h> |
0eafd4b7 | 15 | #include <asm/arch/at91_spi.h> |
bcee8d67 | 16 | #if CONFIG_IS_ENABLED(DM_GPIO) |
0eafd4b7 WY |
17 | #include <asm/gpio.h> |
18 | #endif | |
beeb34ac | 19 | #include <linux/bitops.h> |
1e94b46f | 20 | #include <linux/printk.h> |
beeb34ac JT |
21 | |
22 | /* | |
23 | * Register definitions for the Atmel AT32/AT91 SPI Controller | |
24 | */ | |
25 | /* Register offsets */ | |
26 | #define ATMEL_SPI_CR 0x0000 | |
27 | #define ATMEL_SPI_MR 0x0004 | |
28 | #define ATMEL_SPI_RDR 0x0008 | |
29 | #define ATMEL_SPI_TDR 0x000c | |
30 | #define ATMEL_SPI_SR 0x0010 | |
31 | #define ATMEL_SPI_IER 0x0014 | |
32 | #define ATMEL_SPI_IDR 0x0018 | |
33 | #define ATMEL_SPI_IMR 0x001c | |
34 | #define ATMEL_SPI_CSR(x) (0x0030 + 4 * (x)) | |
35 | #define ATMEL_SPI_VERSION 0x00fc | |
36 | ||
37 | /* Bits in CR */ | |
38 | #define ATMEL_SPI_CR_SPIEN BIT(0) | |
39 | #define ATMEL_SPI_CR_SPIDIS BIT(1) | |
40 | #define ATMEL_SPI_CR_SWRST BIT(7) | |
41 | #define ATMEL_SPI_CR_LASTXFER BIT(24) | |
42 | ||
43 | /* Bits in MR */ | |
44 | #define ATMEL_SPI_MR_MSTR BIT(0) | |
45 | #define ATMEL_SPI_MR_PS BIT(1) | |
46 | #define ATMEL_SPI_MR_PCSDEC BIT(2) | |
47 | #define ATMEL_SPI_MR_FDIV BIT(3) | |
48 | #define ATMEL_SPI_MR_MODFDIS BIT(4) | |
49 | #define ATMEL_SPI_MR_WDRBT BIT(5) | |
50 | #define ATMEL_SPI_MR_LLB BIT(7) | |
51 | #define ATMEL_SPI_MR_PCS(x) (((x) & 15) << 16) | |
52 | #define ATMEL_SPI_MR_DLYBCS(x) ((x) << 24) | |
60445cb5 | 53 | |
beeb34ac JT |
54 | /* Bits in RDR */ |
55 | #define ATMEL_SPI_RDR_RD(x) (x) | |
56 | #define ATMEL_SPI_RDR_PCS(x) ((x) << 16) | |
57 | ||
58 | /* Bits in TDR */ | |
59 | #define ATMEL_SPI_TDR_TD(x) (x) | |
60 | #define ATMEL_SPI_TDR_PCS(x) ((x) << 16) | |
61 | #define ATMEL_SPI_TDR_LASTXFER BIT(24) | |
62 | ||
63 | /* Bits in SR/IER/IDR/IMR */ | |
64 | #define ATMEL_SPI_SR_RDRF BIT(0) | |
65 | #define ATMEL_SPI_SR_TDRE BIT(1) | |
66 | #define ATMEL_SPI_SR_MODF BIT(2) | |
67 | #define ATMEL_SPI_SR_OVRES BIT(3) | |
68 | #define ATMEL_SPI_SR_ENDRX BIT(4) | |
69 | #define ATMEL_SPI_SR_ENDTX BIT(5) | |
70 | #define ATMEL_SPI_SR_RXBUFF BIT(6) | |
71 | #define ATMEL_SPI_SR_TXBUFE BIT(7) | |
72 | #define ATMEL_SPI_SR_NSSR BIT(8) | |
73 | #define ATMEL_SPI_SR_TXEMPTY BIT(9) | |
74 | #define ATMEL_SPI_SR_SPIENS BIT(16) | |
75 | ||
76 | /* Bits in CSRx */ | |
77 | #define ATMEL_SPI_CSRx_CPOL BIT(0) | |
78 | #define ATMEL_SPI_CSRx_NCPHA BIT(1) | |
79 | #define ATMEL_SPI_CSRx_CSAAT BIT(3) | |
80 | #define ATMEL_SPI_CSRx_BITS(x) ((x) << 4) | |
81 | #define ATMEL_SPI_CSRx_SCBR(x) ((x) << 8) | |
82 | #define ATMEL_SPI_CSRx_SCBR_MAX GENMASK(7, 0) | |
83 | #define ATMEL_SPI_CSRx_DLYBS(x) ((x) << 16) | |
84 | #define ATMEL_SPI_CSRx_DLYBCT(x) ((x) << 24) | |
85 | ||
86 | /* Bits in VERSION */ | |
87 | #define ATMEL_SPI_VERSION_REV(x) ((x) & 0xfff) | |
88 | #define ATMEL_SPI_VERSION_MFN(x) ((x) << 16) | |
89 | ||
90 | /* Constants for CSRx:BITS */ | |
91 | #define ATMEL_SPI_BITS_8 0 | |
92 | #define ATMEL_SPI_BITS_9 1 | |
93 | #define ATMEL_SPI_BITS_10 2 | |
94 | #define ATMEL_SPI_BITS_11 3 | |
95 | #define ATMEL_SPI_BITS_12 4 | |
96 | #define ATMEL_SPI_BITS_13 5 | |
97 | #define ATMEL_SPI_BITS_14 6 | |
98 | #define ATMEL_SPI_BITS_15 7 | |
99 | #define ATMEL_SPI_BITS_16 8 | |
5270df28 | 100 | |
5270df28 | 101 | #define MAX_CS_COUNT 4 |
0eafd4b7 | 102 | |
beeb34ac JT |
103 | /* Register access macros */ |
104 | #define spi_readl(as, reg) \ | |
105 | readl(as->regs + ATMEL_SPI_##reg) | |
106 | #define spi_writel(as, reg, value) \ | |
107 | writel(value, as->regs + ATMEL_SPI_##reg) | |
108 | ||
8a8d24bd | 109 | struct atmel_spi_plat { |
0eafd4b7 WY |
110 | struct at91_spi *regs; |
111 | }; | |
112 | ||
113 | struct atmel_spi_priv { | |
114 | unsigned int freq; /* Default frequency */ | |
115 | unsigned int mode; | |
116 | ulong bus_clk_rate; | |
bcee8d67 | 117 | #if CONFIG_IS_ENABLED(DM_GPIO) |
0eafd4b7 | 118 | struct gpio_desc cs_gpios[MAX_CS_COUNT]; |
9bf48e2e | 119 | #endif |
0eafd4b7 WY |
120 | }; |
121 | ||
122 | static int atmel_spi_claim_bus(struct udevice *dev) | |
123 | { | |
124 | struct udevice *bus = dev_get_parent(dev); | |
8a8d24bd | 125 | struct atmel_spi_plat *bus_plat = dev_get_plat(bus); |
0eafd4b7 | 126 | struct atmel_spi_priv *priv = dev_get_priv(bus); |
8a8d24bd | 127 | struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); |
0eafd4b7 WY |
128 | struct at91_spi *reg_base = bus_plat->regs; |
129 | u32 cs = slave_plat->cs; | |
130 | u32 freq = priv->freq; | |
131 | u32 scbr, csrx, mode; | |
132 | ||
133 | scbr = (priv->bus_clk_rate + freq - 1) / freq; | |
5270df28 | 134 | if (scbr > ATMEL_SPI_CSRx_SCBR_MAX) |
0eafd4b7 WY |
135 | return -EINVAL; |
136 | ||
137 | if (scbr < 1) | |
138 | scbr = 1; | |
139 | ||
5270df28 TR |
140 | csrx = ATMEL_SPI_CSRx_SCBR(scbr); |
141 | csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8); | |
0eafd4b7 WY |
142 | |
143 | if (!(priv->mode & SPI_CPHA)) | |
5270df28 | 144 | csrx |= ATMEL_SPI_CSRx_NCPHA; |
0eafd4b7 | 145 | if (priv->mode & SPI_CPOL) |
5270df28 | 146 | csrx |= ATMEL_SPI_CSRx_CPOL; |
0eafd4b7 WY |
147 | |
148 | writel(csrx, ®_base->csr[cs]); | |
149 | ||
150 | mode = ATMEL_SPI_MR_MSTR | | |
151 | ATMEL_SPI_MR_MODFDIS | | |
152 | ATMEL_SPI_MR_WDRBT | | |
153 | ATMEL_SPI_MR_PCS(~(1 << cs)); | |
154 | ||
155 | writel(mode, ®_base->mr); | |
156 | ||
157 | writel(ATMEL_SPI_CR_SPIEN, ®_base->cr); | |
158 | ||
159 | return 0; | |
160 | } | |
161 | ||
162 | static int atmel_spi_release_bus(struct udevice *dev) | |
163 | { | |
164 | struct udevice *bus = dev_get_parent(dev); | |
8a8d24bd | 165 | struct atmel_spi_plat *bus_plat = dev_get_plat(bus); |
0eafd4b7 WY |
166 | |
167 | writel(ATMEL_SPI_CR_SPIDIS, &bus_plat->regs->cr); | |
168 | ||
169 | return 0; | |
170 | } | |
171 | ||
172 | static void atmel_spi_cs_activate(struct udevice *dev) | |
173 | { | |
bcee8d67 | 174 | #if CONFIG_IS_ENABLED(DM_GPIO) |
0eafd4b7 WY |
175 | struct udevice *bus = dev_get_parent(dev); |
176 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
8a8d24bd | 177 | struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); |
0eafd4b7 WY |
178 | u32 cs = slave_plat->cs; |
179 | ||
61a77ce1 WY |
180 | if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) |
181 | return; | |
182 | ||
0eafd4b7 | 183 | dm_gpio_set_value(&priv->cs_gpios[cs], 0); |
9bf48e2e | 184 | #endif |
0eafd4b7 WY |
185 | } |
186 | ||
187 | static void atmel_spi_cs_deactivate(struct udevice *dev) | |
188 | { | |
bcee8d67 | 189 | #if CONFIG_IS_ENABLED(DM_GPIO) |
0eafd4b7 WY |
190 | struct udevice *bus = dev_get_parent(dev); |
191 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
8a8d24bd | 192 | struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); |
0eafd4b7 WY |
193 | u32 cs = slave_plat->cs; |
194 | ||
61a77ce1 WY |
195 | if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) |
196 | return; | |
197 | ||
0eafd4b7 | 198 | dm_gpio_set_value(&priv->cs_gpios[cs], 1); |
9bf48e2e | 199 | #endif |
0eafd4b7 WY |
200 | } |
201 | ||
202 | static int atmel_spi_xfer(struct udevice *dev, unsigned int bitlen, | |
203 | const void *dout, void *din, unsigned long flags) | |
204 | { | |
205 | struct udevice *bus = dev_get_parent(dev); | |
8a8d24bd | 206 | struct atmel_spi_plat *bus_plat = dev_get_plat(bus); |
0eafd4b7 WY |
207 | struct at91_spi *reg_base = bus_plat->regs; |
208 | ||
209 | u32 len_tx, len_rx, len; | |
210 | u32 status; | |
211 | const u8 *txp = dout; | |
212 | u8 *rxp = din; | |
213 | u8 value; | |
214 | ||
215 | if (bitlen == 0) | |
216 | goto out; | |
217 | ||
218 | /* | |
219 | * The controller can do non-multiple-of-8 bit | |
220 | * transfers, but this driver currently doesn't support it. | |
221 | * | |
222 | * It's also not clear how such transfers are supposed to be | |
223 | * represented as a stream of bytes...this is a limitation of | |
224 | * the current SPI interface. | |
225 | */ | |
226 | if (bitlen % 8) { | |
227 | /* Errors always terminate an ongoing transfer */ | |
228 | flags |= SPI_XFER_END; | |
229 | goto out; | |
230 | } | |
231 | ||
232 | len = bitlen / 8; | |
233 | ||
234 | /* | |
235 | * The controller can do automatic CS control, but it is | |
236 | * somewhat quirky, and it doesn't really buy us much anyway | |
237 | * in the context of U-Boot. | |
238 | */ | |
239 | if (flags & SPI_XFER_BEGIN) { | |
240 | atmel_spi_cs_activate(dev); | |
241 | ||
242 | /* | |
243 | * sometimes the RDR is not empty when we get here, | |
244 | * in theory that should not happen, but it DOES happen. | |
245 | * Read it here to be on the safe side. | |
246 | * That also clears the OVRES flag. Required if the | |
247 | * following loop exits due to OVRES! | |
248 | */ | |
249 | readl(®_base->rdr); | |
250 | } | |
251 | ||
252 | for (len_tx = 0, len_rx = 0; len_rx < len; ) { | |
253 | status = readl(®_base->sr); | |
254 | ||
255 | if (status & ATMEL_SPI_SR_OVRES) | |
256 | return -1; | |
257 | ||
258 | if ((len_tx < len) && (status & ATMEL_SPI_SR_TDRE)) { | |
259 | if (txp) | |
260 | value = *txp++; | |
261 | else | |
262 | value = 0; | |
263 | writel(value, ®_base->tdr); | |
264 | len_tx++; | |
265 | } | |
266 | ||
267 | if (status & ATMEL_SPI_SR_RDRF) { | |
268 | value = readl(®_base->rdr); | |
269 | if (rxp) | |
270 | *rxp++ = value; | |
271 | len_rx++; | |
272 | } | |
273 | } | |
274 | ||
275 | out: | |
276 | if (flags & SPI_XFER_END) { | |
277 | /* | |
278 | * Wait until the transfer is completely done before | |
279 | * we deactivate CS. | |
280 | */ | |
48263504 ÁFR |
281 | wait_for_bit_le32(®_base->sr, |
282 | ATMEL_SPI_SR_TXEMPTY, true, 1000, false); | |
0eafd4b7 WY |
283 | |
284 | atmel_spi_cs_deactivate(dev); | |
285 | } | |
286 | ||
287 | return 0; | |
288 | } | |
289 | ||
290 | static int atmel_spi_set_speed(struct udevice *bus, uint speed) | |
291 | { | |
292 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
293 | ||
294 | priv->freq = speed; | |
295 | ||
296 | return 0; | |
297 | } | |
298 | ||
299 | static int atmel_spi_set_mode(struct udevice *bus, uint mode) | |
300 | { | |
301 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
302 | ||
303 | priv->mode = mode; | |
304 | ||
305 | return 0; | |
306 | } | |
307 | ||
308 | static const struct dm_spi_ops atmel_spi_ops = { | |
309 | .claim_bus = atmel_spi_claim_bus, | |
310 | .release_bus = atmel_spi_release_bus, | |
311 | .xfer = atmel_spi_xfer, | |
312 | .set_speed = atmel_spi_set_speed, | |
313 | .set_mode = atmel_spi_set_mode, | |
314 | /* | |
315 | * cs_info is not needed, since we require all chip selects to be | |
316 | * in the device tree explicitly | |
317 | */ | |
318 | }; | |
319 | ||
320 | static int atmel_spi_enable_clk(struct udevice *bus) | |
321 | { | |
322 | struct atmel_spi_priv *priv = dev_get_priv(bus); | |
323 | struct clk clk; | |
324 | ulong clk_rate; | |
325 | int ret; | |
326 | ||
327 | ret = clk_get_by_index(bus, 0, &clk); | |
328 | if (ret) | |
329 | return -EINVAL; | |
330 | ||
331 | ret = clk_enable(&clk); | |
332 | if (ret) | |
333 | return ret; | |
334 | ||
335 | clk_rate = clk_get_rate(&clk); | |
336 | if (!clk_rate) | |
337 | return -EINVAL; | |
338 | ||
339 | priv->bus_clk_rate = clk_rate; | |
340 | ||
0eafd4b7 WY |
341 | return 0; |
342 | } | |
343 | ||
344 | static int atmel_spi_probe(struct udevice *bus) | |
345 | { | |
8a8d24bd | 346 | struct atmel_spi_plat *bus_plat = dev_get_plat(bus); |
9bf48e2e | 347 | int ret; |
0eafd4b7 WY |
348 | |
349 | ret = atmel_spi_enable_clk(bus); | |
350 | if (ret) | |
351 | return ret; | |
352 | ||
8613c8d8 | 353 | bus_plat->regs = dev_read_addr_ptr(bus); |
0eafd4b7 | 354 | |
bcee8d67 | 355 | #if CONFIG_IS_ENABLED(DM_GPIO) |
9bf48e2e JT |
356 | struct atmel_spi_priv *priv = dev_get_priv(bus); |
357 | int i; | |
358 | ||
0eafd4b7 WY |
359 | ret = gpio_request_list_by_name(bus, "cs-gpios", priv->cs_gpios, |
360 | ARRAY_SIZE(priv->cs_gpios), 0); | |
361 | if (ret < 0) { | |
9b643e31 | 362 | pr_err("Can't get %s gpios! Error: %d", bus->name, ret); |
0eafd4b7 WY |
363 | return ret; |
364 | } | |
365 | ||
5270df28 | 366 | for(i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { |
61a77ce1 WY |
367 | if (!dm_gpio_is_valid(&priv->cs_gpios[i])) |
368 | continue; | |
369 | ||
0eafd4b7 WY |
370 | dm_gpio_set_dir_flags(&priv->cs_gpios[i], |
371 | GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); | |
372 | } | |
9bf48e2e | 373 | #endif |
0eafd4b7 WY |
374 | |
375 | writel(ATMEL_SPI_CR_SWRST, &bus_plat->regs->cr); | |
376 | ||
377 | return 0; | |
378 | } | |
379 | ||
380 | static const struct udevice_id atmel_spi_ids[] = { | |
381 | { .compatible = "atmel,at91rm9200-spi" }, | |
382 | { } | |
383 | }; | |
384 | ||
385 | U_BOOT_DRIVER(atmel_spi) = { | |
386 | .name = "atmel_spi", | |
387 | .id = UCLASS_SPI, | |
388 | .of_match = atmel_spi_ids, | |
389 | .ops = &atmel_spi_ops, | |
8a8d24bd | 390 | .plat_auto = sizeof(struct atmel_spi_plat), |
41575d8e | 391 | .priv_auto = sizeof(struct atmel_spi_priv), |
0eafd4b7 WY |
392 | .probe = atmel_spi_probe, |
393 | }; |