]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - packages/io/flash/v2_0/src/flash.c
TX51 Release 2011-07-27
[karo-tx-redboot.git] / packages / io / flash / v2_0 / src / flash.c
index aee6b861c522a76affdf2ca92f06c1a21eb70088..59725c5083fc252919b6c8ed9b85412ced7b5d5c 100644 (file)
 // Author(s):    gthomas
 // Contributors: gthomas
 // Date:         2000-07-26
-// Purpose:
-// Description:
-//
+// Purpose:      
+// Description:  
+//              
 //####DESCRIPTIONEND####
 //
 //==========================================================================
+
 #include <pkgconf/system.h>
 #include <pkgconf/io_flash.h>
 
@@ -84,17 +85,17 @@ externC code_fun flash_unlock_block;
 int
 flash_init(_printf *pf)
 {
-       int err;
+    int err;
 
-       flash_info.pf = pf; // Do this before calling into the driver
-       if (flash_info.init) return FLASH_ERR_OK;
+    flash_info.pf = pf; // Do this before calling into the driver
+    if (flash_info.init) return FLASH_ERR_OK;
 
-       if ((err = flash_hwr_init()) != FLASH_ERR_OK) {
-               return err;
-       }
-       flash_info.block_mask = ~(flash_info.block_size - 1);
-       flash_info.init = 1;
-       return FLASH_ERR_OK;
+    if ((err = flash_hwr_init()) != FLASH_ERR_OK) {
+        return err;
+    }
+    flash_info.block_mask = ~(flash_info.block_size-1);
+    flash_info.init = 1;
+    return FLASH_ERR_OK;
 }
 
 // Use this function to make function pointers anonymous - forcing the
@@ -111,285 +112,286 @@ static void *__anonymizer(void *p)
 void
 flash_dev_query(void *data)
 {
-       typedef void code_fun(void *);
-       code_fun *_flash_query;
-       int d_cache, i_cache;
+    typedef void code_fun(void *);
+    code_fun *_flash_query;
+    int d_cache, i_cache;
 
-       _flash_query = (code_fun*)__anonymizer(&flash_query);
+    _flash_query = (code_fun*)__anonymizer(&flash_query);
 
-       HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-       (*_flash_query)(data);
-       HAL_FLASH_CACHES_ON(d_cache, i_cache);
+    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+    (*_flash_query)(data);
+    HAL_FLASH_CACHES_ON(d_cache, i_cache);
 }
 
 int
 flash_verify_addr(void *target)
 {
-       if (!flash_info.init) {
-               return FLASH_ERR_NOT_INIT;
-       }
-       if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) &&
-               ((CYG_ADDRESS)target <= ((CYG_ADDRESS)flash_info.end - 1))) {
-               return FLASH_ERR_OK;
-       } else {
-               return FLASH_ERR_INVALID;
-       }
+    if (!flash_info.init) {
+        return FLASH_ERR_NOT_INIT;
+    }
+    if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) &&
+        ((CYG_ADDRESS)target <= ((CYG_ADDRESS)flash_info.end - 1))) {
+        return FLASH_ERR_OK;
+    } else {
+        return FLASH_ERR_INVALID;
+    }
 }
 
 int
 flash_get_limits(void *target, void **start, void **end)
 {
-       if (!flash_info.init) {
-               return FLASH_ERR_NOT_INIT;
-       }
-       *start = flash_info.start;
-       *end = flash_info.end;
-       return FLASH_ERR_OK;
+    if (!flash_info.init) {
+        return FLASH_ERR_NOT_INIT;
+    }
+    *start = flash_info.start;
+    *end = flash_info.end;
+    return FLASH_ERR_OK;
 }
 
 int
 flash_get_block_info(int *block_size, int *blocks)
 {
-       if (!flash_info.init) {
-               return FLASH_ERR_NOT_INIT;
-       }
-       *block_size = flash_info.block_size;
-       *blocks = flash_info.blocks;
-       return FLASH_ERR_OK;
+    if (!flash_info.init) {
+        return FLASH_ERR_NOT_INIT;
+    }
+    *block_size = flash_info.block_size;
+    *blocks = flash_info.blocks;
+    return FLASH_ERR_OK;
 }
 
 int
 flash_erase(void *addr, int len, void **err_addr)
 {
-       unsigned short *block, *end_addr;
-       int stat = 0;
-       typedef int code_fun(unsigned short *, unsigned int);
-       code_fun *_flash_erase_block;
-       int d_cache, i_cache;
+    unsigned short *block, *end_addr;
+    int stat = 0;
+    typedef int code_fun(unsigned short *, unsigned int);
+    code_fun *_flash_erase_block;
+    int d_cache, i_cache;
 
-       if (!flash_info.init) {
-               return FLASH_ERR_NOT_INIT;
-       }
+    if (!flash_info.init) {
+        return FLASH_ERR_NOT_INIT;
+    }
 
 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
-       if (plf_flash_query_soft_wp(addr,len))
-               return FLASH_ERR_PROTECT;
+    if (plf_flash_query_soft_wp(addr,len))
+        return FLASH_ERR_PROTECT;
 #endif
 
-       _flash_erase_block = (code_fun*)__anonymizer(&flash_erase_block);
+     _flash_erase_block = (code_fun*)__anonymizer(&flash_erase_block);
 
-       block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
-       end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
+    block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
+    end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
 
-       /* Check to see if end_addr overflowed */
-       if ((end_addr < block) && (len > 0)) {
-               end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end);
-       }
+    /* Check to see if end_addr overflowed */
+    if ((end_addr < block) && (len > 0)) {
+        end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
+    }
 
 #ifdef CYGSEM_IO_FLASH_CHATTER
-       flash_info.pf("... Erase from %p-%p: ", block, end_addr);
+    flash_info.pf("... Erase from %p-%p: ", block, end_addr);
 #endif
 
-       HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-       FLASH_Enable(block, end_addr);
-       while (block < end_addr) {
-               // Supply the blocksize for a gross check for erase success
-               unsigned short *tmp_block;
+    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+    FLASH_Enable(block, end_addr);
+    while (block < end_addr) {
+        // Supply the blocksize for a gross check for erase success
+        unsigned short *tmp_block;
 #if !defined(CYGSEM_IO_FLASH_READ_INDIRECT)
-               int i;
-               unsigned char *dp;
-               bool erased = true;
-
-               dp = (unsigned char *)block;
-               for (i = 0; i < flash_info.block_size; i++) {
-                       if (*dp++ != 0xFF) {
-                               erased = false;
-                               break;
-                       }
-               }
+        int i;
+        unsigned char *dp;
+        bool erased = true;
+
+        dp = (unsigned char *)block;
+        for (i = 0;  i < flash_info.block_size;  i++) {
+            if (*dp++ != 0xFF) {
+                erased = false;
+                break;
+            }
+        }
 #else
-               bool erased = false;
+        bool erased = false;
 #endif
 
-               if (!erased) {
-                       stat = (*_flash_erase_block)(block, flash_info.block_size);
-                       stat = flash_hwr_map_error(stat);
-               }
-               if (stat) {
-                       *err_addr = block;
-                       break;
-               }
-
-               // Check to see if block will overflow
-               tmp_block = block + flash_info.block_size / sizeof(*block);
-               if (tmp_block < block) {
-                       // If block address overflows, set block value to end on this loop
-                       block = end_addr;
-               } else {
-                       block = tmp_block;
-               }
+        if (!erased) {
+            stat = (*_flash_erase_block)(block, flash_info.block_size);
+            stat = flash_hwr_map_error(stat);
+        }
+        if (stat) {
+            *err_addr = block;
+            break;
+        }
+
+        // Check to see if block will overflow
+        tmp_block = block + flash_info.block_size / sizeof(*block);
+        if (tmp_block < block) {
+            // If block address overflows, set block value to end on this loop
+            block = end_addr;
+        } else {
+            block = tmp_block;
+        }
 #ifdef CYGSEM_IO_FLASH_CHATTER
-               flash_info.pf(".");
+        flash_info.pf(".");
 #endif
-       }
-       FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
-                               end_addr);
-       HAL_FLASH_CACHES_ON(d_cache, i_cache);
+    }
+    FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
+                                 end_addr);
+    HAL_FLASH_CACHES_ON(d_cache, i_cache);
 #ifdef CYGSEM_IO_FLASH_CHATTER
-       flash_info.pf("\n");
+    flash_info.pf("\n");
 #endif
-       return stat;
+    return stat;
 }
 
 int
 flash_program(void *_addr, void *_data, int len, void **err_addr)
 {
-       int stat = 0;
-       int size;
-       typedef int code_fun(void *, void *, int, unsigned long, int);
-       code_fun *_flash_program_buf;
-       unsigned char *addr = _addr;
-       unsigned char *data = _data;
-       CYG_ADDRESS tmp;
-       int d_cache, i_cache;
-
-       if (!flash_info.init) {
-               return FLASH_ERR_NOT_INIT;
-       }
+    int stat = 0;
+    int size;
+    typedef int code_fun(void *, void *, int, unsigned long, int);
+    code_fun *_flash_program_buf;
+    unsigned char *addr = _addr;
+    unsigned char *data = _data;
+    CYG_ADDRESS tmp;
+    int d_cache, i_cache;
+
+    if (!flash_info.init) {
+        return FLASH_ERR_NOT_INIT;
+    }
 
 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
-       if (plf_flash_query_soft_wp(addr,len))
-               return FLASH_ERR_PROTECT;
+    if (plf_flash_query_soft_wp(addr,len))
+        return FLASH_ERR_PROTECT;
 #endif
 
-       _flash_program_buf = (code_fun*)__anonymizer(&flash_program_buf);
+    _flash_program_buf = (code_fun*)__anonymizer(&flash_program_buf);
 
 #ifdef CYGSEM_IO_FLASH_CHATTER
-       flash_info.pf("... Program from %p-%p at %p: ", data,
-                               (void *)((CYG_ADDRESS)data + len), addr);
+    flash_info.pf("... Program from %p-%p at %p: ", data, 
+                     (void *)((CYG_ADDRESS)data + len), addr);
 #endif
 
-       HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-       FLASH_Enable(addr, addr + len);
-       while (len > 0) {
-               size = len;
+    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+    FLASH_Enable(addr, addr + len);
+    while (len > 0) {
+        size = len;
 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
-               if (flash_info.start != 0)
+        if (flash_info.start != 0)
 #endif
-                       if (size > flash_info.block_size) size = flash_info.block_size;
+        if (size > flash_info.block_size) size = flash_info.block_size;
 
-               tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
-               if (tmp) {
-                       tmp = flash_info.block_size - tmp;
-                       if (size > tmp) size = tmp;
-               }
+        tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
+        if (tmp) {
+                tmp = flash_info.block_size - tmp;
+                if (size > tmp) size = tmp;
+        }
 
-               stat = (*_flash_program_buf)(addr, data, size,
-                                                                       flash_info.block_mask, flash_info.buffer_size);
-               stat = flash_hwr_map_error(stat);
+        stat = (*_flash_program_buf)(addr, data, size, 
+                                     flash_info.block_mask, flash_info.buffer_size);
+        stat = flash_hwr_map_error(stat);
 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
-               if (0 == stat) // Claims to be OK
-                       if (memcmp(addr, data, size) != 0) {
-                               stat = 0x0BAD;
+        if (0 == stat) // Claims to be OK
+            if (memcmp(addr, data, size) != 0) {                
+                stat = 0x0BAD;
 #ifdef CYGSEM_IO_FLASH_CHATTER
-                               flash_info.pf("V");
+                flash_info.pf("V");
 #endif
-                       }
+            }
 #endif
-               if (stat) {
-                       *err_addr = addr;
-                       break;
-               }
+        if (stat) {
+            *err_addr = addr;
+            break;
+        }
 #ifdef CYGSEM_IO_FLASH_CHATTER
-               flash_info.pf(".");
+        flash_info.pf(".");
 #endif
-               len -= size;
-               addr += size / sizeof(*addr);
-               data += size / sizeof(*data);
-       }
-       FLASH_Disable(_addr, addr + len);
-       HAL_FLASH_CACHES_ON(d_cache, i_cache);
+        len -= size;
+        addr += size / sizeof(*addr);
+        data += size / sizeof(*data);
+    }
+    FLASH_Disable(_addr, addr + len);
+    HAL_FLASH_CACHES_ON(d_cache, i_cache);
 #ifdef CYGSEM_IO_FLASH_CHATTER
-       flash_info.pf("\n");
+    flash_info.pf("\n");
 #endif
-       return stat;
+    return stat;
 }
 
 int
 flash_read(void *_addr, void *_data, int len, void **err_addr)
 {
 #ifdef CYGSEM_IO_FLASH_READ_INDIRECT
-       int stat = 0;
-       int size;
-       typedef int code_fun(void *, void *, int, unsigned long, int);
-       code_fun *_flash_read_buf;
-       unsigned char *addr = _addr;
-       unsigned char *data = _data;
-       CYG_ADDRESS tmp;
-       int d_cache, i_cache;
+    int stat = 0;
+    int size;
+    typedef int code_fun(void *, void *, int, unsigned long, int);
+    code_fun *_flash_read_buf;
+    unsigned char *addr = _addr;
+    unsigned char *data = _data;
+    CYG_ADDRESS tmp;
+    int d_cache, i_cache;
 
-       if (!flash_info.init) {
-               return FLASH_ERR_NOT_INIT;
-       }
+    if (!flash_info.init) {
+        return FLASH_ERR_NOT_INIT;
+    }
 
-       _flash_read_buf = (code_fun*)__anonymizer(&flash_read_buf);
+    _flash_read_buf = (code_fun*)__anonymizer(&flash_read_buf);
 
 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
-       flash_info.pf("... Read from %p-%p at %p: ", data,
-                               (void *)((CYG_ADDRESS)data + len), addr);
+    flash_info.pf("... Read from %p-%p at %p: ", data, 
+                     (void *)((CYG_ADDRESS)data + len), addr);
 #endif
 
-       HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-       FLASH_Enable(addr, addr + len);
-       while (len > 0) {
-               size = len;
+    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+    FLASH_Enable(addr, addr + len);
+    while (len > 0) {
+        size = len;
 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
-               if (flash_info.start != 0)
+        if (flash_info.start !=0)
 #endif
-               if (size > flash_info.block_size) size = flash_info.block_size;
+        if (size > flash_info.block_size) size = flash_info.block_size;
 
-               tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
-               if (tmp) {
-                       tmp = flash_info.block_size - tmp;
-                       if (size>tmp) size = tmp;
-               }
+        tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
+        if (tmp) {
+                tmp = flash_info.block_size - tmp;
+                if (size>tmp) size = tmp;
 
-               stat = (*_flash_read_buf)(addr, data, size,
-                                                               flash_info.block_mask, flash_info.buffer_size);
-               stat = flash_hwr_map_error(stat);
+        }
+
+        stat = (*_flash_read_buf)(addr, data, size, 
+                                     flash_info.block_mask, flash_info.buffer_size);
+        stat = flash_hwr_map_error(stat);
 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
-               if (0 == stat) // Claims to be OK
-                       if (memcmp(addr, data, size) != 0) {
-                               stat = 0x0BAD;
+        if (0 == stat) // Claims to be OK
+            if (memcmp(addr, data, size) != 0) {                
+                stat = 0x0BAD;
 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
-                               flash_info.pf("V");
+                flash_info.pf("V");
 #endif
-                       }
+            }
 #endif
-               if (stat) {
-                       *err_addr = addr;
-                       break;
-               }
+        if (stat) {
+            *err_addr = addr;
+            break;
+        }
 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
-               flash_info.pf(".");
+        flash_info.pf(".");
 #endif
-               len -= size;
-               addr += size / sizeof(*addr);
-               data += size / sizeof(*data);
-       }
-       FLASH_Disable(_addr, addr + len);
-       HAL_FLASH_CACHES_ON(d_cache, i_cache);
+        len -= size;
+        addr += size / sizeof(*addr);
+        data += size / sizeof(*data);
+    }
+    FLASH_Disable(_addr, addr + len);
+    HAL_FLASH_CACHES_ON(d_cache, i_cache);
 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
-       flash_info.pf("\n");
+    flash_info.pf("\n");
 #endif
-       return stat;
+    return stat;
 #else // CYGSEM_IO_FLASH_READ_INDIRECT
-       // Direct access to FLASH memory is possible - just move the requested bytes
-       if (!flash_info.init) {
-               return FLASH_ERR_NOT_INIT;
-       }
-       memcpy(_data, _addr, len);
-       return FLASH_ERR_OK;
+    // Direct access to FLASH memory is possible - just move the requested bytes
+    if (!flash_info.init) {
+        return FLASH_ERR_NOT_INIT;
+    }
+    memcpy(_data, _addr, len);
+    return FLASH_ERR_OK;
 #endif
 }
 
@@ -398,65 +400,65 @@ flash_read(void *_addr, void *_data, int len, void **err_addr)
 int
 flash_lock(void *addr, int len, void **err_addr)
 {
-       unsigned short *block, *end_addr;
-       int stat = 0;
-       typedef int code_fun(unsigned short *);
-       code_fun *_flash_lock_block;
-       int d_cache, i_cache;
+    unsigned short *block, *end_addr;
+    int stat = 0;
+    typedef int code_fun(unsigned short *);
+    code_fun *_flash_lock_block;
+    int d_cache, i_cache;
 
-       if (!flash_info.init) {
-               return FLASH_ERR_NOT_INIT;
-       }
+    if (!flash_info.init) {
+        return FLASH_ERR_NOT_INIT;
+    }
 
 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
-       if (plf_flash_query_soft_wp(addr,len))
-               return FLASH_ERR_PROTECT;
+    if (plf_flash_query_soft_wp(addr,len))
+        return FLASH_ERR_PROTECT;
 #endif
 
-       _flash_lock_block = (code_fun*)__anonymizer(&flash_lock_block);
+    _flash_lock_block = (code_fun*)__anonymizer(&flash_lock_block);
 
-       block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
-       end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
+    block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
+    end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
 
-       /* Check to see if end_addr overflowed */
-       if ((end_addr < block) && (len > 0)) {
-               end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
-       }
+    /* Check to see if end_addr overflowed */
+    if ((end_addr < block) && (len > 0)) {
+        end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
+    }
 
 #ifdef CYGSEM_IO_FLASH_CHATTER
-       flash_info.pf("... Lock from %p-%p: ", block, end_addr);
+    flash_info.pf("... Lock from %p-%p: ", block, end_addr);
 #endif
 
-       HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-       FLASH_Enable(block, end_addr);
-       while (block < end_addr) {
-               unsigned short *tmp_block;
-               stat = (*_flash_lock_block)(block);
-               stat = flash_hwr_map_error(stat);
-               if (stat) {
-                       *err_addr = block;
-                       break;
-               }
-
-               // Check to see if block will overflow
-               tmp_block = block + flash_info.block_size / sizeof(*block);
-               if (tmp_block < block) {
-                       // If block address overflows, set block value to end on this loop
-                       block = end_addr;
-               } else {
-                       block = tmp_block;
-               }
+    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+    FLASH_Enable(block, end_addr);
+    while (block < end_addr) {
+        unsigned short *tmp_block;
+        stat = (*_flash_lock_block)(block);
+        stat = flash_hwr_map_error(stat);
+        if (stat) {
+            *err_addr = block;
+            break;
+        }
+
+        // Check to see if block will overflow
+        tmp_block = block + flash_info.block_size / sizeof(*block);
+        if (tmp_block < block) {
+            // If block address overflows, set block value to end on this loop
+            block = end_addr;
+        } else {
+            block = tmp_block;
+        }
 #ifdef CYGSEM_IO_FLASH_CHATTER
-               flash_info.pf(".");
+        flash_info.pf(".");
 #endif
-       }
-       FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
-                               end_addr);
-       HAL_FLASH_CACHES_ON(d_cache, i_cache);
+    }
+    FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
+                                 end_addr);
+    HAL_FLASH_CACHES_ON(d_cache, i_cache);
 #ifdef CYGSEM_IO_FLASH_CHATTER
-       flash_info.pf("\n");
+    flash_info.pf("\n");
 #endif
-       return stat;
+    return stat;
 }
 
 int
@@ -526,38 +528,38 @@ flash_unlock(void *addr, int len, void **err_addr)
 char *
 flash_errmsg(int err)
 {
-       switch (err) {
-       case FLASH_ERR_OK:
-               return "No error - operation complete";
-       case FLASH_ERR_ERASE_SUSPEND:
-               return "Device is in erase suspend state";
-       case FLASH_ERR_PROGRAM_SUSPEND:
-               return "Device is in program suspend state";
-       case FLASH_ERR_INVALID:
-               return "Invalid FLASH address";
-       case FLASH_ERR_ERASE:
-               return "Error trying to erase";
-       case FLASH_ERR_LOCK:
-               return "Error trying to lock/unlock";
-       case FLASH_ERR_PROGRAM:
-               return "Error trying to program";
-       case FLASH_ERR_PROTOCOL:
-               return "Generic error";
-       case FLASH_ERR_PROTECT:
-               return "Device/region is write-protected";
-       case FLASH_ERR_NOT_INIT:
-               return "FLASH sub-system not initialized";
-       case FLASH_ERR_DRV_VERIFY:
-               return "Data verify failed after operation";
-       case FLASH_ERR_DRV_TIMEOUT:
-               return "Driver timed out waiting for device";
-       case FLASH_ERR_DRV_WRONG_PART:
-               return "Driver does not support device";
-       case FLASH_ERR_LOW_VOLTAGE:
-               return "Device reports low voltage";
-       default:
-               return "Unknown error";
-       }
+    switch (err) {
+    case FLASH_ERR_OK:
+        return "No error - operation complete";
+    case FLASH_ERR_ERASE_SUSPEND:
+        return "Device is in erase suspend state";
+    case FLASH_ERR_PROGRAM_SUSPEND:
+        return "Device is in program suspend state";
+    case FLASH_ERR_INVALID:
+        return "Invalid FLASH address";
+    case FLASH_ERR_ERASE:
+        return "Error trying to erase";
+    case FLASH_ERR_LOCK:
+        return "Error trying to lock/unlock";
+    case FLASH_ERR_PROGRAM:
+        return "Error trying to program";
+    case FLASH_ERR_PROTOCOL:
+        return "Generic error";
+    case FLASH_ERR_PROTECT:
+        return "Device/region is write-protected";
+    case FLASH_ERR_NOT_INIT:
+        return "FLASH sub-system not initialized";
+    case FLASH_ERR_DRV_VERIFY:
+        return "Data verify failed after operation";
+    case FLASH_ERR_DRV_TIMEOUT:
+        return "Driver timed out waiting for device";
+    case FLASH_ERR_DRV_WRONG_PART:
+        return "Driver does not support device";
+    case FLASH_ERR_LOW_VOLTAGE:
+        return "Device reports low voltage";
+    default:
+        return "Unknown error";
+    }
 }
 
 // EOF io/flash/..../flash.c