How to Check E_ERR/P_ERR Status Errors in the Linux MTD SPI Driver – KBA220225

Version: **

 

Question:

How do I add flash program/erase failure status checking to the Linux SPI MTD SPI Driver?

 

Answer:

The Linux master code doesn’t check for program/erase failure of SPI driver. The following steps will add this error-checking feature to the driver

 

1. Add E_ERR and P_ERR bit field definitions to SPI driver for FL-S and FS-S (in case of FL-L, use Status Register 2 instead of Status Register 1):

  • Open include/linux/mtd/spi-nor.h
  • Find Status Register bits definitions and replace the following:

          #define SR_TB BIT(5) /* Top/Bottom protect */

 

          with:

 

          #define SR_E_ERR BIT(5) /* Erase error occurred */

          #define SR_P_ERR BIT(6) /* Programming error occurred */

  • Find Flash opcodes section and add Clear Status Register opcode

          #define SPINOR_OP_CLSR 0x30 /* Clear status register */

 

2. Add E_ERR and P_ERR status bit checking to the Status Ready checking subroutine:

  • Open drivers/mtd/spi-nor/spi-nor.c
  • Add clear_sr() subroutine

          /*

          * Clear status register

          * Returns negative if error occurred.

          */

          static inline int clear_sr(struct spi_nor *nor)

          {

               return nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);

          }

  • Add a user notification subroutine when erase or program failure happens, for example, user_error_handler()
  • Find static inline int spi_nor_sr_ready(struct spi_nor *nor)
  • Modify the code from:

 

                 int sr = read_sr(nor);

                         if (sr < 0)

                         return sr;

 

                         else

                         return !(sr & SR_WIP);

                         to:

 

                         int sr = read_sr(nor);

                         if (sr < 0)

                              return sr;

                         else if ((sr & SR_E_ERR) || (sr & SR_P_ERR))

                        {

                                    user_error_handler();

                                    write_enable(nor);

                                    clear_sr(nor);

                        }

                        return !(sr & SR_WIP);