All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support
@ 2016-01-22  9:14 Zhiqiang Hou
  2016-01-22  9:14 ` [PATCHv3 2/2] mtd: m25p80: Add Power Management support Zhiqiang Hou
  2016-04-14  7:59 ` [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support Zhiqiang Hou
  0 siblings, 2 replies; 3+ messages in thread
From: Zhiqiang Hou @ 2016-01-22  9:14 UTC (permalink / raw)
  To: linux-mtd, computersforpeace, dwmw2, jteki, marex
  Cc: Mingkai.Hu, Hou Zhiqiang

From: Hou Zhiqiang <Zhiqiang.Hou@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@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
-- 
2.1.0.27.g96db324

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCHv3 2/2] mtd: m25p80: Add Power Management support
  2016-01-22  9:14 [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support Zhiqiang Hou
@ 2016-01-22  9:14 ` Zhiqiang Hou
  2016-04-14  7:59 ` [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support Zhiqiang Hou
  1 sibling, 0 replies; 3+ messages in thread
From: Zhiqiang Hou @ 2016-01-22  9:14 UTC (permalink / raw)
  To: linux-mtd, computersforpeace, dwmw2, jteki, marex
  Cc: Mingkai.Hu, Hou Zhiqiang

From: Hou Zhiqiang <Zhiqiang.Hou@freescale.com>

Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@freescale.com>
---
V3:
 - No change.
V2:
 - Call spi_nor_suspend/resume instead of spi_nor_scan.

 drivers/mtd/devices/m25p80.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index c9c3b7f..016fe94 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -224,6 +224,26 @@ static int m25p_remove(struct spi_device *spi)
 	return mtd_device_unregister(&flash->spi_nor.mtd);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int m25p_suspend(struct device *dev)
+{
+	struct m25p *flash = dev_get_drvdata(dev);
+	struct spi_nor *nor = &flash->spi_nor;
+
+	return spi_nor_suspend(nor);
+}
+
+static int m25p_resume(struct device *dev)
+{
+	struct m25p *flash = dev_get_drvdata(dev);
+	struct spi_nor *nor = &flash->spi_nor;
+
+	return spi_nor_resume(nor);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(m25p_pm_ops, m25p_suspend, m25p_resume);
+
 /*
  * Do NOT add to this array without reading the following:
  *
@@ -290,6 +310,7 @@ static struct spi_driver m25p80_driver = {
 	.driver = {
 		.name	= "m25p80",
 		.of_match_table = m25p_of_table,
+		.pm	= &m25p_pm_ops,
 	},
 	.id_table	= m25p_ids,
 	.probe	= m25p_probe,
-- 
2.1.0.27.g96db324

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* RE: [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support
  2016-01-22  9:14 [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support Zhiqiang Hou
  2016-01-22  9:14 ` [PATCHv3 2/2] mtd: m25p80: Add Power Management support Zhiqiang Hou
@ 2016-04-14  7:59 ` Zhiqiang Hou
  1 sibling, 0 replies; 3+ messages in thread
From: Zhiqiang Hou @ 2016-04-14  7:59 UTC (permalink / raw)
  To: Zhiqiang Hou, linux-mtd, computersforpeace, dwmw2, jteki, marex
  Cc: Mingkai.Hu

Hi,

Any comments?

> -----Original Message-----
> From: Zhiqiang Hou [mailto:Zhiqiang.Hou@freescale.com]
> Sent: 2016年1月22日 17:14
> To: linux-mtd@lists.infradead.org; computersforpeace@gmail.com;
> dwmw2@infradead.org; jteki@openedev.com; marex@denx.de
> Cc: Mingkai.Hu@freescale.com; Hou Zhiqiang <Zhiqiang.Hou@freescale.com>
> Subject: [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support
> 
> From: Hou Zhiqiang <Zhiqiang.Hou@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@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

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-04-14  8:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-22  9:14 [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support Zhiqiang Hou
2016-01-22  9:14 ` [PATCHv3 2/2] mtd: m25p80: Add Power Management support Zhiqiang Hou
2016-04-14  7:59 ` [PATCHv3 1/2] mtd: spi-nor: Add SPI NOR layer PM support Zhiqiang Hou

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.