sound/soc/fsl/fsl_audmix.c

Source file repositories/reference/linux-study-clean/sound/soc/fsl/fsl_audmix.c

File Facts

System
Linux kernel
Corpus path
sound/soc/fsl/fsl_audmix.c
Extension
.c
Size
16319 bytes
Lines
579
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 fsl_audmix_state {
	u8 tdms;
	u8 clk;
	char msg[64];
};

static const struct fsl_audmix_state prms[4][4] = {{
	/* DIS->DIS, do nothing */
	{ .tdms = 0, .clk = 0, .msg = "" },
	/* DIS->TDM1*/
	{ .tdms = 1, .clk = 1, .msg = "DIS->TDM1: TDM1 not started!\n" },
	/* DIS->TDM2*/
	{ .tdms = 2, .clk = 2, .msg = "DIS->TDM2: TDM2 not started!\n" },
	/* DIS->MIX */
	{ .tdms = 3, .clk = 0, .msg = "DIS->MIX: Please start both TDMs!\n" }
}, {	/* TDM1->DIS */
	{ .tdms = 1, .clk = 0, .msg = "TDM1->DIS: TDM1 not started!\n" },
	/* TDM1->TDM1, do nothing */
	{ .tdms = 0, .clk = 0, .msg = "" },
	/* TDM1->TDM2 */
	{ .tdms = 3, .clk = 2, .msg = "TDM1->TDM2: Please start both TDMs!\n" },
	/* TDM1->MIX */
	{ .tdms = 3, .clk = 0, .msg = "TDM1->MIX: Please start both TDMs!\n" }
}, {	/* TDM2->DIS */
	{ .tdms = 2, .clk = 0, .msg = "TDM2->DIS: TDM2 not started!\n" },
	/* TDM2->TDM1 */
	{ .tdms = 3, .clk = 1, .msg = "TDM2->TDM1: Please start both TDMs!\n" },
	/* TDM2->TDM2, do nothing */
	{ .tdms = 0, .clk = 0, .msg = "" },
	/* TDM2->MIX */
	{ .tdms = 3, .clk = 0, .msg = "TDM2->MIX: Please start both TDMs!\n" }
}, {	/* MIX->DIS */
	{ .tdms = 3, .clk = 0, .msg = "MIX->DIS: Please start both TDMs!\n" },
	/* MIX->TDM1 */
	{ .tdms = 3, .clk = 1, .msg = "MIX->TDM1: Please start both TDMs!\n" },
	/* MIX->TDM2 */
	{ .tdms = 3, .clk = 2, .msg = "MIX->TDM2: Please start both TDMs!\n" },
	/* MIX->MIX, do nothing */
	{ .tdms = 0, .clk = 0, .msg = "" }
}, };

static int fsl_audmix_state_trans(struct snd_soc_component *comp,
				  unsigned int *mask, unsigned int *ctr,
				  const struct fsl_audmix_state prm)
{
	struct fsl_audmix *priv = snd_soc_component_get_drvdata(comp);
	/* Enforce all required TDMs are started */
	if ((priv->tdms & prm.tdms) != prm.tdms) {
		dev_dbg(comp->dev, "%s", prm.msg);
		return -EINVAL;
	}

	switch (prm.clk) {
	case 1:
	case 2:
		/* Set mix clock */
		(*mask) |= FSL_AUDMIX_CTR_MIXCLK_MASK;
		(*ctr)  |= FSL_AUDMIX_CTR_MIXCLK(prm.clk - 1);
		break;
	default:
		break;
	}

	return 0;
}

static int fsl_audmix_put_mix_clk_src(struct snd_kcontrol *kcontrol,
				      struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
	struct fsl_audmix *priv = snd_soc_component_get_drvdata(comp);
	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
	unsigned int *item = ucontrol->value.enumerated.item;
	unsigned int reg_val, val, mix_clk;

	if (item[0] >= e->items)
		return -EINVAL;

	/* Get current state */
	reg_val = snd_soc_component_read(comp, FSL_AUDMIX_CTR);
	mix_clk = ((reg_val & FSL_AUDMIX_CTR_MIXCLK_MASK)
			>> FSL_AUDMIX_CTR_MIXCLK_SHIFT);
	val = snd_soc_enum_item_to_val(e, item[0]);

	dev_dbg(comp->dev, "TDMs=x%08x, val=x%08x\n", priv->tdms, val);

	/**
	 * Ensure the current selected mixer clock is available
	 * for configuration propagation
	 */

Annotation

Implementation Notes