at91_spi.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * $Log: at91_spi.c,v $
00036  * Revision 1.5  2008/06/23 16:48:00  haraldkipp
00037  * Bug #1963841 fixed.
00038  *
00039  * Revision 1.4  2007/10/04 19:50:41  olereinhardt
00040  * small bugfix for cpu with only one spi channel
00041  *
00042  * Revision 1.3  2007/07/17 18:30:08  haraldkipp
00043  * Documentation added.
00044  *
00045  * Revision 1.2  2006/10/08 16:48:07  haraldkipp
00046  * Documentation fixed
00047  *
00048  * Revision 1.1  2006/09/29 12:34:59  haraldkipp
00049  * Basic AT91 SPI support added.
00050  *
00051  */
00052 #include <stdio.h>
00053 
00054 #include <cfg/arch.h>
00055 #include <dev/board.h>
00056 #include <dev/irqreg.h>
00057 
00058 #include <sys/event.h>
00059 #include <sys/timer.h>
00060 
00061 #include <dev/at91_spi.h>
00062 
00063 static HANDLE spi0_que;
00064 #if defined (SPI1_BASE)
00065 static HANDLE spi1_que;
00066 #endif
00067 
00073 static void At91Spi0Interrupt(void *arg)
00074 {
00075     NutEventPostFromIrq(&spi0_que);
00076 }
00077 
00081 int At91Spi0Init(void)
00082 {
00083     /* Enable SPI peripherals. */
00084     At91Spi0Enable();
00085     /* Enable SPI clock. */
00086     outr(PMC_PCER, _BV(SPI0_ID));
00087 
00088     /* Register and enable SPI0 interrupt handler. */
00089     NutRegisterIrqHandler(&sig_SPI0, At91Spi0Interrupt, 0);
00090     NutIrqEnable(&sig_SPI0);
00091 
00092     return At91SpiReset(SPI0_BASE);
00093 }
00094 
00104 int At91Spi0InitChipSelects(u_int mask)
00105 {
00106     if (mask & _BV(0)) {
00107 #if defined(SPI0_CS0_PIN)
00108         outr(SPI0_CS0_PIO_BASE + SPI0_CS0_PSR_OFF, SPI0_CS0_PIN);
00109         outr(SPI0_CS0_PIO_BASE + PIO_PDR_OFF, SPI0_CS0_PIN);
00110         mask &= ~_BV(0);
00111 #endif                          /* SPI0_CS0_PIN */
00112     }
00113     if (mask & _BV(1)) {
00114 #if defined(SPI0_CS1_PIN)
00115         outr(SPI0_CS1_PIO_BASE + SPI0_CS1_PSR_OFF, SPI0_CS1_PIN);
00116         outr(SPI0_CS1_PIO_BASE + PIO_PDR_OFF, SPI0_CS1_PIN);
00117         mask &= ~_BV(1);
00118 #endif                          /* SPI0_CS1_PIN */
00119     }
00120     if (mask & _BV(2)) {
00121 #if defined(SPI0_CS2_PIN)
00122         outr(SPI0_CS2_PIO_BASE + SPI0_CS2_PSR_OFF, SPI0_CS2_PIN);
00123         outr(SPI0_CS2_PIO_BASE + PIO_PDR_OFF, SPI0_CS2_PIN);
00124         mask &= ~_BV(2);
00125 #endif                          /* SPI0_CS2_PIN */
00126     }
00127     if (mask & _BV(3)) {
00128 #if defined(SPI0_CS3_PIN)
00129         outr(SPI0_CS3_PIO_BASE + SPI0_CS3_PSR_OFF, SPI0_CS3_PIN);
00130         outr(SPI0_CS3_PIO_BASE + PIO_PDR_OFF, SPI0_CS3_PIN);
00131         mask &= ~_BV(3);
00132 #endif                          /* SPI0_CS3_PIN */
00133     }
00134     return mask ? -1 : 0;
00135 }
00136 
00140 int At91Spi0Enable(void)
00141 {
00142     /* Enable SPI peripherals. */
00143     outr(SPI0_PIO_BASE + SPI0_PSR_OFF, SPI0_PINS);
00144     outr(SPI0_PIO_BASE + PIO_PDR_OFF, SPI0_PINS);
00145 
00146     return 0;
00147 }
00148 
00149 #if defined(SPI1_BASE)
00150 
00156 static void At91Spi1Interrupt(void *arg)
00157 {
00158     NutEventPostFromIrq(&spi1_que);
00159 }
00160 
00164 int At91Spi1Init(void)
00165 {
00166     /* Enable SPI peripherals. */
00167     At91Spi1Enable();
00168     /* Enable SPI clock. */
00169     outr(PMC_PCER, _BV(SPI1_ID));
00170 
00171     /* Register and enable SPI1 interrupt handler. */
00172     NutRegisterIrqHandler(&sig_SPI1, At91Spi1Interrupt, 0);
00173     NutIrqEnable(&sig_SPI1);
00174 
00175     return At91SpiReset(SPI1_BASE);
00176 }
00177 
00187 int At91Spi1InitChipSelects(u_int mask)
00188 {
00189 #if defined(SPI1_CS0_PIN)
00190     if (mask & _BV(0)) {
00191         outr(SPI1_CS0_PIO_BASE + SPI1_CS0_PSR_OFF, SPI1_CS0_PIN);
00192         outr(SPI1_CS0_PIO_BASE + PIO_PDR_OFF, SPI1_CS0_PIN);
00193         mask &= ~_BV(0);
00194     }
00195 #endif                          /* SPI1_CS0_PIN */
00196 #if defined(SPI1_CS1_PIN)
00197     if (mask & _BV(1)) {
00198         outr(SPI1_CS1_PIO_BASE + SPI1_CS1_PSR_OFF, SPI1_CS1_PIN);
00199         outr(SPI1_CS1_PIO_BASE + PIO_PDR_OFF, SPI1_CS1_PIN);
00200         mask &= ~_BV(1);
00201     }
00202 #endif                          /* SPI1_CS1_PIN */
00203 #if defined(SPI1_CS2_PIN)
00204     if (mask & _BV(2)) {
00205         outr(SPI1_CS2_PIO_BASE + SPI1_CS2_PSR_OFF, SPI1_CS2_PIN);
00206         outr(SPI1_CS2_PIO_BASE + PIO_PDR_OFF, SPI1_CS2_PIN);
00207         mask &= ~_BV(2);
00208     }
00209 #endif                          /* SPI1_CS2_PIN */
00210 #if defined(SPI1_CS3_PIN)
00211     if (mask & _BV(3)) {
00212         outr(SPI1_CS3_PIO_BASE + SPI1_CS3_PSR_OFF, SPI1_CS3_PIN);
00213         outr(SPI1_CS3_PIO_BASE + PIO_PDR_OFF, SPI1_CS3_PIN);
00214         mask &= ~_BV(3);
00215     }
00216 #endif                          /* SPI1_CS3_PIN */
00217     return mask ? -1 : 0;
00218 }
00219 
00223 int At91Spi1Enable(void)
00224 {
00225     /* Enable SPI peripherals. */
00226     outr(SPI1_PIO_BASE + SPI1_PSR_OFF, SPI1_PINS);
00227     outr(SPI1_PIO_BASE + PIO_PDR_OFF, SPI1_PINS);
00228 
00229     return 0;
00230 }
00231 
00232 #endif                          /* SPI1_BASE */
00233 
00242 int At91SpiInit(u_int base)
00243 {
00244     int rc = -1;
00245 
00246     /* 
00247      * Enable PIO lines and clock. 
00248      */
00249     if (base == SPI0_BASE) {
00250         rc = At91Spi0Init();
00251     }
00252 #if defined(SPI1_BASE)
00253     if (base == SPI1_BASE) {
00254         rc = At91Spi1Init();
00255     }
00256 #endif
00257     return rc;
00258 }
00259 
00260 int At91SpiEnable(u_int base)
00261 {
00262     outr(base + SPI_CR_OFF, SPI_SPIEN);
00263 
00264     return 0;
00265 }
00266 
00267 int At91SpiDisable(u_int base)
00268 {
00269     outr(base + SPI_CR_OFF, SPI_SPIDIS);
00270 
00271     return 0;
00272 }
00273 
00282 int At91SpiReset(u_int base)
00283 {
00284     int rc = -1;
00285 
00286     /* Disable SPI. */
00287     At91SpiDisable(base);
00288 
00289     /* Reset SPI. */
00290     outr(base + SPI_CR_OFF, SPI_SWRST);
00291 
00292     /* Set SPI to master mode, fixed peripheral at no chip select, fault detection disabled. */
00293     outr(base + SPI_MR_OFF, (90 << SPI_DLYBCS_LSB) | SPI_PCS | SPI_MODFDIS | SPI_MSTR);
00294 
00295     /* Enable SPI. */
00296     At91SpiEnable(base);
00297 
00298     return rc;
00299 }
00300 
00312 int At91SpiInitChipSelects(u_int base, u_int mask)
00313 {
00314     int rc = -1;
00315 
00316     /* Init chip select lines for SPI 0. */
00317     if (base == SPI0_BASE) {
00318         rc = At91Spi0InitChipSelects(mask);
00319     }
00320     /* Init chip select lines for SPI 1. */
00321 #if defined(SPI1_BASE)
00322     if (base == SPI1_BASE) {
00323         rc = At91Spi1InitChipSelects(mask);
00324     }
00325 #endif
00326     return rc;
00327 }
00328 
00338 int At91SpiSetRate(u_int base, u_int cs, u_long rate)
00339 {
00340     int rc = 0;
00341     u_int divider;
00342 
00343     /* The SPI clock is driven by the master clock. */
00344     divider = (u_int) At91GetMasterClock();
00345     /* Calculate the SPI clock divider. Avoid rounding errors. */
00346     divider += (u_int) (rate / 2);
00347     divider /= rate;
00348     /* A divider value of 0 is not allowed. */
00349     if (divider < 1) {
00350         divider = 1;
00351     }
00352     /* The divider value maximum is 255. */
00353     else if (divider > 255) {
00354         divider = 255;
00355     }
00356     switch (cs) {
00357     case 0:
00358         outr(base + SPI_CSR0_OFF, (inr(base + SPI_CSR0_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00359         break;
00360     case 1:
00361         outr(base + SPI_CSR1_OFF, (inr(base + SPI_CSR1_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00362         break;
00363     case 2:
00364         outr(base + SPI_CSR2_OFF, (inr(base + SPI_CSR2_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00365         break;
00366     case 3:
00367         outr(base + SPI_CSR3_OFF, (inr(base + SPI_CSR3_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00368         break;
00369     default:
00370         rc = -1;
00371         break;
00372     }
00373     return 0;
00374 }
00375 
00376 u_long At91SpiGetModeFlags(u_int base, u_int cs)
00377 {
00378     u_long rc = SPIMF_MFDETECT;
00379     u_int mv = inr(base + SPI_MR_OFF);
00380 
00381     if (mv & SPI_MSTR) {
00382         rc |= SPI_MSTR;
00383     }
00384     if (mv & SPI_PCSDEC) {
00385         rc |= SPIMF_MASTER;
00386     }
00387     if (mv & SPI_MODFDIS) {
00388         rc &= ~SPIMF_MFDETECT;
00389     }
00390     if (mv & SPI_LLB) {
00391         rc |= SPIMF_LOOPBACK;
00392     }
00393 
00394     mv = inr(base + SPI_CSR0_OFF + cs * 4);
00395     if (mv & SPI_CPOL) {
00396         if (mv & SPI_NCPHA) {
00397             rc |= SPIMF_SCKIAHI;
00398         } else {
00399             rc |= SPIMF_SCKIAHI | SPIMF_CAPRISE;
00400         }
00401     } else if (mv & SPI_NCPHA) {
00402         rc |= SPIMF_CAPRISE;
00403     }
00404     return rc;
00405 }
00406 
00421 int At91SpiSetModeFlags(u_int base, u_int cs, u_long mode)
00422 {
00423     u_int mv;
00424 
00425     mv = inr(base + SPI_MR_OFF) & ~(SPI_MSTR | SPI_PCSDEC | SPI_MODFDIS | SPI_LLB);
00426     if (mode & SPIMF_MASTER) {
00427         mv |= SPI_MSTR;
00428     }
00429     if (mode & SPIMF_PCSDEC) {
00430         mv |= SPI_PCSDEC;
00431     }
00432     if (mode & SPIMF_MFDETECT) {
00433         mv &= ~SPI_MODFDIS;
00434     }
00435     if (mode & SPIMF_LOOPBACK) {
00436         mv |= SPI_LLB;
00437     }
00438     outr(base + SPI_MR_OFF, mv);
00439 
00440     mv = inr(base + SPI_CSR0_OFF + cs * 4) & ~(SPI_CPOL | SPI_NCPHA | SPI_CSAAT);
00441     if (mode & SPIMF_SCKIAHI) {
00442         if (mode & SPIMF_CAPRISE) {
00443             mv |= SPI_CPOL;
00444         } else {
00445             mv |= SPI_CPOL | SPI_NCPHA;
00446         }
00447     } else {
00448         if (mode & SPIMF_CAPRISE) {
00449             mv |= SPI_NCPHA;
00450         }
00451     }
00452     if (mode & SPIMF_KEEPCS) {
00453         mv |= SPI_CSAAT;
00454     }
00455     outr(base + SPI_CSR0_OFF + cs * 4, mv);
00456 
00457     if (At91SpiGetModeFlags(base, cs) != mode) {
00458         return -1;
00459     }
00460     return 0;
00461 }
00462 
00463 u_int At91SpiGetBits(u_int base, u_int cs)
00464 {
00465     u_int rc;
00466 
00467     switch (inr(base + SPI_CSR0_OFF + cs * 4) & SPI_BITS) {
00468     case SPI_BITS_9:
00469         rc = 9;
00470         break;
00471     case SPI_BITS_10:
00472         rc = 10;
00473         break;
00474     case SPI_BITS_11:
00475         rc = 11;
00476         break;
00477     case SPI_BITS_12:
00478         rc = 12;
00479         break;
00480     case SPI_BITS_13:
00481         rc = 13;
00482         break;
00483     case SPI_BITS_14:
00484         rc = 14;
00485         break;
00486     case SPI_BITS_15:
00487         rc = 15;
00488         break;
00489     case SPI_BITS_16:
00490         rc = 16;
00491         break;
00492     default:
00493         rc = 8;
00494         break;
00495     }
00496     return rc;
00497 }
00498 
00499 int At91SpiSetBits(u_int base, u_int cs, u_int bits)
00500 {
00501     u_int mv;
00502 
00503     mv = inr(base + SPI_CSR0_OFF + cs * 4) & ~SPI_BITS;
00504     switch (bits) {
00505     case 9:
00506         mv |= SPI_BITS_9;
00507         break;
00508     case 10:
00509         mv |= SPI_BITS_10;
00510         break;
00511     case 11:
00512         mv |= SPI_BITS_11;
00513         break;
00514     case 12:
00515         mv |= SPI_BITS_12;
00516         break;
00517     case 13:
00518         mv |= SPI_BITS_13;
00519         break;
00520     case 14:
00521         mv |= SPI_BITS_14;
00522         break;
00523     case 15:
00524         mv |= SPI_BITS_15;
00525         break;
00526     case 16:
00527         mv |= SPI_BITS_16;
00528         break;
00529     default:
00530         mv |= SPI_BITS_8;
00531         break;
00532     }
00533     outr(base + SPI_CSR0_OFF + cs * 4, mv);
00534 
00535     if (At91SpiGetBits(base, cs) != bits) {
00536         return -1;
00537     }
00538     return 0;
00539 }
00540 
00541 u_int At91SpiGetSckDelay(u_int base, u_int cs)
00542 {
00543     return (inr(base + SPI_CSR0_OFF + cs * 4) & ~SPI_DLYBS) >> SPI_DLYBS_LSB;
00544 }
00545 
00546 int At91SpiSetSckDelay(u_int base, u_int cs, u_int dly)
00547 {
00548     u_int csr = base + SPI_CSR0_OFF + cs * 4;
00549 
00550     outr(csr, (inr(csr) & ~SPI_DLYBS) | ((dly << SPI_DLYBS_LSB) & SPI_DLYBS));
00551 
00552     if (At91SpiGetSckDelay(base, cs) != dly) {
00553         return -1;
00554     }
00555     return 0;
00556 }
00557 
00558 u_int At91SpiGetTxDelay(u_int base, u_int cs)
00559 {
00560     return (inr(base + SPI_CSR0_OFF + cs * 4) & ~SPI_DLYBCT) >> SPI_DLYBCT_LSB;
00561 }
00562 
00563 int At91SpiSetTxDelay(u_int base, u_int cs, u_int dly)
00564 {
00565     u_int csr = base + SPI_CSR0_OFF + cs * 4;
00566 
00567     outr(csr, (inr(csr) & ~SPI_DLYBCT) | ((dly << SPI_DLYBCT_LSB) & SPI_DLYBCT));
00568 
00569     if (At91SpiGetTxDelay(base, cs) != dly) {
00570         return -1;
00571     }
00572     return 0;
00573 }
00574 
00575 u_int At91SpiGetCsDelay(u_int base)
00576 {
00577     return (inr(base + SPI_MR_OFF) & ~SPI_DLYBCS) >> SPI_DLYBCS_LSB;
00578 }
00579 
00580 int At91SpiSetCsDelay(u_int base, u_int dly)
00581 {
00582     outr(base + SPI_MR_OFF, (inr(base + SPI_MR_OFF) & ~SPI_DLYBCS) | ((dly << SPI_DLYBCS_LSB) & SPI_DLYBCS));
00583 
00584     if (At91SpiGetCsDelay(base) != dly) {
00585         return -1;
00586     }
00587     return 0;
00588 }
00589 
00602 int At91SpiTransfer2(u_int base, u_int cs, CONST void *txbuf, void *rxbuf, int xlen, CONST void *txnbuf, void *rxnbuf, int xnlen)
00603 {
00604     int rc = -1;
00605     u_int flags;
00606     u_int sr;
00607 
00608     outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00609 
00610     flags = inr(base + SPI_MR_OFF) & ~SPI_PCS;
00611     switch (cs) {
00612     case 0:
00613         flags |= SPI_PCS_0;
00614         break;
00615     case 1:
00616         flags |= SPI_PCS_1;
00617         break;
00618     case 2:
00619         flags |= SPI_PCS_2;
00620         break;
00621     case 3:
00622         flags |= SPI_PCS_3;
00623         break;
00624     }
00625     outr(base + SPI_MR_OFF, flags);
00626 
00627     /* Set first transmit pointer and counter. */
00628     outr(base + PERIPH_TPR_OFF, (u_int) txbuf);
00629     outr(base + PERIPH_TCR_OFF, (u_int) xlen);
00630     /* Set first receive pointer and counter. */
00631     outr(base + PERIPH_RPR_OFF, (u_int) rxbuf);
00632     outr(base + PERIPH_RCR_OFF, (u_int) xlen);
00633 
00634     /* Set second transmit pointer and counter. */
00635     outr(base + PERIPH_TNPR_OFF, (u_int) txnbuf);
00636     outr(base + PERIPH_TNCR_OFF, (u_int) xnlen);
00637 
00638     /* Set second receive pointer and counter. */
00639     outr(base + PERIPH_RNPR_OFF, (u_int) rxnbuf);
00640     outr(base + PERIPH_RNCR_OFF, (u_int) xnlen);
00641 
00642     outr(base + SPI_IDR_OFF, (u_int) - 1);
00643     outr(base + SPI_IER_OFF, SPI_RXBUFF);
00644     outr(base + PERIPH_PTCR_OFF, PDC_TXTEN | PDC_RXTEN);
00645 
00646     while (((sr = inr(base + SPI_SR_OFF)) & SPI_RXBUFF) == 0) {
00647         if (base == SPI0_BASE) {
00648             if ((rc = NutEventWait(&spi0_que, 500)) != 0) {
00649                 printf("[TO]");
00650                 break;
00651             }
00652         }
00653 #if defined(SPI1_BASE)
00654         else if (base == SPI1_BASE) {
00655             if ((rc = NutEventWait(&spi1_que, 500)) != 0) {
00656                 break;
00657             }
00658         }
00659 #endif
00660     }
00661     outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00662 
00663     return rc;
00664 }

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/