Commit ef3e1b8a authored by Mark Brown's avatar Mark Brown

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
parents 781118bc 2d066c6a
...@@ -344,6 +344,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral, ...@@ -344,6 +344,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
switch (status) { switch (status) {
case SDW_SLAVE_ATTACHED: case SDW_SLAVE_ATTACHED:
dev_dbg(cs42l42->dev, "ATTACHED\n"); 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. * Initialise codec, this only needs to be done once.
* When resuming from suspend, resume callback will handle re-init of codec, * 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, ...@@ -354,6 +364,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
break; break;
case SDW_SLAVE_UNATTACHED: case SDW_SLAVE_UNATTACHED:
dev_dbg(cs42l42->dev, "UNATTACHED\n"); 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; break;
default: default:
break; break;
......
...@@ -2320,7 +2320,26 @@ int cs42l42_common_probe(struct cs42l42_private *cs42l42, ...@@ -2320,7 +2320,26 @@ int cs42l42_common_probe(struct cs42l42_private *cs42l42,
if (cs42l42->reset_gpio) { if (cs42l42->reset_gpio) {
dev_dbg(cs42l42->dev, "Found reset GPIO\n"); 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); usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
......
...@@ -53,6 +53,7 @@ struct cs42l42_private { ...@@ -53,6 +53,7 @@ struct cs42l42_private {
u8 stream_use; u8 stream_use;
bool hp_adc_up_pending; bool hp_adc_up_pending;
bool suspended; bool suspended;
bool sdw_waiting_first_unattach;
bool init_done; bool init_done;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment