ASoC: cs42l42: Fix handling of hard reset

Merge series from Stefan Binding <sbinding@opensource.cirrus.com>:

These patches fix 3 problems with hard reset:
1. Ensure a minimum reset pulse width
2. Deal with ACPI overriding the requested default GPIO state
3. Avoid a race condition when hard-resetting a SoundWire peripheral
   that is already enumerated
This commit is contained in:
Mark Brown 2023-09-13 22:46:18 +01:00
commit ef3e1b8a31
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0
3 changed files with 41 additions and 1 deletions

View file

@ -344,6 +344,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
switch (status) {
case SDW_SLAVE_ATTACHED:
dev_dbg(cs42l42->dev, "ATTACHED\n");
/*
* The SoundWire core can report stale ATTACH notifications
* if we hard-reset CS42L42 in probe() but it had already been
* enumerated. Reject the ATTACH if we haven't yet seen an
* UNATTACH report for the device being in reset.
*/
if (cs42l42->sdw_waiting_first_unattach)
break;
/*
* Initialise codec, this only needs to be done once.
* When resuming from suspend, resume callback will handle re-init of codec,
@ -354,6 +364,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
break;
case SDW_SLAVE_UNATTACHED:
dev_dbg(cs42l42->dev, "UNATTACHED\n");
if (cs42l42->sdw_waiting_first_unattach) {
/*
* SoundWire core has seen that CS42L42 is not on
* the bus so release RESET and wait for ATTACH.
*/
cs42l42->sdw_waiting_first_unattach = false;
gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
}
break;
default:
break;

View file

@ -2320,7 +2320,26 @@ int cs42l42_common_probe(struct cs42l42_private *cs42l42,
if (cs42l42->reset_gpio) {
dev_dbg(cs42l42->dev, "Found reset GPIO\n");
gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
/*
* ACPI can override the default GPIO state we requested
* so ensure that we start with RESET low.
*/
gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
/* Ensure minimum reset pulse width */
usleep_range(10, 500);
/*
* On SoundWire keep the chip in reset until we get an UNATTACH
* notification from the SoundWire core. This acts as a
* synchronization point to reject stale ATTACH notifications
* if the chip was already enumerated before we reset it.
*/
if (cs42l42->sdw_peripheral)
cs42l42->sdw_waiting_first_unattach = true;
else
gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
}
usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);

View file

@ -53,6 +53,7 @@ struct cs42l42_private {
u8 stream_use;
bool hp_adc_up_pending;
bool suspended;
bool sdw_waiting_first_unattach;
bool init_done;
};