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 }