Unverified Commit ef3e1b8a authored by Mark Brown's avatar Mark Brown
Browse files

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
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -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;
+20 −1
Original line number Diff line number Diff line
@@ -2320,6 +2320,25 @@ int cs42l42_common_probe(struct cs42l42_private *cs42l42,

	if (cs42l42->reset_gpio) {
		dev_dbg(cs42l42->dev, "Found reset GPIO\n");

		/*
		 * 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);
+1 −0
Original line number Diff line number Diff line
@@ -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;
};