[PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support

Zhiqiang Hou zhiqiang.hou at nxp.com
Thu Apr 14 00:59:39 PDT 2016


Hi,

Any comments?

> -----Original Message-----
> From: Zhiqiang Hou [mailto:Zhiqiang.Hou at freescale.com]
> Sent: 2016年1月22日 17:14
> To: linux-mtd at lists.infradead.org; computersforpeace at gmail.com;
> dwmw2 at infradead.org; jteki at openedev.com; marex at denx.de
> Cc: Mingkai.Hu at freescale.com; Hou Zhiqiang <Zhiqiang.Hou at freescale.com>
> Subject: [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support
> 
> From: Hou Zhiqiang <Zhiqiang.Hou at freescale.com>
> 
> Add the Power Management API in SPI NOR framework.
> The Power Management system will turn off power supply to SPI flash when
> system suspending, and then the SPI flash will be in the reset state after system
> resuming. As a result, the status&configurations of SPI flash driver will mismatch
> with its current hardware state.
> So reinitialize SPI flash to make sure it is resumed to the correct state.
> And the SPI NOR layer just do common configuration depending on the records in
> structure spi_nor.
> 
> Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou at freescale.com>
> ---
> Tested on T1042D4RDB.
> 
> V3:
>  - Remove the condition #ifdef CONFIG_PM_SLEEP
>  - Define the spi_nor_unprotect_on_powerup() to make it reuseable.
> 
>  drivers/mtd/spi-nor/spi-nor.c | 73 ++++++++++++++++++++++++++++++++++++----
> ---
>  include/linux/mtd/spi-nor.h   |  9 ++++++
>  2 files changed, 71 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index
> ed0c19c..7e416fb 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -1179,6 +1179,26 @@ static int spi_nor_check(struct spi_nor *nor)
>  	return 0;
>  }
> 
> +/*
> + * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
> + * with the software protection bits set  */ static int
> +spi_nor_unprotect_on_powerup(struct spi_nor *nor) {
> +	const struct flash_info *info = NULL;
> +	int ret = 0;
> +
> +	info = spi_nor_read_id(nor);
> +	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
> +	    JEDEC_MFR(info) == SNOR_MFR_INTEL ||
> +	    JEDEC_MFR(info) == SNOR_MFR_SST) {
> +		write_enable(nor);
> +		ret = write_sr(nor, 0);
> +	}
> +
> +	return ret;
> +}
> +
>  int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
> {
>  	const struct flash_info *info = NULL;
> @@ -1226,17 +1246,9 @@ int spi_nor_scan(struct spi_nor *nor, const char
> *name, enum read_mode mode)
> 
>  	mutex_init(&nor->lock);
> 
> -	/*
> -	 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
> -	 * with the software protection bits set
> -	 */
> -
> -	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
> -	    JEDEC_MFR(info) == SNOR_MFR_INTEL ||
> -	    JEDEC_MFR(info) == SNOR_MFR_SST) {
> -		write_enable(nor);
> -		write_sr(nor, 0);
> -	}
> +	ret = spi_nor_unprotect_on_powerup(nor);
> +	if (ret)
> +		return ret;
> 
>  	if (!mtd->name)
>  		mtd->name = dev_name(dev);
> @@ -1402,6 +1414,45 @@ int spi_nor_scan(struct spi_nor *nor, const char
> *name, enum read_mode mode)  }  EXPORT_SYMBOL_GPL(spi_nor_scan);
> 
> +static int spi_nor_hw_reinit(struct spi_nor *nor) {
> +	const struct flash_info *info = NULL;
> +	struct device *dev = nor->dev;
> +	int ret;
> +
> +	info = spi_nor_read_id(nor);
> +
> +	ret = spi_nor_unprotect_on_powerup(nor);
> +	if (ret)
> +		return ret;
> +
> +	if (nor->flash_read == SPI_NOR_QUAD) {
> +		ret = set_quad_mode(nor, info);
> +		if (ret) {
> +			dev_err(dev, "quad mode not supported\n");
> +			return ret;
> +		}
> +	}
> +
> +	if (nor->addr_width == 4 &&
> +			JEDEC_MFR(info) != SNOR_MFR_SPANSION)
> +		set_4byte(nor, info, 1);
> +
> +	return 0;
> +}
> +
> +int spi_nor_suspend(struct spi_nor *nor) {
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(spi_nor_suspend);
> +
> +int spi_nor_resume(struct spi_nor *nor) {
> +	return spi_nor_hw_reinit(nor);
> +}
> +EXPORT_SYMBOL_GPL(spi_nor_resume);
> +
>  static const struct flash_info *spi_nor_match_id(const char *name)  {
>  	const struct flash_info *id = spi_nor_ids; diff --git a/include/linux/mtd/spi-
> nor.h b/include/linux/mtd/spi-nor.h index 62356d5..32f12cc 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -210,4 +210,13 @@ static inline struct device_node
> *spi_nor_get_flash_node(struct spi_nor *nor)
>   */
>  int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode);
> 
> +/**
> + * spi_nor_suspend/resume() - the SPI NOR layer PM API
> + * @nor:	the spi_nor structure
> + *
> + * Return: 0 for success, others for failure.
> + */
> +int spi_nor_suspend(struct spi_nor *nor); int spi_nor_resume(struct
> +spi_nor *nor);
> +
>  #endif
> --

Thanks,
Zhiqiang


More information about the linux-mtd mailing list