]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/spi/omap3_spi.c
drivers/spi/omap3: Bug fix of premature write transfer completion
[karo-tx-uboot.git] / drivers / spi / omap3_spi.c
1 /*
2  * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
3  *
4  * Driver for McSPI controller on OMAP3. Based on davinci_spi.c
5  * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
6  *
7  * Copyright (C) 2007 Atmel Corporation
8  *
9  * Parts taken from linux/drivers/spi/omap2_mcspi.c
10  * Copyright (C) 2005, 2006 Nokia Corporation
11  *
12  * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.com>
13  *
14  * SPDX-License-Identifier:     GPL-2.0+
15  */
16
17 #include <common.h>
18 #include <spi.h>
19 #include <malloc.h>
20 #include <asm/io.h>
21 #include "omap3_spi.h"
22
23 #define SPI_WAIT_TIMEOUT 3000000
24
25 static void spi_reset(struct omap3_spi_slave *ds)
26 {
27         unsigned int tmp;
28
29         writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &ds->regs->sysconfig);
30         do {
31                 tmp = readl(&ds->regs->sysstatus);
32         } while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE));
33
34         writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
35                                  OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
36                                  OMAP3_MCSPI_SYSCONFIG_SMARTIDLE,
37                                  &ds->regs->sysconfig);
38
39         writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &ds->regs->wakeupenable);
40 }
41
42 static void omap3_spi_write_chconf(struct omap3_spi_slave *ds, int val)
43 {
44         writel(val, &ds->regs->channel[ds->slave.cs].chconf);
45         /* Flash post writes to make immediate effect */
46         readl(&ds->regs->channel[ds->slave.cs].chconf);
47 }
48
49 static void omap3_spi_set_enable(struct omap3_spi_slave *ds, int enable)
50 {
51         writel(enable, &ds->regs->channel[ds->slave.cs].chctrl);
52         /* Flash post writes to make immediate effect */
53         readl(&ds->regs->channel[ds->slave.cs].chctrl);
54 }
55
56 void spi_init()
57 {
58         /* do nothing */
59 }
60
61 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
62                                   unsigned int max_hz, unsigned int mode)
63 {
64         struct omap3_spi_slave  *ds;
65         struct mcspi *regs;
66
67         /*
68          * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
69          * with different number of chip selects (CS, channels):
70          * McSPI1 has 4 CS (bus 0, cs 0 - 3)
71          * McSPI2 has 2 CS (bus 1, cs 0 - 1)
72          * McSPI3 has 2 CS (bus 2, cs 0 - 1)
73          * McSPI4 has 1 CS (bus 3, cs 0)
74          */
75
76         switch (bus) {
77         case 0:
78                 regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
79                 break;
80 #ifdef OMAP3_MCSPI2_BASE
81         case 1:
82                 regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
83                 break;
84 #endif
85 #ifdef OMAP3_MCSPI3_BASE
86         case 2:
87                 regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
88                 break;
89 #endif
90 #ifdef OMAP3_MCSPI4_BASE
91         case 3:
92                 regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
93                 break;
94 #endif
95         default:
96                 printf("SPI error: unsupported bus %i. \
97                         Supported busses 0 - 3\n", bus);
98                 return NULL;
99         }
100
101         if (((bus == 0) && (cs > 3)) ||
102                         ((bus == 1) && (cs > 1)) ||
103                         ((bus == 2) && (cs > 1)) ||
104                         ((bus == 3) && (cs > 0))) {
105                 printf("SPI error: unsupported chip select %i \
106                         on bus %i\n", cs, bus);
107                 return NULL;
108         }
109
110         if (max_hz > OMAP3_MCSPI_MAX_FREQ) {
111                 printf("SPI error: unsupported frequency %i Hz. \
112                         Max frequency is 48 Mhz\n", max_hz);
113                 return NULL;
114         }
115
116         if (mode > SPI_MODE_3) {
117                 printf("SPI error: unsupported SPI mode %i\n", mode);
118                 return NULL;
119         }
120
121         ds = spi_alloc_slave(struct omap3_spi_slave, bus, cs);
122         if (!ds) {
123                 printf("SPI error: malloc of SPI structure failed\n");
124                 return NULL;
125         }
126
127         ds->regs = regs;
128         ds->freq = max_hz;
129         ds->mode = mode;
130
131         return &ds->slave;
132 }
133
134 void spi_free_slave(struct spi_slave *slave)
135 {
136         struct omap3_spi_slave *ds = to_omap3_spi(slave);
137
138         free(ds);
139 }
140
141 int spi_claim_bus(struct spi_slave *slave)
142 {
143         struct omap3_spi_slave *ds = to_omap3_spi(slave);
144         unsigned int conf, div = 0;
145
146         /* McSPI global module configuration */
147
148         /*
149          * setup when switching from (reset default) slave mode
150          * to single-channel master mode
151          */
152         spi_reset(ds);
153         conf = readl(&ds->regs->modulctrl);
154         conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
155         conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
156         writel(conf, &ds->regs->modulctrl);
157
158         /* McSPI individual channel configuration */
159
160         /* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
161         if (ds->freq) {
162                 while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
163                                          > ds->freq)
164                         div++;
165         } else
166                 div = 0xC;
167
168         conf = readl(&ds->regs->channel[ds->slave.cs].chconf);
169
170         /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
171          * REVISIT: this controller could support SPI_3WIRE mode.
172          */
173 #ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED
174         /*
175          * Some boards have D0 wired as MOSI / D1 as MISO instead of
176          * The normal D0 as MISO / D1 as MOSI.
177          */
178         conf &= ~OMAP3_MCSPI_CHCONF_DPE0;
179         conf |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1;
180 #else
181         conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
182         conf |= OMAP3_MCSPI_CHCONF_DPE0;
183 #endif
184
185         /* wordlength */
186         conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
187         conf |= (ds->slave.wordlen - 1) << 7;
188
189         /* set chipselect polarity; manage with FORCE */
190         if (!(ds->mode & SPI_CS_HIGH))
191                 conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
192         else
193                 conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
194
195         /* set clock divisor */
196         conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
197         conf |= div << 2;
198
199         /* set SPI mode 0..3 */
200         if (ds->mode & SPI_CPOL)
201                 conf |= OMAP3_MCSPI_CHCONF_POL;
202         else
203                 conf &= ~OMAP3_MCSPI_CHCONF_POL;
204         if (ds->mode & SPI_CPHA)
205                 conf |= OMAP3_MCSPI_CHCONF_PHA;
206         else
207                 conf &= ~OMAP3_MCSPI_CHCONF_PHA;
208
209         /* Transmit & receive mode */
210         conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
211
212         omap3_spi_write_chconf(ds,conf);
213
214         return 0;
215 }
216
217 void spi_release_bus(struct spi_slave *slave)
218 {
219         struct omap3_spi_slave *ds = to_omap3_spi(slave);
220
221         /* Reset the SPI hardware */
222         spi_reset(ds);
223 }
224
225 int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
226                     unsigned long flags)
227 {
228         struct omap3_spi_slave *ds = to_omap3_spi(slave);
229         int i;
230         int timeout = SPI_WAIT_TIMEOUT;
231         int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
232
233         /* Enable the channel */
234         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
235
236         chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
237         chconf |= (ds->slave.wordlen - 1) << 7;
238         chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
239         chconf |= OMAP3_MCSPI_CHCONF_FORCE;
240         omap3_spi_write_chconf(ds,chconf);
241
242         for (i = 0; i < len; i++) {
243                 /* wait till TX register is empty (TXS == 1) */
244                 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
245                          OMAP3_MCSPI_CHSTAT_TXS)) {
246                         if (--timeout <= 0) {
247                                 printf("SPI TXS timed out, status=0x%08x\n",
248                                        readl(&ds->regs->channel[ds->slave.cs].chstat));
249                                 return -1;
250                         }
251                 }
252                 /* Write the data */
253                 unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx;
254                 if (ds->slave.wordlen > 16)
255                         writel(((u32 *)txp)[i], tx);
256                 else if (ds->slave.wordlen > 8)
257                         writel(((u16 *)txp)[i], tx);
258                 else
259                         writel(((u8 *)txp)[i], tx);
260         }
261
262         /* wait to finish of transfer */
263         while ((readl(&ds->regs->channel[ds->slave.cs].chstat) &
264                          (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) !=
265                          (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS));
266
267         /* Disable the channel otherwise the next immediate RX will get affected */
268         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
269
270         if (flags & SPI_XFER_END) {
271
272                 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
273                 omap3_spi_write_chconf(ds,chconf);
274         }
275         return 0;
276 }
277
278 int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp,
279                    unsigned long flags)
280 {
281         struct omap3_spi_slave *ds = to_omap3_spi(slave);
282         int i;
283         int timeout = SPI_WAIT_TIMEOUT;
284         int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
285
286         /* Enable the channel */
287         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
288
289         chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
290         chconf |= (ds->slave.wordlen - 1) << 7;
291         chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
292         chconf |= OMAP3_MCSPI_CHCONF_FORCE;
293         omap3_spi_write_chconf(ds,chconf);
294
295         writel(0, &ds->regs->channel[ds->slave.cs].tx);
296
297         for (i = 0; i < len; i++) {
298                 /* Wait till RX register contains data (RXS == 1) */
299                 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
300                          OMAP3_MCSPI_CHSTAT_RXS)) {
301                         if (--timeout <= 0) {
302                                 printf("SPI RXS timed out, status=0x%08x\n",
303                                        readl(&ds->regs->channel[ds->slave.cs].chstat));
304                                 return -1;
305                         }
306                 }
307
308                 /* Disable the channel to prevent furher receiving */
309                 if(i == (len - 1))
310                         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
311
312                 /* Read the data */
313                 unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx;
314                 if (ds->slave.wordlen > 16)
315                         ((u32 *)rxp)[i] = readl(rx);
316                 else if (ds->slave.wordlen > 8)
317                         ((u16 *)rxp)[i] = (u16)readl(rx);
318                 else
319                         ((u8 *)rxp)[i] = (u8)readl(rx);
320         }
321
322         if (flags & SPI_XFER_END) {
323                 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
324                 omap3_spi_write_chconf(ds,chconf);
325         }
326
327         return 0;
328 }
329
330 /*McSPI Transmit Receive Mode*/
331 int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
332                    const void *txp, void *rxp, unsigned long flags)
333 {
334         struct omap3_spi_slave *ds = to_omap3_spi(slave);
335         int timeout = SPI_WAIT_TIMEOUT;
336         int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
337         int irqstatus = readl(&ds->regs->irqstatus);
338         int i=0;
339
340         /*Enable SPI channel*/
341         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
342
343         /*set TRANSMIT-RECEIVE Mode*/
344         chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
345         chconf |= (ds->slave.wordlen - 1) << 7;
346         chconf |= OMAP3_MCSPI_CHCONF_FORCE;
347         omap3_spi_write_chconf(ds,chconf);
348
349         /*Shift in and out 1 byte at time*/
350         for (i=0; i < len; i++){
351                 /* Write: wait for TX empty (TXS == 1)*/
352                 irqstatus |= (1<< (4*(ds->slave.bus)));
353                 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
354                          OMAP3_MCSPI_CHSTAT_TXS)) {
355                         if (--timeout <= 0) {
356                                 printf("SPI TXS timed out, status=0x%08x\n",
357                                        readl(&ds->regs->channel[ds->slave.cs].chstat));
358                                 return -1;
359                         }
360                 }
361                 /* Write the data */
362                 unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx;
363                 if (ds->slave.wordlen > 16)
364                         writel(((u32 *)txp)[i], tx);
365                 else if (ds->slave.wordlen > 8)
366                         writel(((u16 *)txp)[i], tx);
367                 else
368                         writel(((u8 *)txp)[i], tx);
369
370                 /*Read: wait for RX containing data (RXS == 1)*/
371                 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
372                          OMAP3_MCSPI_CHSTAT_RXS)) {
373                         if (--timeout <= 0) {
374                                 printf("SPI RXS timed out, status=0x%08x\n",
375                                        readl(&ds->regs->channel[ds->slave.cs].chstat));
376                                 return -1;
377                         }
378                 }
379                 /* Read the data */
380                 unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx;
381                 if (ds->slave.wordlen > 16)
382                         ((u32 *)rxp)[i] = readl(rx);
383                 else if (ds->slave.wordlen > 8)
384                         ((u16 *)rxp)[i] = (u16)readl(rx);
385                 else
386                         ((u8 *)rxp)[i] = (u8)readl(rx);
387         }
388         /* Disable the channel */
389         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
390
391         /*if transfer must be terminated disable the channel*/
392         if (flags & SPI_XFER_END) {
393                 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
394                 omap3_spi_write_chconf(ds,chconf);
395         }
396
397         return 0;
398 }
399
400 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
401              const void *dout, void *din, unsigned long flags)
402 {
403         struct omap3_spi_slave *ds = to_omap3_spi(slave);
404         unsigned int    len;
405         int ret = -1;
406
407         if (ds->slave.wordlen < 4 || ds->slave.wordlen > 32) {
408                 printf("omap3_spi: invalid wordlen %d\n", ds->slave.wordlen);
409                 return -1;
410         }
411
412         if (bitlen % ds->slave.wordlen)
413                 return -1;
414
415         len = bitlen / ds->slave.wordlen;
416
417         if (bitlen == 0) {       /* only change CS */
418                 int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
419
420                 if (flags & SPI_XFER_BEGIN) {
421                         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
422                         chconf |= OMAP3_MCSPI_CHCONF_FORCE;
423                         omap3_spi_write_chconf(ds,chconf);
424                 }
425                 if (flags & SPI_XFER_END) {
426                         chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
427                         omap3_spi_write_chconf(ds,chconf);
428                         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
429                 }
430                 ret = 0;
431         } else {
432                 if (dout != NULL && din != NULL)
433                         ret = omap3_spi_txrx(slave, len, dout, din, flags);
434                 else if (dout != NULL)
435                         ret = omap3_spi_write(slave, len, dout, flags);
436                 else if (din != NULL)
437                         ret = omap3_spi_read(slave, len, din, flags);
438         }
439         return ret;
440 }
441
442 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
443 {
444         return 1;
445 }
446
447 void spi_cs_activate(struct spi_slave *slave)
448 {
449 }
450
451 void spi_cs_deactivate(struct spi_slave *slave)
452 {
453 }