[alsa-devel] [PATCH 0/6] soundwire: inits and PM additions for 5.4
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
This is an update on the RFC, to be applied after the '[PATCH v2 0/3] soundwire: debugfs support for 5.4' and '[PATCH 00/17] soundwire: fixes for 5.4' series.
Total that makes 28 patches submitted for review, broken in 3 sets.
Changes since RFC (Feedback from GregKH, Vinod, Cezary, Guennadi): Squashed init sequence fixes in one patch, which remains readable. Tested all return values and called update_config() as needed. Fixed hw-reset debugfs (removed -unsafe and noisy dev_info traces) Simplified enable_interrupt() with goto Fixed style, removed typos and FIXMES in pm_runtime code Clarified commit messages
Pierre-Louis Bossart (6): soundwire: fix startup sequence for Intel/Cadence soundwire: cadence_master: add hw_reset capability in debugfs soundwire: intel: add helper for initialization soundwire: intel: Add basic power management support soundwire: cadence_master: make clock stop exit configurable on init soundwire: intel: add pm_runtime support
drivers/soundwire/cadence_master.c | 135 ++++++++++++++------ drivers/soundwire/cadence_master.h | 5 +- drivers/soundwire/intel.c | 194 +++++++++++++++++++++++++++-- 3 files changed, 289 insertions(+), 45 deletions(-)
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
Multiple changes squashed in single patch to avoid tick-tock effect.
1. Per the hardware documentation, all changes to MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL need to be validated with a self-clearing write to MCP_CONFIG_UPDATE. Add a helper and do the update when the CONFIG is changed.
2. Move interrupt enable after interrupt handler registration
3. Add a new helper to start the hardware bus reset with maximum duration to make sure the Slave(s) correctly detect the reset pattern and to ensure electrical conflicts can be resolved.
4. flush command FIFOs
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- drivers/soundwire/cadence_master.c | 84 +++++++++++++++++++++--------- drivers/soundwire/cadence_master.h | 1 + drivers/soundwire/intel.c | 14 ++++- 3 files changed, 73 insertions(+), 26 deletions(-)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 502ed4ec8f07..046622e4b264 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -231,6 +231,22 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value) return -EAGAIN; }
+/* + * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL + * need to be confirmed with a write to MCP_CONFIG_UPDATE + */ +static int cdns_update_config(struct sdw_cdns *cdns) +{ + int ret; + + ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE, + CDNS_MCP_CONFIG_UPDATE_BIT); + if (ret < 0) + dev_err(cdns->dev, "Config update timedout\n"); + + return ret; +} + /* * debugfs */ @@ -752,7 +768,42 @@ EXPORT_SYMBOL(sdw_cdns_thread); /* * init routines */ -static int _cdns_enable_interrupt(struct sdw_cdns *cdns) + +/** + * sdw_cdns_exit_reset() - Program reset parameters and start bus operations + * @cdns: Cadence instance + */ +int sdw_cdns_exit_reset(struct sdw_cdns *cdns) +{ + int ret; + + /* program maximum length reset to be safe */ + cdns_updatel(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_RST_DELAY, + CDNS_MCP_CONTROL_RST_DELAY); + + /* use hardware generated reset */ + cdns_updatel(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_HW_RST, + CDNS_MCP_CONTROL_HW_RST); + + /* enable bus operations with clock and data */ + cdns_updatel(cdns, CDNS_MCP_CONFIG, + CDNS_MCP_CONFIG_OP, + CDNS_MCP_CONFIG_OP_NORMAL); + + /* commit changes */ + ret = cdns_update_config(cdns); + + return ret; +} +EXPORT_SYMBOL(sdw_cdns_exit_reset); + +/** + * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config + * @cdns: Cadence instance + */ +int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns) { u32 mask;
@@ -784,24 +835,8 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
- return 0; -} - -/** - * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config - * @cdns: Cadence instance - */ -int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns) -{ - int ret; - - _cdns_enable_interrupt(cdns); - ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE, - CDNS_MCP_CONFIG_UPDATE_BIT); - if (ret < 0) - dev_err(cdns->dev, "Config update timedout\n"); - - return ret; + /* commit changes */ + return cdns_update_config(cdns); } EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
@@ -975,6 +1010,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns) cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL); cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, CDNS_DEFAULT_SSP_INTERVAL);
+ /* flush command FIFOs */ + cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST, + CDNS_MCP_CONTROL_CMD_RST); + /* Set cmd accept mode */ cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, CDNS_MCP_CONTROL_CMD_ACCEPT); @@ -997,13 +1036,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns) /* Set cmd mode for Tx and Rx cmds */ val &= ~CDNS_MCP_CONFIG_CMD;
- /* Set operation to normal */ - val &= ~CDNS_MCP_CONFIG_OP; - val |= CDNS_MCP_CONFIG_OP_NORMAL; - cdns_writel(cdns, CDNS_MCP_CONFIG, val);
- return 0; + /* commit changes */ + return cdns_update_config(cdns); } EXPORT_SYMBOL(sdw_cdns_init);
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 0b72b7094735..1a67728c5000 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -161,6 +161,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id); int sdw_cdns_init(struct sdw_cdns *cdns); int sdw_cdns_pdi_init(struct sdw_cdns *cdns, struct sdw_cdns_stream_config config); +int sdw_cdns_exit_reset(struct sdw_cdns *cdns); int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
#ifdef CONFIG_DEBUG_FS diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 13c54eac0cc3..5f14c6acce80 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1043,8 +1043,6 @@ static int intel_probe(struct platform_device *pdev) if (ret) goto err_init;
- ret = sdw_cdns_enable_interrupt(&sdw->cdns); - /* Read the PDI config and initialize cadence PDI */ intel_pdi_init(sdw, &config); ret = sdw_cdns_pdi_init(&sdw->cdns, config); @@ -1062,6 +1060,18 @@ static int intel_probe(struct platform_device *pdev) goto err_init; }
+ ret = sdw_cdns_enable_interrupt(&sdw->cdns); + if (ret < 0) { + dev_err(sdw->cdns.dev, "cannot enable interrupts\n"); + goto err_init; + } + + ret = sdw_cdns_exit_reset(&sdw->cdns); + if (ret < 0) { + dev_err(sdw->cdns.dev, "unable to exit bus reset sequence\n"); + goto err_init; + } + /* Register DAIs */ ret = intel_register_dai(sdw); if (ret) {
![](https://secure.gravatar.com/avatar/722e39d3e216d4853d437fd35b87d9f2.jpg?s=120&d=mm&r=g)
On 13-08-19, 16:32, Pierre-Louis Bossart wrote:
Multiple changes squashed in single patch to avoid tick-tock effect.
- Per the hardware documentation, all changes to MCP_CONFIG,
MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL need to be validated with a self-clearing write to MCP_CONFIG_UPDATE. Add a helper and do the update when the CONFIG is changed.
Move interrupt enable after interrupt handler registration
Add a new helper to start the hardware bus reset with maximum duration
to make sure the Slave(s) correctly detect the reset pattern and to ensure electrical conflicts can be resolved.
- flush command FIFOs
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
drivers/soundwire/cadence_master.c | 84 +++++++++++++++++++++--------- drivers/soundwire/cadence_master.h | 1 + drivers/soundwire/intel.c | 14 ++++- 3 files changed, 73 insertions(+), 26 deletions(-)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 502ed4ec8f07..046622e4b264 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -231,6 +231,22 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value) return -EAGAIN; }
+/*
- all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL
- need to be confirmed with a write to MCP_CONFIG_UPDATE
- */
+static int cdns_update_config(struct sdw_cdns *cdns) +{
- int ret;
- ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT);
- if (ret < 0)
dev_err(cdns->dev, "Config update timedout\n");
- return ret;
+}
/*
- debugfs
*/ @@ -752,7 +768,42 @@ EXPORT_SYMBOL(sdw_cdns_thread); /*
- init routines
*/ -static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
+/**
- sdw_cdns_exit_reset() - Program reset parameters and start bus operations
- @cdns: Cadence instance
- */
+int sdw_cdns_exit_reset(struct sdw_cdns *cdns) +{
- int ret;
- /* program maximum length reset to be safe */
- cdns_updatel(cdns, CDNS_MCP_CONTROL,
CDNS_MCP_CONTROL_RST_DELAY,
CDNS_MCP_CONTROL_RST_DELAY);
- /* use hardware generated reset */
- cdns_updatel(cdns, CDNS_MCP_CONTROL,
CDNS_MCP_CONTROL_HW_RST,
CDNS_MCP_CONTROL_HW_RST);
- /* enable bus operations with clock and data */
- cdns_updatel(cdns, CDNS_MCP_CONFIG,
CDNS_MCP_CONFIG_OP,
CDNS_MCP_CONFIG_OP_NORMAL);
- /* commit changes */
- ret = cdns_update_config(cdns);
- return ret;
return cdns_update_config() ?
+} +EXPORT_SYMBOL(sdw_cdns_exit_reset);
+/**
- sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
- @cdns: Cadence instance
- */
+int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns) { u32 mask;
@@ -784,24 +835,8 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
- return 0;
-}
-/**
- sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
- @cdns: Cadence instance
- */
-int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns) -{
- int ret;
- _cdns_enable_interrupt(cdns);
- ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT);
- if (ret < 0)
dev_err(cdns->dev, "Config update timedout\n");
- return ret;
- /* commit changes */
- return cdns_update_config(cdns);
} EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
@@ -975,6 +1010,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns) cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL); cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, CDNS_DEFAULT_SSP_INTERVAL);
- /* flush command FIFOs */
- cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST,
CDNS_MCP_CONTROL_CMD_RST);
- /* Set cmd accept mode */ cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, CDNS_MCP_CONTROL_CMD_ACCEPT);
@@ -997,13 +1036,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns) /* Set cmd mode for Tx and Rx cmds */ val &= ~CDNS_MCP_CONFIG_CMD;
/* Set operation to normal */
val &= ~CDNS_MCP_CONFIG_OP;
val |= CDNS_MCP_CONFIG_OP_NORMAL;
cdns_writel(cdns, CDNS_MCP_CONFIG, val);
return 0;
- /* commit changes */
- return cdns_update_config(cdns);
} EXPORT_SYMBOL(sdw_cdns_init);
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 0b72b7094735..1a67728c5000 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -161,6 +161,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id); int sdw_cdns_init(struct sdw_cdns *cdns); int sdw_cdns_pdi_init(struct sdw_cdns *cdns, struct sdw_cdns_stream_config config); +int sdw_cdns_exit_reset(struct sdw_cdns *cdns); int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
#ifdef CONFIG_DEBUG_FS diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 13c54eac0cc3..5f14c6acce80 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c
As I have said in the past it doesnt help having a patch touching two components. The patch is titled cadence!
@@ -1043,8 +1043,6 @@ static int intel_probe(struct platform_device *pdev) if (ret) goto err_init;
- ret = sdw_cdns_enable_interrupt(&sdw->cdns);
- /* Read the PDI config and initialize cadence PDI */ intel_pdi_init(sdw, &config); ret = sdw_cdns_pdi_init(&sdw->cdns, config);
@@ -1062,6 +1060,18 @@ static int intel_probe(struct platform_device *pdev) goto err_init; }
- ret = sdw_cdns_enable_interrupt(&sdw->cdns);
- if (ret < 0) {
dev_err(sdw->cdns.dev, "cannot enable interrupts\n");
goto err_init;
- }
- ret = sdw_cdns_exit_reset(&sdw->cdns);
- if (ret < 0) {
dev_err(sdw->cdns.dev, "unable to exit bus reset sequence\n");
goto err_init;
Don't you want to disable interrupts at least... before you return error? err_init does bus cleanup and not controller one
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
On 9/4/19 2:11 AM, Vinod Koul wrote:
On 13-08-19, 16:32, Pierre-Louis Bossart wrote:
Multiple changes squashed in single patch to avoid tick-tock effect.
- Per the hardware documentation, all changes to MCP_CONFIG,
MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL need to be validated with a self-clearing write to MCP_CONFIG_UPDATE. Add a helper and do the update when the CONFIG is changed.
Move interrupt enable after interrupt handler registration
Add a new helper to start the hardware bus reset with maximum duration
to make sure the Slave(s) correctly detect the reset pattern and to ensure electrical conflicts can be resolved.
- flush command FIFOs
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
drivers/soundwire/cadence_master.c | 84 +++++++++++++++++++++--------- drivers/soundwire/cadence_master.h | 1 + drivers/soundwire/intel.c | 14 ++++- 3 files changed, 73 insertions(+), 26 deletions(-)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 502ed4ec8f07..046622e4b264 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -231,6 +231,22 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value) return -EAGAIN; }
+/*
- all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL
- need to be confirmed with a write to MCP_CONFIG_UPDATE
- */
+static int cdns_update_config(struct sdw_cdns *cdns) +{
- int ret;
- ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT);
- if (ret < 0)
dev_err(cdns->dev, "Config update timedout\n");
- return ret;
+}
- /*
*/
- debugfs
@@ -752,7 +768,42 @@ EXPORT_SYMBOL(sdw_cdns_thread); /*
- init routines
*/ -static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
+/**
- sdw_cdns_exit_reset() - Program reset parameters and start bus operations
- @cdns: Cadence instance
- */
+int sdw_cdns_exit_reset(struct sdw_cdns *cdns) +{
- int ret;
- /* program maximum length reset to be safe */
- cdns_updatel(cdns, CDNS_MCP_CONTROL,
CDNS_MCP_CONTROL_RST_DELAY,
CDNS_MCP_CONTROL_RST_DELAY);
- /* use hardware generated reset */
- cdns_updatel(cdns, CDNS_MCP_CONTROL,
CDNS_MCP_CONTROL_HW_RST,
CDNS_MCP_CONTROL_HW_RST);
- /* enable bus operations with clock and data */
- cdns_updatel(cdns, CDNS_MCP_CONFIG,
CDNS_MCP_CONFIG_OP,
CDNS_MCP_CONFIG_OP_NORMAL);
- /* commit changes */
- ret = cdns_update_config(cdns);
- return ret;
return cdns_update_config() ?
ok
+} +EXPORT_SYMBOL(sdw_cdns_exit_reset);
+/**
- sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
- @cdns: Cadence instance
- */
+int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns) { u32 mask;
@@ -784,24 +835,8 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
- return 0;
-}
-/**
- sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
- @cdns: Cadence instance
- */
-int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns) -{
- int ret;
- _cdns_enable_interrupt(cdns);
- ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT);
- if (ret < 0)
dev_err(cdns->dev, "Config update timedout\n");
- return ret;
- /* commit changes */
- return cdns_update_config(cdns); } EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
@@ -975,6 +1010,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns) cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL); cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, CDNS_DEFAULT_SSP_INTERVAL);
- /* flush command FIFOs */
- cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST,
CDNS_MCP_CONTROL_CMD_RST);
- /* Set cmd accept mode */ cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, CDNS_MCP_CONTROL_CMD_ACCEPT);
@@ -997,13 +1036,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns) /* Set cmd mode for Tx and Rx cmds */ val &= ~CDNS_MCP_CONFIG_CMD;
/* Set operation to normal */
val &= ~CDNS_MCP_CONFIG_OP;
val |= CDNS_MCP_CONFIG_OP_NORMAL;
cdns_writel(cdns, CDNS_MCP_CONFIG, val);
return 0;
- /* commit changes */
- return cdns_update_config(cdns); } EXPORT_SYMBOL(sdw_cdns_init);
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 0b72b7094735..1a67728c5000 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -161,6 +161,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id); int sdw_cdns_init(struct sdw_cdns *cdns); int sdw_cdns_pdi_init(struct sdw_cdns *cdns, struct sdw_cdns_stream_config config); +int sdw_cdns_exit_reset(struct sdw_cdns *cdns); int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
#ifdef CONFIG_DEBUG_FS diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 13c54eac0cc3..5f14c6acce80 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c
As I have said in the past it doesnt help having a patch touching two components. The patch is titled cadence!
no, it's called 'fix startup sequence for Intel/Cadence' and it's intentional to modify the two parts in a single patch. I tried to split this but it's very difficult due to the dependencies. If you look at all the initial comments from early July people were lost when I did these changes in steps. I try to keep patches local and self-contained, but in this case it's nearly impossible or makes the review very hard for no good reason.
@@ -1043,8 +1043,6 @@ static int intel_probe(struct platform_device *pdev) if (ret) goto err_init;
- ret = sdw_cdns_enable_interrupt(&sdw->cdns);
- /* Read the PDI config and initialize cadence PDI */ intel_pdi_init(sdw, &config); ret = sdw_cdns_pdi_init(&sdw->cdns, config);
@@ -1062,6 +1060,18 @@ static int intel_probe(struct platform_device *pdev) goto err_init; }
- ret = sdw_cdns_enable_interrupt(&sdw->cdns);
- if (ret < 0) {
dev_err(sdw->cdns.dev, "cannot enable interrupts\n");
goto err_init;
- }
- ret = sdw_cdns_exit_reset(&sdw->cdns);
- if (ret < 0) {
dev_err(sdw->cdns.dev, "unable to exit bus reset sequence\n");
goto err_init;
Don't you want to disable interrupts at least... before you return error? err_init does bus cleanup and not controller one
yes good point, let me look at this.
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
@@ -1043,8 +1043,6 @@ static int intel_probe(struct platform_device *pdev) if (ret) goto err_init; - ret = sdw_cdns_enable_interrupt(&sdw->cdns);
/* Read the PDI config and initialize cadence PDI */ intel_pdi_init(sdw, &config); ret = sdw_cdns_pdi_init(&sdw->cdns, config); @@ -1062,6 +1060,18 @@ static int intel_probe(struct platform_device *pdev) goto err_init; } + ret = sdw_cdns_enable_interrupt(&sdw->cdns); + if (ret < 0) { + dev_err(sdw->cdns.dev, "cannot enable interrupts\n"); + goto err_init; + }
+ ret = sdw_cdns_exit_reset(&sdw->cdns); + if (ret < 0) { + dev_err(sdw->cdns.dev, "unable to exit bus reset sequence\n"); + goto err_init;
Don't you want to disable interrupts at least... before you return error? err_init does bus cleanup and not controller one
yes good point, let me look at this.
The existing code has no interrupt disable sequence.
I will add this improved error handling in a follow-up patch, after the capability to disable interrupts is added.
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
Provide debugfs capability to kick link and devices into hard-reset (as defined by MIPI). This capability is really useful when some devices are no longer responsive and/or to check the software handling of resynchronization.
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- drivers/soundwire/cadence_master.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 046622e4b264..bd58d80ff636 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -340,6 +340,23 @@ static int cdns_reg_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(cdns_reg);
+static int cdns_hw_reset(void *data, u64 value) +{ + struct sdw_cdns *cdns = data; + int ret; + + if (value != 1) + return 0; + + ret = sdw_cdns_exit_reset(cdns); + + dev_dbg(cdns->dev, "link hw_reset done: %d\n", ret); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n"); + /** * sdw_cdns_debugfs_init() - Cadence debugfs init * @cdns: Cadence instance @@ -348,6 +365,9 @@ DEFINE_SHOW_ATTRIBUTE(cdns_reg); void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root) { debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops); + + debugfs_create_file("cdns-hw-reset", 0200, root, cdns, + &cdns_hw_reset_fops); } EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);
![](https://secure.gravatar.com/avatar/722e39d3e216d4853d437fd35b87d9f2.jpg?s=120&d=mm&r=g)
On 13-08-19, 16:32, Pierre-Louis Bossart wrote:
Provide debugfs capability to kick link and devices into hard-reset (as defined by MIPI). This capability is really useful when some devices are no longer responsive and/or to check the software handling of resynchronization.
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
drivers/soundwire/cadence_master.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 046622e4b264..bd58d80ff636 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -340,6 +340,23 @@ static int cdns_reg_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(cdns_reg);
+static int cdns_hw_reset(void *data, u64 value) +{
- struct sdw_cdns *cdns = data;
- int ret;
- if (value != 1)
return 0;
Should this not be EINVAL to indicate invalid value passed?
- ret = sdw_cdns_exit_reset(cdns);
- dev_dbg(cdns->dev, "link hw_reset done: %d\n", ret);
- return ret;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n");
/**
- sdw_cdns_debugfs_init() - Cadence debugfs init
- @cdns: Cadence instance
@@ -348,6 +365,9 @@ DEFINE_SHOW_ATTRIBUTE(cdns_reg); void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root) { debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
- debugfs_create_file("cdns-hw-reset", 0200, root, cdns,
&cdns_hw_reset_fops);
} EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);
-- 2.20.1
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
On 9/4/19 2:13 AM, Vinod Koul wrote:
On 13-08-19, 16:32, Pierre-Louis Bossart wrote:
Provide debugfs capability to kick link and devices into hard-reset (as defined by MIPI). This capability is really useful when some devices are no longer responsive and/or to check the software handling of resynchronization.
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
drivers/soundwire/cadence_master.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 046622e4b264..bd58d80ff636 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -340,6 +340,23 @@ static int cdns_reg_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(cdns_reg);
+static int cdns_hw_reset(void *data, u64 value) +{
- struct sdw_cdns *cdns = data;
- int ret;
- if (value != 1)
return 0;
Should this not be EINVAL to indicate invalid value passed?
Maybe. I must admit I don't know what -EINVAL would do, this is used for debugfs so it's not clear to me if the user will see a difference?
- ret = sdw_cdns_exit_reset(cdns);
- dev_dbg(cdns->dev, "link hw_reset done: %d\n", ret);
- return ret;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n");
- /**
- sdw_cdns_debugfs_init() - Cadence debugfs init
- @cdns: Cadence instance
@@ -348,6 +365,9 @@ DEFINE_SHOW_ATTRIBUTE(cdns_reg); void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root) { debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
- debugfs_create_file("cdns-hw-reset", 0200, root, cdns,
} EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);&cdns_hw_reset_fops);
-- 2.20.1
![](https://secure.gravatar.com/avatar/722e39d3e216d4853d437fd35b87d9f2.jpg?s=120&d=mm&r=g)
On 04-09-19, 08:18, Pierre-Louis Bossart wrote:
On 9/4/19 2:13 AM, Vinod Koul wrote:
On 13-08-19, 16:32, Pierre-Louis Bossart wrote:
Provide debugfs capability to kick link and devices into hard-reset (as defined by MIPI). This capability is really useful when some devices are no longer responsive and/or to check the software handling of resynchronization.
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
drivers/soundwire/cadence_master.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 046622e4b264..bd58d80ff636 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -340,6 +340,23 @@ static int cdns_reg_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(cdns_reg); +static int cdns_hw_reset(void *data, u64 value) +{
- struct sdw_cdns *cdns = data;
- int ret;
- if (value != 1)
return 0;
Should this not be EINVAL to indicate invalid value passed?
Maybe. I must admit I don't know what -EINVAL would do, this is used for debugfs so it's not clear to me if the user will see a difference?
Well user should see "write error: Invalid argument" when he writes anything other than valid values :)
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
On 9/4/19 11:49 AM, Vinod Koul wrote:
On 04-09-19, 08:18, Pierre-Louis Bossart wrote:
On 9/4/19 2:13 AM, Vinod Koul wrote:
On 13-08-19, 16:32, Pierre-Louis Bossart wrote:
Provide debugfs capability to kick link and devices into hard-reset (as defined by MIPI). This capability is really useful when some devices are no longer responsive and/or to check the software handling of resynchronization.
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
drivers/soundwire/cadence_master.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 046622e4b264..bd58d80ff636 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -340,6 +340,23 @@ static int cdns_reg_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(cdns_reg); +static int cdns_hw_reset(void *data, u64 value) +{
- struct sdw_cdns *cdns = data;
- int ret;
- if (value != 1)
return 0;
Should this not be EINVAL to indicate invalid value passed?
Maybe. I must admit I don't know what -EINVAL would do, this is used for debugfs so it's not clear to me if the user will see a difference?
Well user should see "write error: Invalid argument" when he writes anything other than valid values :)
ok then, will do.
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
Move code to helper for reuse in power management routines
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- drivers/soundwire/intel.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 5f14c6acce80..3d22c9023a9b 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -993,6 +993,15 @@ static struct sdw_master_ops sdw_intel_ops = { .post_bank_switch = intel_post_bank_switch, };
+static int intel_init(struct sdw_intel *sdw) +{ + /* Initialize shim and controller */ + intel_link_power_up(sdw); + intel_shim_init(sdw); + + return sdw_cdns_init(&sdw->cdns); +} + /* * probe and init */ @@ -1035,11 +1044,8 @@ static int intel_probe(struct platform_device *pdev) return 0; }
- /* Initialize shim and controller */ - intel_link_power_up(sdw); - intel_shim_init(sdw); - - ret = sdw_cdns_init(&sdw->cdns); + /* Initialize shim, controller and Cadence IP */ + ret = intel_init(sdw); if (ret) goto err_init;
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
Implement suspend/resume capabilities (not runtime_pm for now)
Credits: this patch is based on an earlier internal contribution by Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah.
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- drivers/soundwire/cadence_master.c | 18 ++-- drivers/soundwire/cadence_master.h | 2 +- drivers/soundwire/intel.c | 128 ++++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 8 deletions(-)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index bd58d80ff636..fdf9eec7cde1 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -823,14 +823,17 @@ EXPORT_SYMBOL(sdw_cdns_exit_reset); * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config * @cdns: Cadence instance */ -int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns) +int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state) { - u32 mask; + u32 slave_intmask0 = 0; + u32 slave_intmask1 = 0; + u32 mask = 0; + + if (!state) + goto update_masks;
- cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, - CDNS_MCP_SLAVE_INTMASK0_MASK); - cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, - CDNS_MCP_SLAVE_INTMASK1_MASK); + slave_intmask0 = CDNS_MCP_SLAVE_INTMASK0_MASK; + slave_intmask1 = CDNS_MCP_SLAVE_INTMASK1_MASK;
/* enable detection of all slave state changes */ mask = CDNS_MCP_INT_SLAVE_MASK; @@ -853,6 +856,9 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns) if (interrupt_mask) /* parameter override */ mask = interrupt_mask;
+update_masks: + cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0); + cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1); cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
/* commit changes */ diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 1a67728c5000..302351808098 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -162,7 +162,7 @@ int sdw_cdns_init(struct sdw_cdns *cdns); int sdw_cdns_pdi_init(struct sdw_cdns *cdns, struct sdw_cdns_stream_config config); int sdw_cdns_exit_reset(struct sdw_cdns *cdns); -int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns); +int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state);
#ifdef CONFIG_DEBUG_FS void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root); diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 3d22c9023a9b..42bdc870c3ee 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -12,6 +12,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <sound/pcm_params.h> +#include <linux/pm_runtime.h> #include <sound/soc.h> #include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw.h> @@ -284,6 +285,35 @@ static void intel_debugfs_exit(struct sdw_intel *sdw) {} /* * shim ops */ +static int intel_link_power_down(struct sdw_intel *sdw) +{ + int link_control, spa_mask, cpa_mask, ret; + unsigned int link_id = sdw->instance; + void __iomem *shim = sdw->res->shim; + u16 ioctl; + + /* Glue logic */ + ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id)); + ioctl |= SDW_SHIM_IOCTL_BKE; + ioctl |= SDW_SHIM_IOCTL_COE; + intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + + ioctl &= ~(SDW_SHIM_IOCTL_MIF); + intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + + /* Link power down sequence */ + link_control = intel_readl(shim, SDW_SHIM_LCTL); + spa_mask = ~(SDW_SHIM_LCTL_SPA << link_id); + cpa_mask = (SDW_SHIM_LCTL_CPA << link_id); + link_control &= spa_mask; + + ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); + if (ret < 0) + return ret; + + sdw->cdns.link_up = false; + return 0; +}
static int intel_link_power_up(struct sdw_intel *sdw) { @@ -306,6 +336,29 @@ static int intel_link_power_up(struct sdw_intel *sdw) return 0; }
+static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) +{ + void __iomem *shim = sdw->res->shim; + unsigned int link_id = sdw->instance; + u16 wake_en, wake_sts; + + if (wake_enable) { + /* Enable the wakeup */ + intel_writew(shim, SDW_SHIM_WAKEEN, + (SDW_SHIM_WAKEEN_ENABLE << link_id)); + } else { + /* Disable the wake up interrupt */ + wake_en = intel_readw(shim, SDW_SHIM_WAKEEN); + wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id); + intel_writew(shim, SDW_SHIM_WAKEEN, wake_en); + + /* Clear wake status */ + wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); + wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id); + intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts); + } +} + static int intel_shim_init(struct sdw_intel *sdw) { void __iomem *shim = sdw->res->shim; @@ -1066,7 +1119,7 @@ static int intel_probe(struct platform_device *pdev) goto err_init; }
- ret = sdw_cdns_enable_interrupt(&sdw->cdns); + ret = sdw_cdns_enable_interrupt(&sdw->cdns, true); if (ret < 0) { dev_err(sdw->cdns.dev, "cannot enable interrupts\n"); goto err_init; @@ -1114,11 +1167,84 @@ static int intel_remove(struct platform_device *pdev) return 0; }
+/* + * PM calls + */ + +#ifdef CONFIG_PM + +static int intel_suspend(struct device *dev) +{ + struct sdw_intel *sdw = dev_get_drvdata(dev); + int ret; + + if (sdw->cdns.bus.prop.hw_disabled) { + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + sdw->cdns.bus.link_id); + return 0; + } + + ret = sdw_cdns_enable_interrupt(&sdw->cdns, false); + if (ret < 0) { + dev_err(sdw->cdns.dev, "cannot disable interrupts on suspend\n"); + return ret; + } + + ret = intel_link_power_down(sdw); + if (ret) { + dev_err(dev, "Link power down failed: %d", ret); + return ret; + } + + intel_shim_wake(sdw, false); + + return 0; +} + +static int intel_resume(struct device *dev) +{ + struct sdw_intel *sdw = dev_get_drvdata(dev); + int ret; + + if (sdw->cdns.bus.prop.hw_disabled) { + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + sdw->cdns.bus.link_id); + return 0; + } + + ret = intel_init(sdw); + if (ret) { + dev_err(dev, "%s failed: %d", __func__, ret); + return ret; + } + + ret = sdw_cdns_enable_interrupt(&sdw->cdns, true); + if (ret < 0) { + dev_err(sdw->cdns.dev, "cannot enable interrupts during resume\n"); + return ret; + } + + ret = sdw_cdns_exit_reset(&sdw->cdns); + if (ret < 0) { + dev_err(sdw->cdns.dev, "unable to exit bus reset sequence during resume\n"); + return ret; + } + + return ret; +} + +#endif + +static const struct dev_pm_ops intel_pm = { + SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume) +}; + static struct platform_driver sdw_intel_drv = { .probe = intel_probe, .remove = intel_remove, .driver = { .name = "int-sdw", + .pm = &intel_pm,
}, };
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
The use of clock stop is not a requirement, the IP can e.g. be completely power gated and not detect any wakes while in s2idle/deep sleep.
For now clock-stop is not supported anyways so the control parameter is always false. This will be revisited when we add clock stop.
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- drivers/soundwire/cadence_master.c | 15 ++++++++------- drivers/soundwire/cadence_master.h | 2 +- drivers/soundwire/intel.c | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index fdf9eec7cde1..17ac2ecd8d5c 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1000,7 +1000,7 @@ static u32 cdns_set_initial_frame_shape(int n_rows, int n_cols) * sdw_cdns_init() - Cadence initialization * @cdns: Cadence instance */ -int sdw_cdns_init(struct sdw_cdns *cdns) +int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit) { struct sdw_bus *bus = &cdns->bus; struct sdw_master_prop *prop = &bus->prop; @@ -1008,12 +1008,13 @@ int sdw_cdns_init(struct sdw_cdns *cdns) int divider; int ret;
- /* Exit clock stop */ - ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL, - CDNS_MCP_CONTROL_CLK_STOP_CLR); - if (ret < 0) { - dev_err(cdns->dev, "Couldn't exit from clock stop\n"); - return ret; + if (clock_stop_exit) { + ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_CLK_STOP_CLR); + if (ret < 0) { + dev_err(cdns->dev, "Couldn't exit from clock stop\n"); + return ret; + } }
/* Set clock divider */ diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 302351808098..9d7a48ac6fc4 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -158,7 +158,7 @@ extern struct sdw_master_ops sdw_cdns_master_ops; irqreturn_t sdw_cdns_irq(int irq, void *dev_id); irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
-int sdw_cdns_init(struct sdw_cdns *cdns); +int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit); int sdw_cdns_pdi_init(struct sdw_cdns *cdns, struct sdw_cdns_stream_config config); int sdw_cdns_exit_reset(struct sdw_cdns *cdns); diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 42bdc870c3ee..fd2d0a9ccb00 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1052,7 +1052,7 @@ static int intel_init(struct sdw_intel *sdw) intel_link_power_up(sdw); intel_shim_init(sdw);
- return sdw_cdns_init(&sdw->cdns); + return sdw_cdns_init(&sdw->cdns, false); }
/*
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
Add basic hooks in DAI .startup and .shutdown callbacks. The SoundWire IP should be powered between those two calls.
By default the platform_device is in SUSPENDED mode, it is required to call pm_runtime_set_active() before _enable()
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- drivers/soundwire/intel.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index fd2d0a9ccb00..c95222f18c75 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -716,6 +716,23 @@ static void intel_port_cleanup(struct sdw_cdns_dma_data *dma) } }
+static int intel_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = pm_runtime_get_sync(cdns->dev); + if (ret < 0) { + dev_err_ratelimited(cdns->dev, + "pm_runtime_get_sync failed in %s, ret %d\n", + __func__, ret); + pm_runtime_put_noidle(cdns->dev); + } + + return ret; +} + static int intel_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -838,6 +855,8 @@ static void intel_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sdw_cdns_dma_data *dma; + struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + int ret;
dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) @@ -845,6 +864,13 @@ static void intel_shutdown(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(dai, substream, NULL); kfree(dma); + + pm_runtime_mark_last_busy(cdns->dev); + ret = pm_runtime_put_autosuspend(cdns->dev); + if (ret < 0) + dev_err_ratelimited(cdns->dev, + "pm_runtime_put_autosuspend failed in %s:, ret %d\n", + __func__, ret); }
static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai, @@ -860,6 +886,7 @@ static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai, }
static const struct snd_soc_dai_ops intel_pcm_dai_ops = { + .startup = intel_startup, .hw_params = intel_hw_params, .hw_free = intel_hw_free, .shutdown = intel_shutdown, @@ -1141,6 +1168,15 @@ static int intel_probe(struct platform_device *pdev)
intel_debugfs_init(sdw);
+ /* Enable PM */ + pm_runtime_set_autosuspend_delay(&pdev->dev, 3000); + pm_runtime_use_autosuspend(&pdev->dev); + + pm_runtime_mark_last_busy(&pdev->dev); + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + return 0;
err_dai: @@ -1158,6 +1194,7 @@ static int intel_remove(struct platform_device *pdev) sdw = platform_get_drvdata(pdev);
if (!sdw->cdns.bus.prop.hw_disabled) { + pm_runtime_disable(&pdev->dev); intel_debugfs_exit(sdw); free_irq(sdw->res->irq, sdw); snd_soc_unregister_component(sdw->cdns.dev); @@ -1237,6 +1274,7 @@ static int intel_resume(struct device *dev)
static const struct dev_pm_ops intel_pm = { SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume) + SET_RUNTIME_PM_OPS(intel_suspend, intel_resume, NULL) };
static struct platform_driver sdw_intel_drv = {
![](https://secure.gravatar.com/avatar/59bffa8d29505a5951521a2fd09a4fd9.jpg?s=120&d=mm&r=g)
On 8/13/19 4:32 PM, Pierre-Louis Bossart wrote:
This is an update on the RFC, to be applied after the '[PATCH v2 0/3] soundwire: debugfs support for 5.4' and '[PATCH 00/17] soundwire: fixes for 5.4' series.
Total that makes 28 patches submitted for review, broken in 3 sets.
I double-checked that this patchset does apply on top of soundwire/next + the 4 debugfs patches I just sent earlier.
I will now send the rather big changes needed for SOF integration as an RFC, assuming this set is applied.
Changes since RFC (Feedback from GregKH, Vinod, Cezary, Guennadi): Squashed init sequence fixes in one patch, which remains readable. Tested all return values and called update_config() as needed. Fixed hw-reset debugfs (removed -unsafe and noisy dev_info traces) Simplified enable_interrupt() with goto Fixed style, removed typos and FIXMES in pm_runtime code Clarified commit messages
Pierre-Louis Bossart (6): soundwire: fix startup sequence for Intel/Cadence soundwire: cadence_master: add hw_reset capability in debugfs soundwire: intel: add helper for initialization soundwire: intel: Add basic power management support soundwire: cadence_master: make clock stop exit configurable on init soundwire: intel: add pm_runtime support
drivers/soundwire/cadence_master.c | 135 ++++++++++++++------ drivers/soundwire/cadence_master.h | 5 +- drivers/soundwire/intel.c | 194 +++++++++++++++++++++++++++-- 3 files changed, 289 insertions(+), 45 deletions(-)
participants (2)
-
Pierre-Louis Bossart
-
Vinod Koul