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

ASoC: cs35l56: Update hibernate/wake sequences and

Merge series from Richard Fitzgerald <rf@opensource.cirrus.com>:

Update the hibernate and wake command sequences to meet the latest
datasheet specification and enable hibernation for I2C and SPI control
interfaces.

Richard Fitzgerald (1):
ASoC: cs35l56: Enable low-power hibernation mode on SPI

Simon Trimmer (3):
ASoC: cs35l56: Change hibernate sequence to use allow auto hibernate
ASoC: cs35l56: Wake transactions need to be issued twice
ASoC: cs35l56: Enable low-power hibernation mode on i2c

include/sound/cs35l56.h | 1 +
sound/soc/codecs/cs35l56-i2c.c | 1 +
sound/soc/codecs/cs35l56-shared.c | 66 +++++++++++++++++++------------
sound/soc/codecs/cs35l56-spi.c | 1 +
4 files changed, 43 insertions(+), 26 deletions(-)

--
2.30.2

+43 -26
+1
include/sound/cs35l56.h
··· 243 243 #define CS35L56_HALO_STATE_POLL_US 1000 244 244 #define CS35L56_HALO_STATE_TIMEOUT_US 50000 245 245 #define CS35L56_RESET_PULSE_MIN_US 1100 246 + #define CS35L56_WAKE_HOLD_TIME_US 1000 246 247 247 248 #define CS35L56_SDW1_PLAYBACK_PORT 1 248 249 #define CS35L56_SDW1_CAPTURE_PORT 3
+1
sound/soc/codecs/cs35l56-i2c.c
··· 27 27 return -ENOMEM; 28 28 29 29 cs35l56->base.dev = dev; 30 + cs35l56->base.can_hibernate = true; 30 31 31 32 i2c_set_clientdata(client, cs35l56); 32 33 cs35l56->base.regmap = devm_regmap_init_i2c(client, regmap_config);
+40 -26
sound/soc/codecs/cs35l56-shared.c
··· 439 439 440 440 static const struct reg_sequence cs35l56_hibernate_seq[] = { 441 441 /* This must be the last register access */ 442 - REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW), 442 + REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE), 443 443 }; 444 444 445 445 static const struct reg_sequence cs35l56_hibernate_wake_seq[] = { 446 446 REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP), 447 447 }; 448 + 449 + static void cs35l56_issue_wake_event(struct cs35l56_base *cs35l56_base) 450 + { 451 + /* 452 + * Dummy transactions to trigger I2C/SPI auto-wake. Issue two 453 + * transactions to meet the minimum required time from the rising edge 454 + * to the last falling edge of wake. 455 + * 456 + * It uses bypassed write because we must wake the chip before 457 + * disabling regmap cache-only. 458 + * 459 + * This can NAK on I2C which will terminate the write sequence so the 460 + * single-write sequence is issued twice. 461 + */ 462 + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, 463 + cs35l56_hibernate_wake_seq, 464 + ARRAY_SIZE(cs35l56_hibernate_wake_seq)); 465 + 466 + usleep_range(CS35L56_WAKE_HOLD_TIME_US, 2 * CS35L56_WAKE_HOLD_TIME_US); 467 + 468 + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, 469 + cs35l56_hibernate_wake_seq, 470 + ARRAY_SIZE(cs35l56_hibernate_wake_seq)); 471 + 472 + cs35l56_wait_control_port_ready(); 473 + } 448 474 449 475 int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base) 450 476 { ··· 500 474 } 501 475 502 476 /* 503 - * Enable auto-hibernate. If it is woken by some other wake source 504 - * it will automatically return to hibernate. 505 - */ 506 - cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE); 507 - 508 - /* 509 477 * Must enter cache-only first so there can't be any more register 510 478 * accesses other than the controlled hibernate sequence below. 511 479 */ ··· 526 506 if (!cs35l56_base->can_hibernate) 527 507 goto out_sync; 528 508 529 - if (!is_soundwire) { 530 - /* 531 - * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C. 532 - * Must be done before releasing cache-only. 533 - */ 534 - regmap_multi_reg_write_bypassed(cs35l56_base->regmap, 535 - cs35l56_hibernate_wake_seq, 536 - ARRAY_SIZE(cs35l56_hibernate_wake_seq)); 537 - 538 - cs35l56_wait_control_port_ready(); 539 - } 509 + /* Must be done before releasing cache-only */ 510 + if (!is_soundwire) 511 + cs35l56_issue_wake_event(cs35l56_base); 540 512 541 513 out_sync: 542 514 regcache_cache_only(cs35l56_base->regmap, false); ··· 557 545 return 0; 558 546 559 547 err: 560 - regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, 561 - CS35L56_MBOX_CMD_HIBERNATE_NOW); 562 - 563 548 regcache_cache_only(cs35l56_base->regmap, true); 549 + 550 + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, 551 + cs35l56_hibernate_seq, 552 + ARRAY_SIZE(cs35l56_hibernate_seq)); 564 553 565 554 return ret; 566 555 } ··· 596 583 unsigned int devid, revid, otpid, secured; 597 584 598 585 /* 599 - * If the system is not using a reset_gpio then issue a 600 - * dummy read to force a wakeup. 586 + * When the system is not using a reset_gpio ensure the device is 587 + * awake, otherwise the device has just been released from reset and 588 + * the driver must wait for the control port to become usable. 601 589 */ 602 590 if (!cs35l56_base->reset_gpio) 603 - regmap_read(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid); 604 - 605 - cs35l56_wait_control_port_ready(); 591 + cs35l56_issue_wake_event(cs35l56_base); 592 + else 593 + cs35l56_wait_control_port_ready(); 606 594 607 595 /* 608 596 * The HALO_STATE register is in different locations on Ax and B0
+1
sound/soc/codecs/cs35l56-spi.c
··· 32 32 } 33 33 34 34 cs35l56->base.dev = &spi->dev; 35 + cs35l56->base.can_hibernate = true; 35 36 36 37 ret = cs35l56_common_probe(cs35l56); 37 38 if (ret != 0)