162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This driver supports the digital controls for the internal codec
462306a36Sopenharmony_ci * found in Allwinner's A33 SoCs.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * (C) Copyright 2010-2016
762306a36Sopenharmony_ci * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
862306a36Sopenharmony_ci * huangxin <huangxin@Reuuimllatech.com>
962306a36Sopenharmony_ci * Mylène Josserand <mylene.josserand@free-electrons.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/clk.h>
1562306a36Sopenharmony_ci#include <linux/io.h>
1662306a36Sopenharmony_ci#include <linux/of_device.h>
1762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1862306a36Sopenharmony_ci#include <linux/regmap.h>
1962306a36Sopenharmony_ci#include <linux/log2.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <sound/pcm_params.h>
2262306a36Sopenharmony_ci#include <sound/soc.h>
2362306a36Sopenharmony_ci#include <sound/soc-dapm.h>
2462306a36Sopenharmony_ci#include <sound/tlv.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL				0x00c
2762306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_AIF1CLK_ENA			11
2862306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL		(0x2 << 8)
2962306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_AIF2CLK_ENA			7
3062306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL		(0x2 << 4)
3162306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_SYSCLK_ENA			3
3262306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_SYSCLK_SRC			0
3362306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK		(0x0 << 0)
3462306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK		(0x1 << 0)
3562306a36Sopenharmony_ci#define SUN8I_MOD_CLK_ENA				0x010
3662306a36Sopenharmony_ci#define SUN8I_MOD_CLK_ENA_AIF1				15
3762306a36Sopenharmony_ci#define SUN8I_MOD_CLK_ENA_AIF2				14
3862306a36Sopenharmony_ci#define SUN8I_MOD_CLK_ENA_AIF3				13
3962306a36Sopenharmony_ci#define SUN8I_MOD_CLK_ENA_ADC				3
4062306a36Sopenharmony_ci#define SUN8I_MOD_CLK_ENA_DAC				2
4162306a36Sopenharmony_ci#define SUN8I_MOD_RST_CTL				0x014
4262306a36Sopenharmony_ci#define SUN8I_MOD_RST_CTL_AIF1				15
4362306a36Sopenharmony_ci#define SUN8I_MOD_RST_CTL_AIF2				14
4462306a36Sopenharmony_ci#define SUN8I_MOD_RST_CTL_AIF3				13
4562306a36Sopenharmony_ci#define SUN8I_MOD_RST_CTL_ADC				3
4662306a36Sopenharmony_ci#define SUN8I_MOD_RST_CTL_DAC				2
4762306a36Sopenharmony_ci#define SUN8I_SYS_SR_CTRL				0x018
4862306a36Sopenharmony_ci#define SUN8I_SYS_SR_CTRL_AIF1_FS			12
4962306a36Sopenharmony_ci#define SUN8I_SYS_SR_CTRL_AIF2_FS			8
5062306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
5162306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
5262306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_CLK_INV			13
5362306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
5462306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
5562306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
5662306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
5762306a36Sopenharmony_ci#define SUN8I_AIF1_ADCDAT_CTRL				0x044
5862306a36Sopenharmony_ci#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA		15
5962306a36Sopenharmony_ci#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
6062306a36Sopenharmony_ci#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC		10
6162306a36Sopenharmony_ci#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC		8
6262306a36Sopenharmony_ci#define SUN8I_AIF1_DACDAT_CTRL				0x048
6362306a36Sopenharmony_ci#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA		15
6462306a36Sopenharmony_ci#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA		14
6562306a36Sopenharmony_ci#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC		10
6662306a36Sopenharmony_ci#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC		8
6762306a36Sopenharmony_ci#define SUN8I_AIF1_MXR_SRC				0x04c
6862306a36Sopenharmony_ci#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L	15
6962306a36Sopenharmony_ci#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL	14
7062306a36Sopenharmony_ci#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL		13
7162306a36Sopenharmony_ci#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR	12
7262306a36Sopenharmony_ci#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R	11
7362306a36Sopenharmony_ci#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR	10
7462306a36Sopenharmony_ci#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR		9
7562306a36Sopenharmony_ci#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL	8
7662306a36Sopenharmony_ci#define SUN8I_AIF1_VOL_CTRL1				0x050
7762306a36Sopenharmony_ci#define SUN8I_AIF1_VOL_CTRL1_AD0L_VOL			8
7862306a36Sopenharmony_ci#define SUN8I_AIF1_VOL_CTRL1_AD0R_VOL			0
7962306a36Sopenharmony_ci#define SUN8I_AIF1_VOL_CTRL3				0x058
8062306a36Sopenharmony_ci#define SUN8I_AIF1_VOL_CTRL3_DA0L_VOL			8
8162306a36Sopenharmony_ci#define SUN8I_AIF1_VOL_CTRL3_DA0R_VOL			0
8262306a36Sopenharmony_ci#define SUN8I_AIF2_ADCDAT_CTRL				0x084
8362306a36Sopenharmony_ci#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA		15
8462306a36Sopenharmony_ci#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA		14
8562306a36Sopenharmony_ci#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC		10
8662306a36Sopenharmony_ci#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC		8
8762306a36Sopenharmony_ci#define SUN8I_AIF2_DACDAT_CTRL				0x088
8862306a36Sopenharmony_ci#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA		15
8962306a36Sopenharmony_ci#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA		14
9062306a36Sopenharmony_ci#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC		10
9162306a36Sopenharmony_ci#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC		8
9262306a36Sopenharmony_ci#define SUN8I_AIF2_MXR_SRC				0x08c
9362306a36Sopenharmony_ci#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L	15
9462306a36Sopenharmony_ci#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L	14
9562306a36Sopenharmony_ci#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR	13
9662306a36Sopenharmony_ci#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL		12
9762306a36Sopenharmony_ci#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R	11
9862306a36Sopenharmony_ci#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R	10
9962306a36Sopenharmony_ci#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL	9
10062306a36Sopenharmony_ci#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR		8
10162306a36Sopenharmony_ci#define SUN8I_AIF2_VOL_CTRL1				0x090
10262306a36Sopenharmony_ci#define SUN8I_AIF2_VOL_CTRL1_ADCL_VOL			8
10362306a36Sopenharmony_ci#define SUN8I_AIF2_VOL_CTRL1_ADCR_VOL			0
10462306a36Sopenharmony_ci#define SUN8I_AIF2_VOL_CTRL2				0x098
10562306a36Sopenharmony_ci#define SUN8I_AIF2_VOL_CTRL2_DACL_VOL			8
10662306a36Sopenharmony_ci#define SUN8I_AIF2_VOL_CTRL2_DACR_VOL			0
10762306a36Sopenharmony_ci#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1		(0x0 << 0)
10862306a36Sopenharmony_ci#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2		(0x1 << 0)
10962306a36Sopenharmony_ci#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1CLK	(0x2 << 0)
11062306a36Sopenharmony_ci#define SUN8I_AIF3_PATH_CTRL				0x0cc
11162306a36Sopenharmony_ci#define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC		10
11262306a36Sopenharmony_ci#define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC		8
11362306a36Sopenharmony_ci#define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI		7
11462306a36Sopenharmony_ci#define SUN8I_ADC_DIG_CTRL				0x100
11562306a36Sopenharmony_ci#define SUN8I_ADC_DIG_CTRL_ENAD				15
11662306a36Sopenharmony_ci#define SUN8I_ADC_DIG_CTRL_ADOUT_DTS			2
11762306a36Sopenharmony_ci#define SUN8I_ADC_DIG_CTRL_ADOUT_DLY			1
11862306a36Sopenharmony_ci#define SUN8I_ADC_VOL_CTRL				0x104
11962306a36Sopenharmony_ci#define SUN8I_ADC_VOL_CTRL_ADCL_VOL			8
12062306a36Sopenharmony_ci#define SUN8I_ADC_VOL_CTRL_ADCR_VOL			0
12162306a36Sopenharmony_ci#define SUN8I_DAC_DIG_CTRL				0x120
12262306a36Sopenharmony_ci#define SUN8I_DAC_DIG_CTRL_ENDA				15
12362306a36Sopenharmony_ci#define SUN8I_DAC_VOL_CTRL				0x124
12462306a36Sopenharmony_ci#define SUN8I_DAC_VOL_CTRL_DACL_VOL			8
12562306a36Sopenharmony_ci#define SUN8I_DAC_VOL_CTRL_DACR_VOL			0
12662306a36Sopenharmony_ci#define SUN8I_DAC_MXR_SRC				0x130
12762306a36Sopenharmony_ci#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L		15
12862306a36Sopenharmony_ci#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L		14
12962306a36Sopenharmony_ci#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL		13
13062306a36Sopenharmony_ci#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL		12
13162306a36Sopenharmony_ci#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R		11
13262306a36Sopenharmony_ci#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R		10
13362306a36Sopenharmony_ci#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR		9
13462306a36Sopenharmony_ci#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR		8
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK	GENMASK(9, 8)
13762306a36Sopenharmony_ci#define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK	GENMASK(5, 4)
13862306a36Sopenharmony_ci#define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK		GENMASK(15, 12)
13962306a36Sopenharmony_ci#define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK		GENMASK(11, 8)
14062306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
14162306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
14262306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
14362306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
14462306a36Sopenharmony_ci#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
14562306a36Sopenharmony_ci#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK	GENMASK(1, 0)
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
15062306a36Sopenharmony_ci				 SNDRV_PCM_FMTBIT_S16_LE |\
15162306a36Sopenharmony_ci				 SNDRV_PCM_FMTBIT_S20_LE |\
15262306a36Sopenharmony_ci				 SNDRV_PCM_FMTBIT_S24_LE |\
15362306a36Sopenharmony_ci				 SNDRV_PCM_FMTBIT_S20_3LE|\
15462306a36Sopenharmony_ci				 SNDRV_PCM_FMTBIT_S24_3LE)
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
15762306a36Sopenharmony_ci				 SNDRV_PCM_RATE_88200     |\
15862306a36Sopenharmony_ci				 SNDRV_PCM_RATE_96000     |\
15962306a36Sopenharmony_ci				 SNDRV_PCM_RATE_176400    |\
16062306a36Sopenharmony_ci				 SNDRV_PCM_RATE_192000    |\
16162306a36Sopenharmony_ci				 SNDRV_PCM_RATE_KNOT)
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cienum {
16462306a36Sopenharmony_ci	SUN8I_CODEC_AIF1,
16562306a36Sopenharmony_ci	SUN8I_CODEC_AIF2,
16662306a36Sopenharmony_ci	SUN8I_CODEC_AIF3,
16762306a36Sopenharmony_ci	SUN8I_CODEC_NAIFS
16862306a36Sopenharmony_ci};
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistruct sun8i_codec_aif {
17162306a36Sopenharmony_ci	unsigned int	lrck_div_order;
17262306a36Sopenharmony_ci	unsigned int	sample_rate;
17362306a36Sopenharmony_ci	unsigned int	slots;
17462306a36Sopenharmony_ci	unsigned int	slot_width;
17562306a36Sopenharmony_ci	unsigned int	active_streams	: 2;
17662306a36Sopenharmony_ci	unsigned int	open_streams	: 2;
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistruct sun8i_codec_quirks {
18062306a36Sopenharmony_ci	bool legacy_widgets	: 1;
18162306a36Sopenharmony_ci	bool lrck_inversion	: 1;
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistruct sun8i_codec {
18562306a36Sopenharmony_ci	struct regmap			*regmap;
18662306a36Sopenharmony_ci	struct clk			*clk_module;
18762306a36Sopenharmony_ci	const struct sun8i_codec_quirks	*quirks;
18862306a36Sopenharmony_ci	struct sun8i_codec_aif		aifs[SUN8I_CODEC_NAIFS];
18962306a36Sopenharmony_ci	unsigned int			sysclk_rate;
19062306a36Sopenharmony_ci	int				sysclk_refcnt;
19162306a36Sopenharmony_ci};
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic struct snd_soc_dai_driver sun8i_codec_dais[];
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int sun8i_codec_runtime_resume(struct device *dev)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct sun8i_codec *scodec = dev_get_drvdata(dev);
19862306a36Sopenharmony_ci	int ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	regcache_cache_only(scodec->regmap, false);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	ret = regcache_sync(scodec->regmap);
20362306a36Sopenharmony_ci	if (ret) {
20462306a36Sopenharmony_ci		dev_err(dev, "Failed to sync regmap cache\n");
20562306a36Sopenharmony_ci		return ret;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	return 0;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic int sun8i_codec_runtime_suspend(struct device *dev)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct sun8i_codec *scodec = dev_get_drvdata(dev);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	regcache_cache_only(scodec->regmap, true);
21662306a36Sopenharmony_ci	regcache_mark_dirty(scodec->regmap);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int sun8i_codec_get_hw_rate(unsigned int sample_rate)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	switch (sample_rate) {
22462306a36Sopenharmony_ci	case 7350:
22562306a36Sopenharmony_ci	case 8000:
22662306a36Sopenharmony_ci		return 0x0;
22762306a36Sopenharmony_ci	case 11025:
22862306a36Sopenharmony_ci		return 0x1;
22962306a36Sopenharmony_ci	case 12000:
23062306a36Sopenharmony_ci		return 0x2;
23162306a36Sopenharmony_ci	case 14700:
23262306a36Sopenharmony_ci	case 16000:
23362306a36Sopenharmony_ci		return 0x3;
23462306a36Sopenharmony_ci	case 22050:
23562306a36Sopenharmony_ci		return 0x4;
23662306a36Sopenharmony_ci	case 24000:
23762306a36Sopenharmony_ci		return 0x5;
23862306a36Sopenharmony_ci	case 29400:
23962306a36Sopenharmony_ci	case 32000:
24062306a36Sopenharmony_ci		return 0x6;
24162306a36Sopenharmony_ci	case 44100:
24262306a36Sopenharmony_ci		return 0x7;
24362306a36Sopenharmony_ci	case 48000:
24462306a36Sopenharmony_ci		return 0x8;
24562306a36Sopenharmony_ci	case 88200:
24662306a36Sopenharmony_ci	case 96000:
24762306a36Sopenharmony_ci		return 0x9;
24862306a36Sopenharmony_ci	case 176400:
24962306a36Sopenharmony_ci	case 192000:
25062306a36Sopenharmony_ci		return 0xa;
25162306a36Sopenharmony_ci	default:
25262306a36Sopenharmony_ci		return -EINVAL;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	unsigned int max_rate = 0;
25962306a36Sopenharmony_ci	int hw_rate, i;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	for (i = SUN8I_CODEC_AIF1; i < SUN8I_CODEC_NAIFS; ++i) {
26262306a36Sopenharmony_ci		struct sun8i_codec_aif *aif = &scodec->aifs[i];
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		if (aif->active_streams)
26562306a36Sopenharmony_ci			max_rate = max(max_rate, aif->sample_rate);
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
26962306a36Sopenharmony_ci	if (!max_rate)
27062306a36Sopenharmony_ci		max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	hw_rate = sun8i_codec_get_hw_rate(max_rate);
27362306a36Sopenharmony_ci	if (hw_rate < 0)
27462306a36Sopenharmony_ci		return hw_rate;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
27762306a36Sopenharmony_ci			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
27862306a36Sopenharmony_ci			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	return 0;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
28662306a36Sopenharmony_ci	u32 dsp_format, format, invert, value;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* clock masters */
28962306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
29062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBC_CFC: /* Codec slave, DAI master */
29162306a36Sopenharmony_ci		value = 0x1;
29262306a36Sopenharmony_ci		break;
29362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBP_CFP: /* Codec Master, DAI slave */
29462306a36Sopenharmony_ci		value = 0x0;
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	default:
29762306a36Sopenharmony_ci		return -EINVAL;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (dai->id == SUN8I_CODEC_AIF3) {
30162306a36Sopenharmony_ci		/* AIF3 only supports master mode. */
30262306a36Sopenharmony_ci		if (value)
30362306a36Sopenharmony_ci			return -EINVAL;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		/* Use the AIF2 BCLK and LRCK for AIF3. */
30662306a36Sopenharmony_ci		regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
30762306a36Sopenharmony_ci				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
30862306a36Sopenharmony_ci				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
30962306a36Sopenharmony_ci	} else {
31062306a36Sopenharmony_ci		regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
31162306a36Sopenharmony_ci				   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
31262306a36Sopenharmony_ci				   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* DAI format */
31662306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
31762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
31862306a36Sopenharmony_ci		format = 0x0;
31962306a36Sopenharmony_ci		break;
32062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
32162306a36Sopenharmony_ci		format = 0x1;
32262306a36Sopenharmony_ci		break;
32362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
32462306a36Sopenharmony_ci		format = 0x2;
32562306a36Sopenharmony_ci		break;
32662306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A:
32762306a36Sopenharmony_ci		format = 0x3;
32862306a36Sopenharmony_ci		dsp_format = 0x0; /* Set LRCK_INV to 0 */
32962306a36Sopenharmony_ci		break;
33062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_B:
33162306a36Sopenharmony_ci		format = 0x3;
33262306a36Sopenharmony_ci		dsp_format = 0x1; /* Set LRCK_INV to 1 */
33362306a36Sopenharmony_ci		break;
33462306a36Sopenharmony_ci	default:
33562306a36Sopenharmony_ci		return -EINVAL;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (dai->id == SUN8I_CODEC_AIF3) {
33962306a36Sopenharmony_ci		/* AIF3 only supports DSP mode. */
34062306a36Sopenharmony_ci		if (format != 3)
34162306a36Sopenharmony_ci			return -EINVAL;
34262306a36Sopenharmony_ci	} else {
34362306a36Sopenharmony_ci		regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
34462306a36Sopenharmony_ci				   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
34562306a36Sopenharmony_ci				   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* clock inversion */
34962306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
35062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_NB_NF: /* Normal */
35162306a36Sopenharmony_ci		invert = 0x0;
35262306a36Sopenharmony_ci		break;
35362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
35462306a36Sopenharmony_ci		invert = 0x1;
35562306a36Sopenharmony_ci		break;
35662306a36Sopenharmony_ci	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
35762306a36Sopenharmony_ci		invert = 0x2;
35862306a36Sopenharmony_ci		break;
35962306a36Sopenharmony_ci	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
36062306a36Sopenharmony_ci		invert = 0x3;
36162306a36Sopenharmony_ci		break;
36262306a36Sopenharmony_ci	default:
36362306a36Sopenharmony_ci		return -EINVAL;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (format == 0x3) {
36762306a36Sopenharmony_ci		/* Inverted LRCK is not available in DSP mode. */
36862306a36Sopenharmony_ci		if (invert & BIT(0))
36962306a36Sopenharmony_ci			return -EINVAL;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		/* Instead, the bit selects between DSP A/B formats. */
37262306a36Sopenharmony_ci		invert |= dsp_format;
37362306a36Sopenharmony_ci	} else {
37462306a36Sopenharmony_ci		/*
37562306a36Sopenharmony_ci		 * It appears that the DAI and the codec in the A33 SoC don't
37662306a36Sopenharmony_ci		 * share the same polarity for the LRCK signal when they mean
37762306a36Sopenharmony_ci		 * 'normal' and 'inverted' in the datasheet.
37862306a36Sopenharmony_ci		 *
37962306a36Sopenharmony_ci		 * Since the DAI here is our regular i2s driver that have been
38062306a36Sopenharmony_ci		 * tested with way more codecs than just this one, it means
38162306a36Sopenharmony_ci		 * that the codec probably gets it backward, and we have to
38262306a36Sopenharmony_ci		 * invert the value here.
38362306a36Sopenharmony_ci		 */
38462306a36Sopenharmony_ci		invert ^= scodec->quirks->lrck_inversion;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
38862306a36Sopenharmony_ci			   SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
38962306a36Sopenharmony_ci			   invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return 0;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
39562306a36Sopenharmony_ci				    unsigned int tx_mask, unsigned int rx_mask,
39662306a36Sopenharmony_ci				    int slots, int slot_width)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
39962306a36Sopenharmony_ci	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	if (slot_width && !is_power_of_2(slot_width))
40262306a36Sopenharmony_ci		return -EINVAL;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	aif->slots = slots;
40562306a36Sopenharmony_ci	aif->slot_width = slot_width;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	return 0;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic const unsigned int sun8i_codec_rates[] = {
41162306a36Sopenharmony_ci	  7350,   8000,  11025,  12000,  14700,  16000,  22050,  24000,
41262306a36Sopenharmony_ci	 29400,  32000,  44100,  48000,  88200,  96000, 176400, 192000,
41362306a36Sopenharmony_ci};
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
41662306a36Sopenharmony_ci	.list	= sun8i_codec_rates,
41762306a36Sopenharmony_ci	.count	= ARRAY_SIZE(sun8i_codec_rates),
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
42162306a36Sopenharmony_ci	.list	= sun8i_codec_rates,
42262306a36Sopenharmony_ci	.count	= ARRAY_SIZE(sun8i_codec_rates),
42362306a36Sopenharmony_ci	.mask	= 0x5555,
42462306a36Sopenharmony_ci};
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
42762306a36Sopenharmony_ci	.list	= sun8i_codec_rates,
42862306a36Sopenharmony_ci	.count	= ARRAY_SIZE(sun8i_codec_rates),
42962306a36Sopenharmony_ci	.mask	= 0xaaaa,
43062306a36Sopenharmony_ci};
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int sun8i_codec_startup(struct snd_pcm_substream *substream,
43362306a36Sopenharmony_ci			       struct snd_soc_dai *dai)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
43662306a36Sopenharmony_ci	const struct snd_pcm_hw_constraint_list *list;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* hw_constraints is not relevant for codec2codec DAIs. */
43962306a36Sopenharmony_ci	if (dai->id != SUN8I_CODEC_AIF1)
44062306a36Sopenharmony_ci		return 0;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (!scodec->sysclk_refcnt)
44362306a36Sopenharmony_ci		list = &sun8i_codec_all_rates;
44462306a36Sopenharmony_ci	else if (scodec->sysclk_rate == 22579200)
44562306a36Sopenharmony_ci		list = &sun8i_codec_22M_rates;
44662306a36Sopenharmony_ci	else if (scodec->sysclk_rate == 24576000)
44762306a36Sopenharmony_ci		list = &sun8i_codec_24M_rates;
44862306a36Sopenharmony_ci	else
44962306a36Sopenharmony_ci		return -EINVAL;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	return snd_pcm_hw_constraint_list(substream->runtime, 0,
45262306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_RATE, list);
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistruct sun8i_codec_clk_div {
45662306a36Sopenharmony_ci	u8	div;
45762306a36Sopenharmony_ci	u8	val;
45862306a36Sopenharmony_ci};
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
46162306a36Sopenharmony_ci	{ .div = 1,	.val = 0 },
46262306a36Sopenharmony_ci	{ .div = 2,	.val = 1 },
46362306a36Sopenharmony_ci	{ .div = 4,	.val = 2 },
46462306a36Sopenharmony_ci	{ .div = 6,	.val = 3 },
46562306a36Sopenharmony_ci	{ .div = 8,	.val = 4 },
46662306a36Sopenharmony_ci	{ .div = 12,	.val = 5 },
46762306a36Sopenharmony_ci	{ .div = 16,	.val = 6 },
46862306a36Sopenharmony_ci	{ .div = 24,	.val = 7 },
46962306a36Sopenharmony_ci	{ .div = 32,	.val = 8 },
47062306a36Sopenharmony_ci	{ .div = 48,	.val = 9 },
47162306a36Sopenharmony_ci	{ .div = 64,	.val = 10 },
47262306a36Sopenharmony_ci	{ .div = 96,	.val = 11 },
47362306a36Sopenharmony_ci	{ .div = 128,	.val = 12 },
47462306a36Sopenharmony_ci	{ .div = 192,	.val = 13 },
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
47862306a36Sopenharmony_ci				    unsigned int lrck_div_order,
47962306a36Sopenharmony_ci				    unsigned int sample_rate)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
48262306a36Sopenharmony_ci	int i;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
48562306a36Sopenharmony_ci		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		if (bdiv->div == div)
48862306a36Sopenharmony_ci			return bdiv->val;
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	return -EINVAL;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic int sun8i_codec_get_lrck_div_order(unsigned int slots,
49562306a36Sopenharmony_ci					  unsigned int slot_width)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	unsigned int div = slots * slot_width;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (div < 16 || div > 256)
50062306a36Sopenharmony_ci		return -EINVAL;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	return order_base_2(div);
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	return (sample_rate % 4000) ? 22579200 : 24576000;
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
51162306a36Sopenharmony_ci				 struct snd_pcm_hw_params *params,
51262306a36Sopenharmony_ci				 struct snd_soc_dai *dai)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
51562306a36Sopenharmony_ci	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
51662306a36Sopenharmony_ci	unsigned int sample_rate = params_rate(params);
51762306a36Sopenharmony_ci	unsigned int slots = aif->slots ?: params_channels(params);
51862306a36Sopenharmony_ci	unsigned int slot_width = aif->slot_width ?: params_width(params);
51962306a36Sopenharmony_ci	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
52062306a36Sopenharmony_ci	int bclk_div, lrck_div_order, ret, word_size;
52162306a36Sopenharmony_ci	u32 clk_reg;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* word size */
52462306a36Sopenharmony_ci	switch (params_width(params)) {
52562306a36Sopenharmony_ci	case 8:
52662306a36Sopenharmony_ci		word_size = 0x0;
52762306a36Sopenharmony_ci		break;
52862306a36Sopenharmony_ci	case 16:
52962306a36Sopenharmony_ci		word_size = 0x1;
53062306a36Sopenharmony_ci		break;
53162306a36Sopenharmony_ci	case 20:
53262306a36Sopenharmony_ci		word_size = 0x2;
53362306a36Sopenharmony_ci		break;
53462306a36Sopenharmony_ci	case 24:
53562306a36Sopenharmony_ci		word_size = 0x3;
53662306a36Sopenharmony_ci		break;
53762306a36Sopenharmony_ci	default:
53862306a36Sopenharmony_ci		return -EINVAL;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
54262306a36Sopenharmony_ci			   SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
54362306a36Sopenharmony_ci			   word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	/* LRCK divider (BCLK/LRCK ratio) */
54662306a36Sopenharmony_ci	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
54762306a36Sopenharmony_ci	if (lrck_div_order < 0)
54862306a36Sopenharmony_ci		return lrck_div_order;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (dai->id == SUN8I_CODEC_AIF2 || dai->id == SUN8I_CODEC_AIF3) {
55162306a36Sopenharmony_ci		/* AIF2 and AIF3 share AIF2's BCLK and LRCK generation circuitry. */
55262306a36Sopenharmony_ci		int partner = (SUN8I_CODEC_AIF2 + SUN8I_CODEC_AIF3) - dai->id;
55362306a36Sopenharmony_ci		const struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner];
55462306a36Sopenharmony_ci		const char *partner_name = sun8i_codec_dais[partner].name;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		if (partner_aif->open_streams &&
55762306a36Sopenharmony_ci		    (lrck_div_order != partner_aif->lrck_div_order ||
55862306a36Sopenharmony_ci		     sample_rate != partner_aif->sample_rate)) {
55962306a36Sopenharmony_ci			dev_err(dai->dev,
56062306a36Sopenharmony_ci				"%s sample and bit rates must match %s when both are used\n",
56162306a36Sopenharmony_ci				dai->name, partner_name);
56262306a36Sopenharmony_ci			return -EBUSY;
56362306a36Sopenharmony_ci		}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		clk_reg = SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF2);
56662306a36Sopenharmony_ci	} else {
56762306a36Sopenharmony_ci		clk_reg = SUN8I_AIF_CLK_CTRL(dai->id);
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	regmap_update_bits(scodec->regmap, clk_reg,
57162306a36Sopenharmony_ci			   SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
57262306a36Sopenharmony_ci			   (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/* BCLK divider (SYSCLK/BCLK ratio) */
57562306a36Sopenharmony_ci	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
57662306a36Sopenharmony_ci	if (bclk_div < 0)
57762306a36Sopenharmony_ci		return bclk_div;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	regmap_update_bits(scodec->regmap, clk_reg,
58062306a36Sopenharmony_ci			   SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
58162306a36Sopenharmony_ci			   bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	/*
58462306a36Sopenharmony_ci	 * SYSCLK rate
58562306a36Sopenharmony_ci	 *
58662306a36Sopenharmony_ci	 * Clock rate protection is reference counted; but hw_params may be
58762306a36Sopenharmony_ci	 * called many times per substream, without matching calls to hw_free.
58862306a36Sopenharmony_ci	 * Protect the clock rate once per AIF, on the first hw_params call
58962306a36Sopenharmony_ci	 * for the first substream. clk_set_rate() will allow clock rate
59062306a36Sopenharmony_ci	 * changes on subsequent calls if only one AIF has open streams.
59162306a36Sopenharmony_ci	 */
59262306a36Sopenharmony_ci	ret = (aif->open_streams ? clk_set_rate : clk_set_rate_exclusive)(scodec->clk_module,
59362306a36Sopenharmony_ci									  sysclk_rate);
59462306a36Sopenharmony_ci	if (ret == -EBUSY)
59562306a36Sopenharmony_ci		dev_err(dai->dev,
59662306a36Sopenharmony_ci			"%s sample rate (%u Hz) conflicts with other audio streams\n",
59762306a36Sopenharmony_ci			dai->name, sample_rate);
59862306a36Sopenharmony_ci	if (ret < 0)
59962306a36Sopenharmony_ci		return ret;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (!aif->open_streams)
60262306a36Sopenharmony_ci		scodec->sysclk_refcnt++;
60362306a36Sopenharmony_ci	scodec->sysclk_rate = sysclk_rate;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	aif->lrck_div_order = lrck_div_order;
60662306a36Sopenharmony_ci	aif->sample_rate = sample_rate;
60762306a36Sopenharmony_ci	aif->open_streams |= BIT(substream->stream);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	return sun8i_codec_update_sample_rate(scodec);
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
61362306a36Sopenharmony_ci			       struct snd_soc_dai *dai)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
61662306a36Sopenharmony_ci	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* Drop references when the last substream for the AIF is freed. */
61962306a36Sopenharmony_ci	if (aif->open_streams != BIT(substream->stream))
62062306a36Sopenharmony_ci		goto done;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	clk_rate_exclusive_put(scodec->clk_module);
62362306a36Sopenharmony_ci	scodec->sysclk_refcnt--;
62462306a36Sopenharmony_ci	aif->lrck_div_order = 0;
62562306a36Sopenharmony_ci	aif->sample_rate = 0;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cidone:
62862306a36Sopenharmony_ci	aif->open_streams &= ~BIT(substream->stream);
62962306a36Sopenharmony_ci	return 0;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
63362306a36Sopenharmony_ci	.set_fmt	= sun8i_codec_set_fmt,
63462306a36Sopenharmony_ci	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
63562306a36Sopenharmony_ci	.startup	= sun8i_codec_startup,
63662306a36Sopenharmony_ci	.hw_params	= sun8i_codec_hw_params,
63762306a36Sopenharmony_ci	.hw_free	= sun8i_codec_hw_free,
63862306a36Sopenharmony_ci};
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic struct snd_soc_dai_driver sun8i_codec_dais[] = {
64162306a36Sopenharmony_ci	{
64262306a36Sopenharmony_ci		.name	= "sun8i-codec-aif1",
64362306a36Sopenharmony_ci		.id	= SUN8I_CODEC_AIF1,
64462306a36Sopenharmony_ci		.ops	= &sun8i_codec_dai_ops,
64562306a36Sopenharmony_ci		/* capture capabilities */
64662306a36Sopenharmony_ci		.capture = {
64762306a36Sopenharmony_ci			.stream_name	= "AIF1 Capture",
64862306a36Sopenharmony_ci			.channels_min	= 1,
64962306a36Sopenharmony_ci			.channels_max	= 2,
65062306a36Sopenharmony_ci			.rates		= SUN8I_CODEC_PCM_RATES,
65162306a36Sopenharmony_ci			.formats	= SUN8I_CODEC_PCM_FORMATS,
65262306a36Sopenharmony_ci			.sig_bits	= 24,
65362306a36Sopenharmony_ci		},
65462306a36Sopenharmony_ci		/* playback capabilities */
65562306a36Sopenharmony_ci		.playback = {
65662306a36Sopenharmony_ci			.stream_name	= "AIF1 Playback",
65762306a36Sopenharmony_ci			.channels_min	= 1,
65862306a36Sopenharmony_ci			.channels_max	= 2,
65962306a36Sopenharmony_ci			.rates		= SUN8I_CODEC_PCM_RATES,
66062306a36Sopenharmony_ci			.formats	= SUN8I_CODEC_PCM_FORMATS,
66162306a36Sopenharmony_ci		},
66262306a36Sopenharmony_ci		.symmetric_rate		= true,
66362306a36Sopenharmony_ci		.symmetric_channels	= true,
66462306a36Sopenharmony_ci		.symmetric_sample_bits	= true,
66562306a36Sopenharmony_ci	},
66662306a36Sopenharmony_ci	{
66762306a36Sopenharmony_ci		.name	= "sun8i-codec-aif2",
66862306a36Sopenharmony_ci		.id	= SUN8I_CODEC_AIF2,
66962306a36Sopenharmony_ci		.ops	= &sun8i_codec_dai_ops,
67062306a36Sopenharmony_ci		/* capture capabilities */
67162306a36Sopenharmony_ci		.capture = {
67262306a36Sopenharmony_ci			.stream_name	= "AIF2 Capture",
67362306a36Sopenharmony_ci			.channels_min	= 1,
67462306a36Sopenharmony_ci			.channels_max	= 2,
67562306a36Sopenharmony_ci			.rates		= SUN8I_CODEC_PCM_RATES,
67662306a36Sopenharmony_ci			.formats	= SUN8I_CODEC_PCM_FORMATS,
67762306a36Sopenharmony_ci			.sig_bits	= 24,
67862306a36Sopenharmony_ci		},
67962306a36Sopenharmony_ci		/* playback capabilities */
68062306a36Sopenharmony_ci		.playback = {
68162306a36Sopenharmony_ci			.stream_name	= "AIF2 Playback",
68262306a36Sopenharmony_ci			.channels_min	= 1,
68362306a36Sopenharmony_ci			.channels_max	= 2,
68462306a36Sopenharmony_ci			.rates		= SUN8I_CODEC_PCM_RATES,
68562306a36Sopenharmony_ci			.formats	= SUN8I_CODEC_PCM_FORMATS,
68662306a36Sopenharmony_ci		},
68762306a36Sopenharmony_ci		.symmetric_rate		= true,
68862306a36Sopenharmony_ci		.symmetric_channels	= true,
68962306a36Sopenharmony_ci		.symmetric_sample_bits	= true,
69062306a36Sopenharmony_ci	},
69162306a36Sopenharmony_ci	{
69262306a36Sopenharmony_ci		.name	= "sun8i-codec-aif3",
69362306a36Sopenharmony_ci		.id	= SUN8I_CODEC_AIF3,
69462306a36Sopenharmony_ci		.ops	= &sun8i_codec_dai_ops,
69562306a36Sopenharmony_ci		/* capture capabilities */
69662306a36Sopenharmony_ci		.capture = {
69762306a36Sopenharmony_ci			.stream_name	= "AIF3 Capture",
69862306a36Sopenharmony_ci			.channels_min	= 1,
69962306a36Sopenharmony_ci			.channels_max	= 1,
70062306a36Sopenharmony_ci			.rates		= SUN8I_CODEC_PCM_RATES,
70162306a36Sopenharmony_ci			.formats	= SUN8I_CODEC_PCM_FORMATS,
70262306a36Sopenharmony_ci			.sig_bits	= 24,
70362306a36Sopenharmony_ci		},
70462306a36Sopenharmony_ci		/* playback capabilities */
70562306a36Sopenharmony_ci		.playback = {
70662306a36Sopenharmony_ci			.stream_name	= "AIF3 Playback",
70762306a36Sopenharmony_ci			.channels_min	= 1,
70862306a36Sopenharmony_ci			.channels_max	= 1,
70962306a36Sopenharmony_ci			.rates		= SUN8I_CODEC_PCM_RATES,
71062306a36Sopenharmony_ci			.formats	= SUN8I_CODEC_PCM_FORMATS,
71162306a36Sopenharmony_ci		},
71262306a36Sopenharmony_ci		.symmetric_rate		= true,
71362306a36Sopenharmony_ci		.symmetric_channels	= true,
71462306a36Sopenharmony_ci		.symmetric_sample_bits	= true,
71562306a36Sopenharmony_ci	},
71662306a36Sopenharmony_ci};
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(sun8i_codec_vol_scale, -12000, 75, 1);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_controls[] = {
72162306a36Sopenharmony_ci	SOC_DOUBLE_TLV("AIF1 AD0 Capture Volume",
72262306a36Sopenharmony_ci		       SUN8I_AIF1_VOL_CTRL1,
72362306a36Sopenharmony_ci		       SUN8I_AIF1_VOL_CTRL1_AD0L_VOL,
72462306a36Sopenharmony_ci		       SUN8I_AIF1_VOL_CTRL1_AD0R_VOL,
72562306a36Sopenharmony_ci		       0xc0, 0, sun8i_codec_vol_scale),
72662306a36Sopenharmony_ci	SOC_DOUBLE_TLV("AIF1 DA0 Playback Volume",
72762306a36Sopenharmony_ci		       SUN8I_AIF1_VOL_CTRL3,
72862306a36Sopenharmony_ci		       SUN8I_AIF1_VOL_CTRL3_DA0L_VOL,
72962306a36Sopenharmony_ci		       SUN8I_AIF1_VOL_CTRL3_DA0R_VOL,
73062306a36Sopenharmony_ci		       0xc0, 0, sun8i_codec_vol_scale),
73162306a36Sopenharmony_ci	SOC_DOUBLE_TLV("AIF2 ADC Capture Volume",
73262306a36Sopenharmony_ci		       SUN8I_AIF2_VOL_CTRL1,
73362306a36Sopenharmony_ci		       SUN8I_AIF2_VOL_CTRL1_ADCL_VOL,
73462306a36Sopenharmony_ci		       SUN8I_AIF2_VOL_CTRL1_ADCR_VOL,
73562306a36Sopenharmony_ci		       0xc0, 0, sun8i_codec_vol_scale),
73662306a36Sopenharmony_ci	SOC_DOUBLE_TLV("AIF2 DAC Playback Volume",
73762306a36Sopenharmony_ci		       SUN8I_AIF2_VOL_CTRL2,
73862306a36Sopenharmony_ci		       SUN8I_AIF2_VOL_CTRL2_DACL_VOL,
73962306a36Sopenharmony_ci		       SUN8I_AIF2_VOL_CTRL2_DACR_VOL,
74062306a36Sopenharmony_ci		       0xc0, 0, sun8i_codec_vol_scale),
74162306a36Sopenharmony_ci	SOC_DOUBLE_TLV("ADC Capture Volume",
74262306a36Sopenharmony_ci		       SUN8I_ADC_VOL_CTRL,
74362306a36Sopenharmony_ci		       SUN8I_ADC_VOL_CTRL_ADCL_VOL,
74462306a36Sopenharmony_ci		       SUN8I_ADC_VOL_CTRL_ADCR_VOL,
74562306a36Sopenharmony_ci		       0xc0, 0, sun8i_codec_vol_scale),
74662306a36Sopenharmony_ci	SOC_DOUBLE_TLV("DAC Playback Volume",
74762306a36Sopenharmony_ci		       SUN8I_DAC_VOL_CTRL,
74862306a36Sopenharmony_ci		       SUN8I_DAC_VOL_CTRL_DACL_VOL,
74962306a36Sopenharmony_ci		       SUN8I_DAC_VOL_CTRL_DACR_VOL,
75062306a36Sopenharmony_ci		       0xc0, 0, sun8i_codec_vol_scale),
75162306a36Sopenharmony_ci};
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
75462306a36Sopenharmony_ci				 struct snd_kcontrol *kcontrol, int event)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
75762306a36Sopenharmony_ci	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
75862306a36Sopenharmony_ci	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
75962306a36Sopenharmony_ci	int stream = w->id == snd_soc_dapm_aif_out;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if (SND_SOC_DAPM_EVENT_ON(event))
76262306a36Sopenharmony_ci		aif->active_streams |= BIT(stream);
76362306a36Sopenharmony_ci	else
76462306a36Sopenharmony_ci		aif->active_streams &= ~BIT(stream);
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	return sun8i_codec_update_sample_rate(scodec);
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic const char *const sun8i_aif_stereo_mux_enum_values[] = {
77062306a36Sopenharmony_ci	"Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono"
77162306a36Sopenharmony_ci};
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
77462306a36Sopenharmony_ci			    SUN8I_AIF1_ADCDAT_CTRL,
77562306a36Sopenharmony_ci			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC,
77662306a36Sopenharmony_ci			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC,
77762306a36Sopenharmony_ci			    sun8i_aif_stereo_mux_enum_values);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control =
78062306a36Sopenharmony_ci	SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route",
78162306a36Sopenharmony_ci		      sun8i_aif1_ad0_stereo_mux_enum);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum,
78462306a36Sopenharmony_ci			    SUN8I_AIF2_ADCDAT_CTRL,
78562306a36Sopenharmony_ci			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC,
78662306a36Sopenharmony_ci			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC,
78762306a36Sopenharmony_ci			    sun8i_aif_stereo_mux_enum_values);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_aif2_adc_stereo_mux_control =
79062306a36Sopenharmony_ci	SOC_DAPM_ENUM("AIF2 ADC Stereo Capture Route",
79162306a36Sopenharmony_ci		      sun8i_aif2_adc_stereo_mux_enum);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic const char *const sun8i_aif3_adc_mux_enum_values[] = {
79462306a36Sopenharmony_ci	"None", "AIF2 ADCL", "AIF2 ADCR"
79562306a36Sopenharmony_ci};
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(sun8i_aif3_adc_mux_enum,
79862306a36Sopenharmony_ci			    SUN8I_AIF3_PATH_CTRL,
79962306a36Sopenharmony_ci			    SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC,
80062306a36Sopenharmony_ci			    sun8i_aif3_adc_mux_enum_values);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_aif3_adc_mux_control =
80362306a36Sopenharmony_ci	SOC_DAPM_ENUM("AIF3 ADC Source Capture Route",
80462306a36Sopenharmony_ci		      sun8i_aif3_adc_mux_enum);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
80762306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
80862306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC,
80962306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L,
81062306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
81162306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch",
81262306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC,
81362306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL,
81462306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
81562306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
81662306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC,
81762306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL,
81862306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
81962306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
82062306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC,
82162306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR,
82262306a36Sopenharmony_ci			SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
82362306a36Sopenharmony_ci};
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_aif2_adc_mixer_controls[] = {
82662306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch",
82762306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC,
82862306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L,
82962306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R, 1, 0),
83062306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch",
83162306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC,
83262306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L,
83362306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R, 1, 0),
83462306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch",
83562306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC,
83662306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR,
83762306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL, 1, 0),
83862306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch",
83962306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC,
84062306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL,
84162306a36Sopenharmony_ci			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR, 1, 0),
84262306a36Sopenharmony_ci};
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistatic const char *const sun8i_aif2_dac_mux_enum_values[] = {
84562306a36Sopenharmony_ci	"AIF2", "AIF3+2", "AIF2+3"
84662306a36Sopenharmony_ci};
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(sun8i_aif2_dac_mux_enum,
84962306a36Sopenharmony_ci			    SUN8I_AIF3_PATH_CTRL,
85062306a36Sopenharmony_ci			    SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC,
85162306a36Sopenharmony_ci			    sun8i_aif2_dac_mux_enum_values);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_aif2_dac_mux_control =
85462306a36Sopenharmony_ci	SOC_DAPM_ENUM("AIF2 DAC Source Playback Route",
85562306a36Sopenharmony_ci		      sun8i_aif2_dac_mux_enum);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum,
85862306a36Sopenharmony_ci			    SUN8I_AIF1_DACDAT_CTRL,
85962306a36Sopenharmony_ci			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC,
86062306a36Sopenharmony_ci			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC,
86162306a36Sopenharmony_ci			    sun8i_aif_stereo_mux_enum_values);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control =
86462306a36Sopenharmony_ci	SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route",
86562306a36Sopenharmony_ci		      sun8i_aif1_da0_stereo_mux_enum);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(sun8i_aif2_dac_stereo_mux_enum,
86862306a36Sopenharmony_ci			    SUN8I_AIF2_DACDAT_CTRL,
86962306a36Sopenharmony_ci			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC,
87062306a36Sopenharmony_ci			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC,
87162306a36Sopenharmony_ci			    sun8i_aif_stereo_mux_enum_values);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_aif2_dac_stereo_mux_control =
87462306a36Sopenharmony_ci	SOC_DAPM_ENUM("AIF2 DAC Stereo Playback Route",
87562306a36Sopenharmony_ci		      sun8i_aif2_dac_stereo_mux_enum);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
87862306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
87962306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC,
88062306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
88162306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
88262306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
88362306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC,
88462306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
88562306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0),
88662306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
88762306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
88862306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
88962306a36Sopenharmony_ci	SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
89062306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
89162306a36Sopenharmony_ci			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
89262306a36Sopenharmony_ci};
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
89562306a36Sopenharmony_ci	/* System Clocks */
89662306a36Sopenharmony_ci	SND_SOC_DAPM_CLOCK_SUPPLY("mod"),
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("AIF1CLK",
89962306a36Sopenharmony_ci			    SUN8I_SYSCLK_CTL,
90062306a36Sopenharmony_ci			    SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
90162306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("AIF2CLK",
90262306a36Sopenharmony_ci			    SUN8I_SYSCLK_CTL,
90362306a36Sopenharmony_ci			    SUN8I_SYSCLK_CTL_AIF2CLK_ENA, 0, NULL, 0),
90462306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("SYSCLK",
90562306a36Sopenharmony_ci			    SUN8I_SYSCLK_CTL,
90662306a36Sopenharmony_ci			    SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/* Module Clocks */
90962306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("CLK AIF1",
91062306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA,
91162306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
91262306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("CLK AIF2",
91362306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA,
91462306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0),
91562306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("CLK AIF3",
91662306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA,
91762306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA_AIF3, 0, NULL, 0),
91862306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("CLK ADC",
91962306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA,
92062306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
92162306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("CLK DAC",
92262306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA,
92362306a36Sopenharmony_ci			    SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	/* Module Resets */
92662306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("RST AIF1",
92762306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL,
92862306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
92962306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("RST AIF2",
93062306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL,
93162306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0),
93262306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("RST AIF3",
93362306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL,
93462306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL_AIF3, 0, NULL, 0),
93562306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("RST ADC",
93662306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL,
93762306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
93862306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("RST DAC",
93962306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL,
94062306a36Sopenharmony_ci			    SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	/* Module Supplies */
94362306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("ADC",
94462306a36Sopenharmony_ci			    SUN8I_ADC_DIG_CTRL,
94562306a36Sopenharmony_ci			    SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0),
94662306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("DAC",
94762306a36Sopenharmony_ci			    SUN8I_DAC_DIG_CTRL,
94862306a36Sopenharmony_ci			    SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0),
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	/* AIF "ADC" Outputs */
95162306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
95262306a36Sopenharmony_ci			       SUN8I_AIF1_ADCDAT_CTRL,
95362306a36Sopenharmony_ci			       SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
95462306a36Sopenharmony_ci			       sun8i_codec_aif_event,
95562306a36Sopenharmony_ci			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
95662306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
95762306a36Sopenharmony_ci			     SUN8I_AIF1_ADCDAT_CTRL,
95862306a36Sopenharmony_ci			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0,
96162306a36Sopenharmony_ci			       SUN8I_AIF2_ADCDAT_CTRL,
96262306a36Sopenharmony_ci			       SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
96362306a36Sopenharmony_ci			       sun8i_codec_aif_event,
96462306a36Sopenharmony_ci			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
96562306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
96662306a36Sopenharmony_ci			     SUN8I_AIF2_ADCDAT_CTRL,
96762306a36Sopenharmony_ci			     SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0),
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT_E("AIF3 ADC", "AIF3 Capture", 0,
97062306a36Sopenharmony_ci			       SND_SOC_NOPM, 0, 0,
97162306a36Sopenharmony_ci			       sun8i_codec_aif_event,
97262306a36Sopenharmony_ci			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	/* AIF "ADC" Mono/Stereo Muxes */
97562306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0,
97662306a36Sopenharmony_ci			 &sun8i_aif1_ad0_stereo_mux_control),
97762306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0,
97862306a36Sopenharmony_ci			 &sun8i_aif1_ad0_stereo_mux_control),
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
98162306a36Sopenharmony_ci			 &sun8i_aif2_adc_stereo_mux_control),
98262306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
98362306a36Sopenharmony_ci			 &sun8i_aif2_adc_stereo_mux_control),
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* AIF "ADC" Output Muxes */
98662306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF3 ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
98762306a36Sopenharmony_ci			 &sun8i_aif3_adc_mux_control),
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/* AIF "ADC" Mixers */
99062306a36Sopenharmony_ci	SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
99162306a36Sopenharmony_ci			sun8i_aif1_ad0_mixer_controls),
99262306a36Sopenharmony_ci	SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
99362306a36Sopenharmony_ci			sun8i_aif1_ad0_mixer_controls),
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
99662306a36Sopenharmony_ci			sun8i_aif2_adc_mixer_controls),
99762306a36Sopenharmony_ci	SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0,
99862306a36Sopenharmony_ci			sun8i_aif2_adc_mixer_controls),
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	/* AIF "DAC" Input Muxes */
100162306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0,
100262306a36Sopenharmony_ci			 &sun8i_aif2_dac_mux_control),
100362306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0,
100462306a36Sopenharmony_ci			 &sun8i_aif2_dac_mux_control),
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	/* AIF "DAC" Mono/Stereo Muxes */
100762306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0,
100862306a36Sopenharmony_ci			 &sun8i_aif1_da0_stereo_mux_control),
100962306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0,
101062306a36Sopenharmony_ci			 &sun8i_aif1_da0_stereo_mux_control),
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0,
101362306a36Sopenharmony_ci			 &sun8i_aif2_dac_stereo_mux_control),
101462306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0,
101562306a36Sopenharmony_ci			 &sun8i_aif2_dac_stereo_mux_control),
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	/* AIF "DAC" Inputs */
101862306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
101962306a36Sopenharmony_ci			      SUN8I_AIF1_DACDAT_CTRL,
102062306a36Sopenharmony_ci			      SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
102162306a36Sopenharmony_ci			      sun8i_codec_aif_event,
102262306a36Sopenharmony_ci			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
102362306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
102462306a36Sopenharmony_ci			    SUN8I_AIF1_DACDAT_CTRL,
102562306a36Sopenharmony_ci			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0,
102862306a36Sopenharmony_ci			      SUN8I_AIF2_DACDAT_CTRL,
102962306a36Sopenharmony_ci			      SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
103062306a36Sopenharmony_ci			      sun8i_codec_aif_event,
103162306a36Sopenharmony_ci			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
103262306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
103362306a36Sopenharmony_ci			    SUN8I_AIF2_DACDAT_CTRL,
103462306a36Sopenharmony_ci			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0),
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_IN_E("AIF3 DAC", "AIF3 Playback", 0,
103762306a36Sopenharmony_ci			      SND_SOC_NOPM, 0, 0,
103862306a36Sopenharmony_ci			      sun8i_codec_aif_event,
103962306a36Sopenharmony_ci			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	/* ADC Inputs (connected to analog codec DAPM context) */
104262306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
104362306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	/* DAC Outputs (connected to analog codec DAPM context) */
104662306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
104762306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	/* DAC Mixers */
105062306a36Sopenharmony_ci	SOC_MIXER_ARRAY("DACL Mixer", SND_SOC_NOPM, 0, 0,
105162306a36Sopenharmony_ci			sun8i_dac_mixer_controls),
105262306a36Sopenharmony_ci	SOC_MIXER_ARRAY("DACR Mixer", SND_SOC_NOPM, 0, 0,
105362306a36Sopenharmony_ci			sun8i_dac_mixer_controls),
105462306a36Sopenharmony_ci};
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_cistatic const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
105762306a36Sopenharmony_ci	/* Clock Routes */
105862306a36Sopenharmony_ci	{ "AIF1CLK", NULL, "mod" },
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	{ "SYSCLK", NULL, "AIF1CLK" },
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	{ "CLK AIF1", NULL, "AIF1CLK" },
106362306a36Sopenharmony_ci	{ "CLK AIF1", NULL, "SYSCLK" },
106462306a36Sopenharmony_ci	{ "RST AIF1", NULL, "CLK AIF1" },
106562306a36Sopenharmony_ci	{ "AIF1 AD0L", NULL, "RST AIF1" },
106662306a36Sopenharmony_ci	{ "AIF1 AD0R", NULL, "RST AIF1" },
106762306a36Sopenharmony_ci	{ "AIF1 DA0L", NULL, "RST AIF1" },
106862306a36Sopenharmony_ci	{ "AIF1 DA0R", NULL, "RST AIF1" },
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	{ "CLK AIF2", NULL, "AIF2CLK" },
107162306a36Sopenharmony_ci	{ "CLK AIF2", NULL, "SYSCLK" },
107262306a36Sopenharmony_ci	{ "RST AIF2", NULL, "CLK AIF2" },
107362306a36Sopenharmony_ci	{ "AIF2 ADCL", NULL, "RST AIF2" },
107462306a36Sopenharmony_ci	{ "AIF2 ADCR", NULL, "RST AIF2" },
107562306a36Sopenharmony_ci	{ "AIF2 DACL", NULL, "RST AIF2" },
107662306a36Sopenharmony_ci	{ "AIF2 DACR", NULL, "RST AIF2" },
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	{ "CLK AIF3", NULL, "AIF1CLK" },
107962306a36Sopenharmony_ci	{ "CLK AIF3", NULL, "SYSCLK" },
108062306a36Sopenharmony_ci	{ "RST AIF3", NULL, "CLK AIF3" },
108162306a36Sopenharmony_ci	{ "AIF3 ADC", NULL, "RST AIF3" },
108262306a36Sopenharmony_ci	{ "AIF3 DAC", NULL, "RST AIF3" },
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	{ "CLK ADC", NULL, "SYSCLK" },
108562306a36Sopenharmony_ci	{ "RST ADC", NULL, "CLK ADC" },
108662306a36Sopenharmony_ci	{ "ADC", NULL, "RST ADC" },
108762306a36Sopenharmony_ci	{ "ADCL", NULL, "ADC" },
108862306a36Sopenharmony_ci	{ "ADCR", NULL, "ADC" },
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	{ "CLK DAC", NULL, "SYSCLK" },
109162306a36Sopenharmony_ci	{ "RST DAC", NULL, "CLK DAC" },
109262306a36Sopenharmony_ci	{ "DAC", NULL, "RST DAC" },
109362306a36Sopenharmony_ci	{ "DACL", NULL, "DAC" },
109462306a36Sopenharmony_ci	{ "DACR", NULL, "DAC" },
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	/* AIF "ADC" Output Routes */
109762306a36Sopenharmony_ci	{ "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
109862306a36Sopenharmony_ci	{ "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	{ "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
110162306a36Sopenharmony_ci	{ "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" },
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	{ "AIF3 ADC", NULL, "AIF3 ADC Source Capture Route" },
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	/* AIF "ADC" Mono/Stereo Mux Routes */
110662306a36Sopenharmony_ci	{ "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" },
110762306a36Sopenharmony_ci	{ "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" },
110862306a36Sopenharmony_ci	{ "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
110962306a36Sopenharmony_ci	{ "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
111062306a36Sopenharmony_ci	{ "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
111162306a36Sopenharmony_ci	{ "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	{ "AIF1 AD0R Stereo Mux", "Stereo", "AIF1 AD0R Mixer" },
111462306a36Sopenharmony_ci	{ "AIF1 AD0R Stereo Mux", "Reverse Stereo", "AIF1 AD0L Mixer" },
111562306a36Sopenharmony_ci	{ "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
111662306a36Sopenharmony_ci	{ "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
111762306a36Sopenharmony_ci	{ "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
111862306a36Sopenharmony_ci	{ "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	{ "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" },
112162306a36Sopenharmony_ci	{ "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" },
112262306a36Sopenharmony_ci	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
112362306a36Sopenharmony_ci	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
112462306a36Sopenharmony_ci	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
112562306a36Sopenharmony_ci	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	{ "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
112862306a36Sopenharmony_ci	{ "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
112962306a36Sopenharmony_ci	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
113062306a36Sopenharmony_ci	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
113162306a36Sopenharmony_ci	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
113262306a36Sopenharmony_ci	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	/* AIF "ADC" Output Mux Routes */
113562306a36Sopenharmony_ci	{ "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" },
113662306a36Sopenharmony_ci	{ "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" },
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	/* AIF "ADC" Mixer Routes */
113962306a36Sopenharmony_ci	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
114062306a36Sopenharmony_ci	{ "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
114162306a36Sopenharmony_ci	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
114262306a36Sopenharmony_ci	{ "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
114562306a36Sopenharmony_ci	{ "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
114662306a36Sopenharmony_ci	{ "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
114762306a36Sopenharmony_ci	{ "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" },
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" },
115062306a36Sopenharmony_ci	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" },
115162306a36Sopenharmony_ci	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
115462306a36Sopenharmony_ci	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
115562306a36Sopenharmony_ci	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	/* AIF "DAC" Input Mux Routes */
115862306a36Sopenharmony_ci	{ "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
115962306a36Sopenharmony_ci	{ "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" },
116062306a36Sopenharmony_ci	{ "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	{ "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
116362306a36Sopenharmony_ci	{ "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
116462306a36Sopenharmony_ci	{ "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" },
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	/* AIF "DAC" Mono/Stereo Mux Routes */
116762306a36Sopenharmony_ci	{ "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" },
116862306a36Sopenharmony_ci	{ "AIF1 DA0L Stereo Mux", "Reverse Stereo", "AIF1 DA0R" },
116962306a36Sopenharmony_ci	{ "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0L" },
117062306a36Sopenharmony_ci	{ "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0R" },
117162306a36Sopenharmony_ci	{ "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0L" },
117262306a36Sopenharmony_ci	{ "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0R" },
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	{ "AIF1 DA0R Stereo Mux", "Stereo", "AIF1 DA0R" },
117562306a36Sopenharmony_ci	{ "AIF1 DA0R Stereo Mux", "Reverse Stereo", "AIF1 DA0L" },
117662306a36Sopenharmony_ci	{ "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0L" },
117762306a36Sopenharmony_ci	{ "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0R" },
117862306a36Sopenharmony_ci	{ "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" },
117962306a36Sopenharmony_ci	{ "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" },
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	{ "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" },
118262306a36Sopenharmony_ci	{ "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" },
118362306a36Sopenharmony_ci	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" },
118462306a36Sopenharmony_ci	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" },
118562306a36Sopenharmony_ci	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" },
118662306a36Sopenharmony_ci	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" },
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	{ "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" },
118962306a36Sopenharmony_ci	{ "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" },
119062306a36Sopenharmony_ci	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" },
119162306a36Sopenharmony_ci	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" },
119262306a36Sopenharmony_ci	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" },
119362306a36Sopenharmony_ci	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" },
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	/* DAC Output Routes */
119662306a36Sopenharmony_ci	{ "DACL", NULL, "DACL Mixer" },
119762306a36Sopenharmony_ci	{ "DACR", NULL, "DACR Mixer" },
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	/* DAC Mixer Routes */
120062306a36Sopenharmony_ci	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
120162306a36Sopenharmony_ci	{ "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" },
120262306a36Sopenharmony_ci	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
120562306a36Sopenharmony_ci	{ "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" },
120662306a36Sopenharmony_ci	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
120762306a36Sopenharmony_ci};
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = {
121062306a36Sopenharmony_ci	/* Legacy ADC Inputs (connected to analog codec DAPM context) */
121162306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0),
121262306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0),
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	/* Legacy DAC Outputs (connected to analog codec DAPM context) */
121562306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0),
121662306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0),
121762306a36Sopenharmony_ci};
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_cistatic const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = {
122062306a36Sopenharmony_ci	/* Legacy ADC Routes */
122162306a36Sopenharmony_ci	{ "ADCL", NULL, "AIF1 Slot 0 Left ADC" },
122262306a36Sopenharmony_ci	{ "ADCR", NULL, "AIF1 Slot 0 Right ADC" },
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	/* Legacy DAC Routes */
122562306a36Sopenharmony_ci	{ "AIF1 Slot 0 Left", NULL, "DACL" },
122662306a36Sopenharmony_ci	{ "AIF1 Slot 0 Right", NULL, "DACR" },
122762306a36Sopenharmony_ci};
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_cistatic int sun8i_codec_component_probe(struct snd_soc_component *component)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
123262306a36Sopenharmony_ci	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
123362306a36Sopenharmony_ci	int ret;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	/* Add widgets for backward compatibility with old device trees. */
123662306a36Sopenharmony_ci	if (scodec->quirks->legacy_widgets) {
123762306a36Sopenharmony_ci		ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets,
123862306a36Sopenharmony_ci						ARRAY_SIZE(sun8i_codec_legacy_widgets));
123962306a36Sopenharmony_ci		if (ret)
124062306a36Sopenharmony_ci			return ret;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci		ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes,
124362306a36Sopenharmony_ci					      ARRAY_SIZE(sun8i_codec_legacy_routes));
124462306a36Sopenharmony_ci		if (ret)
124562306a36Sopenharmony_ci			return ret;
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	/*
124962306a36Sopenharmony_ci	 * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod")
125062306a36Sopenharmony_ci	 * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also
125162306a36Sopenharmony_ci	 * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO
125262306a36Sopenharmony_ci	 * directly to simplify the clock tree.
125362306a36Sopenharmony_ci	 */
125462306a36Sopenharmony_ci	regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
125562306a36Sopenharmony_ci			   SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK |
125662306a36Sopenharmony_ci			   SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK,
125762306a36Sopenharmony_ci			   SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL |
125862306a36Sopenharmony_ci			   SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	/* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */
126162306a36Sopenharmony_ci	regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
126262306a36Sopenharmony_ci			   BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC),
126362306a36Sopenharmony_ci			   SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	/* Program the default sample rate. */
126662306a36Sopenharmony_ci	sun8i_codec_update_sample_rate(scodec);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	return 0;
126962306a36Sopenharmony_ci}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic const struct snd_soc_component_driver sun8i_soc_component = {
127262306a36Sopenharmony_ci	.controls		= sun8i_codec_controls,
127362306a36Sopenharmony_ci	.num_controls		= ARRAY_SIZE(sun8i_codec_controls),
127462306a36Sopenharmony_ci	.dapm_widgets		= sun8i_codec_dapm_widgets,
127562306a36Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(sun8i_codec_dapm_widgets),
127662306a36Sopenharmony_ci	.dapm_routes		= sun8i_codec_dapm_routes,
127762306a36Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(sun8i_codec_dapm_routes),
127862306a36Sopenharmony_ci	.probe			= sun8i_codec_component_probe,
127962306a36Sopenharmony_ci	.idle_bias_on		= 1,
128062306a36Sopenharmony_ci	.endianness		= 1,
128162306a36Sopenharmony_ci};
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic const struct regmap_config sun8i_codec_regmap_config = {
128462306a36Sopenharmony_ci	.reg_bits	= 32,
128562306a36Sopenharmony_ci	.reg_stride	= 4,
128662306a36Sopenharmony_ci	.val_bits	= 32,
128762306a36Sopenharmony_ci	.max_register	= SUN8I_DAC_MXR_SRC,
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	.cache_type	= REGCACHE_FLAT,
129062306a36Sopenharmony_ci};
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_cistatic int sun8i_codec_probe(struct platform_device *pdev)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	struct sun8i_codec *scodec;
129562306a36Sopenharmony_ci	void __iomem *base;
129662306a36Sopenharmony_ci	int ret;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
129962306a36Sopenharmony_ci	if (!scodec)
130062306a36Sopenharmony_ci		return -ENOMEM;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
130362306a36Sopenharmony_ci	if (IS_ERR(scodec->clk_module)) {
130462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to get the module clock\n");
130562306a36Sopenharmony_ci		return PTR_ERR(scodec->clk_module);
130662306a36Sopenharmony_ci	}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
130962306a36Sopenharmony_ci	if (IS_ERR(base)) {
131062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to map the registers\n");
131162306a36Sopenharmony_ci		return PTR_ERR(base);
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base,
131562306a36Sopenharmony_ci						   &sun8i_codec_regmap_config);
131662306a36Sopenharmony_ci	if (IS_ERR(scodec->regmap)) {
131762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to create our regmap\n");
131862306a36Sopenharmony_ci		return PTR_ERR(scodec->regmap);
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	scodec->quirks = of_device_get_match_data(&pdev->dev);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	platform_set_drvdata(pdev, scodec);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
132662306a36Sopenharmony_ci	if (!pm_runtime_enabled(&pdev->dev)) {
132762306a36Sopenharmony_ci		ret = sun8i_codec_runtime_resume(&pdev->dev);
132862306a36Sopenharmony_ci		if (ret)
132962306a36Sopenharmony_ci			goto err_pm_disable;
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
133362306a36Sopenharmony_ci					      sun8i_codec_dais,
133462306a36Sopenharmony_ci					      ARRAY_SIZE(sun8i_codec_dais));
133562306a36Sopenharmony_ci	if (ret) {
133662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register codec\n");
133762306a36Sopenharmony_ci		goto err_suspend;
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	return ret;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cierr_suspend:
134362306a36Sopenharmony_ci	if (!pm_runtime_status_suspended(&pdev->dev))
134462306a36Sopenharmony_ci		sun8i_codec_runtime_suspend(&pdev->dev);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_cierr_pm_disable:
134762306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	return ret;
135062306a36Sopenharmony_ci}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_cistatic void sun8i_codec_remove(struct platform_device *pdev)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
135562306a36Sopenharmony_ci	if (!pm_runtime_status_suspended(&pdev->dev))
135662306a36Sopenharmony_ci		sun8i_codec_runtime_suspend(&pdev->dev);
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_cistatic const struct sun8i_codec_quirks sun8i_a33_quirks = {
136062306a36Sopenharmony_ci	.legacy_widgets	= true,
136162306a36Sopenharmony_ci	.lrck_inversion	= true,
136262306a36Sopenharmony_ci};
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_cistatic const struct sun8i_codec_quirks sun50i_a64_quirks = {
136562306a36Sopenharmony_ci};
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_cistatic const struct of_device_id sun8i_codec_of_match[] = {
136862306a36Sopenharmony_ci	{ .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks },
136962306a36Sopenharmony_ci	{ .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks },
137062306a36Sopenharmony_ci	{}
137162306a36Sopenharmony_ci};
137262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_cistatic const struct dev_pm_ops sun8i_codec_pm_ops = {
137562306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
137662306a36Sopenharmony_ci			   sun8i_codec_runtime_resume, NULL)
137762306a36Sopenharmony_ci};
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_cistatic struct platform_driver sun8i_codec_driver = {
138062306a36Sopenharmony_ci	.driver = {
138162306a36Sopenharmony_ci		.name = "sun8i-codec",
138262306a36Sopenharmony_ci		.of_match_table = sun8i_codec_of_match,
138362306a36Sopenharmony_ci		.pm = &sun8i_codec_pm_ops,
138462306a36Sopenharmony_ci	},
138562306a36Sopenharmony_ci	.probe = sun8i_codec_probe,
138662306a36Sopenharmony_ci	.remove_new = sun8i_codec_remove,
138762306a36Sopenharmony_ci};
138862306a36Sopenharmony_cimodule_platform_driver(sun8i_codec_driver);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ciMODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
139162306a36Sopenharmony_ciMODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
139262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
139362306a36Sopenharmony_ciMODULE_ALIAS("platform:sun8i-codec");
1394