]>
Commit | Line | Data |
---|---|---|
400f5778 MF |
1 | /* |
2 | * Driver for Blackfin On-Chip SPI device | |
3 | * | |
6f070e18 | 4 | * Copyright (c) 2005-2010 Analog Devices Inc. |
400f5778 MF |
5 | * |
6 | * Licensed under the GPL-2 or later. | |
7 | */ | |
8 | ||
9 | /*#define DEBUG*/ | |
10 | ||
11 | #include <common.h> | |
12 | #include <malloc.h> | |
13 | #include <spi.h> | |
14 | ||
15 | #include <asm/blackfin.h> | |
6f070e18 | 16 | #include <asm/dma.h> |
37a4b75d | 17 | #include <asm/gpio.h> |
f3732edf | 18 | #include <asm/portmux.h> |
400f5778 MF |
19 | #include <asm/mach-common/bits/spi.h> |
20 | ||
21 | struct bfin_spi_slave { | |
22 | struct spi_slave slave; | |
23 | void *mmr_base; | |
24 | u16 ctl, baud, flg; | |
25 | }; | |
26 | ||
27 | #define MAKE_SPI_FUNC(mmr, off) \ | |
28 | static inline void write_##mmr(struct bfin_spi_slave *bss, u16 val) { bfin_write16(bss->mmr_base + off, val); } \ | |
29 | static inline u16 read_##mmr(struct bfin_spi_slave *bss) { return bfin_read16(bss->mmr_base + off); } | |
30 | MAKE_SPI_FUNC(SPI_CTL, 0x00) | |
31 | MAKE_SPI_FUNC(SPI_FLG, 0x04) | |
32 | MAKE_SPI_FUNC(SPI_STAT, 0x08) | |
33 | MAKE_SPI_FUNC(SPI_TDBR, 0x0c) | |
34 | MAKE_SPI_FUNC(SPI_RDBR, 0x10) | |
35 | MAKE_SPI_FUNC(SPI_BAUD, 0x14) | |
36 | ||
37 | #define to_bfin_spi_slave(s) container_of(s, struct bfin_spi_slave, slave) | |
38 | ||
37a4b75d MF |
39 | #define gpio_cs(cs) ((cs) - MAX_CTRL_CS) |
40 | #ifdef CONFIG_BFIN_SPI_GPIO_CS | |
41 | # define is_gpio_cs(cs) ((cs) > MAX_CTRL_CS) | |
42 | #else | |
43 | # define is_gpio_cs(cs) 0 | |
44 | #endif | |
45 | ||
400f5778 MF |
46 | int spi_cs_is_valid(unsigned int bus, unsigned int cs) |
47 | { | |
37a4b75d MF |
48 | if (is_gpio_cs(cs)) |
49 | return gpio_is_valid(gpio_cs(cs)); | |
50 | else | |
51 | return (cs >= 1 && cs <= MAX_CTRL_CS); | |
400f5778 MF |
52 | } |
53 | ||
400f5778 MF |
54 | void spi_cs_activate(struct spi_slave *slave) |
55 | { | |
56 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
37a4b75d MF |
57 | |
58 | if (is_gpio_cs(slave->cs)) { | |
59 | unsigned int cs = gpio_cs(slave->cs); | |
60 | gpio_set_value(cs, bss->flg); | |
61 | debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs)); | |
62 | } else { | |
63 | write_SPI_FLG(bss, | |
64 | (read_SPI_FLG(bss) & | |
65 | ~((!bss->flg << 8) << slave->cs)) | | |
66 | (1 << slave->cs)); | |
67 | debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss)); | |
68 | } | |
69 | ||
d04371a1 | 70 | SSYNC(); |
400f5778 MF |
71 | } |
72 | ||
400f5778 MF |
73 | void spi_cs_deactivate(struct spi_slave *slave) |
74 | { | |
75 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
d04371a1 | 76 | |
37a4b75d MF |
77 | if (is_gpio_cs(slave->cs)) { |
78 | unsigned int cs = gpio_cs(slave->cs); | |
79 | gpio_set_value(cs, !bss->flg); | |
80 | debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs)); | |
81 | } else { | |
82 | u16 flg; | |
83 | ||
84 | /* make sure we force the cs to deassert rather than let the | |
85 | * pin float back up. otherwise, exact timings may not be | |
86 | * met some of the time leading to random behavior (ugh). | |
87 | */ | |
88 | flg = read_SPI_FLG(bss) | ((!bss->flg << 8) << slave->cs); | |
89 | write_SPI_FLG(bss, flg); | |
90 | SSYNC(); | |
91 | debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss)); | |
92 | ||
93 | flg &= ~(1 << slave->cs); | |
94 | write_SPI_FLG(bss, flg); | |
95 | debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss)); | |
96 | } | |
97 | ||
d04371a1 | 98 | SSYNC(); |
400f5778 MF |
99 | } |
100 | ||
101 | void spi_init() | |
102 | { | |
103 | } | |
104 | ||
f3732edf MF |
105 | #ifdef SPI_CTL |
106 | # define SPI0_CTL SPI_CTL | |
107 | #endif | |
108 | ||
109 | #define SPI_PINS(n) \ | |
110 | [n] = { 0, P_SPI##n##_SCK, P_SPI##n##_MISO, P_SPI##n##_MOSI, 0 } | |
111 | static unsigned short pins[][5] = { | |
112 | #ifdef SPI0_CTL | |
113 | SPI_PINS(0), | |
114 | #endif | |
115 | #ifdef SPI1_CTL | |
116 | SPI_PINS(1), | |
117 | #endif | |
118 | #ifdef SPI2_CTL | |
119 | SPI_PINS(2), | |
120 | #endif | |
121 | }; | |
122 | ||
123 | #define SPI_CS_PINS(n) \ | |
124 | [n] = { \ | |
125 | P_SPI##n##_SSEL1, P_SPI##n##_SSEL2, P_SPI##n##_SSEL3, \ | |
126 | P_SPI##n##_SSEL4, P_SPI##n##_SSEL5, P_SPI##n##_SSEL6, \ | |
127 | P_SPI##n##_SSEL7, \ | |
128 | } | |
129 | static const unsigned short cs_pins[][7] = { | |
130 | #ifdef SPI0_CTL | |
131 | SPI_CS_PINS(0), | |
132 | #endif | |
133 | #ifdef SPI1_CTL | |
134 | SPI_CS_PINS(1), | |
135 | #endif | |
136 | #ifdef SPI2_CTL | |
137 | SPI_CS_PINS(2), | |
138 | #endif | |
139 | }; | |
140 | ||
400f5778 MF |
141 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, |
142 | unsigned int max_hz, unsigned int mode) | |
143 | { | |
144 | struct bfin_spi_slave *bss; | |
581d92ee | 145 | ulong sclk; |
400f5778 MF |
146 | u32 mmr_base; |
147 | u32 baud; | |
148 | ||
149 | if (!spi_cs_is_valid(bus, cs)) | |
150 | return NULL; | |
151 | ||
f3732edf MF |
152 | if (bus >= ARRAY_SIZE(pins) || pins[bus] == NULL) { |
153 | debug("%s: invalid bus %u\n", __func__, bus); | |
154 | return NULL; | |
155 | } | |
400f5778 | 156 | switch (bus) { |
f3732edf | 157 | #ifdef SPI0_CTL |
400f5778 | 158 | case 0: mmr_base = SPI0_CTL; break; |
f3732edf | 159 | #endif |
400f5778 MF |
160 | #ifdef SPI1_CTL |
161 | case 1: mmr_base = SPI1_CTL; break; | |
162 | #endif | |
163 | #ifdef SPI2_CTL | |
164 | case 2: mmr_base = SPI2_CTL; break; | |
165 | #endif | |
166 | default: return NULL; | |
167 | } | |
168 | ||
581d92ee CC |
169 | sclk = get_sclk(); |
170 | baud = sclk / (2 * max_hz); | |
171 | /* baud should be rounded up */ | |
172 | if (sclk % (2 * max_hz)) | |
173 | baud += 1; | |
400f5778 MF |
174 | if (baud < 2) |
175 | baud = 2; | |
176 | else if (baud > (u16)-1) | |
177 | baud = -1; | |
178 | ||
179 | bss = malloc(sizeof(*bss)); | |
180 | if (!bss) | |
181 | return NULL; | |
182 | ||
183 | bss->slave.bus = bus; | |
184 | bss->slave.cs = cs; | |
185 | bss->mmr_base = (void *)mmr_base; | |
186 | bss->ctl = SPE | MSTR | TDBR_CORE; | |
187 | if (mode & SPI_CPHA) bss->ctl |= CPHA; | |
188 | if (mode & SPI_CPOL) bss->ctl |= CPOL; | |
189 | if (mode & SPI_LSB_FIRST) bss->ctl |= LSBF; | |
190 | bss->baud = baud; | |
191 | bss->flg = mode & SPI_CS_HIGH ? 1 : 0; | |
192 | ||
193 | debug("%s: bus:%i cs:%i mmr:%x ctl:%x baud:%i flg:%i\n", __func__, | |
194 | bus, cs, mmr_base, bss->ctl, baud, bss->flg); | |
195 | ||
196 | return &bss->slave; | |
197 | } | |
198 | ||
199 | void spi_free_slave(struct spi_slave *slave) | |
200 | { | |
201 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
202 | free(bss); | |
203 | } | |
204 | ||
400f5778 MF |
205 | int spi_claim_bus(struct spi_slave *slave) |
206 | { | |
207 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
208 | ||
209 | debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); | |
210 | ||
37a4b75d MF |
211 | if (is_gpio_cs(slave->cs)) { |
212 | unsigned int cs = gpio_cs(slave->cs); | |
213 | gpio_request(cs, "bfin-spi"); | |
214 | gpio_direction_output(cs, !bss->flg); | |
215 | pins[slave->bus][0] = P_DONTCARE; | |
216 | } else | |
217 | pins[slave->bus][0] = cs_pins[slave->bus][slave->cs - 1]; | |
f3732edf MF |
218 | peripheral_request_list(pins[slave->bus], "bfin-spi"); |
219 | ||
400f5778 MF |
220 | write_SPI_CTL(bss, bss->ctl); |
221 | write_SPI_BAUD(bss, bss->baud); | |
222 | SSYNC(); | |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
227 | void spi_release_bus(struct spi_slave *slave) | |
228 | { | |
229 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
f3732edf | 230 | |
400f5778 | 231 | debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); |
f3732edf MF |
232 | |
233 | peripheral_free_list(pins[slave->bus]); | |
37a4b75d MF |
234 | if (is_gpio_cs(slave->cs)) |
235 | gpio_free(gpio_cs(slave->cs)); | |
f3732edf | 236 | |
400f5778 MF |
237 | write_SPI_CTL(bss, 0); |
238 | SSYNC(); | |
239 | } | |
240 | ||
6f070e18 MF |
241 | #ifdef __ADSPBF54x__ |
242 | # define SPI_DMA_BASE DMA4_NEXT_DESC_PTR | |
243 | #elif defined(__ADSPBF533__) || defined(__ADSPBF532__) || defined(__ADSPBF531__) || \ | |
244 | defined(__ADSPBF538__) || defined(__ADSPBF539__) | |
245 | # define SPI_DMA_BASE DMA5_NEXT_DESC_PTR | |
246 | #elif defined(__ADSPBF561__) | |
247 | # define SPI_DMA_BASE DMA2_4_NEXT_DESC_PTR | |
248 | #elif defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__) || \ | |
249 | defined(__ADSPBF52x__) || defined(__ADSPBF51x__) | |
250 | # define SPI_DMA_BASE DMA7_NEXT_DESC_PTR | |
cca07417 MF |
251 | # elif defined(__ADSPBF50x__) |
252 | # define SPI_DMA_BASE DMA6_NEXT_DESC_PTR | |
6f070e18 MF |
253 | #else |
254 | # error "Please provide SPI DMA channel defines" | |
255 | #endif | |
256 | static volatile struct dma_register *dma = (void *)SPI_DMA_BASE; | |
257 | ||
17ebd5bf CC |
258 | #ifndef CONFIG_BFIN_SPI_IDLE_VAL |
259 | # define CONFIG_BFIN_SPI_IDLE_VAL 0xff | |
260 | #endif | |
261 | ||
6f070e18 MF |
262 | #ifdef CONFIG_BFIN_SPI_NO_DMA |
263 | # define SPI_DMA 0 | |
264 | #else | |
265 | # define SPI_DMA 1 | |
266 | #endif | |
267 | ||
268 | static int spi_dma_xfer(struct bfin_spi_slave *bss, const u8 *tx, u8 *rx, | |
269 | uint bytes) | |
270 | { | |
271 | int ret = -1; | |
272 | u16 ndsize, spi_config, dma_config; | |
273 | struct dmasg dmasg[2]; | |
274 | const u8 *buf; | |
275 | ||
276 | if (tx) { | |
277 | debug("%s: doing half duplex TX\n", __func__); | |
278 | buf = tx; | |
279 | spi_config = TDBR_DMA; | |
280 | dma_config = 0; | |
281 | } else { | |
282 | debug("%s: doing half duplex RX\n", __func__); | |
283 | buf = rx; | |
284 | spi_config = RDBR_DMA; | |
285 | dma_config = WNR; | |
286 | } | |
287 | ||
288 | dmasg[0].start_addr = (unsigned long)buf; | |
289 | dmasg[0].x_modify = 1; | |
290 | dma_config |= WDSIZE_8 | DMAEN; | |
291 | if (bytes <= 65536) { | |
292 | blackfin_dcache_flush_invalidate_range(buf, buf + bytes); | |
293 | ndsize = NDSIZE_5; | |
294 | dmasg[0].cfg = NDSIZE_0 | dma_config | FLOW_STOP | DI_EN; | |
295 | dmasg[0].x_count = bytes; | |
296 | } else { | |
297 | blackfin_dcache_flush_invalidate_range(buf, buf + 65536 - 1); | |
298 | ndsize = NDSIZE_7; | |
299 | dmasg[0].cfg = NDSIZE_5 | dma_config | FLOW_ARRAY | DMA2D; | |
300 | dmasg[0].x_count = 0; /* 2^16 */ | |
301 | dmasg[0].y_count = bytes >> 16; /* count / 2^16 */ | |
302 | dmasg[0].y_modify = 1; | |
303 | dmasg[1].start_addr = (unsigned long)(buf + (bytes & ~0xFFFF)); | |
304 | dmasg[1].cfg = NDSIZE_0 | dma_config | FLOW_STOP | DI_EN; | |
305 | dmasg[1].x_count = bytes & 0xFFFF; /* count % 2^16 */ | |
306 | dmasg[1].x_modify = 1; | |
307 | } | |
308 | ||
309 | dma->cfg = 0; | |
310 | dma->irq_status = DMA_DONE | DMA_ERR; | |
311 | dma->curr_desc_ptr = dmasg; | |
312 | write_SPI_CTL(bss, (bss->ctl & ~TDBR_CORE)); | |
313 | write_SPI_STAT(bss, -1); | |
314 | SSYNC(); | |
315 | ||
316 | write_SPI_TDBR(bss, CONFIG_BFIN_SPI_IDLE_VAL); | |
317 | dma->cfg = ndsize | FLOW_ARRAY | DMAEN; | |
318 | write_SPI_CTL(bss, (bss->ctl & ~TDBR_CORE) | spi_config); | |
319 | SSYNC(); | |
320 | ||
321 | /* | |
322 | * We already invalidated the first 64k, | |
323 | * now while we just wait invalidate the remaining part. | |
324 | * Its not likely that the DMA is going to overtake | |
325 | */ | |
326 | if (bytes > 65536) | |
327 | blackfin_dcache_flush_invalidate_range(buf + 65536, buf + bytes); | |
328 | ||
329 | while (!(dma->irq_status & DMA_DONE)) | |
330 | if (ctrlc()) | |
331 | goto done; | |
332 | ||
333 | dma->cfg = 0; | |
334 | ||
335 | ret = 0; | |
336 | done: | |
337 | write_SPI_CTL(bss, bss->ctl); | |
338 | return ret; | |
339 | } | |
340 | ||
341 | static int spi_pio_xfer(struct bfin_spi_slave *bss, const u8 *tx, u8 *rx, | |
342 | uint bytes) | |
343 | { | |
344 | /* todo: take advantage of hardware fifos */ | |
345 | while (bytes--) { | |
346 | u8 value = (tx ? *tx++ : CONFIG_BFIN_SPI_IDLE_VAL); | |
347 | debug("%s: tx:%x ", __func__, value); | |
348 | write_SPI_TDBR(bss, value); | |
349 | SSYNC(); | |
350 | while ((read_SPI_STAT(bss) & TXS)) | |
351 | if (ctrlc()) | |
352 | return -1; | |
353 | while (!(read_SPI_STAT(bss) & SPIF)) | |
354 | if (ctrlc()) | |
355 | return -1; | |
356 | while (!(read_SPI_STAT(bss) & RXS)) | |
357 | if (ctrlc()) | |
358 | return -1; | |
359 | value = read_SPI_RDBR(bss); | |
360 | if (rx) | |
361 | *rx++ = value; | |
362 | debug("rx:%x\n", value); | |
363 | } | |
364 | ||
365 | return 0; | |
366 | } | |
367 | ||
400f5778 MF |
368 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, |
369 | void *din, unsigned long flags) | |
370 | { | |
371 | struct bfin_spi_slave *bss = to_bfin_spi_slave(slave); | |
372 | const u8 *tx = dout; | |
373 | u8 *rx = din; | |
374 | uint bytes = bitlen / 8; | |
375 | int ret = 0; | |
376 | ||
377 | debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__, | |
378 | slave->bus, slave->cs, bitlen, bytes, flags); | |
379 | ||
380 | if (bitlen == 0) | |
381 | goto done; | |
382 | ||
383 | /* we can only do 8 bit transfers */ | |
384 | if (bitlen % 8) { | |
385 | flags |= SPI_XFER_END; | |
386 | goto done; | |
387 | } | |
388 | ||
389 | if (flags & SPI_XFER_BEGIN) | |
390 | spi_cs_activate(slave); | |
391 | ||
6f070e18 MF |
392 | /* TX DMA doesn't work quite right */ |
393 | if (SPI_DMA && bytes > 6 && (!tx /*|| !rx*/)) | |
394 | ret = spi_dma_xfer(bss, tx, rx, bytes); | |
395 | else | |
396 | ret = spi_pio_xfer(bss, tx, rx, bytes); | |
400f5778 MF |
397 | |
398 | done: | |
399 | if (flags & SPI_XFER_END) | |
400 | spi_cs_deactivate(slave); | |
401 | ||
402 | return ret; | |
403 | } |