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.7  2008/10/05 16:40:36  haraldkipp
00037  * Removed forgotten debug output.
00038  *
00039  * Revision 1.6  2008/08/11 06:59:04  haraldkipp
00040  * BSD types replaced by stdint types (feature request #1282721).
00041  *
00042  * Revision 1.5  2008/06/23 16:48:00  haraldkipp
00043  * Bug #1963841 fixed.
00044  *
00045  * Revision 1.4  2007/10/04 19:50:41  olereinhardt
00046  * small bugfix for cpu with only one spi channel
00047  *
00048  * Revision 1.3  2007/07/17 18:30:08  haraldkipp
00049  * Documentation added.
00050  *
00051  * Revision 1.2  2006/10/08 16:48:07  haraldkipp
00052  * Documentation fixed
00053  *
00054  * Revision 1.1  2006/09/29 12:34:59  haraldkipp
00055  * Basic AT91 SPI support added.
00056  *
00057  */
00058 #include <cfg/arch.h>
00059 #include <dev/board.h>
00060 #include <dev/irqreg.h>
00061 
00062 #include <sys/event.h>
00063 #include <sys/timer.h>
00064 
00065 #include <dev/at91_spi.h>
00066 
00067 static HANDLE spi0_que;
00068 #if defined (SPI1_BASE)
00069 static HANDLE spi1_que;
00070 #endif
00071 
00077 static void At91Spi0Interrupt(void *arg)
00078 {
00079     NutEventPostFromIrq(&spi0_que);
00080 }
00081 
00085 int At91Spi0Init(void)
00086 {
00087     /* Enable SPI peripherals. */
00088     At91Spi0Enable();
00089     /* Enable SPI clock. */
00090     outr(PMC_PCER, _BV(SPI0_ID));
00091 
00092     /* Register and enable SPI0 interrupt handler. */
00093     NutRegisterIrqHandler(&sig_SPI0, At91Spi0Interrupt, 0);
00094     NutIrqEnable(&sig_SPI0);
00095 
00096     return At91SpiReset(SPI0_BASE);
00097 }
00098 
00108 int At91Spi0InitChipSelects(u_int mask)
00109 {
00110     if (mask & _BV(0)) {
00111 #if defined(SPI0_CS0_PIN)
00112         outr(SPI0_CS0_PIO_BASE + SPI0_CS0_PSR_OFF, SPI0_CS0_PIN);
00113         outr(SPI0_CS0_PIO_BASE + PIO_PDR_OFF, SPI0_CS0_PIN);
00114         mask &= ~_BV(0);
00115 #endif                          /* SPI0_CS0_PIN */
00116     }
00117     if (mask & _BV(1)) {
00118 #if defined(SPI0_CS1_PIN)
00119         outr(SPI0_CS1_PIO_BASE + SPI0_CS1_PSR_OFF, SPI0_CS1_PIN);
00120         outr(SPI0_CS1_PIO_BASE + PIO_PDR_OFF, SPI0_CS1_PIN);
00121         mask &= ~_BV(1);
00122 #endif                          /* SPI0_CS1_PIN */
00123     }
00124     if (mask & _BV(2)) {
00125 #if defined(SPI0_CS2_PIN)
00126         outr(SPI0_CS2_PIO_BASE + SPI0_CS2_PSR_OFF, SPI0_CS2_PIN);
00127         outr(SPI0_CS2_PIO_BASE + PIO_PDR_OFF, SPI0_CS2_PIN);
00128         mask &= ~_BV(2);
00129 #endif                          /* SPI0_CS2_PIN */
00130     }
00131     if (mask & _BV(3)) {
00132 #if defined(SPI0_CS3_PIN)
00133         outr(SPI0_CS3_PIO_BASE + SPI0_CS3_PSR_OFF, SPI0_CS3_PIN);
00134         outr(SPI0_CS3_PIO_BASE + PIO_PDR_OFF, SPI0_CS3_PIN);
00135         mask &= ~_BV(3);
00136 #endif                          /* SPI0_CS3_PIN */
00137     }
00138     return mask ? -1 : 0;
00139 }
00140 
00144 int At91Spi0Enable(void)
00145 {
00146     /* Enable SPI peripherals. */
00147     outr(SPI0_PIO_BASE + SPI0_PSR_OFF, SPI0_PINS);
00148     outr(SPI0_PIO_BASE + PIO_PDR_OFF, SPI0_PINS);
00149 
00150     return 0;
00151 }
00152 
00153 #if defined(SPI1_BASE)
00154 
00160 static void At91Spi1Interrupt(void *arg)
00161 {
00162     NutEventPostFromIrq(&spi1_que);
00163 }
00164 
00168 int At91Spi1Init(void)
00169 {
00170     /* Enable SPI peripherals. */
00171     At91Spi1Enable();
00172     /* Enable SPI clock. */
00173     outr(PMC_PCER, _BV(SPI1_ID));
00174 
00175     /* Register and enable SPI1 interrupt handler. */
00176     NutRegisterIrqHandler(&sig_SPI1, At91Spi1Interrupt, 0);
00177     NutIrqEnable(&sig_SPI1);
00178 
00179     return At91SpiReset(SPI1_BASE);
00180 }
00181 
00191 int At91Spi1InitChipSelects(u_int mask)
00192 {
00193 #if defined(SPI1_CS0_PIN)
00194     if (mask & _BV(0)) {
00195         outr(SPI1_CS0_PIO_BASE + SPI1_CS0_PSR_OFF, SPI1_CS0_PIN);
00196         outr(SPI1_CS0_PIO_BASE + PIO_PDR_OFF, SPI1_CS0_PIN);
00197         mask &= ~_BV(0);
00198     }
00199 #endif                          /* SPI1_CS0_PIN */
00200 #if defined(SPI1_CS1_PIN)
00201     if (mask & _BV(1)) {
00202         outr(SPI1_CS1_PIO_BASE + SPI1_CS1_PSR_OFF, SPI1_CS1_PIN);
00203         outr(SPI1_CS1_PIO_BASE + PIO_PDR_OFF, SPI1_CS1_PIN);
00204         mask &= ~_BV(1);
00205     }
00206 #endif                          /* SPI1_CS1_PIN */
00207 #if defined(SPI1_CS2_PIN)
00208     if (mask & _BV(2)) {
00209         outr(SPI1_CS2_PIO_BASE + SPI1_CS2_PSR_OFF, SPI1_CS2_PIN);
00210         outr(SPI1_CS2_PIO_BASE + PIO_PDR_OFF, SPI1_CS2_PIN);
00211         mask &= ~_BV(2);
00212     }
00213 #endif                          /* SPI1_CS2_PIN */
00214 #if defined(SPI1_CS3_PIN)
00215     if (mask & _BV(3)) {
00216         outr(SPI1_CS3_PIO_BASE + SPI1_CS3_PSR_OFF, SPI1_CS3_PIN);
00217         outr(SPI1_CS3_PIO_BASE + PIO_PDR_OFF, SPI1_CS3_PIN);
00218         mask &= ~_BV(3);
00219     }
00220 #endif                          /* SPI1_CS3_PIN */
00221     return mask ? -1 : 0;
00222 }
00223 
00227 int At91Spi1Enable(void)
00228 {
00229     /* Enable SPI peripherals. */
00230     outr(SPI1_PIO_BASE + SPI1_PSR_OFF, SPI1_PINS);
00231     outr(SPI1_PIO_BASE + PIO_PDR_OFF, SPI1_PINS);
00232 
00233     return 0;
00234 }
00235 
00236 #endif                          /* SPI1_BASE */
00237 
00246 int At91SpiInit(u_int base)
00247 {
00248     int rc = -1;
00249 
00250     /* 
00251      * Enable PIO lines and clock. 
00252      */
00253     if (base == SPI0_BASE) {
00254         rc = At91Spi0Init();
00255     }
00256 #if defined(SPI1_BASE)
00257     if (base == SPI1_BASE) {
00258         rc = At91Spi1Init();
00259     }
00260 #endif
00261     return rc;
00262 }
00263 
00264 int At91SpiEnable(u_int base)
00265 {
00266     outr(base + SPI_CR_OFF, SPI_SPIEN);
00267 
00268     return 0;
00269 }
00270 
00271 int At91SpiDisable(u_int base)
00272 {
00273     outr(base + SPI_CR_OFF, SPI_SPIDIS);
00274 
00275     return 0;
00276 }
00277 
00286 int At91SpiReset(u_int base)
00287 {
00288     int rc = -1;
00289 
00290     /* Disable SPI. */
00291     At91SpiDisable(base);
00292 
00293     /* Reset SPI. */
00294     outr(base + SPI_CR_OFF, SPI_SWRST);
00295 
00296     /* Set SPI to master mode, fixed peripheral at no chip select, fault detection disabled. */
00297     outr(base + SPI_MR_OFF, (90 << SPI_DLYBCS_LSB) | SPI_PCS | SPI_MODFDIS | SPI_MSTR);
00298 
00299     /* Enable SPI. */
00300     At91SpiEnable(base);
00301 
00302     return rc;
00303 }
00304 
00316 int At91SpiInitChipSelects(u_int base, u_int mask)
00317 {
00318     int rc = -1;
00319 
00320     /* Init chip select lines for SPI 0. */
00321     if (base == SPI0_BASE) {
00322         rc = At91Spi0InitChipSelects(mask);
00323     }
00324     /* Init chip select lines for SPI 1. */
00325 #if defined(SPI1_BASE)
00326     if (base == SPI1_BASE) {
00327         rc = At91Spi1InitChipSelects(mask);
00328     }
00329 #endif
00330     return rc;
00331 }
00332 
00342 int At91SpiSetRate(u_int base, u_int cs, uint32_t rate)
00343 {
00344     int rc = 0;
00345     u_int divider;
00346 
00347     /* The SPI clock is driven by the master clock. */
00348     divider = (u_int) At91GetMasterClock();
00349     /* Calculate the SPI clock divider. Avoid rounding errors. */
00350     divider += (u_int) (rate / 2);
00351     divider /= rate;
00352     /* A divider value of 0 is not allowed. */
00353     if (divider < 1) {
00354         divider = 1;
00355     }
00356     /* The divider value maximum is 255. */
00357     else if (divider > 255) {
00358         divider = 255;
00359     }
00360     switch (cs) {
00361     case 0:
00362         outr(base + SPI_CSR0_OFF, (inr(base + SPI_CSR0_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00363         break;
00364     case 1:
00365         outr(base + SPI_CSR1_OFF, (inr(base + SPI_CSR1_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00366         break;
00367     case 2:
00368         outr(base + SPI_CSR2_OFF, (inr(base + SPI_CSR2_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00369         break;
00370     case 3:
00371         outr(base + SPI_CSR3_OFF, (inr(base + SPI_CSR3_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00372         break;
00373     default:
00374         rc = -1;
00375         break;
00376     }
00377     return 0;
00378 }
00379 
00380 uint32_t At91SpiGetModeFlags(u_int base, u_int cs)
00381 {
00382     uint32_t rc = SPIMF_MFDETECT;
00383     u_int mv = inr(base + SPI_MR_OFF);
00384 
00385     if (mv & SPI_MSTR) {
00386         rc |= SPI_MSTR;
00387     }
00388     if (mv & SPI_PCSDEC) {
00389         rc |= SPIMF_MASTER;
00390     }
00391     if (mv & SPI_MODFDIS) {
00392         rc &= ~SPIMF_MFDETECT;
00393     }
00394     if (mv & SPI_LLB) {
00395         rc |= SPIMF_LOOPBACK;
00396     }
00397 
00398     mv = inr(base + SPI_CSR0_OFF + cs * 4);
00399     if (mv & SPI_CPOL) {
00400         if (mv & SPI_NCPHA) {
00401             rc |= SPIMF_SCKIAHI;
00402         } else {
00403             rc |= SPIMF_SCKIAHI | SPIMF_CAPRISE;
00404         }
00405     } else if (mv & SPI_NCPHA) {
00406         rc |= SPIMF_CAPRISE;
00407     }
00408     return rc;
00409 }
00410 
00425 int At91SpiSetModeFlags(u_int base, u_int cs, uint32_t mode)
00426 {
00427     u_int mv;
00428 
00429     mv = inr(base + SPI_MR_OFF) & ~(SPI_MSTR | SPI_PCSDEC | SPI_MODFDIS | SPI_LLB);
00430     if (mode & SPIMF_MASTER) {
00431         mv |= SPI_MSTR;
00432     }
00433     if (mode & SPIMF_PCSDEC) {
00434         mv |= SPI_PCSDEC;
00435     }
00436     if (mode & SPIMF_MFDETECT) {
00437         mv &= ~SPI_MODFDIS;
00438     }
00439     if (mode & SPIMF_LOOPBACK) {
00440         mv |= SPI_LLB;
00441     }
00442     outr(base + SPI_MR_OFF, mv);
00443 
00444     mv = inr(base + SPI_CSR0_OFF + cs * 4) & ~(SPI_CPOL | SPI_NCPHA | SPI_CSAAT);
00445     if (mode & SPIMF_SCKIAHI) {
00446         if (mode & SPIMF_CAPRISE) {
00447             mv |= SPI_CPOL;
00448         } else {
00449             mv |= SPI_CPOL | SPI_NCPHA;
00450         }
00451     } else {
00452         if (mode & SPIMF_CAPRISE) {
00453             mv |= SPI_NCPHA;
00454         }
00455     }
00456     if (mode & SPIMF_KEEPCS) {
00457         mv |= SPI_CSAAT;
00458     }
00459     outr(base + SPI_CSR0_OFF + cs * 4, mv);
00460 
00461     if (At91SpiGetModeFlags(base, cs) != mode) {
00462         return -1;
00463     }
00464     return 0;
00465 }
00466 
00467 u_int At91SpiGetBits(u_int base, u_int cs)
00468 {
00469     u_int rc;
00470 
00471     switch (inr(base + SPI_CSR0_OFF + cs * 4) & SPI_BITS) {
00472     case SPI_BITS_9:
00473         rc = 9;
00474         break;
00475     case SPI_BITS_10:
00476         rc = 10;
00477         break;
00478     case SPI_BITS_11:
00479         rc = 11;
00480         break;
00481     case SPI_BITS_12:
00482         rc = 12;
00483         break;
00484     case SPI_BITS_13:
00485         rc = 13;
00486         break;
00487     case SPI_BITS_14:
00488         rc = 14;
00489         break;
00490     case SPI_BITS_15:
00491         rc = 15;
00492         break;
00493     case SPI_BITS_16:
00494         rc = 16;
00495         break;
00496     default:
00497         rc = 8;
00498         break;
00499     }
00500     return rc;
00501 }
00502 
00503 int At91SpiSetBits(u_int base, u_int cs, u_int bits)
00504 {
00505     u_int mv;
00506 
00507     mv = inr(base + SPI_CSR0_OFF + cs * 4) & ~SPI_BITS;
00508     switch (bits) {
00509     case 9:
00510         mv |= SPI_BITS_9;
00511         break;
00512     case 10:
00513         mv |= SPI_BITS_10;
00514         break;
00515     case 11:
00516         mv |= SPI_BITS_11;
00517         break;
00518     case 12:
00519         mv |= SPI_BITS_12;
00520         break;
00521     case 13:
00522         mv |= SPI_BITS_13;
00523         break;
00524     case 14:
00525         mv |= SPI_BITS_14;
00526         break;
00527     case 15:
00528         mv |= SPI_BITS_15;
00529         break;
00530     case 16:
00531         mv |= SPI_BITS_16;
00532         break;
00533     default:
00534         mv |= SPI_BITS_8;
00535         break;
00536     }
00537     outr(base + SPI_CSR0_OFF + cs * 4, mv);
00538 
00539     if (At91SpiGetBits(base, cs) != bits) {
00540         return -1;
00541     }
00542     return 0;
00543 }
00544 
00545 u_int At91SpiGetSckDelay(u_int base, u_int cs)
00546 {
00547     return (inr(base + SPI_CSR0_OFF + cs * 4) & ~SPI_DLYBS) >> SPI_DLYBS_LSB;
00548 }
00549 
00550 int At91SpiSetSckDelay(u_int base, u_int cs, u_int dly)
00551 {
00552     u_int csr = base + SPI_CSR0_OFF + cs * 4;
00553 
00554     outr(csr, (inr(csr) & ~SPI_DLYBS) | ((dly << SPI_DLYBS_LSB) & SPI_DLYBS));
00555 
00556     if (At91SpiGetSckDelay(base, cs) != dly) {
00557         return -1;
00558     }
00559     return 0;
00560 }
00561 
00562 u_int At91SpiGetTxDelay(u_int base, u_int cs)
00563 {
00564     return (inr(base + SPI_CSR0_OFF + cs * 4) & ~SPI_DLYBCT) >> SPI_DLYBCT_LSB;
00565 }
00566 
00567 int At91SpiSetTxDelay(u_int base, u_int cs, u_int dly)
00568 {
00569     u_int csr = base + SPI_CSR0_OFF + cs * 4;
00570 
00571     outr(csr, (inr(csr) & ~SPI_DLYBCT) | ((dly << SPI_DLYBCT_LSB) & SPI_DLYBCT));
00572 
00573     if (At91SpiGetTxDelay(base, cs) != dly) {
00574         return -1;
00575     }
00576     return 0;
00577 }
00578 
00579 u_int At91SpiGetCsDelay(u_int base)
00580 {
00581     return (inr(base + SPI_MR_OFF) & ~SPI_DLYBCS) >> SPI_DLYBCS_LSB;
00582 }
00583 
00584 int At91SpiSetCsDelay(u_int base, u_int dly)
00585 {
00586     outr(base + SPI_MR_OFF, (inr(base + SPI_MR_OFF) & ~SPI_DLYBCS) | ((dly << SPI_DLYBCS_LSB) & SPI_DLYBCS));
00587 
00588     if (At91SpiGetCsDelay(base) != dly) {
00589         return -1;
00590     }
00591     return 0;
00592 }
00593 
00606 int At91SpiTransfer2(u_int base, u_int cs, CONST void *txbuf, void *rxbuf, int xlen, CONST void *txnbuf, void *rxnbuf, int xnlen)
00607 {
00608     int rc = -1;
00609     u_int flags;
00610     u_int sr;
00611 
00612     outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00613 
00614     flags = inr(base + SPI_MR_OFF) & ~SPI_PCS;
00615     switch (cs) {
00616     case 0:
00617         flags |= SPI_PCS_0;
00618         break;
00619     case 1:
00620         flags |= SPI_PCS_1;
00621         break;
00622     case 2:
00623         flags |= SPI_PCS_2;
00624         break;
00625     case 3:
00626         flags |= SPI_PCS_3;
00627         break;
00628     }
00629     outr(base + SPI_MR_OFF, flags);
00630 
00631     /* Set first transmit pointer and counter. */
00632     outr(base + PERIPH_TPR_OFF, (u_int) txbuf);
00633     outr(base + PERIPH_TCR_OFF, (u_int) xlen);
00634     /* Set first receive pointer and counter. */
00635     outr(base + PERIPH_RPR_OFF, (u_int) rxbuf);
00636     outr(base + PERIPH_RCR_OFF, (u_int) xlen);
00637 
00638     /* Set second transmit pointer and counter. */
00639     outr(base + PERIPH_TNPR_OFF, (u_int) txnbuf);
00640     outr(base + PERIPH_TNCR_OFF, (u_int) xnlen);
00641 
00642     /* Set second receive pointer and counter. */
00643     outr(base + PERIPH_RNPR_OFF, (u_int) rxnbuf);
00644     outr(base + PERIPH_RNCR_OFF, (u_int) xnlen);
00645 
00646     outr(base + SPI_IDR_OFF, (u_int) - 1);
00647     outr(base + SPI_IER_OFF, SPI_RXBUFF);
00648     outr(base + PERIPH_PTCR_OFF, PDC_TXTEN | PDC_RXTEN);
00649 
00650     while (((sr = inr(base + SPI_SR_OFF)) & SPI_RXBUFF) == 0) {
00651         if (base == SPI0_BASE) {
00652             if ((rc = NutEventWait(&spi0_que, 500)) != 0) {
00653                 break;
00654             }
00655         }
00656 #if defined(SPI1_BASE)
00657         else if (base == SPI1_BASE) {
00658             if ((rc = NutEventWait(&spi1_que, 500)) != 0) {
00659                 break;
00660             }
00661         }
00662 #endif
00663     }
00664     outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00665 
00666     return rc;
00667 }

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