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
00063 AT45D_INFO at45d_info[] = {
00064 {8, 512, 256, 0x0D},
00065 {9, 512, 264, 0x0C},
00066 {8, 1025, 256, 0x15},
00067 {9, 1025, 264, 0x14},
00068 {8, 2048, 256, 0x1D},
00069 {9, 2048, 264, 0x1C},
00070 {8, 4096, 256, 0x25},
00071 {9, 4096, 264, 0x24},
00072 {9, 4096, 512, 0x2D},
00073 {10, 4096, 528, 0x2C},
00074 {9, 8192, 512, 0x35},
00075 {10, 8192, 528, 0x34},
00076 {10, 8192, 1024, 0x39},
00077 {11, 8192, 1056, 0x38},
00078 {10, 8192, 1024, 0x3D},
00079 {11, 8192, 1056, 0x3C}
00080 };
00081
00083 uint_fast8_t at45d_known_types = sizeof(at45d_info) / sizeof(AT45D_INFO);
00084
00096 static int At45dCommand(NUTSPINODE * node, uint8_t op, uint32_t parm, int oplen, CONST void *txbuf, void *rxbuf, int xlen)
00097 {
00098 int rc = -1;
00099 NUTSPIBUS *bus;
00100 uint8_t cmd[8];
00101
00102 NUTASSERT(node != NULL);
00103 bus = (NUTSPIBUS *) node->node_bus;
00104 NUTASSERT(bus != NULL);
00105 NUTASSERT(bus->bus_alloc != NULL);
00106 NUTASSERT(bus->bus_transfer != NULL);
00107 NUTASSERT(bus->bus_release != NULL);
00108
00109 NUTASSERT(oplen <= 8);
00110 memset(cmd, 0, oplen);
00111 cmd[0] = op;
00112 if (parm) {
00113 cmd[1] = (uint8_t) (parm >> 16);
00114 cmd[2] = (uint8_t) (parm >> 8);
00115 cmd[3] = (uint8_t) parm;
00116 }
00117 rc = (*bus->bus_alloc) (node, 1000);
00118 if (rc == 0) {
00119 rc = (*bus->bus_transfer) (node, cmd, NULL, oplen);
00120 if (rc == 0 && xlen) {
00121 rc = (*bus->bus_transfer) (node, txbuf, rxbuf, xlen);
00122 }
00123 (*bus->bus_release) (node);
00124 }
00125 return rc;
00126 }
00127
00135 static uint8_t At45dStatus(NUTSPINODE * node)
00136 {
00137 int rc;
00138 uint8_t cmd[2] = { DFCMD_READ_STATUS, 0xFF };
00139 NUTSPIBUS *bus;
00140
00141 NUTASSERT(node != NULL);
00142 NUTASSERT(node->node_bus != NULL);
00143 bus = (NUTSPIBUS *) node->node_bus;
00144
00145 NUTASSERT(bus->bus_alloc != NULL);
00146 NUTASSERT(bus->bus_transfer != NULL);
00147 NUTASSERT(bus->bus_wait != NULL);
00148 NUTASSERT(bus->bus_release != NULL);
00149
00150 rc = (*bus->bus_alloc) (node, 1000);
00151 if (rc == 0) {
00152 rc = (*bus->bus_transfer) (node, cmd, cmd, 2);
00153 if (rc == 0) {
00154 (*bus->bus_wait) (node, NUT_WAIT_INFINITE);
00155 rc = cmd[1];
00156 }
00157 (*bus->bus_release) (node);
00158 }
00159 return (uint8_t) rc;
00160 }
00161
00169 static int At45dWaitReady(NUTSPINODE * node, uint32_t tmo, int poll)
00170 {
00171 uint8_t sr;
00172
00173 while (((sr = At45dStatus(node)) & 0x80) == 0) {
00174 if (!poll) {
00175 NutSleep(1);
00176 }
00177 if (tmo-- == 0) {
00178 return -1;
00179 }
00180 }
00181 return 0;
00182 }
00183
00195 int SpiAt45dCommand(NUTDEVICE * dev, uint8_t op, uint32_t parm, int oplen, CONST void *txbuf, void *rxbuf, int xlen)
00196 {
00197 NUTASSERT(dev != NULL);
00198 return At45dCommand(dev->dev_icb, op, parm, oplen, txbuf, rxbuf, xlen);
00199 }
00200
00208 uint8_t SpiAt45dStatus(NUTDEVICE * dev)
00209 {
00210 NUTASSERT(dev != NULL);
00211 return At45dStatus(dev->dev_icb);
00212 }
00213
00221 int SpiAt45dWaitReady(NUTDEVICE * dev, uint32_t tmo, int poll)
00222 {
00223 NUTASSERT(dev != NULL);
00224 return At45dWaitReady(dev->dev_icb, tmo, poll);
00225 }
00226
00235 int SpiAt45dPageErase(NUTDEVICE * dev, uint32_t pgn)
00236 {
00237 NUTBLOCKIO *blkio;
00238 AT45D_INFO *info;
00239
00240 NUTASSERT(dev != NULL);
00241 NUTASSERT(dev->dev_dcb != NULL);
00242 blkio = dev->dev_dcb;
00243
00244 info = (AT45D_INFO *) blkio->blkio_info;
00245 NUTASSERT(blkio->blkio_info != NULL);
00246
00247 if (pgn >= info->at45d_pages) {
00248 return -1;
00249 }
00250 pgn <<= info->at45d_pshft;
00251 return At45dCommand((NUTSPINODE *) dev->dev_icb, DFCMD_PAGE_ERASE, pgn, 4, NULL, NULL, 0);
00252 }
00253
00257 int SpiAt45dChipErase(NUTDEVICE * dev)
00258 {
00259 return -1;
00260 }
00261
00274 int SpiAt45dInit(NUTDEVICE * dev)
00275 {
00276 NUTBLOCKIO *blkio;
00277 NUTSPINODE *node;
00278 uint8_t sr;
00279 int_fast8_t i;
00280
00281 NUTASSERT(dev != NULL);
00282 NUTASSERT(dev->dev_dcb != NULL);
00283 NUTASSERT(dev->dev_icb != NULL);
00284 blkio = dev->dev_dcb;
00285 node = dev->dev_icb;
00286
00287
00288 sr = At45dStatus(node);
00289 sr &= AT45D_STATUS_DENSITY | AT45D_STATUS_PAGE_SIZE;
00290 for (i = at45d_known_types; --i >= 0;) {
00291 if (sr == at45d_info[i].at45d_srval) {
00292
00293 blkio->blkio_info = &at45d_info[i];
00294 blkio->blkio_blk_cnt = at45d_info[i].at45d_pages;
00295 blkio->blkio_blk_siz = at45d_info[i].at45d_psize;
00296 return 0;
00297 }
00298 }
00299
00300 return -1;
00301 }
00302
00314 int SpiAt45dPageRead(NUTDEVICE * dev, uint32_t pgn, void *data, int len)
00315 {
00316 NUTBLOCKIO *blkio;
00317 AT45D_INFO *info;
00318
00319 NUTASSERT(dev != NULL);
00320 NUTASSERT(dev->dev_dcb != NULL);
00321 blkio = dev->dev_dcb;
00322
00323 info = (AT45D_INFO *) blkio->blkio_info;
00324 NUTASSERT(blkio->blkio_info != NULL);
00325
00326 if (pgn >= info->at45d_pages) {
00327 return -1;
00328 }
00329 pgn <<= info->at45d_pshft;
00330
00331 if (At45dCommand((NUTSPINODE *) dev->dev_icb, DFCMD_CONT_READ, pgn, 8, NULL, data, len)) {
00332 return -1;
00333 }
00334 return len;
00335 }
00336
00354 int SpiAt45dPageWrite(NUTDEVICE * dev, uint32_t pgn, CONST void *data, int len)
00355 {
00356 int rc = -1;
00357 uint8_t *dp = (uint8_t *) data;
00358 int step;
00359 uint_fast8_t pshft;
00360 uint32_t limit;
00361 NUTBLOCKIO *blkio;
00362 NUTSPINODE *node;
00363
00364
00365 if (len == 0) {
00366 return 0;
00367 }
00368 NUTASSERT(data != NULL);
00369 NUTASSERT(dev != NULL);
00370 NUTASSERT(dev->dev_dcb != NULL);
00371 NUTASSERT(dev->dev_icb != NULL);
00372 blkio = (NUTBLOCKIO *) dev->dev_dcb;
00373 node = (NUTSPINODE *) dev->dev_icb;
00374 NUTASSERT(blkio->blkio_info != NULL);
00375 pshft = ((AT45D_INFO *) blkio->blkio_info)->at45d_pshft;
00376 step = ((AT45D_INFO *) blkio->blkio_info)->at45d_psize;
00377 limit = ((AT45D_INFO *) blkio->blkio_info)->at45d_pages;
00378
00379 while (len) {
00380 if (step > len) {
00381 step = len;
00382 }
00383
00384 if (At45dCommand(node, DFCMD_BUF1_WRITE, 0, 4, dp, NULL, step)) {
00385 break;
00386 }
00387
00388 if (At45dCommand(node, DFCMD_BUF1_FLASH, pgn << pshft, 4, NULL, NULL, 0)) {
00389 break;
00390 }
00391 if (At45dWaitReady(node, AT45_WRITE_POLLS, 1)) {
00392 break;
00393 }
00394 if (rc < 0) {
00395 rc = 0;
00396 }
00397 rc += step;
00398 dp += step;
00399 len -= step;
00400 if (++pgn >= limit) {
00401 break;
00402 }
00403 }
00404 return rc;
00405 }
00406
00407 #ifdef __HARVARD_ARCH__
00408 int SpiAt45dPageWrite_P(NUTDEVICE * dev, uint32_t pgn, PGM_P data, int len)
00409 {
00410 return -1;
00411 }
00412 #endif
00413
00421 uint32_t SpiAt45dPages(NUTDEVICE * dev)
00422 {
00423 NUTBLOCKIO *blkio;
00424
00425 NUTASSERT(dev != NULL);
00426 NUTASSERT(dev->dev_dcb != NULL);
00427 blkio = dev->dev_dcb;
00428
00429 NUTASSERT(blkio->blkio_info != NULL);
00430 return ((AT45D_INFO *) blkio->blkio_info)->at45d_pages;
00431 }
00432
00440 int SpiAt45dPageSize(NUTDEVICE * dev)
00441 {
00442 NUTBLOCKIO *blkio;
00443
00444 NUTASSERT(dev != NULL);
00445 NUTASSERT(dev->dev_dcb != NULL);
00446 blkio = dev->dev_dcb;
00447
00448 NUTASSERT(blkio->blkio_info != NULL);
00449 return ((AT45D_INFO *) blkio->blkio_info)->at45d_psize;
00450 }
00451
00469 int SpiAt45dIOCtl(NUTDEVICE * dev, int req, void *conf)
00470 {
00471 int rc = 0;
00472
00473 switch (req) {
00474 case NUTBLKDEV_MEDIAAVAIL:
00475
00476 {
00477 int *flg;
00478 NUTASSERT(conf != NULL);
00479 flg = (int *) conf;
00480 *flg = 1;
00481 }
00482 break;
00483 case NUTBLKDEV_MEDIACHANGE:
00484
00485 {
00486 int *flg;
00487 NUTASSERT(conf != NULL);
00488 flg = (int *) conf;
00489 *flg = 0;
00490 }
00491 break;
00492 default:
00493 rc = -1;
00494 break;
00495 }
00496 return rc;
00497 }