mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 14:04:26 -04:00 
			
		
		
		
	This flag was added to 4.9 with upstream commit 76a4707de5e18dc32d9cb4e990686140c5664a15. Signed-off-by: Victor Shyba <victor1984@riseup.net> [refresh and adjust platform patches, fix commit message] Signed-off-by: Mathias Kresin <dev@kresin.me>
		
			
				
	
	
		
			139 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 2c5a3db21926e9ebfd7a32e3c36a3256ed84903c Mon Sep 17 00:00:00 2001
 | |
| From: Hou Zhiqiang <Zhiqiang.Hou@freescale.com>
 | |
| Date: Thu, 19 Nov 2015 20:25:24 +0800
 | |
| Subject: [PATCH 090/113] mtd: spi-nor: Add SPI NOR layer PM support
 | |
| 
 | |
| [context adjustment]
 | |
| 
 | |
| 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@freescale.com>
 | |
| Integrated-by: Jiang Yutang <yutang.jiang@nxp.com>
 | |
| ---
 | |
|  drivers/mtd/spi-nor/spi-nor.c |   74 ++++++++++++++++++++++++++++++++++-------
 | |
|  include/linux/mtd/spi-nor.h   |    9 +++++
 | |
|  2 files changed, 71 insertions(+), 12 deletions(-)
 | |
| 
 | |
| --- a/drivers/mtd/spi-nor/spi-nor.c
 | |
| +++ b/drivers/mtd/spi-nor/spi-nor.c
 | |
| @@ -1141,6 +1141,26 @@ static int spi_nor_check(struct spi_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;
 | |
| @@ -1188,19 +1208,9 @@ int spi_nor_scan(struct spi_nor *nor, co
 | |
|  
 | |
|  	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_MACRONIX ||
 | |
| -	    JEDEC_MFR(info) == SNOR_MFR_SST ||
 | |
| -	    info->flags & SPI_NOR_HAS_LOCK) {
 | |
| -		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);
 | |
| @@ -1367,6 +1377,45 @@ int spi_nor_scan(struct spi_nor *nor, co
 | |
|  }
 | |
|  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;
 | |
| --- a/include/linux/mtd/spi-nor.h
 | |
| +++ b/include/linux/mtd/spi-nor.h
 | |
| @@ -210,4 +210,13 @@ static inline struct device_node *spi_no
 | |
|   */
 | |
|  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
 |