kernel/0096-fix-bootspi-support-power-managemnt.patch

330 lines
9.4 KiB
Diff
Raw Permalink Normal View History

2025-01-03 03:30:57 +00:00
From f4e4256f8204198df7156c9b232320c89c34718f Mon Sep 17 00:00:00 2001
2024-12-15 18:29:23 +00:00
From: huangyifeng <huangyifeng@eswincomputing.com>
Date: Thu, 4 Jul 2024 17:28:16 +0800
2024-12-27 22:35:16 +00:00
Subject: [PATCH 096/222] fix:bootspi support power managemnt
2024-12-15 18:29:23 +00:00
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