Nut/OS  4.10.3
API Reference
sbimmc.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 
00072 #include <cfg/arch.h>
00073 #include <cfg/arch/gpio.h>
00074 
00075 #include <sys/event.h>
00076 #include <dev/irqreg.h>
00077 #include <dev/mmcard.h>
00078 #include <dev/sbimmc.h>
00079 
00080 #if 0
00081 /* Use for local debugging. */
00082 #define NUTDEBUG
00083 #include <stdio.h>
00084 #endif
00085 
00090 
00091 #ifndef SPI0_CS_BIT
00092 
00093 #define SPI0_CS_BIT      6
00094 #endif
00095 
00096 #ifndef SPI0_CLK_BIT
00097 
00098 #define SPI0_CLK_BIT     4
00099 #endif
00100 
00101 #ifndef SPI0_MOSI_BIT
00102 
00103 #define SPI0_MOSI_BIT    5
00104 #endif
00105 
00106 #ifndef SPI0_MISO_BIT
00107 
00108 #define SPI0_MISO_BIT    3
00109 #endif
00110 
00111 #if defined(MCU_AT91R40008) || defined(MCU_AT91SAM7X) /* MCU ---------------------- */
00112 
00113 #ifndef SPI0_PE_REG
00114 
00116 #define SPI0_PE_REG  PIO_PER
00117 #endif
00118 
00119 #ifndef SPI0_PD_REG
00120 
00122 #define SPI0_PD_REG  PIO_PDR
00123 #endif
00124 
00125 
00126 #ifndef SPI0_OE_REG
00127 
00128 #define SPI0_OE_REG  PIO_OER
00129 #endif
00130 
00131 #ifndef SPI0_OD_REG
00132 
00133 #define SPI0_OD_REG  PIO_ODR
00134 #endif
00135 
00136 #ifndef SPI0_SOD_REG
00137 
00138 #define SPI0_SOD_REG PIO_SODR
00139 #endif
00140 
00141 #ifndef SPI0_COD_REG
00142 
00143 #define SPI0_COD_REG PIO_CODR
00144 #endif
00145 
00146 #ifndef SPI0_PDS_REG
00147 
00148 #define SPI0_PDS_REG PIO_PDSR
00149 #endif
00150 
00151 #ifndef SPI0_ODS_REG
00152 
00153 #define SPI0_ODS_REG PIO_ODSR
00154 #endif
00155 
00156 #ifdef MMC0_CD_BIT
00157 #if MMC0_CD_BIT == 9
00158 #define SIG_MMC0DETECT   sig_INTERRUPT0
00159 #elif MMC0_CD_BIT == 10
00160 #define SIG_MMC0DETECT   sig_INTERRUPT1
00161 #elif MMC0_CD_BIT == 11
00162 #define SIG_MMC0DETECT   sig_INTERRUPT2
00163 #else
00164 #warning "No external interrupt for card detect"
00165 #undef MMC0_CD_BIT
00166 #endif
00167 #endif
00168 
00169 #elif defined(MCU_ATMEGA2561) || defined(MCU_AT90CAN128) || defined(MCU_ATMEGA128) || defined(MCU_ATMEGA103) /* MCU */
00170 
00171 #ifndef inr
00172 #define inr(a)  inb(a)
00173 #endif
00174 #ifndef outr
00175 #define outr(a, v)  outb(a, v)
00176 #endif
00177 
00178 #ifndef SPI0_OE_REG
00179 #if SPI0_PORT == AVRPORTA
00180 #define SPI0_OE_REG  DDRA
00181 #elif  SPI0_PORT == AVRPORTC
00182 #define SPI0_OE_REG  DDRC
00183 #elif  SPI0_PORT == AVRPORTD
00184 #define SPI0_OE_REG  DDRD
00185 #elif  SPI0_PORT == AVRPORTE
00186 #define SPI0_OE_REG  DDRE
00187 #elif  SPI0_PORT == AVRPORTF
00188 #define SPI0_OE_REG  DDRF
00189 #elif  SPI0_PORT == AVRPORTG
00190 #define SPI0_OE_REG  DDRG
00191 #else
00192 
00193 #define SPI0_OE_REG  DDRB
00194 #endif
00195 #endif
00196 
00197 #ifndef SPI0_SOD_REG
00198 #if SPI0_PORT == AVRPORTA
00199 #define SPI0_SOD_REG  PORTA
00200 #elif  SPI0_PORT == AVRPORTC
00201 #define SPI0_SOD_REG  PORTC
00202 #elif  SPI0_PORT == AVRPORTD
00203 #define SPI0_SOD_REG  PORTD
00204 #elif  SPI0_PORT == AVRPORTE
00205 #define SPI0_SOD_REG  PORTE
00206 #elif  SPI0_PORT == AVRPORTF
00207 #define SPI0_SOD_REG  PORTF
00208 #elif  SPI0_PORT == AVRPORTG
00209 #define SPI0_SOD_REG  PORTG
00210 #else
00211 
00212 #define SPI0_SOD_REG PORTB
00213 #endif
00214 #endif
00215 
00216 #ifndef SPI0_PDS_REG
00217 #if SPI0_PORT == AVRPORTA
00218 #define SPI0_PDS_REG  PINA
00219 #elif  SPI0_PORT == AVRPORTC
00220 #define SPI0_PDS_REG  PINC
00221 #elif  SPI0_PORT == AVRPORTD
00222 #define SPI0_PDS_REG  PIND
00223 #elif  SPI0_PORT == AVRPORTE
00224 #define SPI0_PDS_REG  PINE
00225 #elif  SPI0_PORT == AVRPORTF
00226 #define SPI0_PDS_REG  PINF
00227 #elif  SPI0_PORT == AVRPORTG
00228 #define SPI0_PDS_REG  PING
00229 #else
00230 
00231 #define SPI0_PDS_REG PINB
00232 #endif
00233 #endif
00234 
00235 #elif !defined(SPI0_OE_REG) || !defined(SPI0_SOD_REG) || !defined(SPI0_PDS_REG)
00236 #warning "No SPI bit banging registers for unknown CPU."
00237 #endif  /* MCU ---------------------- */
00238 
00239 #ifdef SPI0_COD_REG
00240 
00241 #define MMC0_CLR_BIT(n)  outr(SPI0_COD_REG, _BV(n))
00242 
00243 #define MMC0_SET_BIT(n)  outr(SPI0_SOD_REG, _BV(n))
00244 #else
00245 #define MMC0_CLR_BIT(n)  outr(SPI0_SOD_REG, inr(SPI0_SOD_REG) & ~_BV(n))
00246 #define MMC0_SET_BIT(n)  outr(SPI0_SOD_REG, inr(SPI0_SOD_REG) | _BV(n))
00247 #endif
00248 
00249 #ifdef SPI0_ODS_REG
00250 
00251 #define MMC0_IS_BIT_SET(n)   ((inr(SPI0_ODS_REG) & _BV(n)) == _BV(n))
00252 #else
00253 #define MMC0_IS_BIT_SET(n)   ((inr(SPI0_SOD_REG) & _BV(n)) == _BV(n))
00254 #endif
00255 
00257 #define MMC0_TST_BIT(n)  ((inr(SPI0_PDS_REG) & _BV(n)) == _BV(n))
00258 
00259 
00263 typedef struct _MMCDCB {
00264     int dcb_avail;              
00265     int dcb_changed;            
00266 } MMCDCB;
00267 
00268 static MMCDCB mmc0_dcb;
00269 
00278 static int SbiMmCard0Init(void)
00279 {
00280     mmc0_dcb.dcb_changed = 0;
00281     if (mmc0_dcb.dcb_avail) {
00282         return 0;
00283     }
00284     return -1;
00285 }
00286 
00295 static int SbiMmCard0Select(int on)
00296 {
00297     int rc = MMC0_IS_BIT_SET(SPI0_CS_BIT);
00298 
00299     /* MMC select is low active. */
00300     if (on == 1) {
00301         MMC0_CLR_BIT(SPI0_CS_BIT);
00302     } else if (on == 0) {
00303         MMC0_SET_BIT(SPI0_CS_BIT);
00304     }
00305     return rc;
00306 }
00307 
00315 static uint8_t SbiMmCard0Io(uint8_t val)
00316 {
00317     uint8_t msk = 0x80;
00318 
00319 #ifdef NUTDEBUG
00320     putchar('[');
00321     if (val != 0xFF) {
00322         printf("s%02X", val);
00323     }
00324 #endif
00325 
00326 #if defined(MCU_AT91R40008) && defined(__GNUC__) && 0
00327     /* ARM assembly version, tested on AT91R40008 only. */
00328     asm volatile (
00329         "\nspi_tran_l:\n\t"
00330         "str     %7, [%3, %5]"  "\n\t"  /* SCK low. */
00331         "tst     %0, %2"        "\n\t"  /* Check data bit. */
00332         "strne   %8, [%3, %4]"  "\n\t"  /* MOSI high. */
00333         "streq   %8, [%3, %5]"  "\n\t"  /* MOSI low. */
00334         "bic     %0, %1, %2"    "\n\t"  /* Clear data bit */
00335         "str     %7, [%3, %4]"  "\n\t"  /* SCK high. */
00336         "ldr     r1, [%3, %6]"  "\n\t"  /* Read MISO */
00337         "tst     r1, %9"        "\n\t"  /* Test MISO */
00338         "orrne   %0, %1, %2"    "\n\t"  /* Set data bit if MOSI was high */
00339         "movs    %2, %2, lsr #1""\n\t"  /* msk <<= 1 */
00340         "bne     spi_tran_l"            /* Loop for next bit. */
00341         : "=r" (val)            /* %0 output */
00342         : "0" (val)             /* %1 input */
00343         , "r" (msk)             /* %2 input */
00344         , "r" (PIO_BASE)        /* %3 input */
00345         , "J" (PIO_SODR - PIO_BASE)    /* %4 input */
00346         , "J" (PIO_CODR - PIO_BASE)    /* %5 input */
00347         , "J" (PIO_PDSR - PIO_BASE)    /* %6 input */
00348         , "r" _BV(SPI0_CLK_BIT)         /* %7 input */
00349         , "r" _BV(SPI0_MOSI_BIT)        /* %8 input */
00350         , "I" _BV(SPI0_MISO_BIT)        /* %9 input */
00351         : "r1"
00352         );
00353 #else
00354     /* Generic code. */
00355     while (msk) {
00356         MMC0_CLR_BIT(SPI0_CLK_BIT);
00357         if (val & msk) {
00358             MMC0_SET_BIT(SPI0_MOSI_BIT);
00359         } else {
00360             MMC0_CLR_BIT(SPI0_MOSI_BIT);
00361         }
00362         MMC0_SET_BIT(SPI0_CLK_BIT);
00363         if (MMC0_TST_BIT(SPI0_MISO_BIT)) {
00364             val |= msk;
00365         }
00366         else {
00367             val &= ~msk;
00368         }
00369         msk >>= 1;
00370     }
00371 #endif
00372 
00373 #ifdef NUTDEBUG
00374     if (val != 0xFF) {
00375         printf("r%02X", val);
00376     }
00377     putchar(']');
00378 #endif
00379     return val;
00380 }
00381 
00392 int SbiMmCard0Avail(void)
00393 {
00394     if (mmc0_dcb.dcb_avail) {
00395         if (mmc0_dcb.dcb_changed) {
00396             return 2;
00397         }
00398         return 1;
00399     }
00400     return 0;
00401 }
00402 
00410 int SbiMmCard0WrProt(void)
00411 {
00412     return 0;
00413 }
00414 
00415 #ifdef MMC0_CD_BIT
00416 
00423 static void SbiMmCard0DetectIrq(void *arg)
00424 {
00425     int mode = NutIrqSetMode(&SIG_MMC0DETECT, NUT_IRQMODE_LOWLEVEL);
00426 
00427     if (mode == NUT_IRQMODE_HIGHLEVEL) {
00428         mmc0_dcb.dcb_avail = 0;
00429     }
00430     else {
00431         NutIrqSetMode(&SIG_MMC0DETECT, NUT_IRQMODE_HIGHLEVEL);
00432         mmc0_dcb.dcb_avail = 1;
00433     }
00434     mmc0_dcb.dcb_changed = 1;
00435 }
00436 #endif
00437 
00446 static int SbiMmcIfcInit(NUTDEVICE * dev)
00447 {
00448 #ifdef SPI0_PE_REG
00449     /* Enable all SPI ports, if a port enable register is defined. */
00450     outr(SPI0_PE_REG, _BV(SPI0_CLK_BIT) | _BV(SPI0_MOSI_BIT) | _BV(SPI0_CS_BIT) | _BV(SPI0_MISO_BIT));
00451 #endif
00452 
00453 #ifdef SPI0_OD_REG
00454     /* Enable CLK, MOSI and CS output pins. */
00455     outr(SPI0_OE_REG, _BV(SPI0_CLK_BIT) | _BV(SPI0_MOSI_BIT) | _BV(SPI0_CS_BIT));
00456     /* Enable MISO input pin. */
00457     outr(SPI0_OD_REG, _BV(SPI0_MISO_BIT));
00458 #else
00459     /*
00460      * If this CPU hasn't got a specific output disable register, we
00461      * assume that inputs are enabled by clearing the corresponding bit
00462      * in the output enable register.
00463      */
00464     outr(SPI0_OE_REG, (inr(SPI0_OE_REG) & ~_BV(SPI0_MISO_BIT))
00465         | _BV(SPI0_CLK_BIT) | _BV(SPI0_MOSI_BIT) | _BV(SPI0_CS_BIT));
00466 #endif
00467 
00468     /* Set all outputs high. */
00469     outr(SPI0_SOD_REG, _BV(SPI0_CLK_BIT) | _BV(SPI0_MOSI_BIT) | _BV(SPI0_CS_BIT));
00470 
00471 #ifdef MMC0_CD_BIT
00472 #ifdef SPI0_PD_REG
00473     outr(SPI0_PD_REG, _BV(MMC0_CD_BIT));
00474 #endif
00475 
00476     /* Register card detection interrupts. */
00477     if (NutRegisterIrqHandler(&SIG_MMC0DETECT, SbiMmCard0DetectIrq, 0)) {
00478         mmc0_dcb.dcb_avail = 1;
00479     }
00480     else {
00481         mmc0_dcb.dcb_avail = 0;
00482         NutIrqSetMode(&SIG_MMC0DETECT, NUT_IRQMODE_LOWLEVEL);
00483         NutIrqEnable(&SIG_MMC0DETECT);
00484     }
00485 #else
00486     mmc0_dcb.dcb_avail = 1;
00487 #endif /* MMC0_CD_BIT */
00488     mmc0_dcb.dcb_changed = 0;
00489 
00490     return MmCardDevInit(dev);
00491 }
00492 
00493 static MMCIFC mmc0_ifc = {
00494     SbiMmCard0Init,             
00495     SbiMmCard0Io,               
00496     SbiMmCard0Select,           
00497     SbiMmCard0Avail,            
00498     SbiMmCard0WrProt            
00499 };
00500 
00513 NUTDEVICE devSbiMmc0 = {
00514     0,                          
00515     {'M', 'M', 'C', '0', 0, 0, 0, 0, 0}
00516     ,                           
00517     0,                          
00518     0,                          
00519     0,                          
00520     &mmc0_ifc,                  
00521     &mmc0_dcb,                  
00522     SbiMmcIfcInit,              
00523     MmCardIOCtl,                
00524     MmCardBlockRead,            
00525     MmCardBlockWrite,           
00526 #ifdef __HARVARD_ARCH__
00527     MmCardBlockWrite_P,         
00528 #endif
00529     MmCardMount,                
00530     MmCardUnmount,              
00531     0                           
00532 };
00533