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

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