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

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