sound/soc/samsung/odroid.c

Source file repositories/reference/linux-study-clean/sound/soc/samsung/odroid.c

File Facts

System
Linux kernel
Corpus path
sound/soc/samsung/odroid.c
Extension
.c
Size
8659 bytes
Lines
341
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 odroid_priv {
	struct snd_soc_card card;
	struct clk *clk_i2s_bus;
	struct clk *sclk_i2s;

	/* Spinlock protecting fields below */
	spinlock_t lock;
	unsigned int be_sample_rate;
	bool be_active;
};

static int odroid_card_fe_startup(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;

	snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);

	return 0;
}

static int odroid_card_fe_hw_params(struct snd_pcm_substream *substream,
				      struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);

	guard(spinlock_irqsave)(&priv->lock);
	if (priv->be_active && priv->be_sample_rate != params_rate(params))
		return -EINVAL;

	return 0;
}

static const struct snd_soc_ops odroid_card_fe_ops = {
	.startup = odroid_card_fe_startup,
	.hw_params = odroid_card_fe_hw_params,
};

static int odroid_card_be_hw_params(struct snd_pcm_substream *substream,
				      struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
	unsigned int pll_freq, rclk_freq, rfs;
	int ret;

	switch (params_rate(params)) {
	case 64000:
		pll_freq = 196608001U;
		rfs = 384;
		break;
	case 44100:
	case 88200:
		pll_freq = 180633609U;
		rfs = 512;
		break;
	case 32000:
	case 48000:
	case 96000:
		pll_freq = 196608001U;
		rfs = 512;
		break;
	default:
		return -EINVAL;
	}

	ret = clk_set_rate(priv->clk_i2s_bus, pll_freq / 2 + 1);
	if (ret < 0)
		return ret;

	/*
	 *  We add 2 to the rclk_freq value in order to avoid too low clock
	 *  frequency values due to the EPLL output frequency not being exact
	 *  multiple of the audio sampling rate.
	 */
	rclk_freq = params_rate(params) * rfs + 2;

	ret = clk_set_rate(priv->sclk_i2s, rclk_freq);
	if (ret < 0)
		return ret;

	if (rtd->dai_link->num_codecs > 1) {
		struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 1);

		ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk_freq,
					     SND_SOC_CLOCK_IN);
		if (ret < 0)
			return ret;
	}

Annotation

Implementation Notes