]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/spi/omap3_spi.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[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  * See file CREDITS for list of people who contributed to this
15  * project.
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License as
19  * published by the Free Software Foundation; either version 2 of
20  * the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30  * MA 02111-1307 USA
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
43 static 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
60 static void omap3_spi_write_chconf(struct omap3_spi_slave *ds, int val)
61 {
62         writel(val, &ds->regs->channel[ds->slave.cs].chconf);
63         /* Flash post writes to make immediate effect */
64         readl(&ds->regs->channel[ds->slave.cs].chconf);
65 }
66
67 static void omap3_spi_set_enable(struct omap3_spi_slave *ds, int enable)
68 {
69         writel(enable, &ds->regs->channel[ds->slave.cs].chctrl);
70         /* Flash post writes to make immediate effect */
71         readl(&ds->regs->channel[ds->slave.cs].chctrl);
72 }
73
74 void spi_init()
75 {
76         /* do nothing */
77 }
78
79 struct 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          * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
87          * with different number of chip selects (CS, channels):
88          * McSPI1 has 4 CS (bus 0, cs 0 - 3)
89          * McSPI2 has 2 CS (bus 1, cs 0 - 1)
90          * McSPI3 has 2 CS (bus 2, cs 0 - 1)
91          * McSPI4 has 1 CS (bus 3, cs 0)
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
152 void spi_free_slave(struct spi_slave *slave)
153 {
154         struct omap3_spi_slave *ds = to_omap3_spi(slave);
155
156         free(ds);
157 }
158
159 int 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         /* McSPI global module configuration */
165
166         /*
167          * setup when switching from (reset default) slave mode
168          * to single-channel master mode
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         /* McSPI individual channel configuration */
177
178         /* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
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         /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
189          * REVISIT: this controller could support SPI_3WIRE mode.
190          */
191 #ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED
192         /*
193          * Some boards have D0 wired as MOSI / D1 as MISO instead of
194          * The normal D0 as MISO / D1 as MOSI.
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         /* wordlength */
204         conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
205         conf |= (WORD_LEN - 1) << 7;
206
207         /* set chipselect polarity; manage with FORCE */
208         if (!(ds->mode & SPI_CS_HIGH))
209                 conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
210         else
211                 conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
212
213         /* set clock divisor */
214         conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
215         conf |= div << 2;
216
217         /* set SPI mode 0..3 */
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         /* Transmit & receive mode */
228         conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
229
230         omap3_spi_write_chconf(ds,conf);
231
232         return 0;
233 }
234
235 void spi_release_bus(struct spi_slave *slave)
236 {
237         struct omap3_spi_slave *ds = to_omap3_spi(slave);
238
239         /* Reset the SPI hardware */
240         spi_reset(ds);
241 }
242
243 int 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         /* Enable the channel */
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                 /* wait till TX register is empty (TXS == 1) */
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                 /* Write the data */
270                 writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
271         }
272
273         /* wait to finish of transfer */
274         while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
275                          OMAP3_MCSPI_CHSTAT_EOT));
276
277         /* Disable the channel otherwise the next immediate RX will get affected */
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
288 int 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         /* Enable the channel */
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                 /* Wait till RX register contains data (RXS == 1) */
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                 /* Disable the channel to prevent furher receiving */
318                 if(i == (len - 1))
319                         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
320
321                 /* Read the data */
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 /*McSPI Transmit Receive Mode*/
334 int 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         /*Enable SPI channel*/
344         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
345
346         /*set TRANSMIT-RECEIVE Mode*/
347         chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
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                 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                 /* Write the data */
364                 writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
365
366                 /*Read: wait for RX containing data (RXS == 1)*/
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                 /* Read the data */
376                 rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
377         }
378         /* Disable the channel */
379         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
380
381         /*if transfer must be terminated disable the channel*/
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
390 int 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) {       /* only change CS */
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
429 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
430 {
431         return 1;
432 }
433
434 void spi_cs_activate(struct spi_slave *slave)
435 {
436 }
437
438 void spi_cs_deactivate(struct spi_slave *slave)
439 {
440 }