Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: cs35l56: Support clock stop mode 1 if enabled in ACPI

Report the ability to support SoundWire clock-stop mode 1 if this is
enabled in ACPI. Mode 1 allows the device to lose state, so it can
reduce power consumption in clock-stop. Also add the necessary
handling to wait for re-enumeration on resume.

This does not use sdw_slave_read_prop(), because that also fills in
other properties from ACPI that were not previously set by the driver
and this has been observed to break some systems. Instead, the
"mipi-sdw-clock-stop-mode1-supported" property is checked directly.

When a SoundWire peripheral has been put into clock-stop mode 1 it
must be re-enumerated after the clock is restarted. A new flag
sdw_in_clock_stop_1 is set to true in cs35l56_sdw_clk_stop() if the
SoundWire core notifies that it is entering clock-stop 1.
cs35l56_sdw_handle_unattach() will wait for re-enumeration if
sdw_in_clock_stop_1 is true.

sdw_in_clock_stop_1 will be reset to false when an ATTACH notification
is received in cs35l56_sdw_update_status().

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Link: https://patch.msgid.link/20260311142153.2201761-1-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Richard Fitzgerald and committed by
Mark Brown
48863104 94ef278e

+30 -5
+29 -5
sound/soc/codecs/cs35l56-sdw.c
··· 14 14 #include <linux/soundwire/sdw.h> 15 15 #include <linux/soundwire/sdw_registers.h> 16 16 #include <linux/soundwire/sdw_type.h> 17 + #include <linux/string_choices.h> 17 18 #include <linux/swab.h> 18 19 #include <linux/types.h> 19 20 #include <linux/workqueue.h> ··· 341 340 struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); 342 341 struct sdw_slave_prop *prop = &peripheral->prop; 343 342 struct sdw_dpn_prop *ports; 343 + u8 clock_stop_1 = false; 344 + int ret; 345 + 346 + ret = fwnode_property_read_u8(dev_fwnode(cs35l56->base.dev), 347 + "mipi-sdw-clock-stop-mode1-supported", 348 + &clock_stop_1); 349 + if (ret == 0) 350 + prop->clk_stop_mode1 = !!clock_stop_1; 344 351 345 352 ports = devm_kcalloc(cs35l56->base.dev, 2, sizeof(*ports), GFP_KERNEL); 346 353 if (!ports) ··· 372 363 ports[1].ch_prep_timeout = 10; 373 364 prop->src_dpn_prop = &ports[1]; 374 365 366 + dev_dbg(&peripheral->dev, "clock stop mode 1 supported: %s\n", 367 + str_yes_no(prop->clk_stop_mode1)); 368 + 375 369 return 0; 376 370 } 377 371 ··· 386 374 switch (status) { 387 375 case SDW_SLAVE_ATTACHED: 388 376 dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__); 377 + cs35l56->sdw_in_clock_stop_1 = false; 389 378 if (cs35l56->sdw_attached) 390 379 break; 391 380 ··· 412 399 { 413 400 struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); 414 401 415 - dev_dbg(cs35l56->base.dev, "%s: mode:%d type:%d\n", __func__, mode, type); 402 + dev_dbg(cs35l56->base.dev, "%s: clock_stop_mode%d stage:%d\n", __func__, mode, type); 416 403 417 - return 0; 404 + switch (type) { 405 + case SDW_CLK_POST_PREPARE: 406 + if (mode == SDW_CLK_STOP_MODE1) 407 + cs35l56->sdw_in_clock_stop_1 = true; 408 + else 409 + cs35l56->sdw_in_clock_stop_1 = false; 410 + return 0; 411 + default: 412 + return 0; 413 + } 418 414 } 419 415 420 416 static const struct sdw_slave_ops cs35l56_sdw_ops = { 421 417 .read_prop = cs35l56_sdw_read_prop, 422 418 .interrupt_callback = cs35l56_sdw_interrupt, 423 419 .update_status = cs35l56_sdw_update_status, 424 - #ifdef DEBUG 425 420 .clk_stop = cs35l56_sdw_clk_stop, 426 - #endif 427 421 }; 428 422 429 423 static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs35l56) 430 424 { 431 425 struct sdw_slave *peripheral = cs35l56->sdw_peripheral; 432 426 433 - if (peripheral->unattach_request) { 427 + dev_dbg(cs35l56->base.dev, "attached:%u unattach_request:%u in_clock_stop_1:%u\n", 428 + cs35l56->sdw_attached, peripheral->unattach_request, cs35l56->sdw_in_clock_stop_1); 429 + 430 + if (cs35l56->sdw_in_clock_stop_1 || peripheral->unattach_request) { 434 431 /* Cannot access registers until bus is re-initialized. */ 435 432 dev_dbg(cs35l56->base.dev, "Wait for initialization_complete\n"); 436 433 if (!wait_for_completion_timeout(&peripheral->initialization_complete, ··· 450 427 } 451 428 452 429 peripheral->unattach_request = 0; 430 + cs35l56->sdw_in_clock_stop_1 = false; 453 431 454 432 /* 455 433 * Don't call regcache_mark_dirty(), we can't be sure that the
+1
sound/soc/codecs/cs35l56.h
··· 42 42 bool sdw_irq_no_unmask; 43 43 bool soft_resetting; 44 44 bool sdw_attached; 45 + bool sdw_in_clock_stop_1; 45 46 struct completion init_completion; 46 47 47 48 int speaker_id;