]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/spi/omap3_spi.c
dm: pmic: max77686: Correct two typos in a comment
[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 10
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         ulong start;
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                 start = get_timer(0);
245                 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
246                          OMAP3_MCSPI_CHSTAT_TXS)) {
247                         if (get_timer(start) > SPI_WAIT_TIMEOUT) {
248                                 printf("SPI TXS timed out, status=0x%08x\n",
249                                        readl(&ds->regs->channel[ds->slave.cs].chstat));
250                                 return -1;
251                         }
252                 }
253                 /* Write the data */
254                 unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx;
255                 if (ds->slave.wordlen > 16)
256                         writel(((u32 *)txp)[i], tx);
257                 else if (ds->slave.wordlen > 8)
258                         writel(((u16 *)txp)[i], tx);
259                 else
260                         writel(((u8 *)txp)[i], tx);
261         }
262
263         /* wait to finish of transfer */
264         while ((readl(&ds->regs->channel[ds->slave.cs].chstat) &
265                          (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) !=
266                          (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS));
267
268         /* Disable the channel otherwise the next immediate RX will get affected */
269         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
270
271         if (flags & SPI_XFER_END) {
272
273                 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
274                 omap3_spi_write_chconf(ds,chconf);
275         }
276         return 0;
277 }
278
279 int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp,
280                    unsigned long flags)
281 {
282         struct omap3_spi_slave *ds = to_omap3_spi(slave);
283         int i;
284         ulong start;
285         int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
286
287         /* Enable the channel */
288         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
289
290         chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
291         chconf |= (ds->slave.wordlen - 1) << 7;
292         chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
293         chconf |= OMAP3_MCSPI_CHCONF_FORCE;
294         omap3_spi_write_chconf(ds,chconf);
295
296         writel(0, &ds->regs->channel[ds->slave.cs].tx);
297
298         for (i = 0; i < len; i++) {
299                 start = get_timer(0);
300                 /* Wait till RX register contains data (RXS == 1) */
301                 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
302                          OMAP3_MCSPI_CHSTAT_RXS)) {
303                         if (get_timer(start) > SPI_WAIT_TIMEOUT) {
304                                 printf("SPI RXS timed out, status=0x%08x\n",
305                                        readl(&ds->regs->channel[ds->slave.cs].chstat));
306                                 return -1;
307                         }
308                 }
309
310                 /* Disable the channel to prevent furher receiving */
311                 if(i == (len - 1))
312                         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
313
314                 /* Read the data */
315                 unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx;
316                 if (ds->slave.wordlen > 16)
317                         ((u32 *)rxp)[i] = readl(rx);
318                 else if (ds->slave.wordlen > 8)
319                         ((u16 *)rxp)[i] = (u16)readl(rx);
320                 else
321                         ((u8 *)rxp)[i] = (u8)readl(rx);
322         }
323
324         if (flags & SPI_XFER_END) {
325                 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
326                 omap3_spi_write_chconf(ds,chconf);
327         }
328
329         return 0;
330 }
331
332 /*McSPI Transmit Receive Mode*/
333 int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
334                    const void *txp, void *rxp, unsigned long flags)
335 {
336         struct omap3_spi_slave *ds = to_omap3_spi(slave);
337         ulong start;
338         int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
339         int irqstatus = readl(&ds->regs->irqstatus);
340         int i=0;
341
342         /*Enable SPI channel*/
343         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
344
345         /*set TRANSMIT-RECEIVE Mode*/
346         chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
347         chconf |= (ds->slave.wordlen - 1) << 7;
348         chconf |= OMAP3_MCSPI_CHCONF_FORCE;
349         omap3_spi_write_chconf(ds,chconf);
350
351         /*Shift in and out 1 byte at time*/
352         for (i=0; i < len; i++){
353                 /* Write: wait for TX empty (TXS == 1)*/
354                 irqstatus |= (1<< (4*(ds->slave.bus)));
355                 start = get_timer(0);
356                 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
357                          OMAP3_MCSPI_CHSTAT_TXS)) {
358                         if (get_timer(start) > SPI_WAIT_TIMEOUT) {
359                                 printf("SPI TXS timed out, status=0x%08x\n",
360                                        readl(&ds->regs->channel[ds->slave.cs].chstat));
361                                 return -1;
362                         }
363                 }
364                 /* Write the data */
365                 unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx;
366                 if (ds->slave.wordlen > 16)
367                         writel(((u32 *)txp)[i], tx);
368                 else if (ds->slave.wordlen > 8)
369                         writel(((u16 *)txp)[i], tx);
370                 else
371                         writel(((u8 *)txp)[i], tx);
372
373                 /*Read: wait for RX containing data (RXS == 1)*/
374                 start = get_timer(0);
375                 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
376                          OMAP3_MCSPI_CHSTAT_RXS)) {
377                         if (get_timer(start) > SPI_WAIT_TIMEOUT) {
378                                 printf("SPI RXS timed out, status=0x%08x\n",
379                                        readl(&ds->regs->channel[ds->slave.cs].chstat));
380                                 return -1;
381                         }
382                 }
383                 /* Read the data */
384                 unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx;
385                 if (ds->slave.wordlen > 16)
386                         ((u32 *)rxp)[i] = readl(rx);
387                 else if (ds->slave.wordlen > 8)
388                         ((u16 *)rxp)[i] = (u16)readl(rx);
389                 else
390                         ((u8 *)rxp)[i] = (u8)readl(rx);
391         }
392         /* Disable the channel */
393         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
394
395         /*if transfer must be terminated disable the channel*/
396         if (flags & SPI_XFER_END) {
397                 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
398                 omap3_spi_write_chconf(ds,chconf);
399         }
400
401         return 0;
402 }
403
404 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
405              const void *dout, void *din, unsigned long flags)
406 {
407         struct omap3_spi_slave *ds = to_omap3_spi(slave);
408         unsigned int    len;
409         int ret = -1;
410
411         if (ds->slave.wordlen < 4 || ds->slave.wordlen > 32) {
412                 printf("omap3_spi: invalid wordlen %d\n", ds->slave.wordlen);
413                 return -1;
414         }
415
416         if (bitlen % ds->slave.wordlen)
417                 return -1;
418
419         len = bitlen / ds->slave.wordlen;
420
421         if (bitlen == 0) {       /* only change CS */
422                 int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
423
424                 if (flags & SPI_XFER_BEGIN) {
425                         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
426                         chconf |= OMAP3_MCSPI_CHCONF_FORCE;
427                         omap3_spi_write_chconf(ds,chconf);
428                 }
429                 if (flags & SPI_XFER_END) {
430                         chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
431                         omap3_spi_write_chconf(ds,chconf);
432                         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
433                 }
434                 ret = 0;
435         } else {
436                 if (dout != NULL && din != NULL)
437                         ret = omap3_spi_txrx(slave, len, dout, din, flags);
438                 else if (dout != NULL)
439                         ret = omap3_spi_write(slave, len, dout, flags);
440                 else if (din != NULL)
441                         ret = omap3_spi_read(slave, len, din, flags);
442         }
443         return ret;
444 }
445
446 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
447 {
448         return 1;
449 }
450
451 void spi_cs_activate(struct spi_slave *slave)
452 {
453 }
454
455 void spi_cs_deactivate(struct spi_slave *slave)
456 {
457 }