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.3  2007/07/17 18:30:08  haraldkipp
00037  * Documentation added.
00038  *
00039  * Revision 1.2  2006/10/08 16:48:07  haraldkipp
00040  * Documentation fixed
00041  *
00042  * Revision 1.1  2006/09/29 12:34:59  haraldkipp
00043  * Basic AT91 SPI support added.
00044  *
00045  */
00046 #include <stdio.h>
00047 
00048 #include <cfg/arch.h>
00049 #include <dev/board.h>
00050 #include <dev/irqreg.h>
00051 
00052 #include <sys/event.h>
00053 #include <sys/timer.h>
00054 
00055 #include <dev/at91_spi.h>
00056 
00057 static HANDLE spi0_que;
00058 static HANDLE spi1_que;
00059 
00065 static void At91Spi0Interrupt(void *arg)
00066 {
00067     NutEventPostFromIrq(&spi0_que);
00068 }
00069 
00073 int At91Spi0Init(void)
00074 {
00075     /* Enable SPI peripherals. */
00076     At91Spi0Enable();
00077     /* Enable SPI clock. */
00078     outr(PMC_PCER, _BV(SPI0_ID));
00079 
00080     /* Register and enable SPI0 interrupt handler. */
00081     NutRegisterIrqHandler(&sig_SPI0, At91Spi0Interrupt, 0);
00082     NutIrqEnable(&sig_SPI0);
00083 
00084     return At91SpiReset(SPI0_BASE);
00085 }
00086 
00096 int At91Spi0InitChipSelects(u_int mask)
00097 {
00098     if (mask & _BV(0)) {
00099 #if defined(SPI0_CS0_PIN)
00100         outr(SPI0_CS0_PIO_BASE + SPI0_CS0_PSR_OFF, SPI0_CS0_PIN);
00101         outr(SPI0_CS0_PIO_BASE + PIO_PDR_OFF, SPI0_CS0_PIN);
00102         mask &= ~_BV(0);
00103 #endif                          /* SPI0_CS0_PIN */
00104     }
00105     if (mask & _BV(1)) {
00106 #if defined(SPI0_CS1_PIN)
00107         outr(SPI0_CS1_PIO_BASE + SPI0_CS1_PSR_OFF, SPI0_CS1_PIN);
00108         outr(SPI0_CS1_PIO_BASE + PIO_PDR_OFF, SPI0_CS1_PIN);
00109         mask &= ~_BV(1);
00110 #endif                          /* SPI0_CS1_PIN */
00111     }
00112     if (mask & _BV(2)) {
00113 #if defined(SPI0_CS2_PIN)
00114         outr(SPI0_CS2_PIO_BASE + SPI0_CS2_PSR_OFF, SPI0_CS2_PIN);
00115         outr(SPI0_CS2_PIO_BASE + PIO_PDR_OFF, SPI0_CS2_PIN);
00116         mask &= ~_BV(2);
00117 #endif                          /* SPI0_CS2_PIN */
00118     }
00119     if (mask & _BV(3)) {
00120 #if defined(SPI0_CS3_PIN)
00121         outr(SPI0_CS3_PIO_BASE + SPI0_CS3_PSR_OFF, SPI0_CS3_PIN);
00122         outr(SPI0_CS3_PIO_BASE + PIO_PDR_OFF, SPI0_CS3_PIN);
00123         mask &= ~_BV(3);
00124 #endif                          /* SPI0_CS3_PIN */
00125     }
00126     return mask ? -1 : 0;
00127 }
00128 
00132 int At91Spi0Enable(void)
00133 {
00134     /* Enable SPI peripherals. */
00135     outr(SPI0_PIO_BASE + SPI0_PSR_OFF, SPI0_PINS);
00136     outr(SPI0_PIO_BASE + PIO_PDR_OFF, SPI0_PINS);
00137 
00138     return 0;
00139 }
00140 
00141 #if defined(SPI1_BASE)
00142 
00148 static void At91Spi1Interrupt(void *arg)
00149 {
00150     NutEventPostFromIrq(&spi1_que);
00151 }
00152 
00156 int At91Spi1Init(void)
00157 {
00158     /* Enable SPI peripherals. */
00159     At91Spi1Enable();
00160     /* Enable SPI clock. */
00161     outr(PMC_PCER, _BV(SPI1_ID));
00162 
00163     /* Register and enable SPI1 interrupt handler. */
00164     NutRegisterIrqHandler(&sig_SPI1, At91Spi1Interrupt, 0);
00165     NutIrqEnable(&sig_SPI1);
00166 
00167     return At91SpiReset(SPI1_BASE);
00168 }
00169 
00179 int At91Spi1InitChipSelects(u_int mask)
00180 {
00181 #if defined(SPI1_CS0_PIN)
00182     if (mask & _BV(0)) {
00183         outr(SPI1_CS0_PIO_BASE + SPI1_CS0_PSR_OFF, SPI1_CS0_PIN);
00184         outr(SPI1_CS0_PIO_BASE + PIO_PDR_OFF, SPI1_CS0_PIN);
00185         mask &= ~_BV(0);
00186     }
00187 #endif                          /* SPI1_CS0_PIN */
00188 #if defined(SPI1_CS1_PIN)
00189     if (mask & _BV(1)) {
00190         outr(SPI1_CS1_PIO_BASE + SPI1_CS1_PSR_OFF, SPI1_CS1_PIN);
00191         outr(SPI1_CS1_PIO_BASE + PIO_PDR_OFF, SPI1_CS1_PIN);
00192         mask &= ~_BV(1);
00193     }
00194 #endif                          /* SPI1_CS1_PIN */
00195 #if defined(SPI1_CS2_PIN)
00196     if (mask & _BV(2)) {
00197         outr(SPI1_CS2_PIO_BASE + SPI1_CS2_PSR_OFF, SPI1_CS2_PIN);
00198         outr(SPI1_CS2_PIO_BASE + PIO_PDR_OFF, SPI1_CS2_PIN);
00199         mask &= ~_BV(2);
00200     }
00201 #endif                          /* SPI1_CS2_PIN */
00202 #if defined(SPI1_CS3_PIN)
00203     if (mask & _BV(3)) {
00204         outr(SPI1_CS3_PIO_BASE + SPI1_CS3_PSR_OFF, SPI1_CS3_PIN);
00205         outr(SPI1_CS3_PIO_BASE + PIO_PDR_OFF, SPI1_CS3_PIN);
00206         mask &= ~_BV(3);
00207     }
00208 #endif                          /* SPI1_CS3_PIN */
00209     return mask ? -1 : 0;
00210 }
00211 
00215 int At91Spi1Enable(void)
00216 {
00217     /* Enable SPI peripherals. */
00218     outr(SPI1_PIO_BASE + SPI1_PSR_OFF, SPI1_PINS);
00219     outr(SPI1_PIO_BASE + PIO_PDR_OFF, SPI1_PINS);
00220 
00221     return 0;
00222 }
00223 
00224 #endif                          /* SPI1_BASE */
00225 
00234 int At91SpiInit(u_int base)
00235 {
00236     int rc = -1;
00237 
00238     /* 
00239      * Enable PIO lines and clock. 
00240      */
00241     if (base == SPI0_BASE) {
00242         rc = At91Spi0Init();
00243     }
00244 #if defined(SPI1_BASE)
00245     if (base == SPI1_BASE) {
00246         rc = At91Spi1Init();
00247     }
00248 #endif
00249     return rc;
00250 }
00251 
00252 int At91SpiEnable(u_int base)
00253 {
00254     outr(base + SPI_CR_OFF, SPI_SPIEN);
00255 
00256     return 0;
00257 }
00258 
00259 int At91SpiDisable(u_int base)
00260 {
00261     outr(base + SPI_CR_OFF, SPI_SPIDIS);
00262 
00263     return 0;
00264 }
00265 
00274 int At91SpiReset(u_int base)
00275 {
00276     int rc = -1;
00277 
00278     /* Disable SPI. */
00279     At91SpiDisable(base);
00280 
00281     /* Reset SPI. */
00282     outr(base + SPI_CR_OFF, SPI_SWRST);
00283 
00284     /* Set SPI to master mode, fixed peripheral at no chip select, fault detection disabled. */
00285     outr(base + SPI_MR_OFF, (90 < SPI_DLYBCS_LSB) | SPI_PCS | SPI_MODFDIS | SPI_MSTR);
00286 
00287     /* Enable SPI. */
00288     At91SpiEnable(base);
00289 
00290     return rc;
00291 }
00292 
00304 int At91SpiInitChipSelects(u_int base, u_int mask)
00305 {
00306     int rc = -1;
00307 
00308     /* Init chip select lines for SPI 0. */
00309     if (base == SPI0_BASE) {
00310         rc = At91Spi0InitChipSelects(mask);
00311     }
00312     /* Init chip select lines for SPI 1. */
00313 #if defined(SPI1_BASE)
00314     if (base == SPI1_BASE) {
00315         rc = At91Spi1InitChipSelects(mask);
00316     }
00317 #endif
00318     return rc;
00319 }
00320 
00330 int At91SpiSetRate(u_int base, u_int cs, u_long rate)
00331 {
00332     int rc = 0;
00333     u_int divider;
00334 
00335     /* The SPI clock is driven by the master clock. */
00336     divider = (u_int) At91GetMasterClock();
00337     /* Calculate the SPI clock divider. Avoid rounding errors. */
00338     divider += (u_int) (rate / 2);
00339     divider /= rate;
00340     /* A divider value of 0 is not allowed. */
00341     if (divider < 1) {
00342         divider = 1;
00343     }
00344     /* The divider value maximum is 255. */
00345     else if (divider > 255) {
00346         divider = 255;
00347     }
00348     switch (cs) {
00349     case 0:
00350         outr(base + SPI_CSR0_OFF, (inr(base + SPI_CSR0_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00351         break;
00352     case 1:
00353         outr(base + SPI_CSR1_OFF, (inr(base + SPI_CSR1_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00354         break;
00355     case 2:
00356         outr(base + SPI_CSR2_OFF, (inr(base + SPI_CSR2_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00357         break;
00358     case 3:
00359         outr(base + SPI_CSR3_OFF, (inr(base + SPI_CSR3_OFF) & ~SPI_SCBR) | (divider << SPI_SCBR_LSB));
00360         break;
00361     default:
00362         rc = -1;
00363         break;
00364     }
00365     return 0;
00366 }
00367 
00368 u_long At91SpiGetModeFlags(u_int base, u_int cs)
00369 {
00370     u_long rc = SPIMF_MFDETECT;
00371     u_int mv = inr(base + SPI_MR_OFF);
00372 
00373     if (mv & SPI_MSTR) {
00374         rc |= SPI_MSTR;
00375     }
00376     if (mv & SPI_PCSDEC) {
00377         rc |= SPIMF_MASTER;
00378     }
00379     if (mv & SPI_MODFDIS) {
00380         rc &= ~SPIMF_MFDETECT;
00381     }
00382     if (mv & SPI_LLB) {
00383         rc |= SPIMF_LOOPBACK;
00384     }
00385 
00386     mv = inr(base + SPI_CSR0_OFF + cs * 4);
00387     if (mv & SPI_CPOL) {
00388         if (mv & SPI_NCPHA) {
00389             rc |= SPIMF_SCKIAHI;
00390         } else {
00391             rc |= SPIMF_SCKIAHI | SPIMF_CAPRISE;
00392         }
00393     } else if (mv & SPI_NCPHA) {
00394         rc |= SPIMF_CAPRISE;
00395     }
00396     return rc;
00397 }
00398 
00413 int At91SpiSetModeFlags(u_int base, u_int cs, u_long mode)
00414 {
00415     u_int mv;
00416 
00417     mv = inr(base + SPI_MR_OFF) & ~(SPI_MSTR | SPI_PCSDEC | SPI_MODFDIS | SPI_LLB);
00418     if (mode & SPIMF_MASTER) {
00419         mv |= SPI_MSTR;
00420     }
00421     if (mode & SPIMF_PCSDEC) {
00422         mv |= SPI_PCSDEC;
00423     }
00424     if (mode & SPIMF_MFDETECT) {
00425         mv &= ~SPI_MODFDIS;
00426     }
00427     if (mode & SPIMF_LOOPBACK) {
00428         mv |= SPI_LLB;
00429     }
00430     outr(base + SPI_MR_OFF, mv);
00431 
00432     mv = inr(base + SPI_CSR0_OFF + cs * 4) & ~(SPI_CPOL | SPI_NCPHA | SPI_CSAAT);
00433     if (mode & SPIMF_SCKIAHI) {
00434         if (mode & SPIMF_CAPRISE) {
00435             mv |= SPI_CPOL;
00436         } else {
00437             mv |= SPI_CPOL | SPI_NCPHA;
00438         }
00439     } else {
00440         if (mode & SPIMF_CAPRISE) {
00441             mv |= SPI_NCPHA;
00442         }
00443     }
00444     if (mode & SPIMF_KEEPCS) {
00445         mv |= SPI_CSAAT;
00446     }
00447     outr(base + SPI_CSR0_OFF + cs * 4, mv);
00448 
00449     if (At91SpiGetModeFlags(base, cs) != mode) {
00450         return -1;
00451     }
00452     return 0;
00453 }
00454 
00455 u_int At91SpiGetBits(u_int base, u_int cs)
00456 {
00457     u_int rc;
00458 
00459     switch (inr(base + SPI_CSR0_OFF + cs * 4) & SPI_BITS) {
00460     case SPI_BITS_9:
00461         rc = 9;
00462         break;
00463     case SPI_BITS_10:
00464         rc = 10;
00465         break;
00466     case SPI_BITS_11:
00467         rc = 11;
00468         break;
00469     case SPI_BITS_12:
00470         rc = 12;
00471         break;
00472     case SPI_BITS_13:
00473         rc = 13;
00474         break;
00475     case SPI_BITS_14:
00476         rc = 14;
00477         break;
00478     case SPI_BITS_15:
00479         rc = 15;
00480         break;
00481     case SPI_BITS_16:
00482         rc = 16;
00483         break;
00484     default:
00485         rc = 8;
00486         break;
00487     }
00488     return rc;
00489 }
00490 
00491 int At91SpiSetBits(u_int base, u_int cs, u_int bits)
00492 {
00493     u_int mv;
00494 
00495     mv = inr(base + SPI_CSR0_OFF + cs * 4) & ~SPI_BITS;
00496     switch (bits) {
00497     case 9:
00498         mv |= SPI_BITS_9;
00499         break;
00500     case 10:
00501         mv |= SPI_BITS_10;
00502         break;
00503     case 11:
00504         mv |= SPI_BITS_11;
00505         break;
00506     case 12:
00507         mv |= SPI_BITS_12;
00508         break;
00509     case 13:
00510         mv |= SPI_BITS_13;
00511         break;
00512     case 14:
00513         mv |= SPI_BITS_14;
00514         break;
00515     case 15:
00516         mv |= SPI_BITS_15;
00517         break;
00518     case 16:
00519         mv |= SPI_BITS_16;
00520         break;
00521     default:
00522         mv |= SPI_BITS_8;
00523         break;
00524     }
00525     outr(base + SPI_CSR0_OFF + cs * 4, mv);
00526 
00527     if (At91SpiGetBits(base, cs) != bits) {
00528         return -1;
00529     }
00530     return 0;
00531 }
00532 
00533 u_int At91SpiGetSckDelay(u_int base, u_int cs)
00534 {
00535     return (inr(base + SPI_CSR0_OFF + cs * 4) & ~SPI_DLYBS) >> SPI_DLYBS_LSB;
00536 }
00537 
00538 int At91SpiSetSckDelay(u_int base, u_int cs, u_int dly)
00539 {
00540     u_int csr = base + SPI_CSR0_OFF + cs * 4;
00541 
00542     outr(csr, (inr(csr) & ~SPI_DLYBS) | ((dly << SPI_DLYBS_LSB) & SPI_DLYBS));
00543 
00544     if (At91SpiGetSckDelay(base, cs) != dly) {
00545         return -1;
00546     }
00547     return 0;
00548 }
00549 
00550 u_int At91SpiGetTxDelay(u_int base, u_int cs)
00551 {
00552     return (inr(base + SPI_CSR0_OFF + cs * 4) & ~SPI_DLYBCT) >> SPI_DLYBCT_LSB;
00553 }
00554 
00555 int At91SpiSetTxDelay(u_int base, u_int cs, u_int dly)
00556 {
00557     u_int csr = base + SPI_CSR0_OFF + cs * 4;
00558 
00559     outr(csr, (inr(csr) & ~SPI_DLYBCT) | ((dly << SPI_DLYBCT_LSB) & SPI_DLYBCT));
00560 
00561     if (At91SpiGetTxDelay(base, cs) != dly) {
00562         return -1;
00563     }
00564     return 0;
00565 }
00566 
00567 u_int At91SpiGetCsDelay(u_int base)
00568 {
00569     return (inr(base + SPI_MR_OFF) & ~SPI_DLYBCS) >> SPI_DLYBCS_LSB;
00570 }
00571 
00572 int At91SpiSetCsDelay(u_int base, u_int dly)
00573 {
00574     outr(base + SPI_MR_OFF, (inr(base + SPI_MR_OFF) & ~SPI_DLYBCS) | ((dly << SPI_DLYBCS_LSB) & SPI_DLYBCS));
00575 
00576     if (At91SpiGetCsDelay(base) != dly) {
00577         return -1;
00578     }
00579     return 0;
00580 }
00581 
00594 int At91SpiTransfer2(u_int base, u_int cs, CONST void *txbuf, void *rxbuf, int xlen, CONST void *txnbuf, void *rxnbuf, int xnlen)
00595 {
00596     int rc = -1;
00597     u_int flags;
00598     u_int sr;
00599 
00600     outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00601 
00602     flags = inr(base + SPI_MR_OFF) & ~SPI_PCS;
00603     switch (cs) {
00604     case 0:
00605         flags |= SPI_PCS_0;
00606         break;
00607     case 1:
00608         flags |= SPI_PCS_1;
00609         break;
00610     case 2:
00611         flags |= SPI_PCS_2;
00612         break;
00613     case 3:
00614         flags |= SPI_PCS_3;
00615         break;
00616     }
00617     outr(base + SPI_MR_OFF, flags);
00618 
00619     /* Set first transmit pointer and counter. */
00620     outr(base + PERIPH_TPR_OFF, (u_int) txbuf);
00621     outr(base + PERIPH_TCR_OFF, (u_int) xlen);
00622     /* Set first receive pointer and counter. */
00623     outr(base + PERIPH_RPR_OFF, (u_int) rxbuf);
00624     outr(base + PERIPH_RCR_OFF, (u_int) xlen);
00625 
00626     /* Set second transmit pointer and counter. */
00627     outr(base + PERIPH_TNPR_OFF, (u_int) txnbuf);
00628     outr(base + PERIPH_TNCR_OFF, (u_int) xnlen);
00629 
00630     /* Set second receive pointer and counter. */
00631     outr(base + PERIPH_RNPR_OFF, (u_int) rxnbuf);
00632     outr(base + PERIPH_RNCR_OFF, (u_int) xnlen);
00633 
00634     outr(base + SPI_IDR_OFF, (u_int) - 1);
00635     outr(base + SPI_IER_OFF, SPI_RXBUFF);
00636     outr(base + PERIPH_PTCR_OFF, PDC_TXTEN | PDC_RXTEN);
00637 
00638     while (((sr = inr(base + SPI_SR_OFF)) & SPI_RXBUFF) == 0) {
00639         if (base == SPI0_BASE) {
00640             if ((rc = NutEventWait(&spi0_que, 500)) != 0) {
00641                 printf("[TO]");
00642                 break;
00643             }
00644         }
00645 #if defined(SPI1_BASE)
00646         else if (base == SPI1_BASE) {
00647             if ((rc = NutEventWait(&spi1_que, 500)) != 0) {
00648                 break;
00649             }
00650         }
00651 #endif
00652     }
00653     outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00654 
00655     return rc;
00656 }

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