18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
48c2ecf20Sopenharmony_ci * Copyright 2009 Sascha Hauer, s.hauer@pengutronix.de
58c2ecf20Sopenharmony_ci * Copyright 2012 Philippe Retornaz, philippe.retornaz@epfl.ch
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Initial development of this code was funded by
88c2ecf20Sopenharmony_ci * Phytec Messtechnik GmbH, https://www.phytec.de
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/device.h>
128c2ecf20Sopenharmony_ci#include <linux/of.h>
138c2ecf20Sopenharmony_ci#include <linux/mfd/mc13xxx.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <sound/core.h>
168c2ecf20Sopenharmony_ci#include <sound/control.h>
178c2ecf20Sopenharmony_ci#include <sound/pcm.h>
188c2ecf20Sopenharmony_ci#include <sound/soc.h>
198c2ecf20Sopenharmony_ci#include <sound/initval.h>
208c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h>
218c2ecf20Sopenharmony_ci#include <linux/regmap.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "mc13783.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define AUDIO_RX0_ALSPEN		(1 << 5)
268c2ecf20Sopenharmony_ci#define AUDIO_RX0_ALSPSEL		(1 << 7)
278c2ecf20Sopenharmony_ci#define AUDIO_RX0_ADDCDC		(1 << 21)
288c2ecf20Sopenharmony_ci#define AUDIO_RX0_ADDSTDC		(1 << 22)
298c2ecf20Sopenharmony_ci#define AUDIO_RX0_ADDRXIN		(1 << 23)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define AUDIO_RX1_PGARXEN		(1 << 0);
328c2ecf20Sopenharmony_ci#define AUDIO_RX1_PGASTEN		(1 << 5)
338c2ecf20Sopenharmony_ci#define AUDIO_RX1_ARXINEN		(1 << 10)
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define AUDIO_TX_AMC1REN		(1 << 5)
368c2ecf20Sopenharmony_ci#define AUDIO_TX_AMC1LEN		(1 << 7)
378c2ecf20Sopenharmony_ci#define AUDIO_TX_AMC2EN			(1 << 9)
388c2ecf20Sopenharmony_ci#define AUDIO_TX_ATXINEN		(1 << 11)
398c2ecf20Sopenharmony_ci#define AUDIO_TX_RXINREC		(1 << 13)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define SSI_NETWORK_CDCTXRXSLOT(x)	(((x) & 0x3) << 2)
428c2ecf20Sopenharmony_ci#define SSI_NETWORK_CDCTXSECSLOT(x)	(((x) & 0x3) << 4)
438c2ecf20Sopenharmony_ci#define SSI_NETWORK_CDCRXSECSLOT(x)	(((x) & 0x3) << 6)
448c2ecf20Sopenharmony_ci#define SSI_NETWORK_CDCRXSECGAIN(x)	(((x) & 0x3) << 8)
458c2ecf20Sopenharmony_ci#define SSI_NETWORK_CDCSUMGAIN(x)	(1 << 10)
468c2ecf20Sopenharmony_ci#define SSI_NETWORK_CDCFSDLY(x)		(1 << 11)
478c2ecf20Sopenharmony_ci#define SSI_NETWORK_DAC_SLOTS_8		(1 << 12)
488c2ecf20Sopenharmony_ci#define SSI_NETWORK_DAC_SLOTS_4		(2 << 12)
498c2ecf20Sopenharmony_ci#define SSI_NETWORK_DAC_SLOTS_2		(3 << 12)
508c2ecf20Sopenharmony_ci#define SSI_NETWORK_DAC_SLOT_MASK	(3 << 12)
518c2ecf20Sopenharmony_ci#define SSI_NETWORK_DAC_RXSLOT_0_1	(0 << 14)
528c2ecf20Sopenharmony_ci#define SSI_NETWORK_DAC_RXSLOT_2_3	(1 << 14)
538c2ecf20Sopenharmony_ci#define SSI_NETWORK_DAC_RXSLOT_4_5	(2 << 14)
548c2ecf20Sopenharmony_ci#define SSI_NETWORK_DAC_RXSLOT_6_7	(3 << 14)
558c2ecf20Sopenharmony_ci#define SSI_NETWORK_DAC_RXSLOT_MASK	(3 << 14)
568c2ecf20Sopenharmony_ci#define SSI_NETWORK_STDCRXSECSLOT(x)	(((x) & 0x3) << 16)
578c2ecf20Sopenharmony_ci#define SSI_NETWORK_STDCRXSECGAIN(x)	(((x) & 0x3) << 18)
588c2ecf20Sopenharmony_ci#define SSI_NETWORK_STDCSUMGAIN		(1 << 20)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/*
618c2ecf20Sopenharmony_ci * MC13783_AUDIO_CODEC and MC13783_AUDIO_DAC mostly share the same
628c2ecf20Sopenharmony_ci * register layout
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_ci#define AUDIO_SSI_SEL			(1 << 0)
658c2ecf20Sopenharmony_ci#define AUDIO_CLK_SEL			(1 << 1)
668c2ecf20Sopenharmony_ci#define AUDIO_CSM			(1 << 2)
678c2ecf20Sopenharmony_ci#define AUDIO_BCL_INV			(1 << 3)
688c2ecf20Sopenharmony_ci#define AUDIO_CFS_INV			(1 << 4)
698c2ecf20Sopenharmony_ci#define AUDIO_CFS(x)			(((x) & 0x3) << 5)
708c2ecf20Sopenharmony_ci#define AUDIO_CLK(x)			(((x) & 0x7) << 7)
718c2ecf20Sopenharmony_ci#define AUDIO_C_EN			(1 << 11)
728c2ecf20Sopenharmony_ci#define AUDIO_C_CLK_EN			(1 << 12)
738c2ecf20Sopenharmony_ci#define AUDIO_C_RESET			(1 << 15)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define AUDIO_CODEC_CDCFS8K16K		(1 << 10)
768c2ecf20Sopenharmony_ci#define AUDIO_DAC_CFS_DLY_B		(1 << 10)
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistruct mc13783_priv {
798c2ecf20Sopenharmony_ci	struct mc13xxx *mc13xxx;
808c2ecf20Sopenharmony_ci	struct regmap *regmap;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	enum mc13783_ssi_port adc_ssi_port;
838c2ecf20Sopenharmony_ci	enum mc13783_ssi_port dac_ssi_port;
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/* Mapping between sample rates and register value */
878c2ecf20Sopenharmony_cistatic unsigned int mc13783_rates[] = {
888c2ecf20Sopenharmony_ci	8000, 11025, 12000, 16000,
898c2ecf20Sopenharmony_ci	22050, 24000, 32000, 44100,
908c2ecf20Sopenharmony_ci	48000, 64000, 96000
918c2ecf20Sopenharmony_ci};
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int mc13783_pcm_hw_params_dac(struct snd_pcm_substream *substream,
948c2ecf20Sopenharmony_ci				struct snd_pcm_hw_params *params,
958c2ecf20Sopenharmony_ci				struct snd_soc_dai *dai)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
988c2ecf20Sopenharmony_ci	unsigned int rate = params_rate(params);
998c2ecf20Sopenharmony_ci	int i;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mc13783_rates); i++) {
1028c2ecf20Sopenharmony_ci		if (rate == mc13783_rates[i]) {
1038c2ecf20Sopenharmony_ci			snd_soc_component_update_bits(component, MC13783_AUDIO_DAC,
1048c2ecf20Sopenharmony_ci					0xf << 17, i << 17);
1058c2ecf20Sopenharmony_ci			return 0;
1068c2ecf20Sopenharmony_ci		}
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return -EINVAL;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
1138c2ecf20Sopenharmony_ci				struct snd_pcm_hw_params *params,
1148c2ecf20Sopenharmony_ci				struct snd_soc_dai *dai)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
1178c2ecf20Sopenharmony_ci	unsigned int rate = params_rate(params);
1188c2ecf20Sopenharmony_ci	unsigned int val;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	switch (rate) {
1218c2ecf20Sopenharmony_ci	case 8000:
1228c2ecf20Sopenharmony_ci		val = 0;
1238c2ecf20Sopenharmony_ci		break;
1248c2ecf20Sopenharmony_ci	case 16000:
1258c2ecf20Sopenharmony_ci		val = AUDIO_CODEC_CDCFS8K16K;
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci	default:
1288c2ecf20Sopenharmony_ci		return -EINVAL;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, MC13783_AUDIO_CODEC, AUDIO_CODEC_CDCFS8K16K,
1328c2ecf20Sopenharmony_ci			val);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return 0;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic int mc13783_pcm_hw_params_sync(struct snd_pcm_substream *substream,
1388c2ecf20Sopenharmony_ci				struct snd_pcm_hw_params *params,
1398c2ecf20Sopenharmony_ci				struct snd_soc_dai *dai)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1428c2ecf20Sopenharmony_ci		return mc13783_pcm_hw_params_dac(substream, params, dai);
1438c2ecf20Sopenharmony_ci	else
1448c2ecf20Sopenharmony_ci		return mc13783_pcm_hw_params_codec(substream, params, dai);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic int mc13783_set_fmt(struct snd_soc_dai *dai, unsigned int fmt,
1488c2ecf20Sopenharmony_ci			unsigned int reg)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
1518c2ecf20Sopenharmony_ci	unsigned int val = 0;
1528c2ecf20Sopenharmony_ci	unsigned int mask = AUDIO_CFS(3) | AUDIO_BCL_INV | AUDIO_CFS_INV |
1538c2ecf20Sopenharmony_ci				AUDIO_CSM | AUDIO_C_CLK_EN | AUDIO_C_RESET;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	/* DAI mode */
1578c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1588c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
1598c2ecf20Sopenharmony_ci		val |= AUDIO_CFS(2);
1608c2ecf20Sopenharmony_ci		break;
1618c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A:
1628c2ecf20Sopenharmony_ci		val |= AUDIO_CFS(1);
1638c2ecf20Sopenharmony_ci		break;
1648c2ecf20Sopenharmony_ci	default:
1658c2ecf20Sopenharmony_ci		return -EINVAL;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/* DAI clock inversion */
1698c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1708c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_NB_NF:
1718c2ecf20Sopenharmony_ci		val |= AUDIO_BCL_INV;
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_NB_IF:
1748c2ecf20Sopenharmony_ci		val |= AUDIO_BCL_INV | AUDIO_CFS_INV;
1758c2ecf20Sopenharmony_ci		break;
1768c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_IB_NF:
1778c2ecf20Sopenharmony_ci		break;
1788c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_IB_IF:
1798c2ecf20Sopenharmony_ci		val |= AUDIO_CFS_INV;
1808c2ecf20Sopenharmony_ci		break;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* DAI clock master masks */
1848c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1858c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFM:
1868c2ecf20Sopenharmony_ci		val |= AUDIO_C_CLK_EN;
1878c2ecf20Sopenharmony_ci		break;
1888c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFS:
1898c2ecf20Sopenharmony_ci		val |= AUDIO_CSM;
1908c2ecf20Sopenharmony_ci		break;
1918c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFS:
1928c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFM:
1938c2ecf20Sopenharmony_ci		return -EINVAL;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	val |= AUDIO_C_RESET;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, reg, mask, val);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	return 0;
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic int mc13783_set_fmt_async(struct snd_soc_dai *dai, unsigned int fmt)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	if (dai->id == MC13783_ID_STEREO_DAC)
2068c2ecf20Sopenharmony_ci		return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
2078c2ecf20Sopenharmony_ci	else
2088c2ecf20Sopenharmony_ci		return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic int mc13783_set_fmt_sync(struct snd_soc_dai *dai, unsigned int fmt)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	int ret;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
2168c2ecf20Sopenharmony_ci	if (ret)
2178c2ecf20Sopenharmony_ci		return ret;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/*
2208c2ecf20Sopenharmony_ci	 * In synchronous mode force the voice codec into slave mode
2218c2ecf20Sopenharmony_ci	 * so that the clock / framesync from the stereo DAC is used
2228c2ecf20Sopenharmony_ci	 */
2238c2ecf20Sopenharmony_ci	fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
2248c2ecf20Sopenharmony_ci	fmt |= SND_SOC_DAIFMT_CBS_CFS;
2258c2ecf20Sopenharmony_ci	ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return ret;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int mc13783_sysclk[] = {
2318c2ecf20Sopenharmony_ci	13000000,
2328c2ecf20Sopenharmony_ci	15360000,
2338c2ecf20Sopenharmony_ci	16800000,
2348c2ecf20Sopenharmony_ci	-1,
2358c2ecf20Sopenharmony_ci	26000000,
2368c2ecf20Sopenharmony_ci	-1, /* 12000000, invalid for voice codec */
2378c2ecf20Sopenharmony_ci	-1, /* 3686400, invalid for voice codec */
2388c2ecf20Sopenharmony_ci	33600000,
2398c2ecf20Sopenharmony_ci};
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int mc13783_set_sysclk(struct snd_soc_dai *dai,
2428c2ecf20Sopenharmony_ci				  int clk_id, unsigned int freq, int dir,
2438c2ecf20Sopenharmony_ci				  unsigned int reg)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
2468c2ecf20Sopenharmony_ci	int clk;
2478c2ecf20Sopenharmony_ci	unsigned int val = 0;
2488c2ecf20Sopenharmony_ci	unsigned int mask = AUDIO_CLK(0x7) | AUDIO_CLK_SEL;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	for (clk = 0; clk < ARRAY_SIZE(mc13783_sysclk); clk++) {
2518c2ecf20Sopenharmony_ci		if (mc13783_sysclk[clk] < 0)
2528c2ecf20Sopenharmony_ci			continue;
2538c2ecf20Sopenharmony_ci		if (mc13783_sysclk[clk] == freq)
2548c2ecf20Sopenharmony_ci			break;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (clk == ARRAY_SIZE(mc13783_sysclk))
2588c2ecf20Sopenharmony_ci		return -EINVAL;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (clk_id == MC13783_CLK_CLIB)
2618c2ecf20Sopenharmony_ci		val |= AUDIO_CLK_SEL;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	val |= AUDIO_CLK(clk);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, reg, mask, val);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return 0;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int mc13783_set_sysclk_dac(struct snd_soc_dai *dai,
2718c2ecf20Sopenharmony_ci				  int clk_id, unsigned int freq, int dir)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic int mc13783_set_sysclk_codec(struct snd_soc_dai *dai,
2778c2ecf20Sopenharmony_ci				  int clk_id, unsigned int freq, int dir)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic int mc13783_set_sysclk_sync(struct snd_soc_dai *dai,
2838c2ecf20Sopenharmony_ci				  int clk_id, unsigned int freq, int dir)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	int ret;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	ret = mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
2888c2ecf20Sopenharmony_ci	if (ret)
2898c2ecf20Sopenharmony_ci		return ret;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
2958c2ecf20Sopenharmony_ci	unsigned int tx_mask, unsigned int rx_mask, int slots,
2968c2ecf20Sopenharmony_ci	int slot_width)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
2998c2ecf20Sopenharmony_ci	unsigned int val = 0;
3008c2ecf20Sopenharmony_ci	unsigned int mask = SSI_NETWORK_DAC_SLOT_MASK |
3018c2ecf20Sopenharmony_ci				SSI_NETWORK_DAC_RXSLOT_MASK;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	switch (slots) {
3048c2ecf20Sopenharmony_ci	case 2:
3058c2ecf20Sopenharmony_ci		val |= SSI_NETWORK_DAC_SLOTS_2;
3068c2ecf20Sopenharmony_ci		break;
3078c2ecf20Sopenharmony_ci	case 4:
3088c2ecf20Sopenharmony_ci		val |= SSI_NETWORK_DAC_SLOTS_4;
3098c2ecf20Sopenharmony_ci		break;
3108c2ecf20Sopenharmony_ci	case 8:
3118c2ecf20Sopenharmony_ci		val |= SSI_NETWORK_DAC_SLOTS_8;
3128c2ecf20Sopenharmony_ci		break;
3138c2ecf20Sopenharmony_ci	default:
3148c2ecf20Sopenharmony_ci		return -EINVAL;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	switch (rx_mask) {
3188c2ecf20Sopenharmony_ci	case 0x03:
3198c2ecf20Sopenharmony_ci		val |= SSI_NETWORK_DAC_RXSLOT_0_1;
3208c2ecf20Sopenharmony_ci		break;
3218c2ecf20Sopenharmony_ci	case 0x0c:
3228c2ecf20Sopenharmony_ci		val |= SSI_NETWORK_DAC_RXSLOT_2_3;
3238c2ecf20Sopenharmony_ci		break;
3248c2ecf20Sopenharmony_ci	case 0x30:
3258c2ecf20Sopenharmony_ci		val |= SSI_NETWORK_DAC_RXSLOT_4_5;
3268c2ecf20Sopenharmony_ci		break;
3278c2ecf20Sopenharmony_ci	case 0xc0:
3288c2ecf20Sopenharmony_ci		val |= SSI_NETWORK_DAC_RXSLOT_6_7;
3298c2ecf20Sopenharmony_ci		break;
3308c2ecf20Sopenharmony_ci	default:
3318c2ecf20Sopenharmony_ci		return -EINVAL;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, MC13783_SSI_NETWORK, mask, val);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return 0;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
3408c2ecf20Sopenharmony_ci	unsigned int tx_mask, unsigned int rx_mask, int slots,
3418c2ecf20Sopenharmony_ci	int slot_width)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
3448c2ecf20Sopenharmony_ci	unsigned int val = 0;
3458c2ecf20Sopenharmony_ci	unsigned int mask = 0x3f;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (slots != 4)
3488c2ecf20Sopenharmony_ci		return -EINVAL;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (tx_mask != 0x3)
3518c2ecf20Sopenharmony_ci		return -EINVAL;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	val |= (0x00 << 2);	/* primary timeslot RX/TX(?) is 0 */
3548c2ecf20Sopenharmony_ci	val |= (0x01 << 4);	/* secondary timeslot TX is 1 */
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, MC13783_SSI_NETWORK, mask, val);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	return 0;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic int mc13783_set_tdm_slot_sync(struct snd_soc_dai *dai,
3628c2ecf20Sopenharmony_ci	unsigned int tx_mask, unsigned int rx_mask, int slots,
3638c2ecf20Sopenharmony_ci	int slot_width)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	int ret;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	ret = mc13783_set_tdm_slot_dac(dai, tx_mask, rx_mask, slots,
3688c2ecf20Sopenharmony_ci			slot_width);
3698c2ecf20Sopenharmony_ci	if (ret)
3708c2ecf20Sopenharmony_ci		return ret;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	ret = mc13783_set_tdm_slot_codec(dai, tx_mask, rx_mask, slots,
3738c2ecf20Sopenharmony_ci			slot_width);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return ret;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mc1l_amp_ctl =
3798c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 7, 1, 0);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mc1r_amp_ctl =
3828c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 5, 1, 0);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mc2_amp_ctl =
3858c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 9, 1, 0);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new atx_amp_ctl =
3888c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 11, 1, 0);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci/* Virtual mux. The chip does the input selection automatically
3928c2ecf20Sopenharmony_ci * as soon as we enable one input. */
3938c2ecf20Sopenharmony_cistatic const char * const adcl_enum_text[] = {
3948c2ecf20Sopenharmony_ci	"MC1L", "RXINL",
3958c2ecf20Sopenharmony_ci};
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new left_input_mux =
4008c2ecf20Sopenharmony_ci	SOC_DAPM_ENUM("Route", adcl_enum);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic const char * const adcr_enum_text[] = {
4038c2ecf20Sopenharmony_ci	"MC1R", "MC2", "RXINR", "TXIN",
4048c2ecf20Sopenharmony_ci};
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new right_input_mux =
4098c2ecf20Sopenharmony_ci	SOC_DAPM_ENUM("Route", adcr_enum);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new samp_ctl =
4128c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic const char * const speaker_amp_source_text[] = {
4158c2ecf20Sopenharmony_ci	"CODEC", "Right"
4168c2ecf20Sopenharmony_ci};
4178c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4,
4188c2ecf20Sopenharmony_ci			    speaker_amp_source_text);
4198c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new speaker_amp_source_mux =
4208c2ecf20Sopenharmony_ci	SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic const char * const headset_amp_source_text[] = {
4238c2ecf20Sopenharmony_ci	"CODEC", "Mixer"
4248c2ecf20Sopenharmony_ci};
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11,
4278c2ecf20Sopenharmony_ci			    headset_amp_source_text);
4288c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new headset_amp_source_mux =
4298c2ecf20Sopenharmony_ci	SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cdcout_ctl =
4328c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 18, 1, 0);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new adc_bypass_ctl =
4358c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_CODEC, 16, 1, 0);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new lamp_ctl =
4388c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new hlamp_ctl =
4418c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 10, 1, 0);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new hramp_ctl =
4448c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 9, 1, 0);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new llamp_ctl =
4478c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 16, 1, 0);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new lramp_ctl =
4508c2ecf20Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 15, 1, 0);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
4538c2ecf20Sopenharmony_ci/* Input */
4548c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("MC1LIN"),
4558c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("MC1RIN"),
4568c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("MC2IN"),
4578c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("RXINR"),
4588c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("RXINL"),
4598c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("TXIN"),
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("MC1 Bias", MC13783_AUDIO_TX, 0, 0, NULL, 0),
4628c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("MC2 Bias", MC13783_AUDIO_TX, 1, 0, NULL, 0),
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("MC1L Amp", MC13783_AUDIO_TX, 7, 0, &mc1l_amp_ctl),
4658c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("MC1R Amp", MC13783_AUDIO_TX, 5, 0, &mc1r_amp_ctl),
4668c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl),
4678c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl),
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
4708c2ecf20Sopenharmony_ci			      &left_input_mux),
4718c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
4728c2ecf20Sopenharmony_ci			      &right_input_mux),
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0,
4758c2ecf20Sopenharmony_ci			 &speaker_amp_source_mux),
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MUX("Headset Amp Source MUX", SND_SOC_NOPM, 0, 0,
4788c2ecf20Sopenharmony_ci			 &headset_amp_source_mux),
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),
4818c2ecf20Sopenharmony_ci	SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0),
4848c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0),
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	SND_SOC_DAPM_PGA("Voice CODEC PGA", MC13783_AUDIO_RX1, 0, 0, NULL, 0),
4878c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("Voice CODEC Bypass", MC13783_AUDIO_CODEC, 16, 0,
4888c2ecf20Sopenharmony_ci			&adc_bypass_ctl),
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci/* Output */
4918c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0),
4928c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0),
4938c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("RXOUTL"),
4948c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("RXOUTR"),
4958c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("HSL"),
4968c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("HSR"),
4978c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LSPL"),
4988c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LSP"),
4998c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("SP"),
5008c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("CDCOUT"),
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 0,
5038c2ecf20Sopenharmony_ci			&cdcout_ctl),
5048c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("Speaker Amp Switch", MC13783_AUDIO_RX0, 3, 0,
5058c2ecf20Sopenharmony_ci			&samp_ctl),
5068c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),
5078c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0,
5088c2ecf20Sopenharmony_ci			&hlamp_ctl),
5098c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("Headset Amp Right", MC13783_AUDIO_RX0, 9, 0,
5108c2ecf20Sopenharmony_ci			&hramp_ctl),
5118c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("Line out Amp Left", MC13783_AUDIO_RX0, 16, 0,
5128c2ecf20Sopenharmony_ci			&llamp_ctl),
5138c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SWITCH("Line out Amp Right", MC13783_AUDIO_RX0, 15, 0,
5148c2ecf20Sopenharmony_ci			&lramp_ctl),
5158c2ecf20Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC", "Playback", MC13783_AUDIO_RX0, 22, 0),
5168c2ecf20Sopenharmony_ci	SND_SOC_DAPM_PGA("DAC PGA", MC13783_AUDIO_RX1, 5, 0, NULL, 0),
5178c2ecf20Sopenharmony_ci};
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic struct snd_soc_dapm_route mc13783_routes[] = {
5208c2ecf20Sopenharmony_ci/* Input */
5218c2ecf20Sopenharmony_ci	{ "MC1L Amp", NULL, "MC1LIN"},
5228c2ecf20Sopenharmony_ci	{ "MC1R Amp", NULL, "MC1RIN" },
5238c2ecf20Sopenharmony_ci	{ "MC2 Amp", NULL, "MC2IN" },
5248c2ecf20Sopenharmony_ci	{ "TXIN Amp", NULL, "TXIN"},
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	{ "PGA Left Input Mux", "MC1L", "MC1L Amp" },
5278c2ecf20Sopenharmony_ci	{ "PGA Left Input Mux", "RXINL", "RXINL"},
5288c2ecf20Sopenharmony_ci	{ "PGA Right Input Mux", "MC1R", "MC1R Amp" },
5298c2ecf20Sopenharmony_ci	{ "PGA Right Input Mux", "MC2",  "MC2 Amp"},
5308c2ecf20Sopenharmony_ci	{ "PGA Right Input Mux", "TXIN", "TXIN Amp"},
5318c2ecf20Sopenharmony_ci	{ "PGA Right Input Mux", "RXINR", "RXINR"},
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	{ "PGA Left Input", NULL, "PGA Left Input Mux"},
5348c2ecf20Sopenharmony_ci	{ "PGA Right Input", NULL, "PGA Right Input Mux"},
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	{ "ADC", NULL, "PGA Left Input"},
5378c2ecf20Sopenharmony_ci	{ "ADC", NULL, "PGA Right Input"},
5388c2ecf20Sopenharmony_ci	{ "ADC", NULL, "ADC_Reset"},
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	{ "Voice CODEC PGA", "Voice CODEC Bypass", "ADC" },
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	{ "Speaker Amp Source MUX", "CODEC", "Voice CODEC PGA"},
5438c2ecf20Sopenharmony_ci	{ "Speaker Amp Source MUX", "Right", "DAC PGA"},
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	{ "Headset Amp Source MUX", "CODEC", "Voice CODEC PGA"},
5468c2ecf20Sopenharmony_ci	{ "Headset Amp Source MUX", "Mixer", "DAC PGA"},
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci/* Output */
5498c2ecf20Sopenharmony_ci	{ "HSL", NULL, "Headset Amp Left" },
5508c2ecf20Sopenharmony_ci	{ "HSR", NULL, "Headset Amp Right"},
5518c2ecf20Sopenharmony_ci	{ "RXOUTL", NULL, "Line out Amp Left"},
5528c2ecf20Sopenharmony_ci	{ "RXOUTR", NULL, "Line out Amp Right"},
5538c2ecf20Sopenharmony_ci	{ "SP", "Speaker Amp Switch", "Speaker Amp Source MUX"},
5548c2ecf20Sopenharmony_ci	{ "LSP", "Loudspeaker Amp", "Speaker Amp Source MUX"},
5558c2ecf20Sopenharmony_ci	{ "HSL", "Headset Amp Left", "Headset Amp Source MUX"},
5568c2ecf20Sopenharmony_ci	{ "HSR", "Headset Amp Right", "Headset Amp Source MUX"},
5578c2ecf20Sopenharmony_ci	{ "Line out Amp Left", NULL, "DAC PGA"},
5588c2ecf20Sopenharmony_ci	{ "Line out Amp Right", NULL, "DAC PGA"},
5598c2ecf20Sopenharmony_ci	{ "DAC PGA", NULL, "DAC"},
5608c2ecf20Sopenharmony_ci	{ "DAC", NULL, "DAC_E"},
5618c2ecf20Sopenharmony_ci	{ "CDCOUT", "CDCOUT Switch", "Voice CODEC PGA"},
5628c2ecf20Sopenharmony_ci};
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
5658c2ecf20Sopenharmony_ci						"Mono", "Mono Mix"};
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(mc13783_enum_3d_mixer,
5688c2ecf20Sopenharmony_ci			    MC13783_AUDIO_RX1, 16,
5698c2ecf20Sopenharmony_ci			    mc13783_3d_mixer);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new mc13783_control_list[] = {
5728c2ecf20Sopenharmony_ci	SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
5738c2ecf20Sopenharmony_ci	SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0),
5748c2ecf20Sopenharmony_ci	SOC_SINGLE("PCM Playback Switch", MC13783_AUDIO_RX1, 5, 1, 0),
5758c2ecf20Sopenharmony_ci	SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),
5768c2ecf20Sopenharmony_ci	SOC_ENUM("3D Control", mc13783_enum_3d_mixer),
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	SOC_SINGLE("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 1, 0),
5798c2ecf20Sopenharmony_ci	SOC_SINGLE("Earpiece Amp Switch", MC13783_AUDIO_RX0, 3, 1, 0),
5808c2ecf20Sopenharmony_ci	SOC_DOUBLE("Headset Amp Switch", MC13783_AUDIO_RX0, 10, 9, 1, 0),
5818c2ecf20Sopenharmony_ci	SOC_DOUBLE("Line out Amp Switch", MC13783_AUDIO_RX0, 16, 15, 1, 0),
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	SOC_SINGLE("PCM Capture Mixin Switch", MC13783_AUDIO_RX0, 22, 1, 0),
5848c2ecf20Sopenharmony_ci	SOC_SINGLE("Line in Capture Mixin Switch", MC13783_AUDIO_RX0, 23, 1, 0),
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	SOC_SINGLE("CODEC Capture Volume", MC13783_AUDIO_RX1, 1, 15, 0),
5878c2ecf20Sopenharmony_ci	SOC_SINGLE("CODEC Capture Mixin Switch", MC13783_AUDIO_RX0, 21, 1, 0),
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	SOC_SINGLE("Line in Capture Volume", MC13783_AUDIO_RX1, 12, 15, 0),
5908c2ecf20Sopenharmony_ci	SOC_SINGLE("Line in Capture Switch", MC13783_AUDIO_RX1, 10, 1, 0),
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	SOC_SINGLE("MC1 Capture Bias Switch", MC13783_AUDIO_TX, 0, 1, 0),
5938c2ecf20Sopenharmony_ci	SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0),
5948c2ecf20Sopenharmony_ci};
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_cistatic int mc13783_probe(struct snd_soc_component *component)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	struct mc13783_priv *priv = snd_soc_component_get_drvdata(component);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	snd_soc_component_init_regmap(component,
6018c2ecf20Sopenharmony_ci				  dev_get_regmap(component->dev->parent, NULL));
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	/* these are the reset values */
6048c2ecf20Sopenharmony_ci	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
6058c2ecf20Sopenharmony_ci	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX1, 0x00d35A);
6068c2ecf20Sopenharmony_ci	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_TX, 0x420000);
6078c2ecf20Sopenharmony_ci	mc13xxx_reg_write(priv->mc13xxx, MC13783_SSI_NETWORK, 0x013060);
6088c2ecf20Sopenharmony_ci	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_CODEC, 0x180027);
6098c2ecf20Sopenharmony_ci	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_DAC, 0x0e0004);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (priv->adc_ssi_port == MC13783_SSI1_PORT)
6128c2ecf20Sopenharmony_ci		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
6138c2ecf20Sopenharmony_ci				AUDIO_SSI_SEL, 0);
6148c2ecf20Sopenharmony_ci	else
6158c2ecf20Sopenharmony_ci		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
6168c2ecf20Sopenharmony_ci				AUDIO_SSI_SEL, AUDIO_SSI_SEL);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	if (priv->dac_ssi_port == MC13783_SSI1_PORT)
6198c2ecf20Sopenharmony_ci		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
6208c2ecf20Sopenharmony_ci				AUDIO_SSI_SEL, 0);
6218c2ecf20Sopenharmony_ci	else
6228c2ecf20Sopenharmony_ci		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
6238c2ecf20Sopenharmony_ci				AUDIO_SSI_SEL, AUDIO_SSI_SEL);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	return 0;
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic void mc13783_remove(struct snd_soc_component *component)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct mc13783_priv *priv = snd_soc_component_get_drvdata(component);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	/* Make sure VAUDIOON is off */
6338c2ecf20Sopenharmony_ci	mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0);
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci#define MC13783_RATES_RECORD (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci#define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
6398c2ecf20Sopenharmony_ci	SNDRV_PCM_FMTBIT_S24_LE)
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops mc13783_ops_dac = {
6428c2ecf20Sopenharmony_ci	.hw_params	= mc13783_pcm_hw_params_dac,
6438c2ecf20Sopenharmony_ci	.set_fmt	= mc13783_set_fmt_async,
6448c2ecf20Sopenharmony_ci	.set_sysclk	= mc13783_set_sysclk_dac,
6458c2ecf20Sopenharmony_ci	.set_tdm_slot	= mc13783_set_tdm_slot_dac,
6468c2ecf20Sopenharmony_ci};
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops mc13783_ops_codec = {
6498c2ecf20Sopenharmony_ci	.hw_params	= mc13783_pcm_hw_params_codec,
6508c2ecf20Sopenharmony_ci	.set_fmt	= mc13783_set_fmt_async,
6518c2ecf20Sopenharmony_ci	.set_sysclk	= mc13783_set_sysclk_codec,
6528c2ecf20Sopenharmony_ci	.set_tdm_slot	= mc13783_set_tdm_slot_codec,
6538c2ecf20Sopenharmony_ci};
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci/*
6568c2ecf20Sopenharmony_ci * The mc13783 has two SSI ports, both of them can be routed either
6578c2ecf20Sopenharmony_ci * to the voice codec or the stereo DAC. When two different SSI ports
6588c2ecf20Sopenharmony_ci * are used for the voice codec and the stereo DAC we can do different
6598c2ecf20Sopenharmony_ci * formats and sysclock settings for playback and capture
6608c2ecf20Sopenharmony_ci * (mc13783-hifi-playback and mc13783-hifi-capture). Using the same port
6618c2ecf20Sopenharmony_ci * forces us to use symmetric rates (mc13783-hifi).
6628c2ecf20Sopenharmony_ci */
6638c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver mc13783_dai_async[] = {
6648c2ecf20Sopenharmony_ci	{
6658c2ecf20Sopenharmony_ci		.name = "mc13783-hifi-playback",
6668c2ecf20Sopenharmony_ci		.id = MC13783_ID_STEREO_DAC,
6678c2ecf20Sopenharmony_ci		.playback = {
6688c2ecf20Sopenharmony_ci			.stream_name = "Playback",
6698c2ecf20Sopenharmony_ci			.channels_min = 2,
6708c2ecf20Sopenharmony_ci			.channels_max = 2,
6718c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_96000,
6728c2ecf20Sopenharmony_ci			.formats = MC13783_FORMATS,
6738c2ecf20Sopenharmony_ci		},
6748c2ecf20Sopenharmony_ci		.ops = &mc13783_ops_dac,
6758c2ecf20Sopenharmony_ci	}, {
6768c2ecf20Sopenharmony_ci		.name = "mc13783-hifi-capture",
6778c2ecf20Sopenharmony_ci		.id = MC13783_ID_STEREO_CODEC,
6788c2ecf20Sopenharmony_ci		.capture = {
6798c2ecf20Sopenharmony_ci			.stream_name = "Capture",
6808c2ecf20Sopenharmony_ci			.channels_min = 2,
6818c2ecf20Sopenharmony_ci			.channels_max = 2,
6828c2ecf20Sopenharmony_ci			.rates = MC13783_RATES_RECORD,
6838c2ecf20Sopenharmony_ci			.formats = MC13783_FORMATS,
6848c2ecf20Sopenharmony_ci		},
6858c2ecf20Sopenharmony_ci		.ops = &mc13783_ops_codec,
6868c2ecf20Sopenharmony_ci	},
6878c2ecf20Sopenharmony_ci};
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops mc13783_ops_sync = {
6908c2ecf20Sopenharmony_ci	.hw_params	= mc13783_pcm_hw_params_sync,
6918c2ecf20Sopenharmony_ci	.set_fmt	= mc13783_set_fmt_sync,
6928c2ecf20Sopenharmony_ci	.set_sysclk	= mc13783_set_sysclk_sync,
6938c2ecf20Sopenharmony_ci	.set_tdm_slot	= mc13783_set_tdm_slot_sync,
6948c2ecf20Sopenharmony_ci};
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver mc13783_dai_sync[] = {
6978c2ecf20Sopenharmony_ci	{
6988c2ecf20Sopenharmony_ci		.name = "mc13783-hifi",
6998c2ecf20Sopenharmony_ci		.id = MC13783_ID_SYNC,
7008c2ecf20Sopenharmony_ci		.playback = {
7018c2ecf20Sopenharmony_ci			.stream_name = "Playback",
7028c2ecf20Sopenharmony_ci			.channels_min = 2,
7038c2ecf20Sopenharmony_ci			.channels_max = 2,
7048c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_96000,
7058c2ecf20Sopenharmony_ci			.formats = MC13783_FORMATS,
7068c2ecf20Sopenharmony_ci		},
7078c2ecf20Sopenharmony_ci		.capture = {
7088c2ecf20Sopenharmony_ci			.stream_name = "Capture",
7098c2ecf20Sopenharmony_ci			.channels_min = 2,
7108c2ecf20Sopenharmony_ci			.channels_max = 2,
7118c2ecf20Sopenharmony_ci			.rates = MC13783_RATES_RECORD,
7128c2ecf20Sopenharmony_ci			.formats = MC13783_FORMATS,
7138c2ecf20Sopenharmony_ci		},
7148c2ecf20Sopenharmony_ci		.ops = &mc13783_ops_sync,
7158c2ecf20Sopenharmony_ci		.symmetric_rates = 1,
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci};
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_mc13783 = {
7208c2ecf20Sopenharmony_ci	.probe			= mc13783_probe,
7218c2ecf20Sopenharmony_ci	.remove			= mc13783_remove,
7228c2ecf20Sopenharmony_ci	.controls		= mc13783_control_list,
7238c2ecf20Sopenharmony_ci	.num_controls		= ARRAY_SIZE(mc13783_control_list),
7248c2ecf20Sopenharmony_ci	.dapm_widgets		= mc13783_dapm_widgets,
7258c2ecf20Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(mc13783_dapm_widgets),
7268c2ecf20Sopenharmony_ci	.dapm_routes		= mc13783_routes,
7278c2ecf20Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(mc13783_routes),
7288c2ecf20Sopenharmony_ci	.idle_bias_on		= 1,
7298c2ecf20Sopenharmony_ci	.use_pmdown_time	= 1,
7308c2ecf20Sopenharmony_ci	.endianness		= 1,
7318c2ecf20Sopenharmony_ci	.non_legacy_dai_naming	= 1,
7328c2ecf20Sopenharmony_ci};
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_cistatic int __init mc13783_codec_probe(struct platform_device *pdev)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	struct mc13783_priv *priv;
7378c2ecf20Sopenharmony_ci	struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
7388c2ecf20Sopenharmony_ci	struct device_node *np;
7398c2ecf20Sopenharmony_ci	int ret;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
7428c2ecf20Sopenharmony_ci	if (!priv)
7438c2ecf20Sopenharmony_ci		return -ENOMEM;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	if (pdata) {
7468c2ecf20Sopenharmony_ci		priv->adc_ssi_port = pdata->adc_ssi_port;
7478c2ecf20Sopenharmony_ci		priv->dac_ssi_port = pdata->dac_ssi_port;
7488c2ecf20Sopenharmony_ci	} else {
7498c2ecf20Sopenharmony_ci		np = of_get_child_by_name(pdev->dev.parent->of_node, "codec");
7508c2ecf20Sopenharmony_ci		if (!np)
7518c2ecf20Sopenharmony_ci			return -ENOSYS;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci		ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
7548c2ecf20Sopenharmony_ci		if (ret) {
7558c2ecf20Sopenharmony_ci			of_node_put(np);
7568c2ecf20Sopenharmony_ci			return ret;
7578c2ecf20Sopenharmony_ci		}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci		ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
7608c2ecf20Sopenharmony_ci		if (ret) {
7618c2ecf20Sopenharmony_ci			of_node_put(np);
7628c2ecf20Sopenharmony_ci			return ret;
7638c2ecf20Sopenharmony_ci		}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci		of_node_put(np);
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	dev_set_drvdata(&pdev->dev, priv);
7698c2ecf20Sopenharmony_ci	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	if (priv->adc_ssi_port == priv->dac_ssi_port)
7728c2ecf20Sopenharmony_ci		ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_mc13783,
7738c2ecf20Sopenharmony_ci			mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync));
7748c2ecf20Sopenharmony_ci	else
7758c2ecf20Sopenharmony_ci		ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_mc13783,
7768c2ecf20Sopenharmony_ci			mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	return ret;
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic int mc13783_codec_remove(struct platform_device *pdev)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	return 0;
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cistatic struct platform_driver mc13783_codec_driver = {
7878c2ecf20Sopenharmony_ci	.driver = {
7888c2ecf20Sopenharmony_ci		.name	= "mc13783-codec",
7898c2ecf20Sopenharmony_ci	},
7908c2ecf20Sopenharmony_ci	.remove = mc13783_codec_remove,
7918c2ecf20Sopenharmony_ci};
7928c2ecf20Sopenharmony_cimodule_platform_driver_probe(mc13783_codec_driver, mc13783_codec_probe);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC MC13783 driver");
7958c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
7968c2ecf20Sopenharmony_ciMODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
7978c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
798