xref: /openbmc/linux/sound/soc/sunxi/sun8i-codec.c (revision a594f423)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
236c68493SMylène Josserand /*
336c68493SMylène Josserand  * This driver supports the digital controls for the internal codec
436c68493SMylène Josserand  * found in Allwinner's A33 SoCs.
536c68493SMylène Josserand  *
636c68493SMylène Josserand  * (C) Copyright 2010-2016
736c68493SMylène Josserand  * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
836c68493SMylène Josserand  * huangxin <huangxin@Reuuimllatech.com>
936c68493SMylène Josserand  * Mylène Josserand <mylene.josserand@free-electrons.com>
1036c68493SMylène Josserand  */
1136c68493SMylène Josserand 
1236c68493SMylène Josserand #include <linux/module.h>
1336c68493SMylène Josserand #include <linux/delay.h>
1436c68493SMylène Josserand #include <linux/clk.h>
1536c68493SMylène Josserand #include <linux/io.h>
1690cac932SSamuel Holland #include <linux/of_device.h>
1736c68493SMylène Josserand #include <linux/pm_runtime.h>
1836c68493SMylène Josserand #include <linux/regmap.h>
1913c3bf17SVasily Khoruzhick #include <linux/log2.h>
2036c68493SMylène Josserand 
2136c68493SMylène Josserand #include <sound/pcm_params.h>
2236c68493SMylène Josserand #include <sound/soc.h>
2336c68493SMylène Josserand #include <sound/soc-dapm.h>
24fd03cf7fSSamuel Holland #include <sound/tlv.h>
2536c68493SMylène Josserand 
2636c68493SMylène Josserand #define SUN8I_SYSCLK_CTL				0x00c
2736c68493SMylène Josserand #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA			11
28d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL		(0x2 << 8)
29d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF2CLK_ENA			7
30d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL		(0x2 << 4)
3136c68493SMylène Josserand #define SUN8I_SYSCLK_CTL_SYSCLK_ENA			3
3236c68493SMylène Josserand #define SUN8I_SYSCLK_CTL_SYSCLK_SRC			0
33d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK		(0x0 << 0)
34d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK		(0x1 << 0)
3536c68493SMylène Josserand #define SUN8I_MOD_CLK_ENA				0x010
3636c68493SMylène Josserand #define SUN8I_MOD_CLK_ENA_AIF1				15
3750ec8422SSamuel Holland #define SUN8I_MOD_CLK_ENA_AIF2				14
385a7f34abSSamuel Holland #define SUN8I_MOD_CLK_ENA_AIF3				13
39eda85d1fSMylene JOSSERAND #define SUN8I_MOD_CLK_ENA_ADC				3
4036c68493SMylène Josserand #define SUN8I_MOD_CLK_ENA_DAC				2
4136c68493SMylène Josserand #define SUN8I_MOD_RST_CTL				0x014
4236c68493SMylène Josserand #define SUN8I_MOD_RST_CTL_AIF1				15
4350ec8422SSamuel Holland #define SUN8I_MOD_RST_CTL_AIF2				14
445a7f34abSSamuel Holland #define SUN8I_MOD_RST_CTL_AIF3				13
45eda85d1fSMylene JOSSERAND #define SUN8I_MOD_RST_CTL_ADC				3
4636c68493SMylène Josserand #define SUN8I_MOD_RST_CTL_DAC				2
4736c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL				0x018
4836c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF1_FS			12
4936c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF2_FS			8
507a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL(n)				(0x040 * (1 + (n)))
517a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_MSTR_MOD			15
527a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_CLK_INV			13
537a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_BCLK_DIV			9
547a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_LRCK_DIV			6
557a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_WORD_SIZ			4
567a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_DATA_FMT			2
57eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_ADCDAT_CTRL				0x044
58fa5c0ca1SSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA		15
59fa5c0ca1SSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA		14
6018ebd62cSSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC		10
6118ebd62cSSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC		8
6236c68493SMylène Josserand #define SUN8I_AIF1_DACDAT_CTRL				0x048
6336c68493SMylène Josserand #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA		15
6436c68493SMylène Josserand #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA		14
6518ebd62cSSamuel Holland #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC		10
6618ebd62cSSamuel Holland #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC		8
67eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC				0x04c
680ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L	15
690ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL	14
700ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL		13
710ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR	12
72eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R	11
73eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR	10
74eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR		9
75eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL	8
76fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL1				0x050
77fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL1_AD0L_VOL			8
78fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL1_AD0R_VOL			0
79fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL3				0x058
80fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL3_DA0L_VOL			8
81fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL3_DA0R_VOL			0
8250ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL				0x084
8350ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA		15
8450ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA		14
8550ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC		10
8650ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC		8
8750ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL				0x088
8850ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA		15
8950ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA		14
9050ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC		10
9150ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC		8
9250ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC				0x08c
9350ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L	15
9450ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L	14
9550ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR	13
9650ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL		12
9750ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R	11
9850ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R	10
9950ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL	9
10050ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR		8
101fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL1				0x090
102fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL1_ADCL_VOL			8
103fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL1_ADCR_VOL			0
104fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL2				0x098
105fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL2_DACL_VOL			8
106fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL2_DACR_VOL			0
1075a7f34abSSamuel Holland #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1		(0x0 << 0)
1085a7f34abSSamuel Holland #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2		(0x1 << 0)
1095a7f34abSSamuel Holland #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1CLK	(0x2 << 0)
11050ec8422SSamuel Holland #define SUN8I_AIF3_PATH_CTRL				0x0cc
11150ec8422SSamuel Holland #define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC		10
11250ec8422SSamuel Holland #define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC		8
11350ec8422SSamuel Holland #define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI		7
114eda85d1fSMylene JOSSERAND #define SUN8I_ADC_DIG_CTRL				0x100
11530aff91eSSamuel Holland #define SUN8I_ADC_DIG_CTRL_ENAD				15
116eda85d1fSMylene JOSSERAND #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS			2
117eda85d1fSMylene JOSSERAND #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY			1
118fd03cf7fSSamuel Holland #define SUN8I_ADC_VOL_CTRL				0x104
119fd03cf7fSSamuel Holland #define SUN8I_ADC_VOL_CTRL_ADCL_VOL			8
120fd03cf7fSSamuel Holland #define SUN8I_ADC_VOL_CTRL_ADCR_VOL			0
12136c68493SMylène Josserand #define SUN8I_DAC_DIG_CTRL				0x120
12236c68493SMylène Josserand #define SUN8I_DAC_DIG_CTRL_ENDA				15
123fd03cf7fSSamuel Holland #define SUN8I_DAC_VOL_CTRL				0x124
124fd03cf7fSSamuel Holland #define SUN8I_DAC_VOL_CTRL_DACL_VOL			8
125fd03cf7fSSamuel Holland #define SUN8I_DAC_VOL_CTRL_DACR_VOL			0
12636c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC				0x130
12736c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L		15
12836c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L		14
12936c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL		13
13036c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL		12
13136c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R		11
13236c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R		10
13336c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR		9
13436c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR		8
13536c68493SMylène Josserand 
136d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK	GENMASK(9, 8)
137d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK	GENMASK(5, 4)
13836c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK		GENMASK(15, 12)
13936c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK		GENMASK(11, 8)
1407a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK		GENMASK(14, 13)
1417a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK	GENMASK(12, 9)
1427a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK	GENMASK(8, 6)
1437a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK	GENMASK(5, 4)
1447a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK	GENMASK(3, 2)
1455a7f34abSSamuel Holland #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK	GENMASK(1, 0)
14636c68493SMylène Josserand 
1476c5326beSSamuel Holland #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
1486c5326beSSamuel Holland 
149342cacb9SSamuel Holland #define SUN8I_CODEC_PCM_FORMATS	(SNDRV_PCM_FMTBIT_S8     |\
150342cacb9SSamuel Holland 				 SNDRV_PCM_FMTBIT_S16_LE |\
151342cacb9SSamuel Holland 				 SNDRV_PCM_FMTBIT_S20_LE |\
152342cacb9SSamuel Holland 				 SNDRV_PCM_FMTBIT_S24_LE |\
153342cacb9SSamuel Holland 				 SNDRV_PCM_FMTBIT_S20_3LE|\
154342cacb9SSamuel Holland 				 SNDRV_PCM_FMTBIT_S24_3LE)
155342cacb9SSamuel Holland 
156c2b751d7SSamuel Holland #define SUN8I_CODEC_PCM_RATES	(SNDRV_PCM_RATE_8000_48000|\
157c2b751d7SSamuel Holland 				 SNDRV_PCM_RATE_88200     |\
158c2b751d7SSamuel Holland 				 SNDRV_PCM_RATE_96000     |\
159c2b751d7SSamuel Holland 				 SNDRV_PCM_RATE_176400    |\
160c2b751d7SSamuel Holland 				 SNDRV_PCM_RATE_192000    |\
161c2b751d7SSamuel Holland 				 SNDRV_PCM_RATE_KNOT)
162c2b751d7SSamuel Holland 
1637826b8d1SSamuel Holland enum {
1647826b8d1SSamuel Holland 	SUN8I_CODEC_AIF1,
16550ec8422SSamuel Holland 	SUN8I_CODEC_AIF2,
1665a7f34abSSamuel Holland 	SUN8I_CODEC_AIF3,
1677826b8d1SSamuel Holland 	SUN8I_CODEC_NAIFS
1687826b8d1SSamuel Holland };
1697826b8d1SSamuel Holland 
170afb1a600SSamuel Holland struct sun8i_codec_aif {
1715a7f34abSSamuel Holland 	unsigned int	lrck_div_order;
1726c5326beSSamuel Holland 	unsigned int	sample_rate;
173afb1a600SSamuel Holland 	unsigned int	slots;
174afb1a600SSamuel Holland 	unsigned int	slot_width;
1756c5326beSSamuel Holland 	unsigned int	active_streams	: 2;
1766c5326beSSamuel Holland 	unsigned int	open_streams	: 2;
177afb1a600SSamuel Holland };
178afb1a600SSamuel Holland 
17990cac932SSamuel Holland struct sun8i_codec_quirks {
18090cac932SSamuel Holland 	bool legacy_widgets	: 1;
1817518805fSSamuel Holland 	bool lrck_inversion	: 1;
18290cac932SSamuel Holland };
18390cac932SSamuel Holland 
18436c68493SMylène Josserand struct sun8i_codec {
18536c68493SMylène Josserand 	struct regmap			*regmap;
18636c68493SMylène Josserand 	struct clk			*clk_module;
18790cac932SSamuel Holland 	const struct sun8i_codec_quirks	*quirks;
188afb1a600SSamuel Holland 	struct sun8i_codec_aif		aifs[SUN8I_CODEC_NAIFS];
18915b45912SSamuel Holland 	unsigned int			sysclk_rate;
19015b45912SSamuel Holland 	int				sysclk_refcnt;
19136c68493SMylène Josserand };
19236c68493SMylène Josserand 
1935a7f34abSSamuel Holland static struct snd_soc_dai_driver sun8i_codec_dais[];
1945a7f34abSSamuel Holland 
sun8i_codec_runtime_resume(struct device * dev)19536c68493SMylène Josserand static int sun8i_codec_runtime_resume(struct device *dev)
19636c68493SMylène Josserand {
19736c68493SMylène Josserand 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
19836c68493SMylène Josserand 	int ret;
19936c68493SMylène Josserand 
20036c68493SMylène Josserand 	regcache_cache_only(scodec->regmap, false);
20136c68493SMylène Josserand 
20236c68493SMylène Josserand 	ret = regcache_sync(scodec->regmap);
20336c68493SMylène Josserand 	if (ret) {
20436c68493SMylène Josserand 		dev_err(dev, "Failed to sync regmap cache\n");
2056b3bb3c8SSamuel Holland 		return ret;
20636c68493SMylène Josserand 	}
20736c68493SMylène Josserand 
20836c68493SMylène Josserand 	return 0;
20936c68493SMylène Josserand }
21036c68493SMylène Josserand 
sun8i_codec_runtime_suspend(struct device * dev)21136c68493SMylène Josserand static int sun8i_codec_runtime_suspend(struct device *dev)
21236c68493SMylène Josserand {
21336c68493SMylène Josserand 	struct sun8i_codec *scodec = dev_get_drvdata(dev);
21436c68493SMylène Josserand 
21536c68493SMylène Josserand 	regcache_cache_only(scodec->regmap, true);
21636c68493SMylène Josserand 	regcache_mark_dirty(scodec->regmap);
21736c68493SMylène Josserand 
21836c68493SMylène Josserand 	return 0;
21936c68493SMylène Josserand }
22036c68493SMylène Josserand 
sun8i_codec_get_hw_rate(unsigned int sample_rate)2216c5326beSSamuel Holland static int sun8i_codec_get_hw_rate(unsigned int sample_rate)
22236c68493SMylène Josserand {
2236c5326beSSamuel Holland 	switch (sample_rate) {
22436c68493SMylène Josserand 	case 7350:
225c2b751d7SSamuel Holland 	case 8000:
22636c68493SMylène Josserand 		return 0x0;
22736c68493SMylène Josserand 	case 11025:
22836c68493SMylène Josserand 		return 0x1;
22936c68493SMylène Josserand 	case 12000:
23036c68493SMylène Josserand 		return 0x2;
231c2b751d7SSamuel Holland 	case 14700:
23236c68493SMylène Josserand 	case 16000:
23336c68493SMylène Josserand 		return 0x3;
23436c68493SMylène Josserand 	case 22050:
23536c68493SMylène Josserand 		return 0x4;
23636c68493SMylène Josserand 	case 24000:
23736c68493SMylène Josserand 		return 0x5;
238c2b751d7SSamuel Holland 	case 29400:
23936c68493SMylène Josserand 	case 32000:
24036c68493SMylène Josserand 		return 0x6;
24136c68493SMylène Josserand 	case 44100:
24236c68493SMylène Josserand 		return 0x7;
24336c68493SMylène Josserand 	case 48000:
24436c68493SMylène Josserand 		return 0x8;
245c2b751d7SSamuel Holland 	case 88200:
24636c68493SMylène Josserand 	case 96000:
24736c68493SMylène Josserand 		return 0x9;
248c2b751d7SSamuel Holland 	case 176400:
24936c68493SMylène Josserand 	case 192000:
25036c68493SMylène Josserand 		return 0xa;
25136c68493SMylène Josserand 	default:
25236c68493SMylène Josserand 		return -EINVAL;
25336c68493SMylène Josserand 	}
25436c68493SMylène Josserand }
25536c68493SMylène Josserand 
sun8i_codec_update_sample_rate(struct sun8i_codec * scodec)2566c5326beSSamuel Holland static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
2576c5326beSSamuel Holland {
2586c5326beSSamuel Holland 	unsigned int max_rate = 0;
2596c5326beSSamuel Holland 	int hw_rate, i;
2606c5326beSSamuel Holland 
2616c5326beSSamuel Holland 	for (i = SUN8I_CODEC_AIF1; i < SUN8I_CODEC_NAIFS; ++i) {
2626c5326beSSamuel Holland 		struct sun8i_codec_aif *aif = &scodec->aifs[i];
2636c5326beSSamuel Holland 
2646c5326beSSamuel Holland 		if (aif->active_streams)
2656c5326beSSamuel Holland 			max_rate = max(max_rate, aif->sample_rate);
2666c5326beSSamuel Holland 	}
2676c5326beSSamuel Holland 
2686c5326beSSamuel Holland 	/* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
2696c5326beSSamuel Holland 	if (!max_rate)
2706c5326beSSamuel Holland 		max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
2716c5326beSSamuel Holland 
2726c5326beSSamuel Holland 	hw_rate = sun8i_codec_get_hw_rate(max_rate);
2736c5326beSSamuel Holland 	if (hw_rate < 0)
2746c5326beSSamuel Holland 		return hw_rate;
2756c5326beSSamuel Holland 
2766c5326beSSamuel Holland 	regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
2776c5326beSSamuel Holland 			   SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
2786c5326beSSamuel Holland 			   hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
2796c5326beSSamuel Holland 
2806c5326beSSamuel Holland 	return 0;
2816c5326beSSamuel Holland }
2826c5326beSSamuel Holland 
sun8i_codec_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)2837826b8d1SSamuel Holland static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
28436c68493SMylène Josserand {
285a886990cSSamuel Holland 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
286c56f5f1cSSamuel Holland 	u32 dsp_format, format, invert, value;
28736c68493SMylène Josserand 
28836c68493SMylène Josserand 	/* clock masters */
2897cc3965fSCharles Keepax 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
290beb89d1dSCharles Keepax 	case SND_SOC_DAIFMT_CBC_CFC: /* Codec slave, DAI master */
291560bfe77SMaxime Ripard 		value = 0x1;
29236c68493SMylène Josserand 		break;
293beb89d1dSCharles Keepax 	case SND_SOC_DAIFMT_CBP_CFP: /* Codec Master, DAI slave */
294560bfe77SMaxime Ripard 		value = 0x0;
29536c68493SMylène Josserand 		break;
29636c68493SMylène Josserand 	default:
29736c68493SMylène Josserand 		return -EINVAL;
29836c68493SMylène Josserand 	}
2997a6b937eSSamuel Holland 
3005a7f34abSSamuel Holland 	if (dai->id == SUN8I_CODEC_AIF3) {
3015a7f34abSSamuel Holland 		/* AIF3 only supports master mode. */
3025a7f34abSSamuel Holland 		if (value)
3035a7f34abSSamuel Holland 			return -EINVAL;
3045a7f34abSSamuel Holland 
3055a7f34abSSamuel Holland 		/* Use the AIF2 BCLK and LRCK for AIF3. */
3065a7f34abSSamuel Holland 		regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
3075a7f34abSSamuel Holland 				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
3085a7f34abSSamuel Holland 				   SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
3095a7f34abSSamuel Holland 	} else {
3107a6b937eSSamuel Holland 		regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
3117a6b937eSSamuel Holland 				   BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
3127a6b937eSSamuel Holland 				   value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
3135a7f34abSSamuel Holland 	}
31436c68493SMylène Josserand 
315fd57ed2dSSamuel Holland 	/* DAI format */
316fd57ed2dSSamuel Holland 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
317fd57ed2dSSamuel Holland 	case SND_SOC_DAIFMT_I2S:
318fd57ed2dSSamuel Holland 		format = 0x0;
319fd57ed2dSSamuel Holland 		break;
320fd57ed2dSSamuel Holland 	case SND_SOC_DAIFMT_LEFT_J:
321fd57ed2dSSamuel Holland 		format = 0x1;
322fd57ed2dSSamuel Holland 		break;
323fd57ed2dSSamuel Holland 	case SND_SOC_DAIFMT_RIGHT_J:
324fd57ed2dSSamuel Holland 		format = 0x2;
325fd57ed2dSSamuel Holland 		break;
326fd57ed2dSSamuel Holland 	case SND_SOC_DAIFMT_DSP_A:
327c56f5f1cSSamuel Holland 		format = 0x3;
328c56f5f1cSSamuel Holland 		dsp_format = 0x0; /* Set LRCK_INV to 0 */
329c56f5f1cSSamuel Holland 		break;
330fd57ed2dSSamuel Holland 	case SND_SOC_DAIFMT_DSP_B:
331fd57ed2dSSamuel Holland 		format = 0x3;
332c56f5f1cSSamuel Holland 		dsp_format = 0x1; /* Set LRCK_INV to 1 */
333fd57ed2dSSamuel Holland 		break;
334fd57ed2dSSamuel Holland 	default:
335fd57ed2dSSamuel Holland 		return -EINVAL;
336fd57ed2dSSamuel Holland 	}
3377a6b937eSSamuel Holland 
3385a7f34abSSamuel Holland 	if (dai->id == SUN8I_CODEC_AIF3) {
3395a7f34abSSamuel Holland 		/* AIF3 only supports DSP mode. */
3405a7f34abSSamuel Holland 		if (format != 3)
3415a7f34abSSamuel Holland 			return -EINVAL;
3425a7f34abSSamuel Holland 	} else {
3437a6b937eSSamuel Holland 		regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
3447a6b937eSSamuel Holland 				   SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
3457a6b937eSSamuel Holland 				   format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
3465a7f34abSSamuel Holland 	}
347fd57ed2dSSamuel Holland 
34836c68493SMylène Josserand 	/* clock inversion */
34936c68493SMylène Josserand 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
35036c68493SMylène Josserand 	case SND_SOC_DAIFMT_NB_NF: /* Normal */
351c56f5f1cSSamuel Holland 		invert = 0x0;
35236c68493SMylène Josserand 		break;
353c56f5f1cSSamuel Holland 	case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
354c56f5f1cSSamuel Holland 		invert = 0x1;
355c56f5f1cSSamuel Holland 		break;
356c56f5f1cSSamuel Holland 	case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
357c56f5f1cSSamuel Holland 		invert = 0x2;
358c56f5f1cSSamuel Holland 		break;
359c56f5f1cSSamuel Holland 	case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
360c56f5f1cSSamuel Holland 		invert = 0x3;
36136c68493SMylène Josserand 		break;
36236c68493SMylène Josserand 	default:
36336c68493SMylène Josserand 		return -EINVAL;
36436c68493SMylène Josserand 	}
365e7b8a6d3SMaxime Ripard 
366c56f5f1cSSamuel Holland 	if (format == 0x3) {
367c56f5f1cSSamuel Holland 		/* Inverted LRCK is not available in DSP mode. */
368c56f5f1cSSamuel Holland 		if (invert & BIT(0))
369c56f5f1cSSamuel Holland 			return -EINVAL;
370c56f5f1cSSamuel Holland 
371c56f5f1cSSamuel Holland 		/* Instead, the bit selects between DSP A/B formats. */
372c56f5f1cSSamuel Holland 		invert |= dsp_format;
373c56f5f1cSSamuel Holland 	} else {
374e7b8a6d3SMaxime Ripard 		/*
3757518805fSSamuel Holland 		 * It appears that the DAI and the codec in the A33 SoC don't
3767518805fSSamuel Holland 		 * share the same polarity for the LRCK signal when they mean
3777518805fSSamuel Holland 		 * 'normal' and 'inverted' in the datasheet.
378e7b8a6d3SMaxime Ripard 		 *
379e7b8a6d3SMaxime Ripard 		 * Since the DAI here is our regular i2s driver that have been
380e7b8a6d3SMaxime Ripard 		 * tested with way more codecs than just this one, it means
381e7b8a6d3SMaxime Ripard 		 * that the codec probably gets it backward, and we have to
382e7b8a6d3SMaxime Ripard 		 * invert the value here.
383e7b8a6d3SMaxime Ripard 		 */
384c56f5f1cSSamuel Holland 		invert ^= scodec->quirks->lrck_inversion;
385c56f5f1cSSamuel Holland 	}
386c56f5f1cSSamuel Holland 
3877a6b937eSSamuel Holland 	regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
3887a6b937eSSamuel Holland 			   SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
3897a6b937eSSamuel Holland 			   invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
39036c68493SMylène Josserand 
39136c68493SMylène Josserand 	return 0;
39236c68493SMylène Josserand }
39336c68493SMylène Josserand 
sun8i_codec_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)394afb1a600SSamuel Holland static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
395afb1a600SSamuel Holland 				    unsigned int tx_mask, unsigned int rx_mask,
396afb1a600SSamuel Holland 				    int slots, int slot_width)
397afb1a600SSamuel Holland {
398afb1a600SSamuel Holland 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
399afb1a600SSamuel Holland 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
400afb1a600SSamuel Holland 
401afb1a600SSamuel Holland 	if (slot_width && !is_power_of_2(slot_width))
402afb1a600SSamuel Holland 		return -EINVAL;
403afb1a600SSamuel Holland 
404afb1a600SSamuel Holland 	aif->slots = slots;
405afb1a600SSamuel Holland 	aif->slot_width = slot_width;
406afb1a600SSamuel Holland 
407afb1a600SSamuel Holland 	return 0;
408afb1a600SSamuel Holland }
409afb1a600SSamuel Holland 
41015b45912SSamuel Holland static const unsigned int sun8i_codec_rates[] = {
41115b45912SSamuel Holland 	  7350,   8000,  11025,  12000,  14700,  16000,  22050,  24000,
41215b45912SSamuel Holland 	 29400,  32000,  44100,  48000,  88200,  96000, 176400, 192000,
41315b45912SSamuel Holland };
41415b45912SSamuel Holland 
41515b45912SSamuel Holland static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
41615b45912SSamuel Holland 	.list	= sun8i_codec_rates,
41715b45912SSamuel Holland 	.count	= ARRAY_SIZE(sun8i_codec_rates),
41815b45912SSamuel Holland };
41915b45912SSamuel Holland 
42015b45912SSamuel Holland static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
42115b45912SSamuel Holland 	.list	= sun8i_codec_rates,
42215b45912SSamuel Holland 	.count	= ARRAY_SIZE(sun8i_codec_rates),
42315b45912SSamuel Holland 	.mask	= 0x5555,
42415b45912SSamuel Holland };
42515b45912SSamuel Holland 
42615b45912SSamuel Holland static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
42715b45912SSamuel Holland 	.list	= sun8i_codec_rates,
42815b45912SSamuel Holland 	.count	= ARRAY_SIZE(sun8i_codec_rates),
42915b45912SSamuel Holland 	.mask	= 0xaaaa,
43015b45912SSamuel Holland };
43115b45912SSamuel Holland 
sun8i_codec_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)43215b45912SSamuel Holland static int sun8i_codec_startup(struct snd_pcm_substream *substream,
43315b45912SSamuel Holland 			       struct snd_soc_dai *dai)
43415b45912SSamuel Holland {
43515b45912SSamuel Holland 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
43615b45912SSamuel Holland 	const struct snd_pcm_hw_constraint_list *list;
43715b45912SSamuel Holland 
43850ec8422SSamuel Holland 	/* hw_constraints is not relevant for codec2codec DAIs. */
43950ec8422SSamuel Holland 	if (dai->id != SUN8I_CODEC_AIF1)
44050ec8422SSamuel Holland 		return 0;
44150ec8422SSamuel Holland 
44215b45912SSamuel Holland 	if (!scodec->sysclk_refcnt)
44315b45912SSamuel Holland 		list = &sun8i_codec_all_rates;
44415b45912SSamuel Holland 	else if (scodec->sysclk_rate == 22579200)
44515b45912SSamuel Holland 		list = &sun8i_codec_22M_rates;
44615b45912SSamuel Holland 	else if (scodec->sysclk_rate == 24576000)
44715b45912SSamuel Holland 		list = &sun8i_codec_24M_rates;
44815b45912SSamuel Holland 	else
44915b45912SSamuel Holland 		return -EINVAL;
45015b45912SSamuel Holland 
45115b45912SSamuel Holland 	return snd_pcm_hw_constraint_list(substream->runtime, 0,
45215b45912SSamuel Holland 					  SNDRV_PCM_HW_PARAM_RATE, list);
45315b45912SSamuel Holland }
45415b45912SSamuel Holland 
455316b7758SMaxime Ripard struct sun8i_codec_clk_div {
456316b7758SMaxime Ripard 	u8	div;
457316b7758SMaxime Ripard 	u8	val;
458316b7758SMaxime Ripard };
459316b7758SMaxime Ripard 
460316b7758SMaxime Ripard static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
461316b7758SMaxime Ripard 	{ .div = 1,	.val = 0 },
462316b7758SMaxime Ripard 	{ .div = 2,	.val = 1 },
463316b7758SMaxime Ripard 	{ .div = 4,	.val = 2 },
464316b7758SMaxime Ripard 	{ .div = 6,	.val = 3 },
465316b7758SMaxime Ripard 	{ .div = 8,	.val = 4 },
466316b7758SMaxime Ripard 	{ .div = 12,	.val = 5 },
467316b7758SMaxime Ripard 	{ .div = 16,	.val = 6 },
468316b7758SMaxime Ripard 	{ .div = 24,	.val = 7 },
469316b7758SMaxime Ripard 	{ .div = 32,	.val = 8 },
470316b7758SMaxime Ripard 	{ .div = 48,	.val = 9 },
471316b7758SMaxime Ripard 	{ .div = 64,	.val = 10 },
472316b7758SMaxime Ripard 	{ .div = 96,	.val = 11 },
473316b7758SMaxime Ripard 	{ .div = 128,	.val = 12 },
474316b7758SMaxime Ripard 	{ .div = 192,	.val = 13 },
475316b7758SMaxime Ripard };
476316b7758SMaxime Ripard 
sun8i_codec_get_bclk_div(unsigned int sysclk_rate,unsigned int lrck_div_order,unsigned int sample_rate)4772464dccaSSamuel Holland static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
47868a4f2caSSamuel Holland 				    unsigned int lrck_div_order,
47968a4f2caSSamuel Holland 				    unsigned int sample_rate)
480316b7758SMaxime Ripard {
48115b45912SSamuel Holland 	unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
482316b7758SMaxime Ripard 	int i;
483316b7758SMaxime Ripard 
484316b7758SMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
485316b7758SMaxime Ripard 		const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
486316b7758SMaxime Ripard 
4872464dccaSSamuel Holland 		if (bdiv->div == div)
4882464dccaSSamuel Holland 			return bdiv->val;
489316b7758SMaxime Ripard 	}
490316b7758SMaxime Ripard 
4912464dccaSSamuel Holland 	return -EINVAL;
492316b7758SMaxime Ripard }
493316b7758SMaxime Ripard 
sun8i_codec_get_lrck_div_order(unsigned int slots,unsigned int slot_width)494e511aed7SSamuel Holland static int sun8i_codec_get_lrck_div_order(unsigned int slots,
495e511aed7SSamuel Holland 					  unsigned int slot_width)
49613c3bf17SVasily Khoruzhick {
497e511aed7SSamuel Holland 	unsigned int div = slots * slot_width;
49813c3bf17SVasily Khoruzhick 
49913c3bf17SVasily Khoruzhick 	if (div < 16 || div > 256)
50013c3bf17SVasily Khoruzhick 		return -EINVAL;
50113c3bf17SVasily Khoruzhick 
502e511aed7SSamuel Holland 	return order_base_2(div);
50313c3bf17SVasily Khoruzhick }
50413c3bf17SVasily Khoruzhick 
sun8i_codec_get_sysclk_rate(unsigned int sample_rate)5053952ec2aSSamuel Holland static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
5063952ec2aSSamuel Holland {
50754f78aebSPierre-Louis Bossart 	return (sample_rate % 4000) ? 22579200 : 24576000;
5083952ec2aSSamuel Holland }
5093952ec2aSSamuel Holland 
sun8i_codec_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)51036c68493SMylène Josserand static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
51136c68493SMylène Josserand 				 struct snd_pcm_hw_params *params,
51236c68493SMylène Josserand 				 struct snd_soc_dai *dai)
51336c68493SMylène Josserand {
514a886990cSSamuel Holland 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
515afb1a600SSamuel Holland 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
5166c5326beSSamuel Holland 	unsigned int sample_rate = params_rate(params);
517afb1a600SSamuel Holland 	unsigned int slots = aif->slots ?: params_channels(params);
518afb1a600SSamuel Holland 	unsigned int slot_width = aif->slot_width ?: params_width(params);
5193952ec2aSSamuel Holland 	unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
5202464dccaSSamuel Holland 	int bclk_div, lrck_div_order, ret, word_size;
5215a7f34abSSamuel Holland 	u32 clk_reg;
52236c68493SMylène Josserand 
5231abb43aeSSamuel Holland 	/* word size */
5241abb43aeSSamuel Holland 	switch (params_width(params)) {
5251abb43aeSSamuel Holland 	case 8:
5261abb43aeSSamuel Holland 		word_size = 0x0;
5271abb43aeSSamuel Holland 		break;
5281abb43aeSSamuel Holland 	case 16:
5291abb43aeSSamuel Holland 		word_size = 0x1;
5301abb43aeSSamuel Holland 		break;
5311abb43aeSSamuel Holland 	case 20:
5321abb43aeSSamuel Holland 		word_size = 0x2;
5331abb43aeSSamuel Holland 		break;
5341abb43aeSSamuel Holland 	case 24:
5351abb43aeSSamuel Holland 		word_size = 0x3;
5361abb43aeSSamuel Holland 		break;
5371abb43aeSSamuel Holland 	default:
5381abb43aeSSamuel Holland 		return -EINVAL;
5391abb43aeSSamuel Holland 	}
5401abb43aeSSamuel Holland 
5417a6b937eSSamuel Holland 	regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
5427a6b937eSSamuel Holland 			   SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
5437a6b937eSSamuel Holland 			   word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
54436c68493SMylène Josserand 
545e511aed7SSamuel Holland 	/* LRCK divider (BCLK/LRCK ratio) */
546e511aed7SSamuel Holland 	lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
547e511aed7SSamuel Holland 	if (lrck_div_order < 0)
548e511aed7SSamuel Holland 		return lrck_div_order;
54913c3bf17SVasily Khoruzhick 
5505a7f34abSSamuel Holland 	if (dai->id == SUN8I_CODEC_AIF2 || dai->id == SUN8I_CODEC_AIF3) {
5515a7f34abSSamuel Holland 		/* AIF2 and AIF3 share AIF2's BCLK and LRCK generation circuitry. */
5525a7f34abSSamuel Holland 		int partner = (SUN8I_CODEC_AIF2 + SUN8I_CODEC_AIF3) - dai->id;
5535a7f34abSSamuel Holland 		const struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner];
5545a7f34abSSamuel Holland 		const char *partner_name = sun8i_codec_dais[partner].name;
5555a7f34abSSamuel Holland 
5565a7f34abSSamuel Holland 		if (partner_aif->open_streams &&
5575a7f34abSSamuel Holland 		    (lrck_div_order != partner_aif->lrck_div_order ||
5585a7f34abSSamuel Holland 		     sample_rate != partner_aif->sample_rate)) {
5595a7f34abSSamuel Holland 			dev_err(dai->dev,
5605a7f34abSSamuel Holland 				"%s sample and bit rates must match %s when both are used\n",
5615a7f34abSSamuel Holland 				dai->name, partner_name);
5625a7f34abSSamuel Holland 			return -EBUSY;
5635a7f34abSSamuel Holland 		}
5645a7f34abSSamuel Holland 
5655a7f34abSSamuel Holland 		clk_reg = SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF2);
5665a7f34abSSamuel Holland 	} else {
5675a7f34abSSamuel Holland 		clk_reg = SUN8I_AIF_CLK_CTRL(dai->id);
5685a7f34abSSamuel Holland 	}
5695a7f34abSSamuel Holland 
5705a7f34abSSamuel Holland 	regmap_update_bits(scodec->regmap, clk_reg,
5717a6b937eSSamuel Holland 			   SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
5727a6b937eSSamuel Holland 			   (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
57336c68493SMylène Josserand 
57468a4f2caSSamuel Holland 	/* BCLK divider (SYSCLK/BCLK ratio) */
57515b45912SSamuel Holland 	bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
5762464dccaSSamuel Holland 	if (bclk_div < 0)
5772464dccaSSamuel Holland 		return bclk_div;
5782464dccaSSamuel Holland 
5795a7f34abSSamuel Holland 	regmap_update_bits(scodec->regmap, clk_reg,
5807a6b937eSSamuel Holland 			   SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
5817a6b937eSSamuel Holland 			   bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
58268a4f2caSSamuel Holland 
5833952ec2aSSamuel Holland 	/*
5843952ec2aSSamuel Holland 	 * SYSCLK rate
5853952ec2aSSamuel Holland 	 *
5863952ec2aSSamuel Holland 	 * Clock rate protection is reference counted; but hw_params may be
5873952ec2aSSamuel Holland 	 * called many times per substream, without matching calls to hw_free.
5883952ec2aSSamuel Holland 	 * Protect the clock rate once per AIF, on the first hw_params call
5893952ec2aSSamuel Holland 	 * for the first substream. clk_set_rate() will allow clock rate
5903952ec2aSSamuel Holland 	 * changes on subsequent calls if only one AIF has open streams.
5913952ec2aSSamuel Holland 	 */
5923952ec2aSSamuel Holland 	ret = (aif->open_streams ? clk_set_rate : clk_set_rate_exclusive)(scodec->clk_module,
5933952ec2aSSamuel Holland 									  sysclk_rate);
5943952ec2aSSamuel Holland 	if (ret == -EBUSY)
5953952ec2aSSamuel Holland 		dev_err(dai->dev,
5963952ec2aSSamuel Holland 			"%s sample rate (%u Hz) conflicts with other audio streams\n",
5973952ec2aSSamuel Holland 			dai->name, sample_rate);
5983952ec2aSSamuel Holland 	if (ret < 0)
5993952ec2aSSamuel Holland 		return ret;
6003952ec2aSSamuel Holland 
60115b45912SSamuel Holland 	if (!aif->open_streams)
60215b45912SSamuel Holland 		scodec->sysclk_refcnt++;
60315b45912SSamuel Holland 	scodec->sysclk_rate = sysclk_rate;
60415b45912SSamuel Holland 
6055a7f34abSSamuel Holland 	aif->lrck_div_order = lrck_div_order;
6066c5326beSSamuel Holland 	aif->sample_rate = sample_rate;
6076c5326beSSamuel Holland 	aif->open_streams |= BIT(substream->stream);
60836c68493SMylène Josserand 
6096c5326beSSamuel Holland 	return sun8i_codec_update_sample_rate(scodec);
6106c5326beSSamuel Holland }
61136c68493SMylène Josserand 
sun8i_codec_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)6126c5326beSSamuel Holland static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
6136c5326beSSamuel Holland 			       struct snd_soc_dai *dai)
6146c5326beSSamuel Holland {
6156c5326beSSamuel Holland 	struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
6166c5326beSSamuel Holland 	struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
6176c5326beSSamuel Holland 
6183952ec2aSSamuel Holland 	/* Drop references when the last substream for the AIF is freed. */
6196c5326beSSamuel Holland 	if (aif->open_streams != BIT(substream->stream))
6206c5326beSSamuel Holland 		goto done;
6216c5326beSSamuel Holland 
6223952ec2aSSamuel Holland 	clk_rate_exclusive_put(scodec->clk_module);
62315b45912SSamuel Holland 	scodec->sysclk_refcnt--;
6245a7f34abSSamuel Holland 	aif->lrck_div_order = 0;
6256c5326beSSamuel Holland 	aif->sample_rate = 0;
6266c5326beSSamuel Holland 
6276c5326beSSamuel Holland done:
6286c5326beSSamuel Holland 	aif->open_streams &= ~BIT(substream->stream);
62936c68493SMylène Josserand 	return 0;
63036c68493SMylène Josserand }
63136c68493SMylène Josserand 
6327826b8d1SSamuel Holland static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
63315011b23SCharles Keepax 	.set_fmt	= sun8i_codec_set_fmt,
634afb1a600SSamuel Holland 	.set_tdm_slot	= sun8i_codec_set_tdm_slot,
63515b45912SSamuel Holland 	.startup	= sun8i_codec_startup,
6367826b8d1SSamuel Holland 	.hw_params	= sun8i_codec_hw_params,
6376c5326beSSamuel Holland 	.hw_free	= sun8i_codec_hw_free,
6387826b8d1SSamuel Holland };
6397826b8d1SSamuel Holland 
6407826b8d1SSamuel Holland static struct snd_soc_dai_driver sun8i_codec_dais[] = {
6417826b8d1SSamuel Holland 	{
6427826b8d1SSamuel Holland 		.name	= "sun8i-codec-aif1",
6437826b8d1SSamuel Holland 		.id	= SUN8I_CODEC_AIF1,
6447826b8d1SSamuel Holland 		.ops	= &sun8i_codec_dai_ops,
6457826b8d1SSamuel Holland 		/* capture capabilities */
6467826b8d1SSamuel Holland 		.capture = {
6477826b8d1SSamuel Holland 			.stream_name	= "AIF1 Capture",
6487826b8d1SSamuel Holland 			.channels_min	= 1,
6497826b8d1SSamuel Holland 			.channels_max	= 2,
650c2b751d7SSamuel Holland 			.rates		= SUN8I_CODEC_PCM_RATES,
651342cacb9SSamuel Holland 			.formats	= SUN8I_CODEC_PCM_FORMATS,
6527826b8d1SSamuel Holland 			.sig_bits	= 24,
6537826b8d1SSamuel Holland 		},
6547826b8d1SSamuel Holland 		/* playback capabilities */
6557826b8d1SSamuel Holland 		.playback = {
6567826b8d1SSamuel Holland 			.stream_name	= "AIF1 Playback",
6577826b8d1SSamuel Holland 			.channels_min	= 1,
6587826b8d1SSamuel Holland 			.channels_max	= 2,
659c2b751d7SSamuel Holland 			.rates		= SUN8I_CODEC_PCM_RATES,
660342cacb9SSamuel Holland 			.formats	= SUN8I_CODEC_PCM_FORMATS,
6617826b8d1SSamuel Holland 		},
66281385708SKuninori Morimoto 		.symmetric_rate		= true,
663e557148aSSamuel Holland 		.symmetric_channels	= true,
66481385708SKuninori Morimoto 		.symmetric_sample_bits	= true,
6657826b8d1SSamuel Holland 	},
66650ec8422SSamuel Holland 	{
66750ec8422SSamuel Holland 		.name	= "sun8i-codec-aif2",
66850ec8422SSamuel Holland 		.id	= SUN8I_CODEC_AIF2,
66950ec8422SSamuel Holland 		.ops	= &sun8i_codec_dai_ops,
67050ec8422SSamuel Holland 		/* capture capabilities */
67150ec8422SSamuel Holland 		.capture = {
67250ec8422SSamuel Holland 			.stream_name	= "AIF2 Capture",
67350ec8422SSamuel Holland 			.channels_min	= 1,
67450ec8422SSamuel Holland 			.channels_max	= 2,
67550ec8422SSamuel Holland 			.rates		= SUN8I_CODEC_PCM_RATES,
67650ec8422SSamuel Holland 			.formats	= SUN8I_CODEC_PCM_FORMATS,
67750ec8422SSamuel Holland 			.sig_bits	= 24,
67850ec8422SSamuel Holland 		},
67950ec8422SSamuel Holland 		/* playback capabilities */
68050ec8422SSamuel Holland 		.playback = {
68150ec8422SSamuel Holland 			.stream_name	= "AIF2 Playback",
68250ec8422SSamuel Holland 			.channels_min	= 1,
68350ec8422SSamuel Holland 			.channels_max	= 2,
68450ec8422SSamuel Holland 			.rates		= SUN8I_CODEC_PCM_RATES,
68550ec8422SSamuel Holland 			.formats	= SUN8I_CODEC_PCM_FORMATS,
68650ec8422SSamuel Holland 		},
68781385708SKuninori Morimoto 		.symmetric_rate		= true,
68850ec8422SSamuel Holland 		.symmetric_channels	= true,
68981385708SKuninori Morimoto 		.symmetric_sample_bits	= true,
69050ec8422SSamuel Holland 	},
6915a7f34abSSamuel Holland 	{
6925a7f34abSSamuel Holland 		.name	= "sun8i-codec-aif3",
6935a7f34abSSamuel Holland 		.id	= SUN8I_CODEC_AIF3,
6945a7f34abSSamuel Holland 		.ops	= &sun8i_codec_dai_ops,
6955a7f34abSSamuel Holland 		/* capture capabilities */
6965a7f34abSSamuel Holland 		.capture = {
6975a7f34abSSamuel Holland 			.stream_name	= "AIF3 Capture",
6985a7f34abSSamuel Holland 			.channels_min	= 1,
6995a7f34abSSamuel Holland 			.channels_max	= 1,
7005a7f34abSSamuel Holland 			.rates		= SUN8I_CODEC_PCM_RATES,
7015a7f34abSSamuel Holland 			.formats	= SUN8I_CODEC_PCM_FORMATS,
7025a7f34abSSamuel Holland 			.sig_bits	= 24,
7035a7f34abSSamuel Holland 		},
7045a7f34abSSamuel Holland 		/* playback capabilities */
7055a7f34abSSamuel Holland 		.playback = {
7065a7f34abSSamuel Holland 			.stream_name	= "AIF3 Playback",
7075a7f34abSSamuel Holland 			.channels_min	= 1,
7085a7f34abSSamuel Holland 			.channels_max	= 1,
7095a7f34abSSamuel Holland 			.rates		= SUN8I_CODEC_PCM_RATES,
7105a7f34abSSamuel Holland 			.formats	= SUN8I_CODEC_PCM_FORMATS,
7115a7f34abSSamuel Holland 		},
71281385708SKuninori Morimoto 		.symmetric_rate		= true,
7135a7f34abSSamuel Holland 		.symmetric_channels	= true,
71481385708SKuninori Morimoto 		.symmetric_sample_bits	= true,
7155a7f34abSSamuel Holland 	},
7167826b8d1SSamuel Holland };
7177826b8d1SSamuel Holland 
718fd03cf7fSSamuel Holland static const DECLARE_TLV_DB_SCALE(sun8i_codec_vol_scale, -12000, 75, 1);
719fd03cf7fSSamuel Holland 
720fd03cf7fSSamuel Holland static const struct snd_kcontrol_new sun8i_codec_controls[] = {
721fd03cf7fSSamuel Holland 	SOC_DOUBLE_TLV("AIF1 AD0 Capture Volume",
722fd03cf7fSSamuel Holland 		       SUN8I_AIF1_VOL_CTRL1,
723fd03cf7fSSamuel Holland 		       SUN8I_AIF1_VOL_CTRL1_AD0L_VOL,
724fd03cf7fSSamuel Holland 		       SUN8I_AIF1_VOL_CTRL1_AD0R_VOL,
725fd03cf7fSSamuel Holland 		       0xc0, 0, sun8i_codec_vol_scale),
726fd03cf7fSSamuel Holland 	SOC_DOUBLE_TLV("AIF1 DA0 Playback Volume",
727fd03cf7fSSamuel Holland 		       SUN8I_AIF1_VOL_CTRL3,
728fd03cf7fSSamuel Holland 		       SUN8I_AIF1_VOL_CTRL3_DA0L_VOL,
729fd03cf7fSSamuel Holland 		       SUN8I_AIF1_VOL_CTRL3_DA0R_VOL,
730fd03cf7fSSamuel Holland 		       0xc0, 0, sun8i_codec_vol_scale),
731fd03cf7fSSamuel Holland 	SOC_DOUBLE_TLV("AIF2 ADC Capture Volume",
732fd03cf7fSSamuel Holland 		       SUN8I_AIF2_VOL_CTRL1,
733fd03cf7fSSamuel Holland 		       SUN8I_AIF2_VOL_CTRL1_ADCL_VOL,
734fd03cf7fSSamuel Holland 		       SUN8I_AIF2_VOL_CTRL1_ADCR_VOL,
735fd03cf7fSSamuel Holland 		       0xc0, 0, sun8i_codec_vol_scale),
736fd03cf7fSSamuel Holland 	SOC_DOUBLE_TLV("AIF2 DAC Playback Volume",
737fd03cf7fSSamuel Holland 		       SUN8I_AIF2_VOL_CTRL2,
738fd03cf7fSSamuel Holland 		       SUN8I_AIF2_VOL_CTRL2_DACL_VOL,
739fd03cf7fSSamuel Holland 		       SUN8I_AIF2_VOL_CTRL2_DACR_VOL,
740fd03cf7fSSamuel Holland 		       0xc0, 0, sun8i_codec_vol_scale),
741fd03cf7fSSamuel Holland 	SOC_DOUBLE_TLV("ADC Capture Volume",
742fd03cf7fSSamuel Holland 		       SUN8I_ADC_VOL_CTRL,
743fd03cf7fSSamuel Holland 		       SUN8I_ADC_VOL_CTRL_ADCL_VOL,
744fd03cf7fSSamuel Holland 		       SUN8I_ADC_VOL_CTRL_ADCR_VOL,
745fd03cf7fSSamuel Holland 		       0xc0, 0, sun8i_codec_vol_scale),
746fd03cf7fSSamuel Holland 	SOC_DOUBLE_TLV("DAC Playback Volume",
747fd03cf7fSSamuel Holland 		       SUN8I_DAC_VOL_CTRL,
748fd03cf7fSSamuel Holland 		       SUN8I_DAC_VOL_CTRL_DACL_VOL,
749fd03cf7fSSamuel Holland 		       SUN8I_DAC_VOL_CTRL_DACR_VOL,
750fd03cf7fSSamuel Holland 		       0xc0, 0, sun8i_codec_vol_scale),
751fd03cf7fSSamuel Holland };
752fd03cf7fSSamuel Holland 
sun8i_codec_aif_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)7536c5326beSSamuel Holland static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
7546c5326beSSamuel Holland 				 struct snd_kcontrol *kcontrol, int event)
7556c5326beSSamuel Holland {
7566c5326beSSamuel Holland 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
7576c5326beSSamuel Holland 	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
7586c5326beSSamuel Holland 	struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
7596c5326beSSamuel Holland 	int stream = w->id == snd_soc_dapm_aif_out;
7606c5326beSSamuel Holland 
7616c5326beSSamuel Holland 	if (SND_SOC_DAPM_EVENT_ON(event))
7626c5326beSSamuel Holland 		aif->active_streams |= BIT(stream);
7636c5326beSSamuel Holland 	else
7646c5326beSSamuel Holland 		aif->active_streams &= ~BIT(stream);
7656c5326beSSamuel Holland 
7666c5326beSSamuel Holland 	return sun8i_codec_update_sample_rate(scodec);
7676c5326beSSamuel Holland }
7686c5326beSSamuel Holland 
76918ebd62cSSamuel Holland static const char *const sun8i_aif_stereo_mux_enum_values[] = {
77018ebd62cSSamuel Holland 	"Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono"
77118ebd62cSSamuel Holland };
77218ebd62cSSamuel Holland 
77318ebd62cSSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
77418ebd62cSSamuel Holland 			    SUN8I_AIF1_ADCDAT_CTRL,
77518ebd62cSSamuel Holland 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC,
77618ebd62cSSamuel Holland 			    SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC,
77718ebd62cSSamuel Holland 			    sun8i_aif_stereo_mux_enum_values);
77818ebd62cSSamuel Holland 
77918ebd62cSSamuel Holland static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control =
78018ebd62cSSamuel Holland 	SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route",
78118ebd62cSSamuel Holland 		      sun8i_aif1_ad0_stereo_mux_enum);
78218ebd62cSSamuel Holland 
78350ec8422SSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum,
78450ec8422SSamuel Holland 			    SUN8I_AIF2_ADCDAT_CTRL,
78550ec8422SSamuel Holland 			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC,
78650ec8422SSamuel Holland 			    SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC,
78750ec8422SSamuel Holland 			    sun8i_aif_stereo_mux_enum_values);
78850ec8422SSamuel Holland 
78950ec8422SSamuel Holland static const struct snd_kcontrol_new sun8i_aif2_adc_stereo_mux_control =
79050ec8422SSamuel Holland 	SOC_DAPM_ENUM("AIF2 ADC Stereo Capture Route",
79150ec8422SSamuel Holland 		      sun8i_aif2_adc_stereo_mux_enum);
79250ec8422SSamuel Holland 
7935a7f34abSSamuel Holland static const char *const sun8i_aif3_adc_mux_enum_values[] = {
7945a7f34abSSamuel Holland 	"None", "AIF2 ADCL", "AIF2 ADCR"
7955a7f34abSSamuel Holland };
7965a7f34abSSamuel Holland 
7975a7f34abSSamuel Holland static SOC_ENUM_SINGLE_DECL(sun8i_aif3_adc_mux_enum,
7985a7f34abSSamuel Holland 			    SUN8I_AIF3_PATH_CTRL,
7995a7f34abSSamuel Holland 			    SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC,
8005a7f34abSSamuel Holland 			    sun8i_aif3_adc_mux_enum_values);
8015a7f34abSSamuel Holland 
8025a7f34abSSamuel Holland static const struct snd_kcontrol_new sun8i_aif3_adc_mux_control =
8035a7f34abSSamuel Holland 	SOC_DAPM_ENUM("AIF3 ADC Source Capture Route",
8045a7f34abSSamuel Holland 		      sun8i_aif3_adc_mux_enum);
8055a7f34abSSamuel Holland 
806d58b7247SSamuel Holland static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
807d58b7247SSamuel Holland 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
808d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC,
809d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L,
810d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
811d58b7247SSamuel Holland 	SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch",
812d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC,
813d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL,
814d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
815d58b7247SSamuel Holland 	SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
816d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC,
817d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL,
818d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
819d58b7247SSamuel Holland 	SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
820d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC,
821d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR,
822d58b7247SSamuel Holland 			SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
823d58b7247SSamuel Holland };
824d58b7247SSamuel Holland 
82550ec8422SSamuel Holland static const struct snd_kcontrol_new sun8i_aif2_adc_mixer_controls[] = {
82650ec8422SSamuel Holland 	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch",
82750ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC,
82850ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L,
82950ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R, 1, 0),
83050ec8422SSamuel Holland 	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch",
83150ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC,
83250ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L,
83350ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R, 1, 0),
83450ec8422SSamuel Holland 	SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch",
83550ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC,
83650ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR,
83750ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL, 1, 0),
83850ec8422SSamuel Holland 	SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch",
83950ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC,
84050ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL,
84150ec8422SSamuel Holland 			SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR, 1, 0),
84250ec8422SSamuel Holland };
84350ec8422SSamuel Holland 
84450ec8422SSamuel Holland static const char *const sun8i_aif2_dac_mux_enum_values[] = {
84550ec8422SSamuel Holland 	"AIF2", "AIF3+2", "AIF2+3"
84650ec8422SSamuel Holland };
84750ec8422SSamuel Holland 
84850ec8422SSamuel Holland static SOC_ENUM_SINGLE_DECL(sun8i_aif2_dac_mux_enum,
84950ec8422SSamuel Holland 			    SUN8I_AIF3_PATH_CTRL,
85050ec8422SSamuel Holland 			    SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC,
85150ec8422SSamuel Holland 			    sun8i_aif2_dac_mux_enum_values);
85250ec8422SSamuel Holland 
85350ec8422SSamuel Holland static const struct snd_kcontrol_new sun8i_aif2_dac_mux_control =
85450ec8422SSamuel Holland 	SOC_DAPM_ENUM("AIF2 DAC Source Playback Route",
85550ec8422SSamuel Holland 		      sun8i_aif2_dac_mux_enum);
85650ec8422SSamuel Holland 
85718ebd62cSSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum,
85818ebd62cSSamuel Holland 			    SUN8I_AIF1_DACDAT_CTRL,
85918ebd62cSSamuel Holland 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC,
86018ebd62cSSamuel Holland 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC,
86118ebd62cSSamuel Holland 			    sun8i_aif_stereo_mux_enum_values);
86218ebd62cSSamuel Holland 
86318ebd62cSSamuel Holland static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control =
86418ebd62cSSamuel Holland 	SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route",
86518ebd62cSSamuel Holland 		      sun8i_aif1_da0_stereo_mux_enum);
86618ebd62cSSamuel Holland 
86750ec8422SSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_dac_stereo_mux_enum,
86850ec8422SSamuel Holland 			    SUN8I_AIF2_DACDAT_CTRL,
86950ec8422SSamuel Holland 			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC,
87050ec8422SSamuel Holland 			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC,
87150ec8422SSamuel Holland 			    sun8i_aif_stereo_mux_enum_values);
87250ec8422SSamuel Holland 
87350ec8422SSamuel Holland static const struct snd_kcontrol_new sun8i_aif2_dac_stereo_mux_control =
87450ec8422SSamuel Holland 	SOC_DAPM_ENUM("AIF2 DAC Stereo Playback Route",
87550ec8422SSamuel Holland 		      sun8i_aif2_dac_stereo_mux_enum);
87650ec8422SSamuel Holland 
877ca14da6eSMylène Josserand static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
878ca14da6eSMylène Josserand 	SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
879ca14da6eSMylène Josserand 			SUN8I_DAC_MXR_SRC,
880ca14da6eSMylène Josserand 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
88136c68493SMylène Josserand 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
882ca14da6eSMylène Josserand 	SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
883ca14da6eSMylène Josserand 			SUN8I_DAC_MXR_SRC,
884ca14da6eSMylène Josserand 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
88536c68493SMylène Josserand 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0),
886ca14da6eSMylène Josserand 	SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
887ca14da6eSMylène Josserand 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
88836c68493SMylène Josserand 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
889ca14da6eSMylène Josserand 	SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
890ca14da6eSMylène Josserand 			SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
89136c68493SMylène Josserand 			SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
89236c68493SMylène Josserand };
89336c68493SMylène Josserand 
89436c68493SMylène Josserand static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
895d8f00682SSamuel Holland 	/* System Clocks */
8966b3bb3c8SSamuel Holland 	SND_SOC_DAPM_CLOCK_SUPPLY("mod"),
8976b3bb3c8SSamuel Holland 
898d8f00682SSamuel Holland 	SND_SOC_DAPM_SUPPLY("AIF1CLK",
899d8f00682SSamuel Holland 			    SUN8I_SYSCLK_CTL,
900d8f00682SSamuel Holland 			    SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
90150ec8422SSamuel Holland 	SND_SOC_DAPM_SUPPLY("AIF2CLK",
90250ec8422SSamuel Holland 			    SUN8I_SYSCLK_CTL,
90350ec8422SSamuel Holland 			    SUN8I_SYSCLK_CTL_AIF2CLK_ENA, 0, NULL, 0),
904d8f00682SSamuel Holland 	SND_SOC_DAPM_SUPPLY("SYSCLK",
905d8f00682SSamuel Holland 			    SUN8I_SYSCLK_CTL,
906d8f00682SSamuel Holland 			    SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
907d8f00682SSamuel Holland 
908ed3caa3bSSamuel Holland 	/* Module Clocks */
909ed3caa3bSSamuel Holland 	SND_SOC_DAPM_SUPPLY("CLK AIF1",
910ed3caa3bSSamuel Holland 			    SUN8I_MOD_CLK_ENA,
911ed3caa3bSSamuel Holland 			    SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
91250ec8422SSamuel Holland 	SND_SOC_DAPM_SUPPLY("CLK AIF2",
91350ec8422SSamuel Holland 			    SUN8I_MOD_CLK_ENA,
91450ec8422SSamuel Holland 			    SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0),
9155a7f34abSSamuel Holland 	SND_SOC_DAPM_SUPPLY("CLK AIF3",
9165a7f34abSSamuel Holland 			    SUN8I_MOD_CLK_ENA,
9175a7f34abSSamuel Holland 			    SUN8I_MOD_CLK_ENA_AIF3, 0, NULL, 0),
918ed3caa3bSSamuel Holland 	SND_SOC_DAPM_SUPPLY("CLK ADC",
919ed3caa3bSSamuel Holland 			    SUN8I_MOD_CLK_ENA,
920ed3caa3bSSamuel Holland 			    SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
921ed3caa3bSSamuel Holland 	SND_SOC_DAPM_SUPPLY("CLK DAC",
922ed3caa3bSSamuel Holland 			    SUN8I_MOD_CLK_ENA,
923ed3caa3bSSamuel Holland 			    SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
924ed3caa3bSSamuel Holland 
925ed3caa3bSSamuel Holland 	/* Module Resets */
926ed3caa3bSSamuel Holland 	SND_SOC_DAPM_SUPPLY("RST AIF1",
927ed3caa3bSSamuel Holland 			    SUN8I_MOD_RST_CTL,
928ed3caa3bSSamuel Holland 			    SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
92950ec8422SSamuel Holland 	SND_SOC_DAPM_SUPPLY("RST AIF2",
93050ec8422SSamuel Holland 			    SUN8I_MOD_RST_CTL,
93150ec8422SSamuel Holland 			    SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0),
9325a7f34abSSamuel Holland 	SND_SOC_DAPM_SUPPLY("RST AIF3",
9335a7f34abSSamuel Holland 			    SUN8I_MOD_RST_CTL,
9345a7f34abSSamuel Holland 			    SUN8I_MOD_RST_CTL_AIF3, 0, NULL, 0),
935ed3caa3bSSamuel Holland 	SND_SOC_DAPM_SUPPLY("RST ADC",
936ed3caa3bSSamuel Holland 			    SUN8I_MOD_RST_CTL,
937ed3caa3bSSamuel Holland 			    SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
938ed3caa3bSSamuel Holland 	SND_SOC_DAPM_SUPPLY("RST DAC",
939ed3caa3bSSamuel Holland 			    SUN8I_MOD_RST_CTL,
940ed3caa3bSSamuel Holland 			    SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
941ed3caa3bSSamuel Holland 
942d58b7247SSamuel Holland 	/* Module Supplies */
943d58b7247SSamuel Holland 	SND_SOC_DAPM_SUPPLY("ADC",
944d58b7247SSamuel Holland 			    SUN8I_ADC_DIG_CTRL,
945d58b7247SSamuel Holland 			    SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0),
946d58b7247SSamuel Holland 	SND_SOC_DAPM_SUPPLY("DAC",
947d58b7247SSamuel Holland 			    SUN8I_DAC_DIG_CTRL,
948d58b7247SSamuel Holland 			    SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0),
94936c68493SMylène Josserand 
95090cac932SSamuel Holland 	/* AIF "ADC" Outputs */
9516c5326beSSamuel Holland 	SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
952eda85d1fSMylene JOSSERAND 			       SUN8I_AIF1_ADCDAT_CTRL,
9536c5326beSSamuel Holland 			       SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
9546c5326beSSamuel Holland 			       sun8i_codec_aif_event,
9556c5326beSSamuel Holland 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
9567826b8d1SSamuel Holland 	SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
957eda85d1fSMylene JOSSERAND 			     SUN8I_AIF1_ADCDAT_CTRL,
958fa5c0ca1SSamuel Holland 			     SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
959eda85d1fSMylene JOSSERAND 
96050ec8422SSamuel Holland 	SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0,
96150ec8422SSamuel Holland 			       SUN8I_AIF2_ADCDAT_CTRL,
96250ec8422SSamuel Holland 			       SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
96350ec8422SSamuel Holland 			       sun8i_codec_aif_event,
96450ec8422SSamuel Holland 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
96550ec8422SSamuel Holland 	SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
96650ec8422SSamuel Holland 			     SUN8I_AIF2_ADCDAT_CTRL,
96750ec8422SSamuel Holland 			     SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0),
96850ec8422SSamuel Holland 
9695a7f34abSSamuel Holland 	SND_SOC_DAPM_AIF_OUT_E("AIF3 ADC", "AIF3 Capture", 0,
9705a7f34abSSamuel Holland 			       SND_SOC_NOPM, 0, 0,
9715a7f34abSSamuel Holland 			       sun8i_codec_aif_event,
9725a7f34abSSamuel Holland 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
9735a7f34abSSamuel Holland 
97418ebd62cSSamuel Holland 	/* AIF "ADC" Mono/Stereo Muxes */
97518ebd62cSSamuel Holland 	SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0,
97618ebd62cSSamuel Holland 			 &sun8i_aif1_ad0_stereo_mux_control),
97718ebd62cSSamuel Holland 	SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0,
97818ebd62cSSamuel Holland 			 &sun8i_aif1_ad0_stereo_mux_control),
97918ebd62cSSamuel Holland 
98050ec8422SSamuel Holland 	SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
98150ec8422SSamuel Holland 			 &sun8i_aif2_adc_stereo_mux_control),
98250ec8422SSamuel Holland 	SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
98350ec8422SSamuel Holland 			 &sun8i_aif2_adc_stereo_mux_control),
98450ec8422SSamuel Holland 
9855a7f34abSSamuel Holland 	/* AIF "ADC" Output Muxes */
9865a7f34abSSamuel Holland 	SND_SOC_DAPM_MUX("AIF3 ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
9875a7f34abSSamuel Holland 			 &sun8i_aif3_adc_mux_control),
9885a7f34abSSamuel Holland 
989d58b7247SSamuel Holland 	/* AIF "ADC" Mixers */
9907b51f3c7SSamuel Holland 	SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
991d58b7247SSamuel Holland 			sun8i_aif1_ad0_mixer_controls),
9927b51f3c7SSamuel Holland 	SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
993d58b7247SSamuel Holland 			sun8i_aif1_ad0_mixer_controls),
994d58b7247SSamuel Holland 
99550ec8422SSamuel Holland 	SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
99650ec8422SSamuel Holland 			sun8i_aif2_adc_mixer_controls),
99750ec8422SSamuel Holland 	SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0,
99850ec8422SSamuel Holland 			sun8i_aif2_adc_mixer_controls),
99950ec8422SSamuel Holland 
100050ec8422SSamuel Holland 	/* AIF "DAC" Input Muxes */
100150ec8422SSamuel Holland 	SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0,
100250ec8422SSamuel Holland 			 &sun8i_aif2_dac_mux_control),
100350ec8422SSamuel Holland 	SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0,
100450ec8422SSamuel Holland 			 &sun8i_aif2_dac_mux_control),
100550ec8422SSamuel Holland 
100618ebd62cSSamuel Holland 	/* AIF "DAC" Mono/Stereo Muxes */
100718ebd62cSSamuel Holland 	SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0,
100818ebd62cSSamuel Holland 			 &sun8i_aif1_da0_stereo_mux_control),
100918ebd62cSSamuel Holland 	SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0,
101018ebd62cSSamuel Holland 			 &sun8i_aif1_da0_stereo_mux_control),
101118ebd62cSSamuel Holland 
101250ec8422SSamuel Holland 	SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0,
101350ec8422SSamuel Holland 			 &sun8i_aif2_dac_stereo_mux_control),
101450ec8422SSamuel Holland 	SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0,
101550ec8422SSamuel Holland 			 &sun8i_aif2_dac_stereo_mux_control),
101650ec8422SSamuel Holland 
1017d58b7247SSamuel Holland 	/* AIF "DAC" Inputs */
10186c5326beSSamuel Holland 	SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
1019d58b7247SSamuel Holland 			      SUN8I_AIF1_DACDAT_CTRL,
10206c5326beSSamuel Holland 			      SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
10216c5326beSSamuel Holland 			      sun8i_codec_aif_event,
10226c5326beSSamuel Holland 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
10237826b8d1SSamuel Holland 	SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
1024d58b7247SSamuel Holland 			    SUN8I_AIF1_DACDAT_CTRL,
1025d58b7247SSamuel Holland 			    SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
1026d58b7247SSamuel Holland 
102750ec8422SSamuel Holland 	SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0,
102850ec8422SSamuel Holland 			      SUN8I_AIF2_DACDAT_CTRL,
102950ec8422SSamuel Holland 			      SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
103050ec8422SSamuel Holland 			      sun8i_codec_aif_event,
103150ec8422SSamuel Holland 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
103250ec8422SSamuel Holland 	SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
103350ec8422SSamuel Holland 			    SUN8I_AIF2_DACDAT_CTRL,
103450ec8422SSamuel Holland 			    SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0),
103550ec8422SSamuel Holland 
10365a7f34abSSamuel Holland 	SND_SOC_DAPM_AIF_IN_E("AIF3 DAC", "AIF3 Playback", 0,
10375a7f34abSSamuel Holland 			      SND_SOC_NOPM, 0, 0,
10385a7f34abSSamuel Holland 			      sun8i_codec_aif_event,
10395a7f34abSSamuel Holland 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
10405a7f34abSSamuel Holland 
104190cac932SSamuel Holland 	/* ADC Inputs (connected to analog codec DAPM context) */
104290cac932SSamuel Holland 	SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
104390cac932SSamuel Holland 	SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
104490cac932SSamuel Holland 
104590cac932SSamuel Holland 	/* DAC Outputs (connected to analog codec DAPM context) */
104690cac932SSamuel Holland 	SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
104790cac932SSamuel Holland 	SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
104890cac932SSamuel Holland 
1049d58b7247SSamuel Holland 	/* DAC Mixers */
10507b51f3c7SSamuel Holland 	SOC_MIXER_ARRAY("DACL Mixer", SND_SOC_NOPM, 0, 0,
1051fa22ca4fSMylène Josserand 			sun8i_dac_mixer_controls),
10527b51f3c7SSamuel Holland 	SOC_MIXER_ARRAY("DACR Mixer", SND_SOC_NOPM, 0, 0,
1053fa22ca4fSMylène Josserand 			sun8i_dac_mixer_controls),
105436c68493SMylène Josserand };
105536c68493SMylène Josserand 
105636c68493SMylène Josserand static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
105736c68493SMylène Josserand 	/* Clock Routes */
1058d8f00682SSamuel Holland 	{ "AIF1CLK", NULL, "mod" },
10596b3bb3c8SSamuel Holland 
1060d8f00682SSamuel Holland 	{ "SYSCLK", NULL, "AIF1CLK" },
106190cac932SSamuel Holland 
1062ed3caa3bSSamuel Holland 	{ "CLK AIF1", NULL, "AIF1CLK" },
1063ed3caa3bSSamuel Holland 	{ "CLK AIF1", NULL, "SYSCLK" },
1064ed3caa3bSSamuel Holland 	{ "RST AIF1", NULL, "CLK AIF1" },
1065ed3caa3bSSamuel Holland 	{ "AIF1 AD0L", NULL, "RST AIF1" },
1066ed3caa3bSSamuel Holland 	{ "AIF1 AD0R", NULL, "RST AIF1" },
1067ed3caa3bSSamuel Holland 	{ "AIF1 DA0L", NULL, "RST AIF1" },
1068ed3caa3bSSamuel Holland 	{ "AIF1 DA0R", NULL, "RST AIF1" },
106936c68493SMylène Josserand 
107050ec8422SSamuel Holland 	{ "CLK AIF2", NULL, "AIF2CLK" },
107150ec8422SSamuel Holland 	{ "CLK AIF2", NULL, "SYSCLK" },
107250ec8422SSamuel Holland 	{ "RST AIF2", NULL, "CLK AIF2" },
107350ec8422SSamuel Holland 	{ "AIF2 ADCL", NULL, "RST AIF2" },
107450ec8422SSamuel Holland 	{ "AIF2 ADCR", NULL, "RST AIF2" },
107550ec8422SSamuel Holland 	{ "AIF2 DACL", NULL, "RST AIF2" },
107650ec8422SSamuel Holland 	{ "AIF2 DACR", NULL, "RST AIF2" },
107750ec8422SSamuel Holland 
10785a7f34abSSamuel Holland 	{ "CLK AIF3", NULL, "AIF1CLK" },
10795a7f34abSSamuel Holland 	{ "CLK AIF3", NULL, "SYSCLK" },
10805a7f34abSSamuel Holland 	{ "RST AIF3", NULL, "CLK AIF3" },
10815a7f34abSSamuel Holland 	{ "AIF3 ADC", NULL, "RST AIF3" },
10825a7f34abSSamuel Holland 	{ "AIF3 DAC", NULL, "RST AIF3" },
10835a7f34abSSamuel Holland 
1084ed3caa3bSSamuel Holland 	{ "CLK ADC", NULL, "SYSCLK" },
1085ed3caa3bSSamuel Holland 	{ "RST ADC", NULL, "CLK ADC" },
1086ed3caa3bSSamuel Holland 	{ "ADC", NULL, "RST ADC" },
108790cac932SSamuel Holland 	{ "ADCL", NULL, "ADC" },
108890cac932SSamuel Holland 	{ "ADCR", NULL, "ADC" },
1089eda85d1fSMylene JOSSERAND 
1090ed3caa3bSSamuel Holland 	{ "CLK DAC", NULL, "SYSCLK" },
1091ed3caa3bSSamuel Holland 	{ "RST DAC", NULL, "CLK DAC" },
1092ed3caa3bSSamuel Holland 	{ "DAC", NULL, "RST DAC" },
1093ed3caa3bSSamuel Holland 	{ "DACL", NULL, "DAC" },
1094ed3caa3bSSamuel Holland 	{ "DACR", NULL, "DAC" },
1095ed3caa3bSSamuel Holland 
1096d58b7247SSamuel Holland 	/* AIF "ADC" Output Routes */
109718ebd62cSSamuel Holland 	{ "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
109818ebd62cSSamuel Holland 	{ "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
109918ebd62cSSamuel Holland 
110050ec8422SSamuel Holland 	{ "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
110150ec8422SSamuel Holland 	{ "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" },
110250ec8422SSamuel Holland 
11035a7f34abSSamuel Holland 	{ "AIF3 ADC", NULL, "AIF3 ADC Source Capture Route" },
11045a7f34abSSamuel Holland 
110518ebd62cSSamuel Holland 	/* AIF "ADC" Mono/Stereo Mux Routes */
110618ebd62cSSamuel Holland 	{ "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" },
110718ebd62cSSamuel Holland 	{ "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" },
110818ebd62cSSamuel Holland 	{ "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
110918ebd62cSSamuel Holland 	{ "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
111018ebd62cSSamuel Holland 	{ "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
111118ebd62cSSamuel Holland 	{ "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
111218ebd62cSSamuel Holland 
111318ebd62cSSamuel Holland 	{ "AIF1 AD0R Stereo Mux", "Stereo", "AIF1 AD0R Mixer" },
111418ebd62cSSamuel Holland 	{ "AIF1 AD0R Stereo Mux", "Reverse Stereo", "AIF1 AD0L Mixer" },
111518ebd62cSSamuel Holland 	{ "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
111618ebd62cSSamuel Holland 	{ "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
111718ebd62cSSamuel Holland 	{ "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
111818ebd62cSSamuel Holland 	{ "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
1119d58b7247SSamuel Holland 
112050ec8422SSamuel Holland 	{ "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" },
112150ec8422SSamuel Holland 	{ "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" },
112250ec8422SSamuel Holland 	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
112350ec8422SSamuel Holland 	{ "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
112450ec8422SSamuel Holland 	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
112550ec8422SSamuel Holland 	{ "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
112650ec8422SSamuel Holland 
112750ec8422SSamuel Holland 	{ "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
112850ec8422SSamuel Holland 	{ "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
112950ec8422SSamuel Holland 	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
113050ec8422SSamuel Holland 	{ "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
113150ec8422SSamuel Holland 	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
113250ec8422SSamuel Holland 	{ "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
113350ec8422SSamuel Holland 
11345a7f34abSSamuel Holland 	/* AIF "ADC" Output Mux Routes */
11355a7f34abSSamuel Holland 	{ "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" },
11365a7f34abSSamuel Holland 	{ "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" },
11375a7f34abSSamuel Holland 
1138d58b7247SSamuel Holland 	/* AIF "ADC" Mixer Routes */
113918ebd62cSSamuel Holland 	{ "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
114050ec8422SSamuel Holland 	{ "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
11417b51f3c7SSamuel Holland 	{ "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
114250ec8422SSamuel Holland 	{ "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
1143d58b7247SSamuel Holland 
114418ebd62cSSamuel Holland 	{ "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
114550ec8422SSamuel Holland 	{ "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
11467b51f3c7SSamuel Holland 	{ "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
114750ec8422SSamuel Holland 	{ "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" },
114850ec8422SSamuel Holland 
114950ec8422SSamuel Holland 	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" },
115050ec8422SSamuel Holland 	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" },
115150ec8422SSamuel Holland 	{ "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
115250ec8422SSamuel Holland 
115350ec8422SSamuel Holland 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
115450ec8422SSamuel Holland 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
115550ec8422SSamuel Holland 	{ "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
115650ec8422SSamuel Holland 
115750ec8422SSamuel Holland 	/* AIF "DAC" Input Mux Routes */
115850ec8422SSamuel Holland 	{ "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
11595a7f34abSSamuel Holland 	{ "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" },
116050ec8422SSamuel Holland 	{ "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
116150ec8422SSamuel Holland 
116250ec8422SSamuel Holland 	{ "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
116350ec8422SSamuel Holland 	{ "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
11645a7f34abSSamuel Holland 	{ "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" },
1165d58b7247SSamuel Holland 
116618ebd62cSSamuel Holland 	/* AIF "DAC" Mono/Stereo Mux Routes */
116718ebd62cSSamuel Holland 	{ "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" },
116818ebd62cSSamuel Holland 	{ "AIF1 DA0L Stereo Mux", "Reverse Stereo", "AIF1 DA0R" },
116918ebd62cSSamuel Holland 	{ "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0L" },
117018ebd62cSSamuel Holland 	{ "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0R" },
117118ebd62cSSamuel Holland 	{ "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0L" },
117218ebd62cSSamuel Holland 	{ "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0R" },
117318ebd62cSSamuel Holland 
117418ebd62cSSamuel Holland 	{ "AIF1 DA0R Stereo Mux", "Stereo", "AIF1 DA0R" },
117518ebd62cSSamuel Holland 	{ "AIF1 DA0R Stereo Mux", "Reverse Stereo", "AIF1 DA0L" },
117618ebd62cSSamuel Holland 	{ "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0L" },
117718ebd62cSSamuel Holland 	{ "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0R" },
117818ebd62cSSamuel Holland 	{ "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" },
117918ebd62cSSamuel Holland 	{ "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" },
118018ebd62cSSamuel Holland 
118150ec8422SSamuel Holland 	{ "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" },
118250ec8422SSamuel Holland 	{ "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" },
118350ec8422SSamuel Holland 	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" },
118450ec8422SSamuel Holland 	{ "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" },
118550ec8422SSamuel Holland 	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" },
118650ec8422SSamuel Holland 	{ "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" },
118750ec8422SSamuel Holland 
118850ec8422SSamuel Holland 	{ "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" },
118950ec8422SSamuel Holland 	{ "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" },
119050ec8422SSamuel Holland 	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" },
119150ec8422SSamuel Holland 	{ "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" },
119250ec8422SSamuel Holland 	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" },
119350ec8422SSamuel Holland 	{ "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" },
119450ec8422SSamuel Holland 
1195d58b7247SSamuel Holland 	/* DAC Output Routes */
11967b51f3c7SSamuel Holland 	{ "DACL", NULL, "DACL Mixer" },
11977b51f3c7SSamuel Holland 	{ "DACR", NULL, "DACR Mixer" },
119836c68493SMylène Josserand 
119936c68493SMylène Josserand 	/* DAC Mixer Routes */
120018ebd62cSSamuel Holland 	{ "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
120150ec8422SSamuel Holland 	{ "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" },
12027b51f3c7SSamuel Holland 	{ "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
1203e47d2dcdSSamuel Holland 
120418ebd62cSSamuel Holland 	{ "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
120550ec8422SSamuel Holland 	{ "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" },
12067b51f3c7SSamuel Holland 	{ "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
120736c68493SMylène Josserand };
120836c68493SMylène Josserand 
120990cac932SSamuel Holland static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = {
121090cac932SSamuel Holland 	/* Legacy ADC Inputs (connected to analog codec DAPM context) */
121190cac932SSamuel Holland 	SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0),
121290cac932SSamuel Holland 	SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0),
121390cac932SSamuel Holland 
121490cac932SSamuel Holland 	/* Legacy DAC Outputs (connected to analog codec DAPM context) */
121590cac932SSamuel Holland 	SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0),
121690cac932SSamuel Holland 	SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0),
121790cac932SSamuel Holland };
121890cac932SSamuel Holland 
121990cac932SSamuel Holland static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = {
122090cac932SSamuel Holland 	/* Legacy ADC Routes */
122190cac932SSamuel Holland 	{ "ADCL", NULL, "AIF1 Slot 0 Left ADC" },
122290cac932SSamuel Holland 	{ "ADCR", NULL, "AIF1 Slot 0 Right ADC" },
122390cac932SSamuel Holland 
122490cac932SSamuel Holland 	/* Legacy DAC Routes */
122590cac932SSamuel Holland 	{ "AIF1 Slot 0 Left", NULL, "DACL" },
122690cac932SSamuel Holland 	{ "AIF1 Slot 0 Right", NULL, "DACR" },
122790cac932SSamuel Holland };
122890cac932SSamuel Holland 
sun8i_codec_component_probe(struct snd_soc_component * component)122990cac932SSamuel Holland static int sun8i_codec_component_probe(struct snd_soc_component *component)
123090cac932SSamuel Holland {
123190cac932SSamuel Holland 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
123290cac932SSamuel Holland 	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
123390cac932SSamuel Holland 	int ret;
123490cac932SSamuel Holland 
123590cac932SSamuel Holland 	/* Add widgets for backward compatibility with old device trees. */
123690cac932SSamuel Holland 	if (scodec->quirks->legacy_widgets) {
123790cac932SSamuel Holland 		ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets,
123890cac932SSamuel Holland 						ARRAY_SIZE(sun8i_codec_legacy_widgets));
123990cac932SSamuel Holland 		if (ret)
124090cac932SSamuel Holland 			return ret;
124190cac932SSamuel Holland 
124290cac932SSamuel Holland 		ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes,
124390cac932SSamuel Holland 					      ARRAY_SIZE(sun8i_codec_legacy_routes));
124490cac932SSamuel Holland 		if (ret)
124590cac932SSamuel Holland 			return ret;
124690cac932SSamuel Holland 	}
124790cac932SSamuel Holland 
1248d8f00682SSamuel Holland 	/*
1249d8f00682SSamuel Holland 	 * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod")
1250d8f00682SSamuel Holland 	 * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also
1251d8f00682SSamuel Holland 	 * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO
1252d8f00682SSamuel Holland 	 * directly to simplify the clock tree.
1253d8f00682SSamuel Holland 	 */
1254d8f00682SSamuel Holland 	regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
1255d8f00682SSamuel Holland 			   SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK |
1256d8f00682SSamuel Holland 			   SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK,
1257d8f00682SSamuel Holland 			   SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL |
1258d8f00682SSamuel Holland 			   SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL);
1259d8f00682SSamuel Holland 
1260d8f00682SSamuel Holland 	/* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */
1261d8f00682SSamuel Holland 	regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
1262d8f00682SSamuel Holland 			   BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC),
1263d8f00682SSamuel Holland 			   SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK);
1264d8f00682SSamuel Holland 
12656c5326beSSamuel Holland 	/* Program the default sample rate. */
12666c5326beSSamuel Holland 	sun8i_codec_update_sample_rate(scodec);
12676c5326beSSamuel Holland 
126890cac932SSamuel Holland 	return 0;
126990cac932SSamuel Holland }
127090cac932SSamuel Holland 
12717ec9b872SKuninori Morimoto static const struct snd_soc_component_driver sun8i_soc_component = {
1272fd03cf7fSSamuel Holland 	.controls		= sun8i_codec_controls,
1273fd03cf7fSSamuel Holland 	.num_controls		= ARRAY_SIZE(sun8i_codec_controls),
127436c68493SMylène Josserand 	.dapm_widgets		= sun8i_codec_dapm_widgets,
127536c68493SMylène Josserand 	.num_dapm_widgets	= ARRAY_SIZE(sun8i_codec_dapm_widgets),
127636c68493SMylène Josserand 	.dapm_routes		= sun8i_codec_dapm_routes,
127736c68493SMylène Josserand 	.num_dapm_routes	= ARRAY_SIZE(sun8i_codec_dapm_routes),
1278a2f6d303SSamuel Holland 	.probe			= sun8i_codec_component_probe,
12797ec9b872SKuninori Morimoto 	.idle_bias_on		= 1,
12807ec9b872SKuninori Morimoto 	.endianness		= 1,
128136c68493SMylène Josserand };
128236c68493SMylène Josserand 
128336c68493SMylène Josserand static const struct regmap_config sun8i_codec_regmap_config = {
128436c68493SMylène Josserand 	.reg_bits	= 32,
128536c68493SMylène Josserand 	.reg_stride	= 4,
128636c68493SMylène Josserand 	.val_bits	= 32,
128736c68493SMylène Josserand 	.max_register	= SUN8I_DAC_MXR_SRC,
128836c68493SMylène Josserand 
128936c68493SMylène Josserand 	.cache_type	= REGCACHE_FLAT,
129036c68493SMylène Josserand };
129136c68493SMylène Josserand 
sun8i_codec_probe(struct platform_device * pdev)129236c68493SMylène Josserand static int sun8i_codec_probe(struct platform_device *pdev)
129336c68493SMylène Josserand {
129436c68493SMylène Josserand 	struct sun8i_codec *scodec;
129536c68493SMylène Josserand 	void __iomem *base;
129636c68493SMylène Josserand 	int ret;
129736c68493SMylène Josserand 
129836c68493SMylène Josserand 	scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
129936c68493SMylène Josserand 	if (!scodec)
130036c68493SMylène Josserand 		return -ENOMEM;
130136c68493SMylène Josserand 
130236c68493SMylène Josserand 	scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
130336c68493SMylène Josserand 	if (IS_ERR(scodec->clk_module)) {
130436c68493SMylène Josserand 		dev_err(&pdev->dev, "Failed to get the module clock\n");
130536c68493SMylène Josserand 		return PTR_ERR(scodec->clk_module);
130636c68493SMylène Josserand 	}
130736c68493SMylène Josserand 
1308790b3657SYueHaibing 	base = devm_platform_ioremap_resource(pdev, 0);
130936c68493SMylène Josserand 	if (IS_ERR(base)) {
131036c68493SMylène Josserand 		dev_err(&pdev->dev, "Failed to map the registers\n");
131136c68493SMylène Josserand 		return PTR_ERR(base);
131236c68493SMylène Josserand 	}
131336c68493SMylène Josserand 
1314efb736fbSSamuel Holland 	scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base,
131536c68493SMylène Josserand 						   &sun8i_codec_regmap_config);
131636c68493SMylène Josserand 	if (IS_ERR(scodec->regmap)) {
131736c68493SMylène Josserand 		dev_err(&pdev->dev, "Failed to create our regmap\n");
131836c68493SMylène Josserand 		return PTR_ERR(scodec->regmap);
131936c68493SMylène Josserand 	}
132036c68493SMylène Josserand 
132190cac932SSamuel Holland 	scodec->quirks = of_device_get_match_data(&pdev->dev);
132290cac932SSamuel Holland 
132336c68493SMylène Josserand 	platform_set_drvdata(pdev, scodec);
132436c68493SMylène Josserand 
132536c68493SMylène Josserand 	pm_runtime_enable(&pdev->dev);
132636c68493SMylène Josserand 	if (!pm_runtime_enabled(&pdev->dev)) {
132736c68493SMylène Josserand 		ret = sun8i_codec_runtime_resume(&pdev->dev);
132836c68493SMylène Josserand 		if (ret)
132936c68493SMylène Josserand 			goto err_pm_disable;
133036c68493SMylène Josserand 	}
133136c68493SMylène Josserand 
13327ec9b872SKuninori Morimoto 	ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
13337826b8d1SSamuel Holland 					      sun8i_codec_dais,
13347826b8d1SSamuel Holland 					      ARRAY_SIZE(sun8i_codec_dais));
133536c68493SMylène Josserand 	if (ret) {
133636c68493SMylène Josserand 		dev_err(&pdev->dev, "Failed to register codec\n");
133736c68493SMylène Josserand 		goto err_suspend;
133836c68493SMylène Josserand 	}
133936c68493SMylène Josserand 
134036c68493SMylène Josserand 	return ret;
134136c68493SMylène Josserand 
134236c68493SMylène Josserand err_suspend:
134336c68493SMylène Josserand 	if (!pm_runtime_status_suspended(&pdev->dev))
134436c68493SMylène Josserand 		sun8i_codec_runtime_suspend(&pdev->dev);
134536c68493SMylène Josserand 
134636c68493SMylène Josserand err_pm_disable:
134736c68493SMylène Josserand 	pm_runtime_disable(&pdev->dev);
134836c68493SMylène Josserand 
134936c68493SMylène Josserand 	return ret;
135036c68493SMylène Josserand }
135136c68493SMylène Josserand 
sun8i_codec_remove(struct platform_device * pdev)1352*a594f423SUwe Kleine-König static void sun8i_codec_remove(struct platform_device *pdev)
135336c68493SMylène Josserand {
135436c68493SMylène Josserand 	pm_runtime_disable(&pdev->dev);
135536c68493SMylène Josserand 	if (!pm_runtime_status_suspended(&pdev->dev))
135636c68493SMylène Josserand 		sun8i_codec_runtime_suspend(&pdev->dev);
135736c68493SMylène Josserand }
135836c68493SMylène Josserand 
135990cac932SSamuel Holland static const struct sun8i_codec_quirks sun8i_a33_quirks = {
136090cac932SSamuel Holland 	.legacy_widgets	= true,
13617518805fSSamuel Holland 	.lrck_inversion	= true,
136290cac932SSamuel Holland };
136390cac932SSamuel Holland 
136490cac932SSamuel Holland static const struct sun8i_codec_quirks sun50i_a64_quirks = {
136590cac932SSamuel Holland };
136690cac932SSamuel Holland 
136736c68493SMylène Josserand static const struct of_device_id sun8i_codec_of_match[] = {
136890cac932SSamuel Holland 	{ .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks },
136990cac932SSamuel Holland 	{ .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks },
137036c68493SMylène Josserand 	{}
137136c68493SMylène Josserand };
137236c68493SMylène Josserand MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
137336c68493SMylène Josserand 
137436c68493SMylène Josserand static const struct dev_pm_ops sun8i_codec_pm_ops = {
137536c68493SMylène Josserand 	SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
137636c68493SMylène Josserand 			   sun8i_codec_runtime_resume, NULL)
137736c68493SMylène Josserand };
137836c68493SMylène Josserand 
137936c68493SMylène Josserand static struct platform_driver sun8i_codec_driver = {
138036c68493SMylène Josserand 	.driver = {
138136c68493SMylène Josserand 		.name = "sun8i-codec",
138236c68493SMylène Josserand 		.of_match_table = sun8i_codec_of_match,
138336c68493SMylène Josserand 		.pm = &sun8i_codec_pm_ops,
138436c68493SMylène Josserand 	},
138536c68493SMylène Josserand 	.probe = sun8i_codec_probe,
1386*a594f423SUwe Kleine-König 	.remove_new = sun8i_codec_remove,
138736c68493SMylène Josserand };
138836c68493SMylène Josserand module_platform_driver(sun8i_codec_driver);
138936c68493SMylène Josserand 
139036c68493SMylène Josserand MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
139136c68493SMylène Josserand MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
139236c68493SMylène Josserand MODULE_LICENSE("GPL");
139336c68493SMylène Josserand MODULE_ALIAS("platform:sun8i-codec");
1394