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) { GPIO_SET_LO(SPI0_CS0_PIO_BIT); }
00064 static INLINE void SPI0_CS0_HI(void) { GPIO_SET_HI(SPI0_CS0_PIO_BIT); }
00065 static INLINE void SPI0_CS0_SO(void) { GPIO_OUTPUT(SPI0_CS0_PIO_BIT); }
00066 #else
00067 #define SPI0_CS0_LO()
00068 #define SPI0_CS0_HI()
00069 #define SPI0_CS0_SO()
00070 #endif
00071 #endif
00072 
00073 #if defined(SPI0_CS1_PIO_BIT)
00074 #if defined(SPI0_CS1_PIO_ID)
00075 #undef GPIO_ID
00076 #define GPIO_ID SPI0_CS1_PIO_ID
00077 #include <cfg/arch/porttran.h>
00078 static INLINE void SPI0_CS1_LO(void) { GPIO_SET_LO(SPI0_CS1_PIO_BIT); }
00079 static INLINE void SPI0_CS1_HI(void) { GPIO_SET_HI(SPI0_CS1_PIO_BIT); }
00080 static INLINE void SPI0_CS1_SO(void) { GPIO_OUTPUT(SPI0_CS1_PIO_BIT); }
00081 #else
00082 #define SPI0_CS1_LO()
00083 #define SPI0_CS1_HI()
00084 #define SPI0_CS1_SO()
00085 #endif
00086 #endif
00087 
00088 #if defined(SPI0_CS2_PIO_BIT)
00089 #if defined(SPI0_CS2_PIO_ID)
00090 #undef GPIO_ID
00091 #define GPIO_ID SPI0_CS2_PIO_ID
00092 #include <cfg/arch/porttran.h>
00093 static INLINE void SPI0_CS2_LO(void) { GPIO_SET_LO(SPI0_CS2_PIO_BIT); }
00094 static INLINE void SPI0_CS2_HI(void) { GPIO_SET_HI(SPI0_CS2_PIO_BIT); }
00095 static INLINE void SPI0_CS2_SO(void) { GPIO_OUTPUT(SPI0_CS2_PIO_BIT); }
00096 #else
00097 #define SPI0_CS2_LO()
00098 #define SPI0_CS2_HI()
00099 #define SPI0_CS2_SO()
00100 #endif
00101 #endif
00102 
00103 #if defined(SPI0_CS3_PIO_BIT)
00104 #if defined(SPI0_CS3_PIO_ID)
00105 #undef GPIO_ID
00106 #define GPIO_ID SPI0_CS3_PIO_ID
00107 #include <cfg/arch/porttran.h>
00108 static INLINE void SPI0_CS3_LO(void) { GPIO_SET_LO(SPI0_CS3_PIO_BIT); }
00109 static INLINE void SPI0_CS3_HI(void) { GPIO_SET_HI(SPI0_CS3_PIO_BIT); }
00110 static INLINE void SPI0_CS3_SO(void) { GPIO_OUTPUT(SPI0_CS3_PIO_BIT); }
00111 #else
00112 #define SPI0_CS3_LO()
00113 #define SPI0_CS3_HI()
00114 #define SPI0_CS3_SO()
00115 #endif
00116 #endif
00117 
00121 int At91Spi0ChipSelect(uint_fast8_t cs, uint_fast8_t hi)
00122 {
00123     int rc = 0;
00124 
00125     switch (cs) {
00126 #if defined(SPI0_CS0_PIO_BIT)
00127     case 0:
00128         if (hi) {
00129             SPI0_CS0_HI();
00130         } else {
00131             SPI0_CS0_LO();
00132         }
00133         SPI0_CS0_SO();
00134         break;
00135 #endif
00136 #if defined(SPI0_CS1_PIO_BIT)
00137     case 1:
00138         if (hi) {
00139             SPI0_CS1_HI();
00140         } else {
00141             SPI0_CS1_LO();
00142         }
00143         SPI0_CS1_SO();
00144         break;
00145 #endif
00146 #if defined(SPI0_CS2_PIO_BIT)
00147     case 2:
00148         if (hi) {
00149             SPI0_CS2_HI();
00150         } else {
00151             SPI0_CS2_LO();
00152         }
00153         SPI0_CS2_SO();
00154         break;
00155 #endif
00156 #if defined(SPI0_CS3_PIO_BIT)
00157     case 3:
00158         if (hi) {
00159             SPI0_CS3_HI();
00160         } else {
00161             SPI0_CS3_LO();
00162         }
00163         SPI0_CS3_SO();
00164         break;
00165 #endif
00166     default:
00167         errno = EIO;
00168         rc = -1;
00169         break;
00170     }
00171     return rc;
00172 }
00173 
00185 int At91SpiBus0Select(NUTSPINODE * node, uint32_t tmo)
00186 {
00187     int rc;
00188 
00189     /* Sanity check. */
00190     NUTASSERT(node != NULL);
00191     NUTASSERT(node->node_bus != NULL);
00192     NUTASSERT(node->node_stat != NULL);
00193 
00194     /* Allocate the bus. */
00195     rc = NutEventWait(&node->node_bus->bus_mutex, tmo);
00196     if (rc) {
00197         errno = EIO;
00198     } else {
00199         AT91SPIREG *spireg = node->node_stat;
00200 
00201         outr(PMC_PCER, _BV(SPI0_ID));
00202 
00203         /* Enable SPI peripherals and clock. */
00204         outr(SPI0_PIO_BASE + SPI0_PSR_OFF, SPI0_PINS);
00205         outr(SPI0_PIO_BASE + PIO_PDR_OFF, SPI0_PINS);
00206 
00207         /* If the mode update bit is set, then update our shadow registers. */
00208         if (node->node_mode & SPI_MODE_UPDATE) {
00209             At91SpiSetup(node);
00210         }
00211 
00212         /* Enable SPI. */
00213         outr(SPI0_CR, SPI_SPIEN);
00214         /* Set SPI mode. */
00215         outr(SPI0_MR, spireg->at91spi_mr);
00216         outr(SPI0_CSR0 + node->node_cs * 4, spireg->at91spi_csr);
00217 
00218         /* Finally activate the node's chip select. */
00219         rc = At91Spi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) != 0);
00220         if (rc) {
00221             /* Release the bus in case of an error. */
00222             NutEventPost(&node->node_bus->bus_mutex);
00223         }
00224     }
00225     return rc;
00226 }
00227 
00236 int At91SpiBus0Deselect(NUTSPINODE * node)
00237 {
00238     /* Sanity check. */
00239     NUTASSERT(node != NULL);
00240     NUTASSERT(node->node_bus != NULL);
00241 
00242 #ifdef SPIBUS0_DOUBLE_BUFFER
00243     At91SpiBusWait(node, NUT_WAIT_INFINITE);
00244 #endif
00245     /* Deactivate the node's chip select. */
00246     At91Spi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0);
00247 
00248     /* Release the bus. */
00249     NutEventPost(&node->node_bus->bus_mutex);
00250 
00251     return 0;
00252 }
00253 
00254 #if !defined(SPIBUS0_POLLING_MODE) || !defined(SPIBUS0_DOUBLE_BUFFER)
00255 
00256 static uint8_t * volatile spi0_txp;
00257 static uint8_t * volatile spi0_rxp;
00258 static volatile size_t spi0_xc;
00259 
00260 void At91SpiBus0Interrupt(void *arg)
00261 {
00262     uint8_t b;
00263 
00264     /* Get the received byte. */
00265     b = inb(SPI0_RDR);
00266     if (spi0_xc) {
00267         if (spi0_rxp) {
00268             *spi0_rxp++ = b;
00269         }
00270         spi0_xc--;
00271     }
00272     if (spi0_xc) {
00273         if (spi0_txp) {
00274             b = *spi0_txp++;
00275         }
00276         outb(SPI0_TDR, b);
00277     } else {
00278         NutEventPostFromIrq((void **)arg);
00279     }
00280 }
00281 
00296 int At91SpiBus0Transfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen)
00297 {
00298     uint8_t b = 0xff;
00299     uintptr_t base;
00300 
00301     /* Sanity check. */
00302     NUTASSERT(node != NULL);
00303     NUTASSERT(node->node_bus != NULL);
00304     NUTASSERT(node->node_bus->bus_base != 0);
00305     base = node->node_bus->bus_base;
00306 
00307     if (xlen) {
00308         spi0_txp = (uint8_t *) txbuf;
00309         spi0_rxp = (uint8_t *) rxbuf;
00310         spi0_xc = (size_t) xlen;
00311         if (spi0_txp) {
00312             b = *spi0_txp++;
00313         }
00314         /* Enable and kick interrupts. */
00315         outr(base + SPI_IER_OFF, SPI_RDRF);
00316         outr(base + SPI_TDR_OFF, b);
00317         /* Wait until transfer has finished. */
00318         NutEventWait(&node->node_bus->bus_ready, NUT_WAIT_INFINITE);
00319         outr(base + SPI_IDR_OFF, (unsigned int) - 1);
00320     }
00321     return 0;
00322 }
00323 #endif
00324 
00328 NUTSPIBUS spiBus0At91 = {
00329     NULL,                       
00330     NULL,                       
00331     SPI0_BASE,                  
00332     &sig_SPI0,                  
00333     At91SpiBusNodeInit,         
00334     At91SpiBus0Select,          
00335     At91SpiBus0Deselect,        
00336 #if defined(SPIBUS0_POLLING_MODE)
00337     At91SpiBusPollTransfer,     
00338 #elif defined(SPIBUS0_DOUBLE_BUFFER)
00339     At91SpiBusDblBufTransfer,
00340 #else
00341     At91SpiBus0Transfer,
00342 #endif
00343 #ifdef SPIBUS0_DOUBLE_BUFFER
00344     At91SpiBusWait,
00345 #else
00346     NutSpiBusWait,              
00347 #endif
00348     NutSpiBusSetMode,           
00349     NutSpiBusSetRate,           
00350     NutSpiBusSetBits            
00351 };

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