sound/soc/sunxi/sun50i-dmic.c

Source file repositories/reference/linux-study-clean/sound/soc/sunxi/sun50i-dmic.c

File Facts

System
Linux kernel
Corpus path
sound/soc/sunxi/sun50i-dmic.c
Extension
.c
Size
12930 bytes
Lines
441
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 sun50i_dmic_dev {
	struct clk *dmic_clk;
	struct clk *bus_clk;
	struct reset_control *rst;
	struct regmap *regmap;
	struct snd_dmaengine_dai_dma_data dma_params_rx;
};

struct dmic_rate {
	unsigned int samplerate;
	unsigned int rate_bit;
};

static const struct dmic_rate dmic_rate_s[] = {
	{48000, 0x0},
	{44100, 0x0},
	{32000, 0x1},
	{24000, 0x2},
	{22050, 0x2},
	{16000, 0x3},
	{12000, 0x4},
	{11025, 0x4},
	{8000,  0x5},
};

static int sun50i_dmic_startup(struct snd_pcm_substream *substream,
			       struct snd_soc_dai *cpu_dai)
{
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));

	/* only support capture */
	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
		return -EINVAL;

	regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL,
			SUN50I_DMIC_RXFIFO_CTL_FLUSH,
			SUN50I_DMIC_RXFIFO_CTL_FLUSH);
	regmap_write(host->regmap, SUN50I_DMIC_CNT, SUN50I_DMIC_CNT_N);

	return 0;
}

static int sun50i_dmic_hw_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *params,
				 struct snd_soc_dai *cpu_dai)
{
	int i = 0;
	unsigned long rate = params_rate(params);
	unsigned int mclk = 0;
	unsigned int channels = params_channels(params);
	unsigned int chan_en = (1 << channels) - 1;
	struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(cpu_dai);

	/* DMIC num is N+1 */
	regmap_update_bits(host->regmap, SUN50I_DMIC_CH_NUM,
			   SUN50I_DMIC_CH_NUM_N_MASK,
			   SUN50I_DMIC_CH_NUM_N(channels - 1));
	regmap_write(host->regmap, SUN50I_DMIC_HPF_CTRL, chan_en);
	regmap_update_bits(host->regmap, SUN50I_DMIC_EN_CTL,
			   SUN50I_DMIC_EN_CTL_CHAN_MASK,
			   SUN50I_DMIC_EN_CTL_CHAN(chan_en));

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL,
				   SUN50I_DMIC_RXFIFO_CTL_SAMPLE_MASK,
				   SUN50I_DMIC_RXFIFO_CTL_SAMPLE_16);
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL,
				   SUN50I_DMIC_RXFIFO_CTL_SAMPLE_MASK,
				   SUN50I_DMIC_RXFIFO_CTL_SAMPLE_24);
		break;
	default:
		dev_err(cpu_dai->dev, "Invalid format!\n");
		return -EINVAL;
	}
	/* The hardware supports FIFO mode 1 for 24-bit samples */
	regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL,
			   SUN50I_DMIC_RXFIFO_CTL_MODE_MASK,
			   SUN50I_DMIC_RXFIFO_CTL_MODE_MSB);

	switch (rate) {
	case 11025:
	case 22050:
	case 44100:
		mclk = 22579200;
		break;
	case 8000:

Annotation

Implementation Notes