spibus1at91.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(SPI1_PIO_BASE)
00059 
00060 #if defined(SPI1_CS0_PIO_BIT)
00061 #if defined(SPI1_CS0_PIO_ID)
00062 #undef GPIO_ID
00063 #define GPIO_ID SPI1_CS0_PIO_ID
00064 #include <cfg/arch/porttran.h>
00065 static INLINE void SPI1_CS0_LO(void) { GPIO_SET_LO(SPI1_CS0_PIO_BIT); }
00066 static INLINE void SPI1_CS0_HI(void) { GPIO_SET_HI(SPI1_CS0_PIO_BIT); }
00067 static INLINE void SPI1_CS0_SO(void) { GPIO_OUTPUT(SPI1_CS0_PIO_BIT); }
00068 #else
00069 #define SPI1_CS0_LO()
00070 #define SPI1_CS0_HI()
00071 #define SPI1_CS0_SO()
00072 #endif
00073 #endif
00074 
00075 #if defined(SPI1_CS1_PIO_BIT)
00076 #if defined(SPI1_CS1_PIO_ID)
00077 #undef GPIO_ID
00078 #define GPIO_ID SPI1_CS1_PIO_ID
00079 #include <cfg/arch/porttran.h>
00080 static INLINE void SPI1_CS1_LO(void) { GPIO_SET_LO(SPI1_CS1_PIO_BIT); }
00081 static INLINE void SPI1_CS1_HI(void) { GPIO_SET_HI(SPI1_CS1_PIO_BIT); }
00082 static INLINE void SPI1_CS1_SO(void) { GPIO_OUTPUT(SPI1_CS1_PIO_BIT); }
00083 #else
00084 #define SPI1_CS1_LO()
00085 #define SPI1_CS1_HI()
00086 #define SPI1_CS1_SO()
00087 #endif
00088 #endif
00089 
00090 #if defined(SPI1_CS2_PIO_BIT)
00091 #if defined(SPI1_CS2_PIO_ID)
00092 #undef GPIO_ID
00093 #define GPIO_ID SPI1_CS2_PIO_ID
00094 #include <cfg/arch/porttran.h>
00095 static INLINE void SPI1_CS2_LO(void) { GPIO_SET_LO(SPI1_CS2_PIO_BIT); }
00096 static INLINE void SPI1_CS2_HI(void) { GPIO_SET_HI(SPI1_CS2_PIO_BIT); }
00097 static INLINE void SPI1_CS2_SO(void) { GPIO_OUTPUT(SPI1_CS2_PIO_BIT); }
00098 #else
00099 #define SPI1_CS2_LO()
00100 #define SPI1_CS2_HI()
00101 #define SPI1_CS2_SO()
00102 #endif
00103 #endif
00104 
00105 #if defined(SPI1_CS3_PIO_BIT)
00106 #if defined(SPI1_CS3_PIO_ID)
00107 #undef GPIO_ID
00108 #define GPIO_ID SPI1_CS3_PIO_ID
00109 #include <cfg/arch/porttran.h>
00110 static INLINE void SPI1_CS3_LO(void) { GPIO_SET_LO(SPI1_CS3_PIO_BIT); }
00111 static INLINE void SPI1_CS3_HI(void) { GPIO_SET_HI(SPI1_CS3_PIO_BIT); }
00112 static INLINE void SPI1_CS3_SO(void) { GPIO_OUTPUT(SPI1_CS3_PIO_BIT); }
00113 #else
00114 #define SPI1_CS3_LO()
00115 #define SPI1_CS3_HI()
00116 #define SPI1_CS3_SO()
00117 #endif
00118 #endif
00119 
00123 int At91Spi1ChipSelect(uint_fast8_t cs, uint_fast8_t hi)
00124 {
00125     int rc = 0;
00126 
00127     switch (cs) {
00128 #if defined(SPI1_CS0_PIO_BIT)
00129     case 0:
00130         if (hi) {
00131             SPI1_CS0_HI();
00132         } else {
00133             SPI1_CS0_LO();
00134         }
00135         SPI1_CS0_SO();
00136         break;
00137 #endif
00138 #if defined(SPI1_CS1_PIO_BIT)
00139     case 1:
00140         if (hi) {
00141             SPI1_CS1_HI();
00142         } else {
00143             SPI1_CS1_LO();
00144         }
00145         SPI1_CS1_SO();
00146         break;
00147 #endif
00148 #if defined(SPI1_CS2_PIO_BIT)
00149     case 2:
00150         if (hi) {
00151             SPI1_CS2_HI();
00152         } else {
00153             SPI1_CS2_LO();
00154         }
00155         SPI1_CS2_SO();
00156         break;
00157 #endif
00158 #if defined(SPI1_CS3_PIO_BIT)
00159     case 3:
00160         if (hi) {
00161             SPI1_CS3_HI();
00162         } else {
00163             SPI1_CS3_LO();
00164         }
00165         SPI1_CS3_SO();
00166         break;
00167 #endif
00168     default:
00169         errno = EIO;
00170         rc = -1;
00171         break;
00172     }
00173     return rc;
00174 }
00175 
00187 int At91SpiBus1Select(NUTSPINODE * node, uint32_t tmo)
00188 {
00189     int rc;
00190 
00191     /* Sanity check. */
00192     NUTASSERT(node != NULL);
00193     NUTASSERT(node->node_bus != NULL);
00194     NUTASSERT(node->node_stat != NULL);
00195 
00196     /* Allocate the bus. */
00197     rc = NutEventWait(&node->node_bus->bus_mutex, tmo);
00198     if (rc) {
00199         errno = EIO;
00200     } else {
00201         AT91SPIREG *spireg = node->node_stat;
00202 
00203         outr(PMC_PCER, _BV(SPI1_ID));
00204 
00205         /* Enable SPI peripherals and clock. */
00206         outr(SPI1_PIO_BASE + SPI1_PSR_OFF, SPI1_PINS);
00207         outr(SPI1_PIO_BASE + PIO_PDR_OFF, SPI1_PINS);
00208 
00209         /* If the mode update bit is set, then update our shadow registers. */
00210         if (node->node_mode & SPI_MODE_UPDATE) {
00211             At91SpiSetup(node);
00212         }
00213 
00214         /* Enable SPI. */
00215         outr(SPI1_CR, SPI_SPIEN);
00216         /* Set SPI mode. */
00217         outr(SPI1_MR, spireg->at91spi_mr);
00218         outr(SPI1_CSR0 + node->node_cs * 4, spireg->at91spi_csr);
00219 
00220         /* Finally activate the node's chip select. */
00221         rc = At91Spi1ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) != 0);
00222         if (rc) {
00223             /* Release the bus in case of an error. */
00224             NutEventPost(&node->node_bus->bus_mutex);
00225         }
00226     }
00227     return rc;
00228 }
00229 
00238 int At91SpiBus1Deselect(NUTSPINODE * node)
00239 {
00240     /* Sanity check. */
00241     NUTASSERT(node != NULL);
00242     NUTASSERT(node->node_bus != NULL);
00243 
00244 #ifdef SPIBUS1_DOUBLE_BUFFER
00245     At91SpiBusWait(node, NUT_WAIT_INFINITE);
00246 #endif
00247     /* Deactivate the node's chip select. */
00248     At91Spi1ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0);
00249 
00250     /* Release the bus. */
00251     NutEventPost(&node->node_bus->bus_mutex);
00252 
00253     return 0;
00254 }
00255 
00256 #if !defined(SPIBUS1_POLLING_MODE) || !defined(SPIBUS1_DOUBLE_BUFFER)
00257 
00258 static uint8_t * volatile spi1_txp;
00259 static uint8_t * volatile spi1_rxp;
00260 static volatile size_t spi1_xc;
00261 
00262 void At91SpiBus1Interrupt(void *arg)
00263 {
00264     uint8_t b;
00265 
00266     /* Get the received byte. */
00267     b = inb(SPI1_RDR);
00268     if (spi1_xc) {
00269         if (spi1_rxp) {
00270             *spi1_rxp++ = b;
00271         }
00272         spi1_xc--;
00273     }
00274     if (spi1_xc) {
00275         if (spi1_txp) {
00276             b = *spi1_txp++;
00277         }
00278         outb(SPI1_TDR, b);
00279     } else {
00280         NutEventPostFromIrq((void **)arg);
00281     }
00282 }
00283 
00298 int At91SpiBus1Transfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen)
00299 {
00300     uint8_t b = 0xff;
00301     uintptr_t base;
00302 
00303     /* Sanity check. */
00304     NUTASSERT(node != NULL);
00305     NUTASSERT(node->node_bus != NULL);
00306     NUTASSERT(node->node_bus->bus_base != 0);
00307     base = node->node_bus->bus_base;
00308 
00309     if (xlen) {
00310         spi1_txp = (uint8_t *) txbuf;
00311         spi1_rxp = (uint8_t *) rxbuf;
00312         spi1_xc = (size_t) xlen;
00313         if (spi1_txp) {
00314             b = *spi1_txp++;
00315         }
00316         /* Enable and kick interrupts. */
00317         outr(base + SPI_IER_OFF, SPI_RDRF);
00318         outr(base + SPI_TDR_OFF, b);
00319         /* Wait until transfer has finished. */
00320         NutEventWait(&node->node_bus->bus_ready, NUT_WAIT_INFINITE);
00321         outr(base + SPI_IDR_OFF, (unsigned int) - 1);
00322     }
00323     return 0;
00324 }
00325 #endif
00326 
00330 NUTSPIBUS spiBus1At91 = {
00331     NULL,                       
00332     NULL,                       
00333     SPI1_BASE,                  
00334     &sig_SPI1,                  
00335     At91SpiBusNodeInit,         
00336     At91SpiBus1Select,          
00337     At91SpiBus1Deselect,        
00338 #if defined(SPIBUS1_POLLING_MODE)
00339     At91SpiBusPollTransfer,     
00340 #elif defined(SPIBUS1_DOUBLE_BUFFER)
00341     At91SpiBusDblBufTransfer,
00342 #else
00343     At91SpiBus1Transfer,
00344 #endif
00345 #ifdef SPIBUS1_DOUBLE_BUFFER
00346     At91SpiBusWait,
00347 #else
00348     NutSpiBusWait,              
00349 #endif
00350     NutSpiBusSetMode,           
00351     NutSpiBusSetRate,           
00352     NutSpiBusSetBits            
00353 };
00354 
00355 #endif /* SPI1_PIO_BASE */

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