]>
Commit | Line | Data |
---|---|---|
8ed58856 SN |
1 | /* |
2 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | |
3 | * | |
4 | * Driver for SPI controller on DaVinci. Based on atmel_spi.c | |
5 | * by Atmel Corporation | |
6 | * | |
7 | * Copyright (C) 2007 Atmel Corporation | |
8 | * | |
1a459660 | 9 | * SPDX-License-Identifier: GPL-2.0+ |
8ed58856 | 10 | */ |
ff6e31d3 | 11 | |
8ed58856 SN |
12 | #include <common.h> |
13 | #include <spi.h> | |
14 | #include <malloc.h> | |
15 | #include <asm/io.h> | |
16 | #include <asm/arch/hardware.h> | |
192bb756 | 17 | #include <dm.h> |
e6d2fbf7 | 18 | |
e6d2fbf7 JT |
19 | /* SPIGCR0 */ |
20 | #define SPIGCR0_SPIENA_MASK 0x1 | |
21 | #define SPIGCR0_SPIRST_MASK 0x0 | |
22 | ||
23 | /* SPIGCR0 */ | |
24 | #define SPIGCR1_CLKMOD_MASK BIT(1) | |
25 | #define SPIGCR1_MASTER_MASK BIT(0) | |
26 | #define SPIGCR1_SPIENA_MASK BIT(24) | |
27 | ||
28 | /* SPIPC0 */ | |
29 | #define SPIPC0_DIFUN_MASK BIT(11) /* SIMO */ | |
30 | #define SPIPC0_DOFUN_MASK BIT(10) /* SOMI */ | |
31 | #define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */ | |
32 | #define SPIPC0_EN0FUN_MASK BIT(0) | |
33 | ||
34 | /* SPIFMT0 */ | |
35 | #define SPIFMT_SHIFTDIR_SHIFT 20 | |
36 | #define SPIFMT_POLARITY_SHIFT 17 | |
37 | #define SPIFMT_PHASE_SHIFT 16 | |
38 | #define SPIFMT_PRESCALE_SHIFT 8 | |
39 | ||
40 | /* SPIDAT1 */ | |
41 | #define SPIDAT1_CSHOLD_SHIFT 28 | |
42 | #define SPIDAT1_CSNR_SHIFT 16 | |
43 | ||
44 | /* SPIDELAY */ | |
45 | #define SPI_C2TDELAY_SHIFT 24 | |
46 | #define SPI_T2CDELAY_SHIFT 16 | |
47 | ||
48 | /* SPIBUF */ | |
49 | #define SPIBUF_RXEMPTY_MASK BIT(31) | |
50 | #define SPIBUF_TXFULL_MASK BIT(29) | |
51 | ||
52 | /* SPIDEF */ | |
53 | #define SPIDEF_CSDEF0_MASK BIT(0) | |
54 | ||
192bb756 | 55 | #ifndef CONFIG_DM_SPI |
e6d2fbf7 JT |
56 | #define SPI0_BUS 0 |
57 | #define SPI0_BASE CONFIG_SYS_SPI_BASE | |
58 | /* | |
59 | * Define default SPI0_NUM_CS as 1 for existing platforms that uses this | |
60 | * driver. Platform can configure number of CS using CONFIG_SYS_SPI0_NUM_CS | |
61 | * if more than one CS is supported and by defining CONFIG_SYS_SPI0. | |
62 | */ | |
63 | #ifndef CONFIG_SYS_SPI0 | |
64 | #define SPI0_NUM_CS 1 | |
65 | #else | |
66 | #define SPI0_NUM_CS CONFIG_SYS_SPI0_NUM_CS | |
67 | #endif | |
68 | ||
69 | /* | |
70 | * define CONFIG_SYS_SPI1 when platform has spi-1 device (bus #1) and | |
71 | * CONFIG_SYS_SPI1_NUM_CS defines number of CS on this bus | |
72 | */ | |
73 | #ifdef CONFIG_SYS_SPI1 | |
74 | #define SPI1_BUS 1 | |
75 | #define SPI1_NUM_CS CONFIG_SYS_SPI1_NUM_CS | |
76 | #define SPI1_BASE CONFIG_SYS_SPI1_BASE | |
77 | #endif | |
78 | ||
79 | /* | |
80 | * define CONFIG_SYS_SPI2 when platform has spi-2 device (bus #2) and | |
81 | * CONFIG_SYS_SPI2_NUM_CS defines number of CS on this bus | |
82 | */ | |
83 | #ifdef CONFIG_SYS_SPI2 | |
84 | #define SPI2_BUS 2 | |
85 | #define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS | |
86 | #define SPI2_BASE CONFIG_SYS_SPI2_BASE | |
87 | #endif | |
192bb756 V |
88 | #endif |
89 | ||
90 | DECLARE_GLOBAL_DATA_PTR; | |
e6d2fbf7 | 91 | |
ff6e31d3 JT |
92 | /* davinci spi register set */ |
93 | struct davinci_spi_regs { | |
94 | dv_reg gcr0; /* 0x00 */ | |
95 | dv_reg gcr1; /* 0x04 */ | |
96 | dv_reg int0; /* 0x08 */ | |
97 | dv_reg lvl; /* 0x0c */ | |
98 | dv_reg flg; /* 0x10 */ | |
99 | dv_reg pc0; /* 0x14 */ | |
100 | dv_reg pc1; /* 0x18 */ | |
101 | dv_reg pc2; /* 0x1c */ | |
102 | dv_reg pc3; /* 0x20 */ | |
103 | dv_reg pc4; /* 0x24 */ | |
104 | dv_reg pc5; /* 0x28 */ | |
105 | dv_reg rsvd[3]; | |
106 | dv_reg dat0; /* 0x38 */ | |
107 | dv_reg dat1; /* 0x3c */ | |
108 | dv_reg buf; /* 0x40 */ | |
109 | dv_reg emu; /* 0x44 */ | |
110 | dv_reg delay; /* 0x48 */ | |
111 | dv_reg def; /* 0x4c */ | |
112 | dv_reg fmt0; /* 0x50 */ | |
113 | dv_reg fmt1; /* 0x54 */ | |
114 | dv_reg fmt2; /* 0x58 */ | |
115 | dv_reg fmt3; /* 0x5c */ | |
116 | dv_reg intvec0; /* 0x60 */ | |
117 | dv_reg intvec1; /* 0x64 */ | |
118 | }; | |
119 | ||
120 | /* davinci spi slave */ | |
e6d2fbf7 | 121 | struct davinci_spi_slave { |
192bb756 | 122 | #ifndef CONFIG_DM_SPI |
e6d2fbf7 | 123 | struct spi_slave slave; |
192bb756 | 124 | #endif |
e6d2fbf7 | 125 | struct davinci_spi_regs *regs; |
192bb756 V |
126 | unsigned int freq; /* current SPI bus frequency */ |
127 | unsigned int mode; /* current SPI mode used */ | |
128 | u8 num_cs; /* total no. of CS available */ | |
129 | u8 cur_cs; /* CS of current slave */ | |
130 | bool half_duplex; /* true, if master is half-duplex only */ | |
e6d2fbf7 JT |
131 | }; |
132 | ||
77436d66 NT |
133 | /* |
134 | * This functions needs to act like a macro to avoid pipeline reloads in the | |
135 | * loops below. Use always_inline. This gains us about 160KiB/s and the bloat | |
136 | * appears to be zero bytes (da830). | |
137 | */ | |
138 | __attribute__((always_inline)) | |
139 | static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data) | |
140 | { | |
141 | u32 buf_reg_val; | |
142 | ||
143 | /* send out data */ | |
144 | writel(data, &ds->regs->dat1); | |
145 | ||
146 | /* wait for the data to clock in/out */ | |
147 | while ((buf_reg_val = readl(&ds->regs->buf)) & SPIBUF_RXEMPTY_MASK) | |
148 | ; | |
149 | ||
150 | return buf_reg_val; | |
151 | } | |
152 | ||
192bb756 | 153 | static int davinci_spi_read(struct davinci_spi_slave *ds, unsigned int len, |
77436d66 NT |
154 | u8 *rxp, unsigned long flags) |
155 | { | |
77436d66 NT |
156 | unsigned int data1_reg_val; |
157 | ||
158 | /* enable CS hold, CS[n] and clear the data bits */ | |
159 | data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | | |
192bb756 | 160 | (ds->cur_cs << SPIDAT1_CSNR_SHIFT)); |
77436d66 NT |
161 | |
162 | /* wait till TXFULL is deasserted */ | |
163 | while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) | |
164 | ; | |
165 | ||
166 | /* preload the TX buffer to avoid clock starvation */ | |
167 | writel(data1_reg_val, &ds->regs->dat1); | |
168 | ||
169 | /* keep reading 1 byte until only 1 byte left */ | |
170 | while ((len--) > 1) | |
171 | *rxp++ = davinci_spi_xfer_data(ds, data1_reg_val); | |
172 | ||
173 | /* clear CS hold when we reach the end */ | |
174 | if (flags & SPI_XFER_END) | |
175 | data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT); | |
176 | ||
177 | /* read the last byte */ | |
178 | *rxp = davinci_spi_xfer_data(ds, data1_reg_val); | |
179 | ||
180 | return 0; | |
181 | } | |
182 | ||
192bb756 | 183 | static int davinci_spi_write(struct davinci_spi_slave *ds, unsigned int len, |
dce6538f | 184 | const u8 *txp, unsigned long flags) |
77436d66 | 185 | { |
77436d66 NT |
186 | unsigned int data1_reg_val; |
187 | ||
188 | /* enable CS hold and clear the data bits */ | |
189 | data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | | |
192bb756 | 190 | (ds->cur_cs << SPIDAT1_CSNR_SHIFT)); |
77436d66 NT |
191 | |
192 | /* wait till TXFULL is deasserted */ | |
193 | while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) | |
194 | ; | |
195 | ||
196 | /* preload the TX buffer to avoid clock starvation */ | |
197 | if (len > 2) { | |
198 | writel(data1_reg_val | *txp++, &ds->regs->dat1); | |
199 | len--; | |
200 | } | |
201 | ||
202 | /* keep writing 1 byte until only 1 byte left */ | |
203 | while ((len--) > 1) | |
204 | davinci_spi_xfer_data(ds, data1_reg_val | *txp++); | |
205 | ||
206 | /* clear CS hold when we reach the end */ | |
207 | if (flags & SPI_XFER_END) | |
208 | data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT); | |
209 | ||
210 | /* write the last byte */ | |
211 | davinci_spi_xfer_data(ds, data1_reg_val | *txp); | |
212 | ||
213 | return 0; | |
214 | } | |
215 | ||
192bb756 V |
216 | static int davinci_spi_read_write(struct davinci_spi_slave *ds, unsigned |
217 | int len, u8 *rxp, const u8 *txp, | |
218 | unsigned long flags) | |
77436d66 | 219 | { |
77436d66 NT |
220 | unsigned int data1_reg_val; |
221 | ||
222 | /* enable CS hold and clear the data bits */ | |
223 | data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | | |
192bb756 | 224 | (ds->cur_cs << SPIDAT1_CSNR_SHIFT)); |
77436d66 NT |
225 | |
226 | /* wait till TXFULL is deasserted */ | |
227 | while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) | |
228 | ; | |
229 | ||
230 | /* keep reading and writing 1 byte until only 1 byte left */ | |
231 | while ((len--) > 1) | |
232 | *rxp++ = davinci_spi_xfer_data(ds, data1_reg_val | *txp++); | |
233 | ||
234 | /* clear CS hold when we reach the end */ | |
235 | if (flags & SPI_XFER_END) | |
236 | data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT); | |
237 | ||
238 | /* read and write the last byte */ | |
239 | *rxp = davinci_spi_xfer_data(ds, data1_reg_val | *txp); | |
240 | ||
241 | return 0; | |
242 | } | |
192bb756 V |
243 | |
244 | ||
245 | static int __davinci_spi_claim_bus(struct davinci_spi_slave *ds, int cs) | |
246 | { | |
247 | unsigned int mode = 0, scalar; | |
248 | ||
249 | /* Enable the SPI hardware */ | |
250 | writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); | |
251 | udelay(1000); | |
252 | writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); | |
253 | ||
254 | /* Set master mode, powered up and not activated */ | |
255 | writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); | |
256 | ||
257 | /* CS, CLK, SIMO and SOMI are functional pins */ | |
258 | writel(((1 << cs) | SPIPC0_CLKFUN_MASK | | |
259 | SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); | |
260 | ||
261 | /* setup format */ | |
262 | scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; | |
263 | ||
264 | /* | |
265 | * Use following format: | |
266 | * character length = 8, | |
267 | * MSB shifted out first | |
268 | */ | |
269 | if (ds->mode & SPI_CPOL) | |
270 | mode |= SPI_CPOL; | |
271 | if (!(ds->mode & SPI_CPHA)) | |
272 | mode |= SPI_CPHA; | |
273 | writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | | |
274 | (mode << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); | |
275 | ||
276 | /* | |
277 | * Including a minor delay. No science here. Should be good even with | |
278 | * no delay | |
279 | */ | |
280 | writel((50 << SPI_C2TDELAY_SHIFT) | | |
281 | (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); | |
282 | ||
283 | /* default chip select register */ | |
284 | writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); | |
285 | ||
286 | /* no interrupts */ | |
287 | writel(0, &ds->regs->int0); | |
288 | writel(0, &ds->regs->lvl); | |
289 | ||
290 | /* enable SPI */ | |
291 | writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); | |
292 | ||
293 | return 0; | |
294 | } | |
295 | ||
296 | static int __davinci_spi_release_bus(struct davinci_spi_slave *ds) | |
297 | { | |
298 | /* Disable the SPI hardware */ | |
299 | writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); | |
300 | ||
301 | return 0; | |
302 | } | |
303 | ||
304 | static int __davinci_spi_xfer(struct davinci_spi_slave *ds, | |
305 | unsigned int bitlen, const void *dout, void *din, | |
306 | unsigned long flags) | |
307 | { | |
308 | unsigned int len; | |
309 | ||
310 | if (bitlen == 0) | |
311 | /* Finish any previously submitted transfers */ | |
312 | goto out; | |
313 | ||
314 | /* | |
315 | * It's not clear how non-8-bit-aligned transfers are supposed to be | |
316 | * represented as a stream of bytes...this is a limitation of | |
317 | * the current SPI interface - here we terminate on receiving such a | |
318 | * transfer request. | |
319 | */ | |
320 | if (bitlen % 8) { | |
321 | /* Errors always terminate an ongoing transfer */ | |
322 | flags |= SPI_XFER_END; | |
323 | goto out; | |
324 | } | |
325 | ||
326 | len = bitlen / 8; | |
327 | ||
328 | if (!dout) | |
329 | return davinci_spi_read(ds, len, din, flags); | |
330 | if (!din) | |
331 | return davinci_spi_write(ds, len, dout, flags); | |
332 | if (!ds->half_duplex) | |
333 | return davinci_spi_read_write(ds, len, din, dout, flags); | |
334 | ||
335 | printf("SPI full duplex not supported\n"); | |
336 | flags |= SPI_XFER_END; | |
337 | ||
338 | out: | |
339 | if (flags & SPI_XFER_END) { | |
340 | u8 dummy = 0; | |
341 | davinci_spi_write(ds, 1, &dummy, flags); | |
342 | } | |
343 | return 0; | |
344 | } | |
345 | ||
346 | #ifndef CONFIG_DM_SPI | |
347 | ||
348 | static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) | |
349 | { | |
350 | return container_of(slave, struct davinci_spi_slave, slave); | |
351 | } | |
77436d66 | 352 | |
ff6e31d3 JT |
353 | int spi_cs_is_valid(unsigned int bus, unsigned int cs) |
354 | { | |
355 | int ret = 0; | |
356 | ||
357 | switch (bus) { | |
358 | case SPI0_BUS: | |
359 | if (cs < SPI0_NUM_CS) | |
360 | ret = 1; | |
361 | break; | |
362 | #ifdef CONFIG_SYS_SPI1 | |
363 | case SPI1_BUS: | |
364 | if (cs < SPI1_NUM_CS) | |
365 | ret = 1; | |
366 | break; | |
367 | #endif | |
368 | #ifdef CONFIG_SYS_SPI2 | |
369 | case SPI2_BUS: | |
370 | if (cs < SPI2_NUM_CS) | |
371 | ret = 1; | |
372 | break; | |
373 | #endif | |
374 | default: | |
375 | /* Invalid bus number. Do nothing */ | |
376 | break; | |
377 | } | |
378 | return ret; | |
379 | } | |
380 | ||
381 | void spi_cs_activate(struct spi_slave *slave) | |
382 | { | |
383 | /* do nothing */ | |
384 | } | |
385 | ||
386 | void spi_cs_deactivate(struct spi_slave *slave) | |
387 | { | |
388 | /* do nothing */ | |
389 | } | |
390 | ||
391 | void spi_init(void) | |
392 | { | |
393 | /* do nothing */ | |
394 | } | |
395 | ||
396 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
397 | unsigned int max_hz, unsigned int mode) | |
398 | { | |
399 | struct davinci_spi_slave *ds; | |
400 | ||
401 | if (!spi_cs_is_valid(bus, cs)) | |
402 | return NULL; | |
403 | ||
404 | ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs); | |
405 | if (!ds) | |
406 | return NULL; | |
407 | ||
408 | switch (bus) { | |
409 | case SPI0_BUS: | |
410 | ds->regs = (struct davinci_spi_regs *)SPI0_BASE; | |
411 | break; | |
412 | #ifdef CONFIG_SYS_SPI1 | |
413 | case SPI1_BUS: | |
414 | ds->regs = (struct davinci_spi_regs *)SPI1_BASE; | |
415 | break; | |
416 | #endif | |
417 | #ifdef CONFIG_SYS_SPI2 | |
418 | case SPI2_BUS: | |
419 | ds->regs = (struct davinci_spi_regs *)SPI2_BASE; | |
420 | break; | |
421 | #endif | |
422 | default: /* Invalid bus number */ | |
423 | return NULL; | |
424 | } | |
425 | ||
426 | ds->freq = max_hz; | |
192bb756 | 427 | ds->mode = mode; |
ff6e31d3 JT |
428 | |
429 | return &ds->slave; | |
430 | } | |
431 | ||
432 | void spi_free_slave(struct spi_slave *slave) | |
433 | { | |
434 | struct davinci_spi_slave *ds = to_davinci_spi(slave); | |
435 | ||
436 | free(ds); | |
437 | } | |
438 | ||
192bb756 V |
439 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, |
440 | const void *dout, void *din, unsigned long flags) | |
441 | { | |
442 | struct davinci_spi_slave *ds = to_davinci_spi(slave); | |
443 | ||
444 | ds->cur_cs = slave->cs; | |
445 | ||
446 | return __davinci_spi_xfer(ds, bitlen, dout, din, flags); | |
447 | } | |
448 | ||
ff6e31d3 JT |
449 | int spi_claim_bus(struct spi_slave *slave) |
450 | { | |
451 | struct davinci_spi_slave *ds = to_davinci_spi(slave); | |
ff6e31d3 | 452 | |
192bb756 V |
453 | #ifdef CONFIG_SPI_HALF_DUPLEX |
454 | ds->half_duplex = true; | |
455 | #else | |
456 | ds->half_duplex = false; | |
457 | #endif | |
458 | return __davinci_spi_claim_bus(ds, ds->slave.cs); | |
459 | } | |
ff6e31d3 | 460 | |
192bb756 V |
461 | void spi_release_bus(struct spi_slave *slave) |
462 | { | |
463 | struct davinci_spi_slave *ds = to_davinci_spi(slave); | |
ff6e31d3 | 464 | |
192bb756 V |
465 | __davinci_spi_release_bus(ds); |
466 | } | |
ff6e31d3 | 467 | |
192bb756 V |
468 | #else |
469 | static int davinci_spi_set_speed(struct udevice *bus, uint max_hz) | |
470 | { | |
471 | struct davinci_spi_slave *ds = dev_get_priv(bus); | |
ff6e31d3 | 472 | |
192bb756 V |
473 | debug("%s speed %u\n", __func__, max_hz); |
474 | if (max_hz > CONFIG_SYS_SPI_CLK / 2) | |
475 | return -EINVAL; | |
ff6e31d3 | 476 | |
192bb756 | 477 | ds->freq = max_hz; |
ff6e31d3 | 478 | |
192bb756 V |
479 | return 0; |
480 | } | |
ff6e31d3 | 481 | |
192bb756 V |
482 | static int davinci_spi_set_mode(struct udevice *bus, uint mode) |
483 | { | |
484 | struct davinci_spi_slave *ds = dev_get_priv(bus); | |
ff6e31d3 | 485 | |
192bb756 V |
486 | debug("%s mode %u\n", __func__, mode); |
487 | ds->mode = mode; | |
ff6e31d3 JT |
488 | |
489 | return 0; | |
490 | } | |
491 | ||
192bb756 | 492 | static int davinci_spi_claim_bus(struct udevice *dev) |
ff6e31d3 | 493 | { |
192bb756 V |
494 | struct dm_spi_slave_platdata *slave_plat = |
495 | dev_get_parent_platdata(dev); | |
496 | struct udevice *bus = dev->parent; | |
497 | struct davinci_spi_slave *ds = dev_get_priv(bus); | |
498 | ||
499 | if (slave_plat->cs >= ds->num_cs) { | |
500 | printf("Invalid SPI chipselect\n"); | |
501 | return -EINVAL; | |
502 | } | |
503 | ds->half_duplex = slave_plat->mode & SPI_PREAMBLE; | |
ff6e31d3 | 504 | |
192bb756 | 505 | return __davinci_spi_claim_bus(ds, slave_plat->cs); |
ff6e31d3 JT |
506 | } |
507 | ||
192bb756 | 508 | static int davinci_spi_release_bus(struct udevice *dev) |
8ed58856 | 509 | { |
192bb756 | 510 | struct davinci_spi_slave *ds = dev_get_priv(dev->parent); |
8ed58856 | 511 | |
192bb756 V |
512 | return __davinci_spi_release_bus(ds); |
513 | } | |
8ed58856 | 514 | |
192bb756 V |
515 | static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen, |
516 | const void *dout, void *din, | |
517 | unsigned long flags) | |
518 | { | |
519 | struct dm_spi_slave_platdata *slave = | |
520 | dev_get_parent_platdata(dev); | |
521 | struct udevice *bus = dev->parent; | |
522 | struct davinci_spi_slave *ds = dev_get_priv(bus); | |
523 | ||
524 | if (slave->cs >= ds->num_cs) { | |
525 | printf("Invalid SPI chipselect\n"); | |
526 | return -EINVAL; | |
8ed58856 | 527 | } |
192bb756 | 528 | ds->cur_cs = slave->cs; |
8ed58856 | 529 | |
192bb756 V |
530 | return __davinci_spi_xfer(ds, bitlen, dout, din, flags); |
531 | } | |
8ed58856 | 532 | |
192bb756 V |
533 | static int davinci_spi_probe(struct udevice *bus) |
534 | { | |
535 | /* Nothing to do */ | |
536 | return 0; | |
537 | } | |
8ed58856 | 538 | |
192bb756 V |
539 | static int davinci_ofdata_to_platadata(struct udevice *bus) |
540 | { | |
541 | struct davinci_spi_slave *ds = dev_get_priv(bus); | |
542 | const void *blob = gd->fdt_blob; | |
e160f7d4 | 543 | int node = dev_of_offset(bus); |
192bb756 V |
544 | |
545 | ds->regs = dev_map_physmem(bus, sizeof(struct davinci_spi_regs)); | |
546 | if (!ds->regs) { | |
547 | printf("%s: could not map device address\n", __func__); | |
548 | return -EINVAL; | |
8ed58856 | 549 | } |
192bb756 V |
550 | ds->num_cs = fdtdec_get_int(blob, node, "num-cs", 4); |
551 | ||
8ed58856 SN |
552 | return 0; |
553 | } | |
192bb756 V |
554 | |
555 | static const struct dm_spi_ops davinci_spi_ops = { | |
556 | .claim_bus = davinci_spi_claim_bus, | |
557 | .release_bus = davinci_spi_release_bus, | |
558 | .xfer = davinci_spi_xfer, | |
559 | .set_speed = davinci_spi_set_speed, | |
560 | .set_mode = davinci_spi_set_mode, | |
561 | }; | |
562 | ||
563 | static const struct udevice_id davinci_spi_ids[] = { | |
564 | { .compatible = "ti,keystone-spi" }, | |
565 | { .compatible = "ti,dm6441-spi" }, | |
566 | { } | |
567 | }; | |
568 | ||
569 | U_BOOT_DRIVER(davinci_spi) = { | |
570 | .name = "davinci_spi", | |
571 | .id = UCLASS_SPI, | |
572 | .of_match = davinci_spi_ids, | |
573 | .ops = &davinci_spi_ops, | |
574 | .ofdata_to_platdata = davinci_ofdata_to_platadata, | |
575 | .priv_auto_alloc_size = sizeof(struct davinci_spi_slave), | |
576 | .probe = davinci_spi_probe, | |
577 | }; | |
578 | #endif |