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 
00066 #include <cfg/clock.h>
00067 
00068 #include <sys/event.h>
00069 
00070 #include <dev/twif.h>
00071 #include <dev/npl.h>
00072 #include <dev/mmcard.h>
00073 #include <dev/cy2239x.h>
00074 #include <dev/nplmmc.h>
00075 
00076 #if !defined(NPL_MMC_CLOCK) || (NPL_MMC_CLOCK < 1000)
00077 #undef NPL_MMC_CLOCK
00078 #define NPL_MMC_CLOCK   12500000
00079 #endif
00080 
00081 #if 0
00082 /* Use for local debugging. */
00083 #define NUTDEBUG
00084 #include <stdio.h>
00085 #endif
00086 
00091 
00092 #ifndef I2C_SLA_PLL
00093 #define I2C_SLA_PLL     0x69
00094 #endif
00095 
00099 typedef struct _MMCDCB {
00100     int dcb_avail;              
00101     int dcb_changed;            
00102 } MMCDCB;
00103 
00104 static MMCDCB mmc0_dcb;
00105 
00111 static int NplMmCard0Init(void)
00112 {
00113     mmc0_dcb.dcb_changed = 0;
00114     if (mmc0_dcb.dcb_avail) {
00115         return 0;
00116     }
00117     return -1;
00118 }
00119 
00128 static int NplMmCard0Select(int on)
00129 {
00130     int rc = (inb(NPL_XER) & NPL_MMCS) == NPL_MMCS;
00131 
00132     if (on == 1) {
00134         outb(NPL_XER, inb(NPL_XER) & ~NPL_MMCS);
00135     } else if (on == 0) {
00137         outb(NPL_XER, inb(NPL_XER) | NPL_MMCS);
00138     }
00139     return rc;
00140 }
00141 
00149 static uint8_t NplMmCard0Io(uint8_t val)
00150 {
00151     uint8_t rc;
00152     u_int tmo = 255;
00153 
00154     while ((inb(NPL_SLR) & NPL_MMCREADY) == 0) {
00155         if (--tmo == 0) {
00156             break;
00157         }
00158     }
00159 
00160     _NOP(); _NOP(); _NOP(); _NOP();
00161     rc = inb(NPL_MMCDR);
00162     _NOP(); _NOP(); _NOP(); _NOP();
00163     outb(NPL_MMCDR, val);
00164     _NOP(); _NOP(); _NOP(); _NOP();
00165 
00166 #ifdef NUTDEBUG
00167     putchar('[');
00168     if (rc != 0xFF) {
00169         printf("r%02X", rc);
00170     } else if (val != 0xFF) {
00171         printf("s%02X", val);
00172     }
00173     putchar(']');
00174 #endif
00175 
00176     return rc;
00177 }
00178 
00189 int NplMmCard0Avail(void)
00190 {
00191     if (mmc0_dcb.dcb_avail) {
00192         if (mmc0_dcb.dcb_changed) {
00193             return 2;
00194         }
00195         return 1;
00196     }
00197     return 0;
00198 }
00199 
00207 int NplMmCard0WrProt(void)
00208 {
00209     return 0;
00210 }
00211 
00219 static void NplMmCard0InsIrq(void *arg)
00220 {
00221     NplIrqDisable(&sig_MMCD);
00222     mmc0_dcb.dcb_avail = 1;
00223     mmc0_dcb.dcb_changed = 1;
00224     NplIrqEnable(&sig_NMMCD);
00225 }
00226 
00234 static void NplMmCard0RemIrq(void *arg)
00235 {
00236     NplIrqDisable(&sig_NMMCD);
00237     mmc0_dcb.dcb_avail = 0;
00238     NplIrqEnable(&sig_MMCD);
00239 }
00240 
00253 static int NplMmcIfcInit(NUTDEVICE * dev)
00254 {
00255     int rc;
00256 
00257     /* Disable card select. */
00258     NplMmCard0Select(0);
00259 
00260 #if defined(NUT_PLL_NPLCLK1)
00261     {
00262         uint32_t val;
00263 
00264         /* Query the PLL number routed to Clock B. */
00265         val = Cy2239xGetPll(NUT_PLL_NPLCLK1);
00266         /* Get the frequency of this PLL. */
00267         val = Cy2239xPllGetFreq((int)val, 7);
00268         /* Calculate the required divider value. */
00269         val = (val + NPL_MMC_CLOCK - 10) / NPL_MMC_CLOCK;
00270         /* 
00271          * Not sure about the Cy-routines. The DIVSEL bit specifies which
00272          * divider is used, which is indirectly connected to S2, which is
00273          * high by default. For now set both dividers. 
00274          */
00275         if (Cy2239xSetDivider(NUT_PLL_NPLCLK1, 1, (int)val)) {
00276             return -1;
00277         }
00278         if (Cy2239xSetDivider(NUT_PLL_NPLCLK1, 0, (int)val)) {
00279             return -1;
00280         }
00281     }
00282 #endif
00283 
00284     /* Initialize the CPLD SPI register. */
00285     inb(NPL_MMCDR);
00286     outb(NPL_MMCDR, 0xFF);
00287 
00288     /* Register card detection interrupts. */
00289     if ((rc = NplRegisterIrqHandler(&sig_MMCD, NplMmCard0InsIrq, 0)) == 0) {
00290         rc = NplRegisterIrqHandler(&sig_NMMCD, NplMmCard0RemIrq, 0);
00291     }
00292     NplIrqEnable(&sig_MMCD);
00293 
00294     return MmCardDevInit(dev);
00295 }
00296 
00297 static MMCIFC mmc0_ifc = {
00298     NplMmCard0Init,             
00299     NplMmCard0Io,               
00300     NplMmCard0Select,           
00301     NplMmCard0Avail,            
00302     NplMmCard0WrProt            
00303 };
00304 
00317 NUTDEVICE devNplMmc0 = {
00318     0,                          
00319     {'M', 'M', 'C', '0', 0, 0, 0, 0, 0}
00320     ,                           
00321     0,                          
00322     0,                          
00323     0,                          
00324     &mmc0_ifc,                  
00325     &mmc0_dcb,                  
00326     NplMmcIfcInit,              
00327     MmCardIOCtl,                
00328     MmCardBlockRead,            
00329     MmCardBlockWrite,           
00330 #ifdef __HARVARD_ARCH__
00331     MmCardBlockWrite_P,         
00332 #endif
00333     MmCardMount,                
00334     MmCardUnmount,              
00335     0                           
00336 };
00337 

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