sound/soc/codecs/cs42l42-sdw.c

Source file repositories/reference/linux-study-clean/sound/soc/codecs/cs42l42-sdw.c

File Facts

System
Linux kernel
Corpus path
sound/soc/codecs/cs42l42-sdw.c
Extension
.c
Size
17282 bytes
Lines
621
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

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;
	}

	return 0;
}

static int cs42l42_sdw_bus_config(struct sdw_slave *peripheral,
				  struct sdw_bus_params *params)
{
	struct cs42l42_private *cs42l42 = dev_get_drvdata(&peripheral->dev);
	unsigned int new_sclk = params->curr_dr_freq / 2;

	/* The cs42l42 cannot support a glitchless SWIRE_CLK change. */
	if ((new_sclk != cs42l42->sclk) && cs42l42->stream_use) {
		dev_warn(cs42l42->dev, "Rejected SCLK change while audio active\n");
		return -EBUSY;
	}

	cs42l42->sclk = new_sclk;

	dev_dbg(cs42l42->dev, "bus_config: sclk=%u c=%u r=%u\n",
		cs42l42->sclk, params->col, params->row);

	return 0;
}

static const struct sdw_slave_ops cs42l42_sdw_ops = {
/* No interrupt callback because only hardware INT is supported for Jack Detect in the CS42L42 */
	.read_prop = cs42l42_sdw_read_prop,
	.update_status = cs42l42_sdw_update_status,
	.bus_config = cs42l42_sdw_bus_config,
	.port_prep = cs42l42_sdw_port_prep,
};

static int cs42l42_sdw_runtime_suspend(struct device *dev)
{
	struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);

	dev_dbg(dev, "Runtime suspend\n");

	if (!cs42l42->init_done)
		return 0;

	/* The host controller could suspend, which would mean no register access */
	regcache_cache_only(cs42l42->regmap, true);

	return 0;
}

static const struct reg_sequence cs42l42_soft_reboot_seq[] = {
	REG_SEQ0(CS42L42_SOFT_RESET_REBOOT, 0x1e),
};

static int cs42l42_sdw_handle_unattach(struct cs42l42_private *cs42l42)
{
	struct sdw_slave *peripheral = cs42l42->sdw_peripheral;
	int ret;

	if (!peripheral->unattach_request)
		return 0;

	/* Cannot access registers until master re-attaches. */
	dev_dbg(&peripheral->dev, "Wait for initialization_complete\n");
	ret = sdw_slave_wait_for_init(peripheral, 5000);
	if (ret)
		return ret;

	/*
	 * After a bus reset there must be a reconfiguration reset to
	 * reinitialize the internal state of CS42L42.
	 */
	regmap_multi_reg_write_bypassed(cs42l42->regmap,
					cs42l42_soft_reboot_seq,
					ARRAY_SIZE(cs42l42_soft_reboot_seq));
	usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
	regcache_mark_dirty(cs42l42->regmap);

	return 0;
}

Annotation

Implementation Notes