Nut/OS  4.10.3
API Reference
spibus0at91.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2009 by egnite GmbH
00003  *
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in the
00014  *    documentation and/or other materials provided with the distribution.
00015  * 3. Neither the name of the copyright holders nor the names of
00016  *    contributors may be used to endorse or promote products derived
00017  *    from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00020  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00023  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00024  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00025  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00026  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00027  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00029  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  *
00032  * For additional information see http://www.ethernut.de/
00033  */
00034 
00047 #include <cfg/spi.h>
00048 #include <cfg/arch/gpio.h>
00049 
00050 #include <dev/spibus_at91.h>
00051 #include <dev/irqreg.h>
00052 #include <sys/event.h>
00053 #include <sys/nutdebug.h>
00054 
00055 #include <stdlib.h>
00056 #include <errno.h>
00057 
00058 #if defined(SPI0_CS0_PIO_BIT)
00059 #if defined(SPI0_CS0_PIO_ID)
00060 #undef GPIO_ID
00061 #define GPIO_ID SPI0_CS0_PIO_ID
00062 #include <cfg/arch/porttran.h>
00063 static INLINE void SPI0_CS0_LO(void)
00064 {
00065     GPIO_SET_LO(SPI0_CS0_PIO_BIT);
00066 }
00067 
00068 static INLINE void SPI0_CS0_HI(void)
00069 {
00070     GPIO_SET_HI(SPI0_CS0_PIO_BIT);
00071 }
00072 
00073 static INLINE void SPI0_CS0_SO(void)
00074 {
00075     GPIO_ENABLE(SPI0_CS0_PIO_BIT);
00076     GPIO_OUTPUT(SPI0_CS0_PIO_BIT);
00077 }
00078 #else
00079 #define SPI0_CS0_LO()
00080 #define SPI0_CS0_HI()
00081 #define SPI0_CS0_SO()
00082 #endif
00083 #endif
00084 
00085 #if defined(SPI0_CS1_PIO_BIT)
00086 #if defined(SPI0_CS1_PIO_ID)
00087 #undef GPIO_ID
00088 #define GPIO_ID SPI0_CS1_PIO_ID
00089 #include <cfg/arch/porttran.h>
00090 static INLINE void SPI0_CS1_LO(void)
00091 {
00092     GPIO_SET_LO(SPI0_CS1_PIO_BIT);
00093 }
00094 
00095 static INLINE void SPI0_CS1_HI(void)
00096 {
00097     GPIO_SET_HI(SPI0_CS1_PIO_BIT);
00098 }
00099 
00100 static INLINE void SPI0_CS1_SO(void)
00101 {
00102     GPIO_ENABLE(SPI0_CS1_PIO_BIT);
00103     GPIO_OUTPUT(SPI0_CS1_PIO_BIT);
00104 }
00105 #else
00106 #define SPI0_CS1_LO()
00107 #define SPI0_CS1_HI()
00108 #define SPI0_CS1_SO()
00109 #endif
00110 #endif
00111 
00112 #if defined(SPI0_CS2_PIO_BIT)
00113 #if defined(SPI0_CS2_PIO_ID)
00114 #undef GPIO_ID
00115 #define GPIO_ID SPI0_CS2_PIO_ID
00116 #include <cfg/arch/porttran.h>
00117 static INLINE void SPI0_CS2_LO(void)
00118 {
00119     GPIO_SET_LO(SPI0_CS2_PIO_BIT);
00120 }
00121 
00122 static INLINE void SPI0_CS2_HI(void)
00123 {
00124     GPIO_SET_HI(SPI0_CS2_PIO_BIT);
00125 }
00126 
00127 static INLINE void SPI0_CS2_SO(void)
00128 {
00129     GPIO_ENABLE(SPI0_CS2_PIO_BIT);
00130     GPIO_OUTPUT(SPI0_CS2_PIO_BIT);
00131 }
00132 #else
00133 #define SPI0_CS2_LO()
00134 #define SPI0_CS2_HI()
00135 #define SPI0_CS2_SO()
00136 #endif
00137 #endif
00138 
00139 #if defined(SPI0_CS3_PIO_BIT)
00140 #if defined(SPI0_CS3_PIO_ID)
00141 #undef GPIO_ID
00142 #define GPIO_ID SPI0_CS3_PIO_ID
00143 #include <cfg/arch/porttran.h>
00144 static INLINE void SPI0_CS3_LO(void)
00145 {
00146     GPIO_SET_LO(SPI0_CS3_PIO_BIT);
00147 }
00148 
00149 static INLINE void SPI0_CS3_HI(void)
00150 {
00151     GPIO_SET_HI(SPI0_CS3_PIO_BIT);
00152 }
00153 
00154 static INLINE void SPI0_CS3_SO(void)
00155 {
00156     GPIO_ENABLE(SPI0_CS3_PIO_BIT);
00157     GPIO_OUTPUT(SPI0_CS3_PIO_BIT);
00158 }
00159 #else
00160 #define SPI0_CS3_LO()
00161 #define SPI0_CS3_HI()
00162 #define SPI0_CS3_SO()
00163 #endif
00164 #endif
00165 
00169 int At91Spi0ChipSelect(uint_fast8_t cs, uint_fast8_t hi)
00170 {
00171     int rc = 0;
00172 
00173     switch (cs) {
00174 #if defined(SPI0_CS0_PIO_BIT)
00175     case 0:
00176         if (hi) {
00177             SPI0_CS0_HI();
00178         } else {
00179             SPI0_CS0_LO();
00180         }
00181         SPI0_CS0_SO();
00182         break;
00183 #endif
00184 #if defined(SPI0_CS1_PIO_BIT)
00185     case 1:
00186         if (hi) {
00187             SPI0_CS1_HI();
00188         } else {
00189             SPI0_CS1_LO();
00190         }
00191         SPI0_CS1_SO();
00192         break;
00193 #endif
00194 #if defined(SPI0_CS2_PIO_BIT)
00195     case 2:
00196         if (hi) {
00197             SPI0_CS2_HI();
00198         } else {
00199             SPI0_CS2_LO();
00200         }
00201         SPI0_CS2_SO();
00202         break;
00203 #endif
00204 #if defined(SPI0_CS3_PIO_BIT)
00205     case 3:
00206         if (hi) {
00207             SPI0_CS3_HI();
00208         } else {
00209             SPI0_CS3_LO();
00210         }
00211         SPI0_CS3_SO();
00212         break;
00213 #endif
00214     default:
00215         errno = EIO;
00216         rc = -1;
00217         break;
00218     }
00219     return rc;
00220 }
00221 
00233 int At91SpiBus0Select(NUTSPINODE * node, uint32_t tmo)
00234 {
00235     int rc;
00236 
00237     /* Sanity check. */
00238     NUTASSERT(node != NULL);
00239     NUTASSERT(node->node_bus != NULL);
00240     NUTASSERT(node->node_stat != NULL);
00241 
00242     /* Allocate the bus. */
00243     rc = NutEventWait(&node->node_bus->bus_mutex, tmo);
00244     if (rc) {
00245         errno = EIO;
00246     } else {
00247         AT91SPIREG *spireg = node->node_stat;
00248 
00249         outr(PMC_PCER, _BV(SPI0_ID));
00250 
00251         /* Enable SPI peripherals and clock. */
00252         outr(SPI0_PIO_BASE + SPI0_PSR_OFF, SPI0_PINS);
00253         outr(SPI0_PIO_BASE + PIO_PDR_OFF, SPI0_PINS);
00254 
00255         /* If the mode update bit is set, then update our shadow registers. */
00256         if (node->node_mode & SPI_MODE_UPDATE) {
00257             At91SpiSetup(node);
00258         }
00259 
00260         /* Enable SPI. */
00261         outr(SPI0_CR, SPI_SPIEN);
00262         /* Set SPI mode. */
00263         outr(SPI0_MR, spireg->at91spi_mr);
00264         outr(SPI0_CSR0 + node->node_cs * 4, spireg->at91spi_csr);
00265 
00266         /* Finally activate the node's chip select. */
00267         rc = At91Spi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) != 0);
00268         if (rc) {
00269             /* Release the bus in case of an error. */
00270             NutEventPost(&node->node_bus->bus_mutex);
00271         }
00272     }
00273     return rc;
00274 }
00275 
00284 int At91SpiBus0Deselect(NUTSPINODE * node)
00285 {
00286     /* Sanity check. */
00287     NUTASSERT(node != NULL);
00288     NUTASSERT(node->node_bus != NULL);
00289 
00290 #ifdef SPIBUS0_DOUBLE_BUFFER
00291     At91SpiBusWait(node, NUT_WAIT_INFINITE);
00292 #endif
00293     /* Deactivate the node's chip select. */
00294     At91Spi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0);
00295 
00296 #ifdef SPIBUS0_PIN_SHARING
00297     /* Disable SPI peripherals if pins are shared. */
00298     outr(SPI0_PIO_BASE + PIO_ODR_OFF, SPI0_PINS);
00299     outr(SPI0_PIO_BASE + PIO_PER_OFF, SPI0_PINS);
00300 #endif
00301 
00302     /* Release the bus. */
00303     NutEventPost(&node->node_bus->bus_mutex);
00304 
00305     return 0;
00306 }
00307 
00308 #if !defined(SPIBUS0_POLLING_MODE) || !defined(SPIBUS0_DOUBLE_BUFFER)
00309 
00310 static uint8_t * volatile spi0_txp;
00311 static uint8_t * volatile spi0_rxp;
00312 static volatile size_t spi0_xc;
00313 
00314 void At91SpiBus0Interrupt(void *arg)
00315 {
00316     uint8_t b;
00317 
00318     /* Get the received byte. */
00319     b = inb(SPI0_RDR);
00320     if (spi0_xc) {
00321         if (spi0_rxp) {
00322             *spi0_rxp++ = b;
00323         }
00324         spi0_xc--;
00325     }
00326     if (spi0_xc) {
00327         if (spi0_txp) {
00328             b = *spi0_txp++;
00329         }
00330         outb(SPI0_TDR, b);
00331     } else {
00332         NutEventPostFromIrq((void **)arg);
00333     }
00334 }
00335 
00350 int At91SpiBus0Transfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen)
00351 {
00352     uint8_t b = 0xff;
00353     uintptr_t base;
00354 
00355     /* Sanity check. */
00356     NUTASSERT(node != NULL);
00357     NUTASSERT(node->node_bus != NULL);
00358     NUTASSERT(node->node_bus->bus_base != 0);
00359     base = node->node_bus->bus_base;
00360 
00361     if (xlen) {
00362         spi0_txp = (uint8_t *) txbuf;
00363         spi0_rxp = (uint8_t *) rxbuf;
00364         spi0_xc = (size_t) xlen;
00365         if (spi0_txp) {
00366             b = *spi0_txp++;
00367         }
00368         /* Enable and kick interrupts. */
00369         outr(base + SPI_IER_OFF, SPI_RDRF);
00370         outr(base + SPI_TDR_OFF, b);
00371         /* Wait until transfer has finished. */
00372         NutEventWait(&node->node_bus->bus_ready, NUT_WAIT_INFINITE);
00373         outr(base + SPI_IDR_OFF, (unsigned int) - 1);
00374     }
00375     return 0;
00376 }
00377 #endif
00378 
00382 NUTSPIBUS spiBus0At91 = {
00383     NULL,                       
00384     NULL,                       
00385     SPI0_BASE,                  
00386     &sig_SPI0,                  
00387     At91SpiBusNodeInit,         
00388     At91SpiBus0Select,          
00389     At91SpiBus0Deselect,        
00390 #if defined(SPIBUS0_POLLING_MODE)
00391     At91SpiBusPollTransfer,     
00392 #elif defined(SPIBUS0_DOUBLE_BUFFER)
00393     At91SpiBusDblBufTransfer,
00394 #else
00395     At91SpiBus0Transfer,
00396 #endif
00397 #ifdef SPIBUS0_DOUBLE_BUFFER
00398     At91SpiBusWait,
00399 #else
00400     NutSpiBusWait,              
00401 #endif
00402     NutSpiBusSetMode,           
00403     NutSpiBusSetRate,           
00404     NutSpiBusSetBits            
00405 };