Skip to content

Commit 81ff58f

Browse files
vijendarmukundavinodkoul
authored andcommitted
soundwire: amd: add runtime pm ops for AMD SoundWire manager driver
Add support for runtime pm ops for AMD SoundWire manager driver. Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com> Signed-off-by: Mastan Katragadda <Mastan.Katragadda@amd.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/lkml/20230227154801.50319-7-Vijendar.Mukunda@amd.com Link: https://lore.kernel.org/r/20230321050901.115439-7-Vijendar.Mukunda@amd.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent 65f93e4 commit 81ff58f

3 files changed

Lines changed: 160 additions & 0 deletions

File tree

drivers/soundwire/amd_manager.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/slab.h>
1515
#include <linux/soundwire/sdw.h>
1616
#include <linux/soundwire/sdw_registers.h>
17+
#include <linux/pm_runtime.h>
1718
#include <linux/wait.h>
1819
#include <sound/pcm_params.h>
1920
#include <sound/soc.h>
@@ -133,6 +134,12 @@ static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
133134
writel(0x00, amd_manager->mmio + ACP_SW_ERROR_INTR_MASK);
134135
}
135136

137+
static int amd_deinit_sdw_manager(struct amd_sdw_manager *amd_manager)
138+
{
139+
amd_disable_sdw_interrupts(amd_manager);
140+
return amd_disable_sdw_manager(amd_manager);
141+
}
142+
136143
static void amd_sdw_set_frameshape(struct amd_sdw_manager *amd_manager)
137144
{
138145
u32 frame_size;
@@ -866,6 +873,12 @@ static void amd_sdw_probe_work(struct work_struct *work)
866873
return;
867874
amd_sdw_set_frameshape(amd_manager);
868875
}
876+
/* Enable runtime PM */
877+
pm_runtime_set_autosuspend_delay(amd_manager->dev, AMD_SDW_MASTER_SUSPEND_DELAY_MS);
878+
pm_runtime_use_autosuspend(amd_manager->dev);
879+
pm_runtime_mark_last_busy(amd_manager->dev);
880+
pm_runtime_set_active(amd_manager->dev);
881+
pm_runtime_enable(amd_manager->dev);
869882
}
870883

871884
static int amd_sdw_manager_probe(struct platform_device *pdev)
@@ -953,17 +966,144 @@ static int amd_sdw_manager_remove(struct platform_device *pdev)
953966
{
954967
struct amd_sdw_manager *amd_manager = dev_get_drvdata(&pdev->dev);
955968

969+
pm_runtime_disable(&pdev->dev);
956970
cancel_work_sync(&amd_manager->probe_work);
957971
amd_disable_sdw_interrupts(amd_manager);
958972
sdw_bus_master_delete(&amd_manager->bus);
959973
return amd_disable_sdw_manager(amd_manager);
960974
}
961975

976+
static int amd_sdw_clock_stop(struct amd_sdw_manager *amd_manager)
977+
{
978+
u32 val;
979+
int ret;
980+
981+
ret = sdw_bus_prep_clk_stop(&amd_manager->bus);
982+
if (ret < 0 && ret != -ENODATA) {
983+
dev_err(amd_manager->dev, "prepare clock stop failed %d", ret);
984+
return 0;
985+
}
986+
ret = sdw_bus_clk_stop(&amd_manager->bus);
987+
if (ret < 0 && ret != -ENODATA) {
988+
dev_err(amd_manager->dev, "bus clock stop failed %d", ret);
989+
return 0;
990+
}
991+
992+
ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL, val,
993+
(val & AMD_SDW_CLK_STOP_DONE), ACP_DELAY_US, AMD_SDW_TIMEOUT);
994+
if (ret) {
995+
dev_err(amd_manager->dev, "SDW%x clock stop failed\n", amd_manager->instance);
996+
return 0;
997+
}
998+
999+
amd_manager->clk_stopped = true;
1000+
if (amd_manager->wake_en_mask)
1001+
writel(0x01, amd_manager->acp_mmio + ACP_SW_WAKE_EN(amd_manager->instance));
1002+
1003+
dev_dbg(amd_manager->dev, "SDW%x clock stop successful\n", amd_manager->instance);
1004+
return 0;
1005+
}
1006+
1007+
static int amd_sdw_clock_stop_exit(struct amd_sdw_manager *amd_manager)
1008+
{
1009+
int ret;
1010+
u32 val;
1011+
1012+
if (amd_manager->clk_stopped) {
1013+
val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
1014+
val |= AMD_SDW_CLK_RESUME_REQ;
1015+
writel(val, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
1016+
ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL, val,
1017+
(val & AMD_SDW_CLK_RESUME_DONE), ACP_DELAY_US,
1018+
AMD_SDW_TIMEOUT);
1019+
if (val & AMD_SDW_CLK_RESUME_DONE) {
1020+
writel(0, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
1021+
ret = sdw_bus_exit_clk_stop(&amd_manager->bus);
1022+
if (ret < 0)
1023+
dev_err(amd_manager->dev, "bus failed to exit clock stop %d\n",
1024+
ret);
1025+
amd_manager->clk_stopped = false;
1026+
}
1027+
}
1028+
if (amd_manager->clk_stopped) {
1029+
dev_err(amd_manager->dev, "SDW%x clock stop exit failed\n", amd_manager->instance);
1030+
return 0;
1031+
}
1032+
dev_dbg(amd_manager->dev, "SDW%x clock stop exit successful\n", amd_manager->instance);
1033+
return 0;
1034+
}
1035+
1036+
static int __maybe_unused amd_suspend_runtime(struct device *dev)
1037+
{
1038+
struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
1039+
struct sdw_bus *bus = &amd_manager->bus;
1040+
int ret;
1041+
1042+
if (bus->prop.hw_disabled) {
1043+
dev_dbg(bus->dev, "SoundWire manager %d is disabled,\n",
1044+
bus->link_id);
1045+
return 0;
1046+
}
1047+
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
1048+
return amd_sdw_clock_stop(amd_manager);
1049+
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
1050+
ret = amd_sdw_clock_stop(amd_manager);
1051+
if (ret)
1052+
return ret;
1053+
return amd_deinit_sdw_manager(amd_manager);
1054+
}
1055+
return 0;
1056+
}
1057+
1058+
static int __maybe_unused amd_resume_runtime(struct device *dev)
1059+
{
1060+
struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
1061+
struct sdw_bus *bus = &amd_manager->bus;
1062+
int ret;
1063+
u32 val;
1064+
1065+
if (bus->prop.hw_disabled) {
1066+
dev_dbg(bus->dev, "SoundWire manager %d is disabled, ignoring\n",
1067+
bus->link_id);
1068+
return 0;
1069+
}
1070+
1071+
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
1072+
return amd_sdw_clock_stop_exit(amd_manager);
1073+
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
1074+
val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
1075+
if (val) {
1076+
val |= AMD_SDW_CLK_RESUME_REQ;
1077+
writel(val, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
1078+
ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL, val,
1079+
(val & AMD_SDW_CLK_RESUME_DONE), ACP_DELAY_US,
1080+
AMD_SDW_TIMEOUT);
1081+
if (val & AMD_SDW_CLK_RESUME_DONE) {
1082+
writel(0, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
1083+
amd_manager->clk_stopped = false;
1084+
}
1085+
}
1086+
sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
1087+
amd_init_sdw_manager(amd_manager);
1088+
amd_enable_sdw_interrupts(amd_manager);
1089+
ret = amd_enable_sdw_manager(amd_manager);
1090+
if (ret)
1091+
return ret;
1092+
amd_sdw_set_frameshape(amd_manager);
1093+
}
1094+
return 0;
1095+
}
1096+
1097+
static const struct dev_pm_ops amd_pm = {
1098+
SET_RUNTIME_PM_OPS(amd_suspend_runtime, amd_resume_runtime, NULL)
1099+
};
1100+
9621101
static struct platform_driver amd_sdw_driver = {
9631102
.probe = &amd_sdw_manager_probe,
9641103
.remove = &amd_sdw_manager_remove,
9651104
.driver = {
9661105
.name = "amd_sdw_manager",
1106+
.pm = &amd_pm,
9671107
}
9681108
};
9691109
module_platform_driver(amd_sdw_driver);

drivers/soundwire/amd_manager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@
186186
#define AMD_SDW0_PAD_KEEPER_DISABLE_MASK 0x1e
187187
#define AMD_SDW1_PAD_KEEPER_DISABLE_MASK 0xf
188188
#define AMD_SDW_PREQ_INTR_STAT BIT(19)
189+
#define AMD_SDW_CLK_STOP_DONE 1
190+
#define AMD_SDW_CLK_RESUME_REQ 2
191+
#define AMD_SDW_CLK_RESUME_DONE 3
189192

190193
static u32 amd_sdw_freq_tbl[AMD_SDW_MAX_FREQ_NUM] = {
191194
AMD_SDW_DEFAULT_CLK_FREQ,

include/linux/soundwire/sdw_amd.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88

99
#include <linux/soundwire/sdw.h>
1010

11+
/* AMD pm_runtime quirk definitions */
12+
13+
/*
14+
* Force the clock to stop(ClockStopMode0) when suspend callback
15+
* is invoked.
16+
*/
17+
#define AMD_SDW_CLK_STOP_MODE 1
18+
19+
/*
20+
* Stop the bus when runtime suspend/system level suspend callback
21+
* is invoked. If set, a complete bus reset and re-enumeration will
22+
* be performed when the bus restarts. In-band wake interrupts are
23+
* not supported in this mode.
24+
*/
25+
#define AMD_SDW_POWER_OFF_MODE 2
1126
#define ACP_SDW0 0
1227
#define ACP_SDW1 1
1328

@@ -57,6 +72,7 @@ struct sdw_amd_dai_runtime {
5772
* @instance: SoundWire manager instance
5873
* @quirks: SoundWire manager quirks
5974
* @wake_en_mask: wake enable mask per SoundWire manager
75+
* @clk_stopped: flag set to true when clock is stopped
6076
* @power_mode_mask: flag interprets amd SoundWire manager power mode
6177
* @dai_runtime_array: dai runtime array
6278
*/
@@ -86,6 +102,7 @@ struct amd_sdw_manager {
86102
u32 quirks;
87103
u32 wake_en_mask;
88104
u32 power_mode_mask;
105+
bool clk_stopped;
89106

90107
struct sdw_amd_dai_runtime **dai_runtime_array;
91108
};

0 commit comments

Comments
 (0)