Nut/OS  4.10.3
API Reference
nplmmc.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005 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 
00070 #include <cfg/clock.h>
00071 
00072 #include <sys/event.h>
00073 
00074 #include <dev/twif.h>
00075 #include <dev/npl.h>
00076 #include <dev/mmcard.h>
00077 #include <dev/cy2239x.h>
00078 #include <dev/nplmmc.h>
00079 
00080 #if !defined(NPL_MMC_CLOCK) || (NPL_MMC_CLOCK < 1000)
00081 #undef NPL_MMC_CLOCK
00082 #define NPL_MMC_CLOCK   12500000
00083 #endif
00084 
00085 #if 0
00086 /* Use for local debugging. */
00087 #define NUTDEBUG
00088 #include <stdio.h>
00089 #endif
00090 
00095 
00096 #ifndef I2C_SLA_PLL
00097 #define I2C_SLA_PLL     0x69
00098 #endif
00099 
00103 typedef struct _MMCDCB {
00104     int dcb_avail;              
00105     int dcb_changed;            
00106 } MMCDCB;
00107 
00108 static MMCDCB mmc0_dcb;
00109 
00115 static int NplMmCard0Init(void)
00116 {
00117     mmc0_dcb.dcb_changed = 0;
00118     if (mmc0_dcb.dcb_avail) {
00119         return 0;
00120     }
00121     return -1;
00122 }
00123 
00132 static int NplMmCard0Select(int on)
00133 {
00134     int rc = (inb(NPL_XER) & NPL_MMCS) == NPL_MMCS;
00135 
00136     if (on == 1) {
00138         outb(NPL_XER, inb(NPL_XER) & ~NPL_MMCS);
00139     } else if (on == 0) {
00141         outb(NPL_XER, inb(NPL_XER) | NPL_MMCS);
00142     }
00143     return rc;
00144 }
00145 
00153 static uint8_t NplMmCard0Io(uint8_t val)
00154 {
00155     uint8_t rc;
00156     unsigned int tmo = 255;
00157 
00158     while ((inb(NPL_SLR) & NPL_MMCREADY) == 0) {
00159         if (--tmo == 0) {
00160             break;
00161         }
00162     }
00163 
00164     _NOP(); _NOP(); _NOP(); _NOP();
00165     rc = inb(NPL_MMCDR);
00166     _NOP(); _NOP(); _NOP(); _NOP();
00167     outb(NPL_MMCDR, val);
00168     _NOP(); _NOP(); _NOP(); _NOP();
00169 
00170 #ifdef NUTDEBUG
00171     putchar('[');
00172     if (rc != 0xFF) {
00173         printf("r%02X", rc);
00174     } else if (val != 0xFF) {
00175         printf("s%02X", val);
00176     }
00177     putchar(']');
00178 #endif
00179 
00180     return rc;
00181 }
00182 
00193 int NplMmCard0Avail(void)
00194 {
00195     if (mmc0_dcb.dcb_avail) {
00196         if (mmc0_dcb.dcb_changed) {
00197             return 2;
00198         }
00199         return 1;
00200     }
00201     return 0;
00202 }
00203 
00211 int NplMmCard0WrProt(void)
00212 {
00213     return 0;
00214 }
00215 
00223 static void NplMmCard0InsIrq(void *arg)
00224 {
00225     NplIrqDisable(&sig_MMCD);
00226     mmc0_dcb.dcb_avail = 1;
00227     mmc0_dcb.dcb_changed = 1;
00228     NplIrqEnable(&sig_NMMCD);
00229 }
00230 
00238 static void NplMmCard0RemIrq(void *arg)
00239 {
00240     NplIrqDisable(&sig_NMMCD);
00241     mmc0_dcb.dcb_avail = 0;
00242     NplIrqEnable(&sig_MMCD);
00243 }
00244 
00257 static int NplMmcIfcInit(NUTDEVICE * dev)
00258 {
00259     int rc;
00260 
00261     /* Disable card select. */
00262     NplMmCard0Select(0);
00263 
00264 #if defined(NUT_PLL_NPLCLK1)
00265     {
00266         uint32_t val;
00267 
00268         /* Query the PLL number routed to Clock B. */
00269         val = Cy2239xGetPll(NUT_PLL_NPLCLK1);
00270         /* Get the frequency of this PLL. */
00271         val = Cy2239xPllGetFreq((int)val, 7);
00272         /* Calculate the required divider value. */
00273         val = (val + NPL_MMC_CLOCK - 10) / NPL_MMC_CLOCK;
00274         /* 
00275          * Not sure about the Cy-routines. The DIVSEL bit specifies which
00276          * divider is used, which is indirectly connected to S2, which is
00277          * high by default. For now set both dividers. 
00278          */
00279         if (Cy2239xSetDivider(NUT_PLL_NPLCLK1, 1, (int)val)) {
00280             return -1;
00281         }
00282         if (Cy2239xSetDivider(NUT_PLL_NPLCLK1, 0, (int)val)) {
00283             return -1;
00284         }
00285     }
00286 #endif
00287 
00288     /* Initialize the CPLD SPI register. */
00289     inb(NPL_MMCDR);
00290     outb(NPL_MMCDR, 0xFF);
00291 
00292     /* Register card detection interrupts. */
00293     if ((rc = NplRegisterIrqHandler(&sig_MMCD, NplMmCard0InsIrq, 0)) == 0) {
00294         rc = NplRegisterIrqHandler(&sig_NMMCD, NplMmCard0RemIrq, 0);
00295     }
00296     NplIrqEnable(&sig_MMCD);
00297 
00298     return MmCardDevInit(dev);
00299 }
00300 
00301 static MMCIFC mmc0_ifc = {
00302     NplMmCard0Init,             
00303     NplMmCard0Io,               
00304     NplMmCard0Select,           
00305     NplMmCard0Avail,            
00306     NplMmCard0WrProt            
00307 };
00308 
00321 NUTDEVICE devNplMmc0 = {
00322     0,                          
00323     {'M', 'M', 'C', '0', 0, 0, 0, 0, 0}
00324     ,                           
00325     0,                          
00326     0,                          
00327     0,                          
00328     &mmc0_ifc,                  
00329     &mmc0_dcb,                  
00330     NplMmcIfcInit,              
00331     MmCardIOCtl,                
00332     MmCardBlockRead,            
00333     MmCardBlockWrite,           
00334 #ifdef __HARVARD_ARCH__
00335     MmCardBlockWrite_P,         
00336 #endif
00337     MmCardMount,                
00338     MmCardUnmount,              
00339     0                           
00340 };
00341