sound/hda/codecs/side-codecs/tas2781_hda_i2c.c

Source file repositories/reference/linux-study-clean/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c

File Facts

System
Linux kernel
Corpus path
sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
Extension
.c
Size
22763 bytes
Lines
828
Domain
Driver Families
Bucket
sound/hda
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

struct tas2781_hda_i2c_priv {
	struct snd_kcontrol *snd_ctls[2];
	int (*save_calibration)(struct tas2781_hda *h);

	int hda_chip_id;
};

static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
{
	struct tasdevice_priv *tas_priv = data;
	struct acpi_resource_i2c_serialbus *sb;

	if (i2c_acpi_get_i2c_resource(ares, &sb)) {
		if (tas_priv->ndev < TASDEVICE_MAX_CHANNELS &&
			sb->slave_address != tas_priv->global_addr) {
			tas_priv->tasdevice[tas_priv->ndev].dev_addr =
				(unsigned int)sb->slave_address;
			tas_priv->ndev++;
		}
	}
	return 1;
}

static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false };

static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {
	{ "speakerid-gpios", &speakerid_gpios, 1 },
	{ }
};

static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
{
	struct gpio_desc *speaker_id;
	struct acpi_device *adev;
	struct device *physdev;
	LIST_HEAD(resources);
	const char *sub;
	uint32_t subid;
	int ret;

	adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
	if (!adev) {
		dev_err(p->dev,
			"Failed to find an ACPI device for %s\n", hid);
		return -ENODEV;
	}

	physdev = get_device(acpi_get_first_physical_node(adev));
	ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);
	if (ret < 0) {
		dev_err(p->dev, "Failed to get ACPI resource.\n");
		goto err;
	}
	sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
	if (IS_ERR(sub)) {
		/* No subsys id in older tas2563 projects. */
		if (!strncmp(hid, "INT8866", sizeof("INT8866"))) {
			p->speaker_id = -1;
			goto end_2563;
		}
		dev_err(p->dev, "Failed to get SUBSYS ID.\n");
		ret = PTR_ERR(sub);
		goto err;
	}
	/* Speaker id was needed for ASUS projects. */
	ret = kstrtou32(sub, 16, &subid);
	if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
		ret = acpi_dev_add_driver_gpios(adev, tas2781_speaker_id_gpios);
		if (ret < 0) {
			dev_err(p->dev, "Failed to add driver gpio %d.\n",
				ret);
			p->speaker_id = -1;
			goto end_2563;
		}

		speaker_id = fwnode_gpiod_get_index(acpi_fwnode_handle(adev),
			"speakerid", 0, GPIOD_IN, NULL);
		if (!IS_ERR(speaker_id)) {
			p->speaker_id = gpiod_get_value_cansleep(speaker_id);
			dev_dbg(p->dev, "Got speaker id gpio from ACPI: %d.\n",
				p->speaker_id);
			gpiod_put(speaker_id);
		} else {
			p->speaker_id = -1;
			ret = PTR_ERR(speaker_id);
			dev_err(p->dev, "Get speaker id gpio failed %d.\n",
				ret);
		}

		acpi_dev_remove_driver_gpios(adev);

Annotation

Implementation Notes