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

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