00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00045 #include <cfg/os.h>
00046 #include <cfg/memory.h>
00047 
00048 #include <dev/blockdev.h>
00049 
00050 #include <sys/nutdebug.h>
00051 #include <sys/timer.h>
00052 
00053 #include <string.h>
00054 
00055 #include <dev/at45d.h>
00056 #include <dev/spi_at45d.h>
00057 
00058 #ifndef AT45_WRITE_POLLS
00059 #define AT45_WRITE_POLLS        1000
00060 #endif
00061 
00062 #if 0
00063 
00064 AT45D_INFO at45d_info[] = {
00065     {8, 512, 256, 0x0D},    
00066     {9, 512, 264, 0x0C},    
00067     {8, 1025, 256, 0x15},   
00068     {9, 1025, 264, 0x14},   
00069     {8, 2048, 256, 0x1D},   
00070     {9, 2048, 264, 0x1C},   
00071     {8, 4096, 256, 0x25},   
00072     {9, 4096, 264, 0x24},   
00073     {9, 4096, 512, 0x2D},   
00074     {10, 4096, 528, 0x2C},  
00075     {9, 8192, 512, 0x35},   
00076     {10, 8192, 528, 0x34},  
00077     {10, 8192, 1024, 0x39}, 
00078     {11, 8192, 1056, 0x38}, 
00079     {10, 8192, 1024, 0x3D}, 
00080     {11, 8192, 1056, 0x3C}  
00081 };
00082 
00084 uint_fast8_t at45d_known_types = sizeof(at45d_info) / sizeof(AT45D_INFO);
00085 #endif
00086 
00098 static int At45dCommand(NUTSPINODE * node, uint8_t op, uint32_t parm, int oplen, CONST void *txbuf, void *rxbuf, int xlen)
00099 {
00100     int rc = -1;
00101     NUTSPIBUS *bus;
00102     uint8_t cmd[8];
00103 
00104     NUTASSERT(node != NULL);
00105     bus = (NUTSPIBUS *) node->node_bus;
00106     NUTASSERT(bus != NULL);
00107     NUTASSERT(bus->bus_alloc != NULL);
00108     NUTASSERT(bus->bus_transfer != NULL);
00109     NUTASSERT(bus->bus_release != NULL);
00110 
00111     NUTASSERT(oplen <= 8);
00112     memset(cmd, 0, oplen);
00113     cmd[0] = op;
00114     if (parm) {
00115         cmd[1] = (uint8_t) (parm >> 16);
00116         cmd[2] = (uint8_t) (parm >> 8);
00117         cmd[3] = (uint8_t) parm;
00118     }
00119     rc = (*bus->bus_alloc) (node, 1000);
00120     if (rc == 0) {
00121         rc = (*bus->bus_transfer) (node, cmd, NULL, oplen);
00122         if (rc == 0 && xlen) {
00123             rc = (*bus->bus_transfer) (node, txbuf, rxbuf, xlen);
00124         }
00125         (*bus->bus_release) (node);
00126     }
00127     return rc;
00128 }
00129 
00137 static uint8_t At45dStatus(NUTSPINODE * node)
00138 {
00139     int rc;
00140     uint8_t cmd[2] = { DFCMD_READ_STATUS, 0xFF };
00141     NUTSPIBUS *bus;
00142 
00143     NUTASSERT(node != NULL);
00144     NUTASSERT(node->node_bus != NULL);
00145     bus = (NUTSPIBUS *) node->node_bus;
00146 
00147     NUTASSERT(bus->bus_alloc != NULL);
00148     NUTASSERT(bus->bus_transfer != NULL);
00149     NUTASSERT(bus->bus_wait != NULL);
00150     NUTASSERT(bus->bus_release != NULL);
00151 
00152     rc = (*bus->bus_alloc) (node, 1000);
00153     if (rc == 0) {
00154         rc = (*bus->bus_transfer) (node, cmd, cmd, 2);
00155         if (rc == 0) {
00156             (*bus->bus_wait) (node, NUT_WAIT_INFINITE);
00157             rc = cmd[1];
00158         }
00159         (*bus->bus_release) (node);
00160     }
00161     return (uint8_t) rc;
00162 }
00163 
00171 static int At45dWaitReady(NUTSPINODE * node, uint32_t tmo, int poll)
00172 {
00173     uint8_t sr;
00174 
00175     while (((sr = At45dStatus(node)) & 0x80) == 0) {
00176         if (!poll) {
00177             NutSleep(1);
00178         }
00179         if (tmo-- == 0) {
00180             return -1;
00181         }
00182     }
00183     return 0;
00184 }
00185 
00197 int SpiAt45dCommand(NUTDEVICE * dev, uint8_t op, uint32_t parm, int oplen, CONST void *txbuf, void *rxbuf, int xlen)
00198 {
00199     NUTASSERT(dev != NULL);
00200     return At45dCommand(dev->dev_icb, op, parm, oplen, txbuf, rxbuf, xlen);
00201 }
00202 
00210 uint8_t SpiAt45dStatus(NUTDEVICE * dev)
00211 {
00212     NUTASSERT(dev != NULL);
00213     return At45dStatus(dev->dev_icb);
00214 }
00215 
00223 int SpiAt45dWaitReady(NUTDEVICE * dev, uint32_t tmo, int poll)
00224 {
00225     NUTASSERT(dev != NULL);
00226     return At45dWaitReady(dev->dev_icb, tmo, poll);
00227 }
00228 
00237 int SpiAt45dPageErase(NUTDEVICE * dev, uint32_t pgn)
00238 {
00239     NUTBLOCKIO *blkio;
00240     AT45D_INFO *info;
00241 
00242     NUTASSERT(dev != NULL);
00243     NUTASSERT(dev->dev_dcb != NULL);
00244     blkio = dev->dev_dcb;
00245     
00246     info = (AT45D_INFO *) blkio->blkio_info;
00247     NUTASSERT(blkio->blkio_info != NULL);
00248 
00249     if (pgn >= info->at45d_pages) {
00250         return -1;
00251     }
00252     pgn <<= info->at45d_pshft;
00253     return At45dCommand((NUTSPINODE *) dev->dev_icb, DFCMD_PAGE_ERASE, pgn, 4, NULL, NULL, 0);
00254 }
00255 
00259 int SpiAt45dChipErase(NUTDEVICE * dev)
00260 {
00261     return -1;
00262 }
00263 
00276 int SpiAt45dInit(NUTDEVICE * dev)
00277 {
00278     NUTBLOCKIO *blkio;
00279     NUTSPINODE *node;
00280     uint8_t sr;
00281     int_fast8_t i;
00282 
00283     NUTASSERT(dev != NULL);
00284     NUTASSERT(dev->dev_dcb != NULL);
00285     NUTASSERT(dev->dev_icb != NULL);
00286     blkio = dev->dev_dcb;
00287     node = dev->dev_icb;
00288 
00289     if (At45dWaitReady(node, 10, 1) == 0) {
00290         
00291         sr = At45dStatus(node);
00292         if (sr != 0xff) {
00293             sr &= AT45D_STATUS_DENSITY | AT45D_STATUS_PAGE_SIZE;
00294             for (i = at45d_known_types; --i >= 0;) {
00295                 if (sr == at45d_info[i].at45d_srval) {
00296                     
00297                     blkio->blkio_info = (void *) &at45d_info[i];
00298                     blkio->blkio_blk_cnt = at45d_info[i].at45d_pages;
00299                     blkio->blkio_blk_siz = at45d_info[i].at45d_psize;
00300                     return 0;
00301                 }
00302             }
00303         }
00304     }
00305     
00306     return -1;
00307 }
00308 
00320 int SpiAt45dPageRead(NUTDEVICE * dev, uint32_t pgn, void *data, int len)
00321 {
00322     NUTBLOCKIO *blkio;
00323     AT45D_INFO *info;
00324 
00325     NUTASSERT(dev != NULL);
00326     NUTASSERT(dev->dev_dcb != NULL);
00327     blkio = dev->dev_dcb;
00328     
00329     info = (AT45D_INFO *) blkio->blkio_info;
00330     NUTASSERT(blkio->blkio_info != NULL);
00331 
00332     if (pgn >= info->at45d_pages) {
00333         return -1;
00334     }
00335     pgn <<= info->at45d_pshft;
00336 
00337     if (At45dCommand((NUTSPINODE *) dev->dev_icb, DFCMD_CONT_READ, pgn, 8, NULL, data, len)) {
00338         return -1;
00339     }
00340     return len;
00341 }
00342 
00360 int SpiAt45dPageWrite(NUTDEVICE * dev, uint32_t pgn, CONST void *data, int len)
00361 {
00362     int rc = -1;
00363     uint8_t *dp = (uint8_t *) data;
00364     int step;
00365     uint_fast8_t pshft;
00366     uint32_t limit;
00367     NUTBLOCKIO *blkio;
00368     NUTSPINODE *node;
00369 
00370     
00371     if (len == 0) {
00372         return 0;
00373     }
00374     NUTASSERT(data != NULL);
00375     NUTASSERT(dev != NULL);
00376     NUTASSERT(dev->dev_dcb != NULL);
00377     NUTASSERT(dev->dev_icb != NULL);
00378     blkio = (NUTBLOCKIO *) dev->dev_dcb;
00379     node = (NUTSPINODE *) dev->dev_icb;
00380     NUTASSERT(blkio->blkio_info != NULL);
00381     pshft = ((AT45D_INFO *) blkio->blkio_info)->at45d_pshft;
00382     step = ((AT45D_INFO *) blkio->blkio_info)->at45d_psize;
00383     limit = ((AT45D_INFO *) blkio->blkio_info)->at45d_pages;
00384 
00385     while (len) {
00386         if (step > len) {
00387             step = len;
00388         }
00389         
00390         if (At45dCommand(node, DFCMD_BUF1_WRITE, 0, 4, dp, NULL, step)) {
00391             break;
00392         }
00393         
00394         if (At45dCommand(node, DFCMD_BUF1_FLASH, pgn << pshft, 4, NULL, NULL, 0)) {
00395             break;
00396         }
00397         if (At45dWaitReady(node, AT45_WRITE_POLLS, 1)) {
00398             break;
00399         }
00400         if (rc < 0) {
00401             rc = 0;
00402         }
00403         rc += step;
00404         dp += step;
00405         len -= step;
00406         if (++pgn >= limit) {
00407             break;
00408         }
00409     }
00410     return rc;
00411 }
00412 
00413 #ifdef __HARVARD_ARCH__
00414 int SpiAt45dPageWrite_P(NUTDEVICE * dev, uint32_t pgn, PGM_P data, int len)
00415 {
00416     return -1;
00417 }
00418 #endif
00419 
00427 uint32_t SpiAt45dPages(NUTDEVICE * dev)
00428 {
00429     NUTBLOCKIO *blkio;
00430 
00431     NUTASSERT(dev != NULL);
00432     NUTASSERT(dev->dev_dcb != NULL);
00433     blkio = dev->dev_dcb;
00434 
00435     NUTASSERT(blkio->blkio_info != NULL);
00436     return ((AT45D_INFO *) blkio->blkio_info)->at45d_pages;
00437 }
00438 
00446 int SpiAt45dPageSize(NUTDEVICE * dev)
00447 {
00448     NUTBLOCKIO *blkio;
00449 
00450     NUTASSERT(dev != NULL);
00451     NUTASSERT(dev->dev_dcb != NULL);
00452     blkio = dev->dev_dcb;
00453 
00454     NUTASSERT(blkio->blkio_info != NULL);
00455     return ((AT45D_INFO *) blkio->blkio_info)->at45d_psize;
00456 }
00457 
00475 int SpiAt45dIOCtl(NUTDEVICE * dev, int req, void *conf)
00476 {
00477     int rc = 0;
00478 
00479     switch (req) {
00480     case NUTBLKDEV_MEDIAAVAIL:
00481         
00482         {
00483             int *flg;
00484             NUTASSERT(conf != NULL);
00485             flg = (int *) conf;
00486             *flg = 1;
00487         }
00488         break;
00489     case NUTBLKDEV_MEDIACHANGE:
00490         
00491         {
00492             int *flg;
00493             NUTASSERT(conf != NULL);
00494             flg = (int *) conf;
00495             *flg = 0;
00496         }
00497         break;
00498     default:
00499         rc = -1;
00500         break;
00501     }
00502     return rc;
00503 }