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 
00060 #include <cfg/clock.h>
00061 
00062 #include <sys/event.h>
00063 
00064 #include <dev/twif.h>
00065 #include <dev/npl.h>
00066 #include <dev/mmcard.h>
00067 #include <dev/cy2239x.h>
00068 #include <dev/nplmmc.h>
00069 
00070 #if !defined(NPL_MMC_CLOCK) || (NPL_MMC_CLOCK < 1000)
00071 #undef NPL_MMC_CLOCK
00072 #define NPL_MMC_CLOCK   12500000
00073 #endif
00074 
00075 #if 0
00076 /* Use for local debugging. */
00077 #define NUTDEBUG
00078 #include <stdio.h>
00079 #endif
00080 
00085 
00086 #ifndef I2C_SLA_PLL
00087 #define I2C_SLA_PLL     0x69
00088 #endif
00089 
00093 typedef struct _MMCDCB {
00094     int dcb_avail;              
00095     int dcb_changed;            
00096 } MMCDCB;
00097 
00098 static MMCDCB mmc0_dcb;
00099 
00105 static int NplMmCard0Init(void)
00106 {
00107     mmc0_dcb.dcb_changed = 0;
00108     if (mmc0_dcb.dcb_avail) {
00109         return 0;
00110     }
00111     return -1;
00112 }
00113 
00122 static int NplMmCard0Select(int on)
00123 {
00124     int rc = (inb(NPL_XER) & NPL_MMCS) == NPL_MMCS;
00125 
00126     if (on == 1) {
00128         outb(NPL_XER, inb(NPL_XER) & ~NPL_MMCS);
00129     } else if (on == 0) {
00131         outb(NPL_XER, inb(NPL_XER) | NPL_MMCS);
00132     }
00133     return rc;
00134 }
00135 
00143 static u_char NplMmCard0Io(u_char val)
00144 {
00145     u_char rc;
00146     u_int tmo = 255;
00147 
00148     while ((inb(NPL_SLR) & NPL_MMCREADY) == 0) {
00149         if (--tmo == 0) {
00150             break;
00151         }
00152     }
00153 
00154     _NOP();
00155     _NOP();
00156     rc = inb(NPL_MMCDR);
00157     _NOP();
00158     _NOP();
00159     outb(NPL_MMCDR, val);
00160     _NOP();
00161     _NOP();
00162 
00163 #ifdef NUTDEBUG
00164     putchar('[');
00165     if (rc != 0xFF) {
00166         printf("r%02X", rc);
00167     } else if (val != 0xFF) {
00168         printf("s%02X", val);
00169     }
00170     putchar(']');
00171 #endif
00172 
00173     return rc;
00174 }
00175 
00186 int NplMmCard0Avail(void)
00187 {
00188     if (mmc0_dcb.dcb_avail) {
00189         if (mmc0_dcb.dcb_changed) {
00190             return 2;
00191         }
00192         return 1;
00193     }
00194     return 0;
00195 }
00196 
00204 int NplMmCard0WrProt(void)
00205 {
00206     return 0;
00207 }
00208 
00216 static void NplMmCard0InsIrq(void *arg)
00217 {
00218     NplIrqDisable(&sig_MMCD);
00219     mmc0_dcb.dcb_avail = 1;
00220     mmc0_dcb.dcb_changed = 1;
00221     NplIrqEnable(&sig_NMMCD);
00222 }
00223 
00231 static void NplMmCard0RemIrq(void *arg)
00232 {
00233     NplIrqDisable(&sig_NMMCD);
00234     mmc0_dcb.dcb_avail = 0;
00235     NplIrqEnable(&sig_MMCD);
00236 }
00237 
00250 static int NplMmcIfcInit(NUTDEVICE * dev)
00251 {
00252     int rc;
00253 
00254     /* Disable card select. */
00255     NplMmCard0Select(0);
00256 
00257 #if defined(NUT_PLL_NPLCLK1)
00258     {
00259         u_long val;
00260 
00261         /* Query the PLL number routed to Clock B. */
00262         val = Cy2239xGetPll(NUT_PLL_NPLCLK1);
00263         /* Get the frequency of this PLL. */
00264         val = Cy2239xPllGetFreq((int)val, 7);
00265         /* Calculate the required divider value. */
00266         val = (val + NPL_MMC_CLOCK - 10) / NPL_MMC_CLOCK;
00267         /* 
00268          * Not sure about the Cy-routines. The DIVSEL bit specifies which
00269          * divider is used, which is indirectly connected to S2, which is
00270          * high by default. For now set both dividers. 
00271          */
00272         if (Cy2239xSetDivider(NUT_PLL_NPLCLK1, 1, (int)val)) {
00273             return -1;
00274         }
00275         if (Cy2239xSetDivider(NUT_PLL_NPLCLK1, 0, (int)val)) {
00276             return -1;
00277         }
00278     }
00279 #endif
00280 
00281     /* Initialize the CPLD SPI register. */
00282     inb(NPL_MMCDR);
00283     outb(NPL_MMCDR, 0xFF);
00284 
00285     /* Register card detection interrupts. */
00286     if ((rc = NplRegisterIrqHandler(&sig_MMCD, NplMmCard0InsIrq, 0)) == 0) {
00287         rc = NplRegisterIrqHandler(&sig_NMMCD, NplMmCard0RemIrq, 0);
00288     }
00289     NplIrqEnable(&sig_MMCD);
00290 
00291     return MmCardDevInit(dev);
00292 }
00293 
00294 static MMCIFC mmc0_ifc = {
00295     NplMmCard0Init,             
00296     NplMmCard0Io,               
00297     NplMmCard0Select,           
00298     NplMmCard0Avail,            
00299     NplMmCard0WrProt            
00300 };
00301 
00314 NUTDEVICE devNplMmc0 = {
00315     0,                          
00316     {'M', 'M', 'C', '0', 0, 0, 0, 0, 0}
00317     ,                           
00318     0,                          
00319     0,                          
00320     0,                          
00321     &mmc0_ifc,                  
00322     &mmc0_dcb,                  
00323     NplMmcIfcInit,              
00324     MmCardIOCtl,                
00325     MmCardBlockRead,            
00326     MmCardBlockWrite,           
00327 #ifdef __HARVARD_ARCH__
00328     MmCardBlockWrite_P,         
00329 #endif
00330     MmCardMount,                
00331     MmCardUnmount,              
00332     0                           
00333 };
00334 

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