1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <common.h>
35#include <spi.h>
36#include <malloc.h>
37#include <asm/io.h>
38#include "omap3_spi.h"
39
40#define WORD_LEN 8
41#define SPI_WAIT_TIMEOUT 3000000;
42
43static void spi_reset(struct omap3_spi_slave *ds)
44{
45 unsigned int tmp;
46
47 writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &ds->regs->sysconfig);
48 do {
49 tmp = readl(&ds->regs->sysstatus);
50 } while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE));
51
52 writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
53 OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
54 OMAP3_MCSPI_SYSCONFIG_SMARTIDLE,
55 &ds->regs->sysconfig);
56
57 writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &ds->regs->wakeupenable);
58}
59
60static void omap3_spi_write_chconf(struct omap3_spi_slave *ds, int val)
61{
62 writel(val, &ds->regs->channel[ds->slave.cs].chconf);
63
64 readl(&ds->regs->channel[ds->slave.cs].chconf);
65}
66
67static void omap3_spi_set_enable(struct omap3_spi_slave *ds, int enable)
68{
69 writel(enable, &ds->regs->channel[ds->slave.cs].chctrl);
70
71 readl(&ds->regs->channel[ds->slave.cs].chctrl);
72}
73
74void spi_init()
75{
76
77}
78
79struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
80 unsigned int max_hz, unsigned int mode)
81{
82 struct omap3_spi_slave *ds;
83 struct mcspi *regs;
84
85
86
87
88
89
90
91
92
93
94 switch (bus) {
95 case 0:
96 regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
97 break;
98#ifdef OMAP3_MCSPI2_BASE
99 case 1:
100 regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
101 break;
102#endif
103#ifdef OMAP3_MCSPI3_BASE
104 case 2:
105 regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
106 break;
107#endif
108#ifdef OMAP3_MCSPI4_BASE
109 case 3:
110 regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
111 break;
112#endif
113 default:
114 printf("SPI error: unsupported bus %i. \
115 Supported busses 0 - 3\n", bus);
116 return NULL;
117 }
118
119 if (((bus == 0) && (cs > 3)) ||
120 ((bus == 1) && (cs > 1)) ||
121 ((bus == 2) && (cs > 1)) ||
122 ((bus == 3) && (cs > 0))) {
123 printf("SPI error: unsupported chip select %i \
124 on bus %i\n", cs, bus);
125 return NULL;
126 }
127
128 if (max_hz > OMAP3_MCSPI_MAX_FREQ) {
129 printf("SPI error: unsupported frequency %i Hz. \
130 Max frequency is 48 Mhz\n", max_hz);
131 return NULL;
132 }
133
134 if (mode > SPI_MODE_3) {
135 printf("SPI error: unsupported SPI mode %i\n", mode);
136 return NULL;
137 }
138
139 ds = spi_alloc_slave(struct omap3_spi_slave, bus, cs);
140 if (!ds) {
141 printf("SPI error: malloc of SPI structure failed\n");
142 return NULL;
143 }
144
145 ds->regs = regs;
146 ds->freq = max_hz;
147 ds->mode = mode;
148
149 return &ds->slave;
150}
151
152void spi_free_slave(struct spi_slave *slave)
153{
154 struct omap3_spi_slave *ds = to_omap3_spi(slave);
155
156 free(ds);
157}
158
159int spi_claim_bus(struct spi_slave *slave)
160{
161 struct omap3_spi_slave *ds = to_omap3_spi(slave);
162 unsigned int conf, div = 0;
163
164
165
166
167
168
169
170 spi_reset(ds);
171 conf = readl(&ds->regs->modulctrl);
172 conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
173 conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
174 writel(conf, &ds->regs->modulctrl);
175
176
177
178
179 if (ds->freq) {
180 while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
181 > ds->freq)
182 div++;
183 } else
184 div = 0xC;
185
186 conf = readl(&ds->regs->channel[ds->slave.cs].chconf);
187
188
189
190
191#ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED
192
193
194
195
196 conf &= ~OMAP3_MCSPI_CHCONF_DPE0;
197 conf |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1;
198#else
199 conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
200 conf |= OMAP3_MCSPI_CHCONF_DPE0;
201#endif
202
203
204 conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
205 conf |= (WORD_LEN - 1) << 7;
206
207
208 if (!(ds->mode & SPI_CS_HIGH))
209 conf |= OMAP3_MCSPI_CHCONF_EPOL;
210 else
211 conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
212
213
214 conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
215 conf |= div << 2;
216
217
218 if (ds->mode & SPI_CPOL)
219 conf |= OMAP3_MCSPI_CHCONF_POL;
220 else
221 conf &= ~OMAP3_MCSPI_CHCONF_POL;
222 if (ds->mode & SPI_CPHA)
223 conf |= OMAP3_MCSPI_CHCONF_PHA;
224 else
225 conf &= ~OMAP3_MCSPI_CHCONF_PHA;
226
227
228 conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
229
230 omap3_spi_write_chconf(ds,conf);
231
232 return 0;
233}
234
235void spi_release_bus(struct spi_slave *slave)
236{
237 struct omap3_spi_slave *ds = to_omap3_spi(slave);
238
239
240 spi_reset(ds);
241}
242
243int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
244 unsigned long flags)
245{
246 struct omap3_spi_slave *ds = to_omap3_spi(slave);
247 int i;
248 int timeout = SPI_WAIT_TIMEOUT;
249 int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
250
251
252 omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
253
254 chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
255 chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
256 chconf |= OMAP3_MCSPI_CHCONF_FORCE;
257 omap3_spi_write_chconf(ds,chconf);
258
259 for (i = 0; i < len; i++) {
260
261 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
262 OMAP3_MCSPI_CHSTAT_TXS)) {
263 if (--timeout <= 0) {
264 printf("SPI TXS timed out, status=0x%08x\n",
265 readl(&ds->regs->channel[ds->slave.cs].chstat));
266 return -1;
267 }
268 }
269
270 writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
271 }
272
273
274 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
275 OMAP3_MCSPI_CHSTAT_EOT));
276
277
278 omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
279
280 if (flags & SPI_XFER_END) {
281
282 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
283 omap3_spi_write_chconf(ds,chconf);
284 }
285 return 0;
286}
287
288int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
289 unsigned long flags)
290{
291 struct omap3_spi_slave *ds = to_omap3_spi(slave);
292 int i;
293 int timeout = SPI_WAIT_TIMEOUT;
294 int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
295
296
297 omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
298
299 chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
300 chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
301 chconf |= OMAP3_MCSPI_CHCONF_FORCE;
302 omap3_spi_write_chconf(ds,chconf);
303
304 writel(0, &ds->regs->channel[ds->slave.cs].tx);
305
306 for (i = 0; i < len; i++) {
307
308 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
309 OMAP3_MCSPI_CHSTAT_RXS)) {
310 if (--timeout <= 0) {
311 printf("SPI RXS timed out, status=0x%08x\n",
312 readl(&ds->regs->channel[ds->slave.cs].chstat));
313 return -1;
314 }
315 }
316
317
318 if(i == (len - 1))
319 omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
320
321
322 rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
323 }
324
325 if (flags & SPI_XFER_END) {
326 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
327 omap3_spi_write_chconf(ds,chconf);
328 }
329
330 return 0;
331}
332
333
334int omap3_spi_txrx(struct spi_slave *slave,
335 unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags)
336{
337 struct omap3_spi_slave *ds = to_omap3_spi(slave);
338 int timeout = SPI_WAIT_TIMEOUT;
339 int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
340 int irqstatus = readl(&ds->regs->irqstatus);
341 int i=0;
342
343
344 omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
345
346
347 chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
348 chconf |= OMAP3_MCSPI_CHCONF_FORCE;
349 omap3_spi_write_chconf(ds,chconf);
350
351
352 for (i=0; i < len; i++){
353
354 irqstatus |= (1<< (4*(ds->slave.bus)));
355 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
356 OMAP3_MCSPI_CHSTAT_TXS)) {
357 if (--timeout <= 0) {
358 printf("SPI TXS timed out, status=0x%08x\n",
359 readl(&ds->regs->channel[ds->slave.cs].chstat));
360 return -1;
361 }
362 }
363
364 writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
365
366
367 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
368 OMAP3_MCSPI_CHSTAT_RXS)) {
369 if (--timeout <= 0) {
370 printf("SPI RXS timed out, status=0x%08x\n",
371 readl(&ds->regs->channel[ds->slave.cs].chstat));
372 return -1;
373 }
374 }
375
376 rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
377 }
378
379 omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
380
381
382 if (flags & SPI_XFER_END) {
383 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
384 omap3_spi_write_chconf(ds,chconf);
385 }
386
387 return 0;
388}
389
390int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
391 const void *dout, void *din, unsigned long flags)
392{
393 struct omap3_spi_slave *ds = to_omap3_spi(slave);
394 unsigned int len;
395 const u8 *txp = dout;
396 u8 *rxp = din;
397 int ret = -1;
398
399 if (bitlen % 8)
400 return -1;
401
402 len = bitlen / 8;
403
404 if (bitlen == 0) {
405 int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
406
407 if (flags & SPI_XFER_BEGIN) {
408 omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
409 chconf |= OMAP3_MCSPI_CHCONF_FORCE;
410 omap3_spi_write_chconf(ds,chconf);
411 }
412 if (flags & SPI_XFER_END) {
413 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
414 omap3_spi_write_chconf(ds,chconf);
415 omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
416 }
417 ret = 0;
418 } else {
419 if (dout != NULL && din != NULL)
420 ret = omap3_spi_txrx(slave, len, txp, rxp, flags);
421 else if (dout != NULL)
422 ret = omap3_spi_write(slave, len, txp, flags);
423 else if (din != NULL)
424 ret = omap3_spi_read(slave, len, rxp, flags);
425 }
426 return ret;
427}
428
429int spi_cs_is_valid(unsigned int bus, unsigned int cs)
430{
431 return 1;
432}
433
434void spi_cs_activate(struct spi_slave *slave)
435{
436}
437
438void spi_cs_deactivate(struct spi_slave *slave)
439{
440}
441