330 lines
9.4 KiB
Diff
330 lines
9.4 KiB
Diff
From e261a906662d58a1efc32088812273ba55cd2fc2 Mon Sep 17 00:00:00 2001
|
|
From: huangyifeng <huangyifeng@eswincomputing.com>
|
|
Date: Thu, 4 Jul 2024 17:28:16 +0800
|
|
Subject: [PATCH 096/219] fix:bootspi support power managemnt
|
|
|
|
Changelogs:
|
|
1.bootspi driver support power managemnt
|
|
2.enable power debug sysfs
|
|
|
|
Signed-off-by: huangyifeng <huangyifeng@eswincomputing.com>
|
|
---
|
|
arch/riscv/configs/win2030_defconfig | 2 +
|
|
drivers/mailbox/eswin-mailbox.c | 8 +-
|
|
drivers/spi/spi-eswin-bootspi.c | 172 ++++++++++++++++++++-------
|
|
3 files changed, 137 insertions(+), 45 deletions(-)
|
|
|
|
diff --git a/arch/riscv/configs/win2030_defconfig b/arch/riscv/configs/win2030_defconfig
|
|
index c9ffac16a286..e7c3b818c598 100644
|
|
--- a/arch/riscv/configs/win2030_defconfig
|
|
+++ b/arch/riscv/configs/win2030_defconfig
|
|
@@ -37,6 +37,8 @@ CONFIG_RISCV_SBI_V01=y
|
|
# CONFIG_RISCV_BOOT_SPINWAIT is not set
|
|
CONFIG_CMDLINE="earlycon=sbi console=tty1 console=ttyS0,115200n8 clk_ignore_unused cma_pernuma=0x2000000 disable_bypass=false no_console_suspend"
|
|
CONFIG_CMDLINE_EXTEND=y
|
|
+CONFIG_PM_DEBUG=y
|
|
+CONFIG_PM_ADVANCED_DEBUG=y
|
|
CONFIG_CPU_FREQ=y
|
|
CONFIG_CPU_FREQ_STAT=y
|
|
CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
|
|
diff --git a/drivers/mailbox/eswin-mailbox.c b/drivers/mailbox/eswin-mailbox.c
|
|
index 6a2c40e4d45e..6727882ee682 100755
|
|
--- a/drivers/mailbox/eswin-mailbox.c
|
|
+++ b/drivers/mailbox/eswin-mailbox.c
|
|
@@ -527,7 +527,7 @@ static int eswin_mbox_remove(struct platform_device *pdev)
|
|
return 0;
|
|
}
|
|
|
|
-static int eswin_mbox_suspend(struct device *dev)
|
|
+__maybe_unused static int eswin_mbox_suspend(struct device *dev)
|
|
{
|
|
if (!pm_runtime_status_suspended(dev)) {
|
|
return eswin_mbox_prepare_clk(dev, false);
|
|
@@ -535,7 +535,7 @@ static int eswin_mbox_suspend(struct device *dev)
|
|
return 0;
|
|
}
|
|
|
|
-static int eswin_mbox_resume(struct device *dev)
|
|
+__maybe_unused static int eswin_mbox_resume(struct device *dev)
|
|
{
|
|
if (!pm_runtime_status_suspended(dev)) {
|
|
eswin_mbox_prepare_clk(dev, true);
|
|
@@ -545,12 +545,12 @@ static int eswin_mbox_resume(struct device *dev)
|
|
return 0;
|
|
}
|
|
|
|
-static int eswin_mbox_runtime_suspend(struct device *dev)
|
|
+__maybe_unused static int eswin_mbox_runtime_suspend(struct device *dev)
|
|
{
|
|
return eswin_mbox_prepare_clk(dev, false);
|
|
}
|
|
|
|
-static int eswin_mbox_runtime_resume(struct device *dev)
|
|
+__maybe_unused static int eswin_mbox_runtime_resume(struct device *dev)
|
|
{
|
|
return eswin_mbox_prepare_clk(dev, true);
|
|
}
|
|
diff --git a/drivers/spi/spi-eswin-bootspi.c b/drivers/spi/spi-eswin-bootspi.c
|
|
index 1205ce3941ae..9d3447538e38 100644
|
|
--- a/drivers/spi/spi-eswin-bootspi.c
|
|
+++ b/drivers/spi/spi-eswin-bootspi.c
|
|
@@ -23,7 +23,6 @@
|
|
#include <linux/clk.h>
|
|
#include <linux/reset.h>
|
|
#include <linux/bitfield.h>
|
|
-#include <linux/interrupt.h>
|
|
#include <linux/iopoll.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mod_devicetable.h>
|
|
@@ -34,6 +33,7 @@
|
|
#include <linux/mtd/spi-nor.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/kobject.h>
|
|
+#include <linux/pm_runtime.h>
|
|
|
|
/* Register offsets */
|
|
#define ES_SPI_CSR_00 0x00 /*WRITE_STATUS_REG_TIME*/
|
|
@@ -645,26 +645,6 @@ static const struct spi_controller_mem_ops eswin_bootspi_mem_ops = {
|
|
static int eswin_bootspi_setup(struct spi_device *spi)
|
|
{
|
|
struct es_spi_priv *priv = spi_master_get_devdata(spi->master);
|
|
- struct device *dev = priv->dev;
|
|
- int ret;
|
|
-
|
|
- ret = clk_prepare_enable(priv->cfg_clk);
|
|
- if (ret) {
|
|
- dev_err(dev, "could not enable cfg clock: %d\n", ret);
|
|
- goto err_cfg_clk;
|
|
- }
|
|
-
|
|
- ret = clk_prepare_enable(priv->clk);
|
|
- if (ret) {
|
|
- dev_err(dev, "could not enable clock: %d\n", ret);
|
|
- goto err_clk;
|
|
- }
|
|
- /* set rate to 50M*/
|
|
- ret = clk_set_rate(priv->clk, 50000000);
|
|
- if (ret) {
|
|
- dev_err(dev, "could not enable clock: %d\n", ret);
|
|
- goto err_clk;
|
|
- }
|
|
|
|
reset_control_deassert(priv->rstc);
|
|
/*
|
|
@@ -681,12 +661,7 @@ static int eswin_bootspi_setup(struct spi_device *spi)
|
|
#endif
|
|
/* Basic HW init */
|
|
eswin_bootspi_write(priv, ES_SPI_CSR_08, 0x0);
|
|
- return ret;
|
|
-
|
|
-err_clk:
|
|
- clk_disable(priv->cfg_clk);
|
|
-err_cfg_clk:
|
|
- return ret;
|
|
+ return 0;
|
|
}
|
|
|
|
static int eswin_bootspi_probe(struct platform_device *pdev)
|
|
@@ -696,7 +671,7 @@ static int eswin_bootspi_probe(struct platform_device *pdev)
|
|
int ret = 0;
|
|
struct device *dev = &pdev->dev;
|
|
|
|
- master = spi_alloc_master(&pdev->dev, sizeof(*priv));
|
|
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*priv));
|
|
if (!master)
|
|
return -ENOMEM;
|
|
|
|
@@ -708,6 +683,7 @@ static int eswin_bootspi_probe(struct platform_device *pdev)
|
|
SPI_BPW_MASK(8);
|
|
master->mem_ops = &eswin_bootspi_mem_ops;
|
|
master->num_chipselect = 1;
|
|
+ master->auto_runtime_pm = true;
|
|
|
|
priv = spi_master_get_devdata(master);
|
|
priv->master = master;
|
|
@@ -734,11 +710,9 @@ static int eswin_bootspi_probe(struct platform_device *pdev)
|
|
|
|
priv->cfg_clk = devm_clk_get(dev, "cfg_clk");
|
|
if (IS_ERR(priv->cfg_clk)) {
|
|
- dev_err(dev, "%s %d:could not get cfg clk: %ld\n", __func__,__LINE__,
|
|
- PTR_ERR(priv->cfg_clk));
|
|
+ dev_err(dev, "%s %d:could not get cfg clk: %ld\n", __func__,__LINE__, PTR_ERR(priv->cfg_clk));
|
|
return PTR_ERR(priv->cfg_clk);
|
|
}
|
|
-
|
|
priv->clk = devm_clk_get(dev, "clk");
|
|
if (IS_ERR(priv->clk)) {
|
|
dev_err(dev, "%s %d:could not get clk: %ld\n",__func__,__LINE__, PTR_ERR(priv->rstc));
|
|
@@ -773,35 +747,150 @@ static int eswin_bootspi_probe(struct platform_device *pdev)
|
|
if (!priv->fifo_len) {
|
|
priv->fifo_len = 256;
|
|
}
|
|
- ret = devm_spi_register_controller(dev, master);
|
|
- if (ret)
|
|
- goto err_put_master;
|
|
-
|
|
// Create sysfs node
|
|
ret = device_create_file(&pdev->dev, &dev_attr_wp_enable);
|
|
if (ret) {
|
|
- dev_err(&pdev->dev, "Failed to create wp_enable attribute\n");
|
|
- goto err_put_master;
|
|
+ dev_err(&pdev->dev, "Failed to create wp_enable attribute ret %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = clk_prepare_enable(priv->cfg_clk);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "could not enable cfg clock: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = clk_prepare_enable(priv->clk);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "could not enable clock: %d\n", ret);
|
|
+ goto out_cfg_clk;
|
|
+ }
|
|
+
|
|
+ /* set rate to 50M*/
|
|
+ ret = clk_set_rate(priv->clk, 50000000);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "could not enable clock: %d\n", ret);
|
|
+ goto out_clk;
|
|
}
|
|
|
|
+ pm_runtime_set_autosuspend_delay(dev, 2000);
|
|
+ pm_runtime_use_autosuspend(dev);
|
|
+ pm_runtime_get_noresume(dev);
|
|
+ pm_runtime_set_active(dev);
|
|
+ pm_runtime_enable(dev);
|
|
+
|
|
+ ret = devm_spi_register_controller(dev, master);
|
|
+ if (ret)
|
|
+ goto out_register_controller;
|
|
+
|
|
+ pm_runtime_mark_last_busy(dev);
|
|
+ pm_runtime_put_autosuspend(dev);
|
|
+
|
|
dev_info(&pdev->dev, "ssi_max_xfer_size %d, fifo_len %d, %s mode.\n",
|
|
- priv->max_xfer, priv->fifo_len, priv->irq ? "irq" : "polling");
|
|
+ priv->max_xfer, priv->fifo_len, priv->irq ? "irq" : "polling");
|
|
return 0;
|
|
|
|
-err_put_master:
|
|
- spi_master_put(master);
|
|
+out_register_controller:
|
|
+ pm_runtime_dont_use_autosuspend(dev);
|
|
+ pm_runtime_set_suspended(dev);
|
|
+ pm_runtime_disable(dev);
|
|
+out_clk:
|
|
+ clk_disable_unprepare(priv->clk);
|
|
+out_cfg_clk:
|
|
+ clk_disable_unprepare(priv->cfg_clk);
|
|
return ret;
|
|
}
|
|
|
|
static int eswin_bootspi_remove(struct platform_device *pdev)
|
|
{
|
|
struct es_spi_priv *priv = platform_get_drvdata(pdev);
|
|
+
|
|
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
|
|
+ pm_runtime_set_suspended(&pdev->dev);
|
|
+ pm_runtime_disable(&pdev->dev);
|
|
+ clk_disable_unprepare(priv->cfg_clk);
|
|
+ clk_disable_unprepare(priv->clk);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __maybe_unused eswin_bootspi_runtime_resume(struct device *dev)
|
|
+{
|
|
+ struct es_spi_priv *priv = dev_get_drvdata(dev);
|
|
+ int ret;
|
|
+
|
|
+ ret = clk_prepare_enable(priv->cfg_clk);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = clk_prepare_enable(priv->clk);
|
|
+ if (ret) {
|
|
+ clk_disable_unprepare(priv->cfg_clk);
|
|
+ return ret;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __maybe_unused eswin_bootspi_runtime_suspend(struct device *dev)
|
|
+{
|
|
+ struct es_spi_priv *priv = dev_get_drvdata(dev);
|
|
+
|
|
+ clk_disable_unprepare(priv->clk);
|
|
+ clk_disable_unprepare(priv->cfg_clk);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __maybe_unused eswin_bootspi_suspend(struct device *dev)
|
|
+{
|
|
+
|
|
+ int ret;
|
|
+ struct es_spi_priv *priv = dev_get_drvdata(dev);
|
|
struct spi_controller *master = priv->master;
|
|
|
|
- spi_master_put(master);
|
|
+ ret = spi_master_suspend(master);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (!pm_runtime_suspended(dev)) {
|
|
+ clk_disable_unprepare(priv->clk);
|
|
+ clk_disable_unprepare(priv->cfg_clk);
|
|
+ }
|
|
return 0;
|
|
}
|
|
|
|
+static int __maybe_unused eswin_bootspi_resume(struct device *dev)
|
|
+{
|
|
+ int ret;
|
|
+ struct es_spi_priv *priv = dev_get_drvdata(dev);
|
|
+ struct spi_controller *master = priv->master;
|
|
+
|
|
+ if (!pm_runtime_suspended(dev)) {
|
|
+ ret = clk_prepare_enable(priv->cfg_clk);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to enable cfg_clk (%d)\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = clk_prepare_enable(priv->clk);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to enable clk (%d)\n", ret);
|
|
+ clk_disable_unprepare(priv->cfg_clk);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+ ret = spi_master_resume(master);
|
|
+ if (ret < 0) {
|
|
+ clk_disable_unprepare(priv->cfg_clk);
|
|
+ clk_disable_unprepare(priv->cfg_clk);
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct dev_pm_ops eswin_bootspi_pm = {
|
|
+ SET_RUNTIME_PM_OPS(eswin_bootspi_runtime_suspend,
|
|
+ eswin_bootspi_runtime_resume, NULL)
|
|
+ SET_SYSTEM_SLEEP_PM_OPS(eswin_bootspi_suspend, eswin_bootspi_resume)
|
|
+};
|
|
+
|
|
static const struct of_device_id eswin_bootspi_of_match[] = {
|
|
{ .compatible = "eswin,bootspi", .data = NULL},
|
|
{ /* end of table */}
|
|
@@ -825,6 +914,7 @@ static struct platform_driver eswin_bootspi_driver = {
|
|
#ifdef CONFIG_ACPI
|
|
.acpi_match_table = eswin_bootspi_acpi_match,
|
|
#endif
|
|
+ .pm = &eswin_bootspi_pm,
|
|
},
|
|
};
|
|
module_platform_driver(eswin_bootspi_driver);
|
|
--
|
|
2.47.0
|
|
|