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