]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - packages/io/flash/v2_0/src/flash.c
TX51/TX53 Release 2011-08-19
[karo-tx-redboot.git] / packages / io / flash / v2_0 / src / flash.c
index 59725c5083fc252919b6c8ed9b85412ced7b5d5c..aee6b861c522a76affdf2ca92f06c1a21eb70088 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>
 
@@ -85,17 +84,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
@@ -112,286 +111,285 @@ 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 - 1);
-    }
+       /* Check to see if end_addr overflowed */
+       if ((end_addr < block) && (len > 0)) {
+               end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end);
+       }
 
 #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
 }
 
@@ -400,65 +398,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
@@ -528,38 +526,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