diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 30b3192d6ce9..9dc47fec1ea0 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -340,6 +341,14 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); struct sdw_slave_prop *prop = &peripheral->prop; struct sdw_dpn_prop *ports; + u8 clock_stop_1 = false; + int ret; + + ret = fwnode_property_read_u8(dev_fwnode(cs35l56->base.dev), + "mipi-sdw-clock-stop-mode1-supported", + &clock_stop_1); + if (ret == 0) + prop->clk_stop_mode1 = !!clock_stop_1; ports = devm_kcalloc(cs35l56->base.dev, 2, sizeof(*ports), GFP_KERNEL); if (!ports) @@ -363,6 +372,9 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) ports[1].ch_prep_timeout = 10; prop->src_dpn_prop = &ports[1]; + dev_dbg(&peripheral->dev, "clock stop mode 1 supported: %s\n", + str_yes_no(prop->clk_stop_mode1)); + return 0; } @@ -374,6 +386,7 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral, switch (status) { case SDW_SLAVE_ATTACHED: dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__); + cs35l56->sdw_in_clock_stop_1 = false; if (cs35l56->sdw_attached) break; @@ -399,25 +412,35 @@ static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral, { struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); - dev_dbg(cs35l56->base.dev, "%s: mode:%d type:%d\n", __func__, mode, type); + dev_dbg(cs35l56->base.dev, "%s: clock_stop_mode%d stage:%d\n", __func__, mode, type); - return 0; + switch (type) { + case SDW_CLK_POST_PREPARE: + if (mode == SDW_CLK_STOP_MODE1) + cs35l56->sdw_in_clock_stop_1 = true; + else + cs35l56->sdw_in_clock_stop_1 = false; + return 0; + default: + return 0; + } } static const struct sdw_slave_ops cs35l56_sdw_ops = { .read_prop = cs35l56_sdw_read_prop, .interrupt_callback = cs35l56_sdw_interrupt, .update_status = cs35l56_sdw_update_status, -#ifdef DEBUG .clk_stop = cs35l56_sdw_clk_stop, -#endif }; static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs35l56) { struct sdw_slave *peripheral = cs35l56->sdw_peripheral; - if (peripheral->unattach_request) { + dev_dbg(cs35l56->base.dev, "attached:%u unattach_request:%u in_clock_stop_1:%u\n", + cs35l56->sdw_attached, peripheral->unattach_request, cs35l56->sdw_in_clock_stop_1); + + if (cs35l56->sdw_in_clock_stop_1 || peripheral->unattach_request) { /* Cannot access registers until bus is re-initialized. */ dev_dbg(cs35l56->base.dev, "Wait for initialization_complete\n"); if (!wait_for_completion_timeout(&peripheral->initialization_complete, @@ -427,6 +450,7 @@ static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs } peripheral->unattach_request = 0; + cs35l56->sdw_in_clock_stop_1 = false; /* * Don't call regcache_mark_dirty(), we can't be sure that the diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index 747529be3e2e..36d239d571cd 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -42,6 +42,7 @@ struct cs35l56_private { bool sdw_irq_no_unmask; bool soft_resetting; bool sdw_attached; + bool sdw_in_clock_stop_1; struct completion init_completion; int speaker_id;