sound/soc/codecs/tpa6130a2.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/codecs/tpa6130a2.c
Extension
.c
Size
8230 bytes
Lines
307
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

struct tpa6130a2_data {
	struct device *dev;
	struct regmap *regmap;
	struct regulator *supply;
	struct gpio_desc *power_gpio;
	enum tpa_model id;
};

static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
{
	int ret = 0, ret2;

	if (enable) {
		ret = regulator_enable(data->supply);
		if (ret != 0) {
			dev_err(data->dev,
				"Failed to enable supply: %d\n", ret);
			return ret;
		}
		/* Power on */
		gpiod_set_value(data->power_gpio, 1);

		/* Sync registers */
		regcache_cache_only(data->regmap, false);
		ret = regcache_sync(data->regmap);
		if (ret != 0) {
			dev_err(data->dev,
				"Failed to sync registers: %d\n", ret);
			regcache_cache_only(data->regmap, true);
			gpiod_set_value(data->power_gpio, 0);
			ret2 = regulator_disable(data->supply);
			if (ret2 != 0)
				dev_err(data->dev,
					"Failed to disable supply: %d\n", ret2);
			return ret;
		}
	} else {
		/* Powered off device does not retain registers. While device
		 * is off, any register updates (i.e. volume changes) should
		 * happen in cache only.
		 */
		regcache_mark_dirty(data->regmap);
		regcache_cache_only(data->regmap, true);

		/* Power off */
		gpiod_set_value(data->power_gpio, 0);

		ret = regulator_disable(data->supply);
		if (ret != 0) {
			dev_err(data->dev,
				"Failed to disable supply: %d\n", ret);
			return ret;
		}
	}

	return ret;
}

static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w,
				 struct snd_kcontrol *kctrl, int event)
{
	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
	struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c);

	if (SND_SOC_DAPM_EVENT_ON(event)) {
		/* Before widget power up: turn chip on, sync registers */
		return tpa6130a2_power(data, true);
	} else {
		/* After widget power down: turn chip off */
		return tpa6130a2_power(data, false);
	}
}

/*
 * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
 * down in gain.
 */
static const DECLARE_TLV_DB_RANGE(tpa6130_tlv,
	0, 1, TLV_DB_SCALE_ITEM(-5950, 600, 0),
	2, 3, TLV_DB_SCALE_ITEM(-5000, 250, 0),
	4, 5, TLV_DB_SCALE_ITEM(-4550, 160, 0),
	6, 7, TLV_DB_SCALE_ITEM(-4140, 190, 0),
	8, 9, TLV_DB_SCALE_ITEM(-3650, 120, 0),
	10, 11, TLV_DB_SCALE_ITEM(-3330, 160, 0),
	12, 13, TLV_DB_SCALE_ITEM(-3040, 180, 0),
	14, 20, TLV_DB_SCALE_ITEM(-2710, 110, 0),
	21, 37, TLV_DB_SCALE_ITEM(-1960, 74, 0),
	38, 63, TLV_DB_SCALE_ITEM(-720, 45, 0)
);

Annotation

Implementation Notes