1*5097c0c8SAlexandre Mergnat // SPDX-License-Identifier: GPL-2.0
2*5097c0c8SAlexandre Mergnat /*
3*5097c0c8SAlexandre Mergnat * MediaTek 8365 ALSA SoC Audio DAI PCM Control
4*5097c0c8SAlexandre Mergnat *
5*5097c0c8SAlexandre Mergnat * Copyright (c) 2024 MediaTek Inc.
6*5097c0c8SAlexandre Mergnat * Authors: Jia Zeng <jia.zeng@mediatek.com>
7*5097c0c8SAlexandre Mergnat * Alexandre Mergnat <amergnat@baylibre.com>
8*5097c0c8SAlexandre Mergnat */
9*5097c0c8SAlexandre Mergnat
10*5097c0c8SAlexandre Mergnat #include <linux/bitops.h>
11*5097c0c8SAlexandre Mergnat #include <linux/regmap.h>
12*5097c0c8SAlexandre Mergnat #include <sound/pcm_params.h>
13*5097c0c8SAlexandre Mergnat #include "mt8365-afe-clk.h"
14*5097c0c8SAlexandre Mergnat #include "mt8365-afe-common.h"
15*5097c0c8SAlexandre Mergnat
16*5097c0c8SAlexandre Mergnat struct mt8365_pcm_intf_data {
17*5097c0c8SAlexandre Mergnat bool slave_mode;
18*5097c0c8SAlexandre Mergnat bool lrck_inv;
19*5097c0c8SAlexandre Mergnat bool bck_inv;
20*5097c0c8SAlexandre Mergnat unsigned int format;
21*5097c0c8SAlexandre Mergnat };
22*5097c0c8SAlexandre Mergnat
23*5097c0c8SAlexandre Mergnat /* DAI Drivers */
24*5097c0c8SAlexandre Mergnat
mt8365_dai_enable_pcm1(struct mtk_base_afe * afe)25*5097c0c8SAlexandre Mergnat static void mt8365_dai_enable_pcm1(struct mtk_base_afe *afe)
26*5097c0c8SAlexandre Mergnat {
27*5097c0c8SAlexandre Mergnat regmap_update_bits(afe->regmap, PCM_INTF_CON1,
28*5097c0c8SAlexandre Mergnat PCM_INTF_CON1_EN, PCM_INTF_CON1_EN);
29*5097c0c8SAlexandre Mergnat }
30*5097c0c8SAlexandre Mergnat
mt8365_dai_disable_pcm1(struct mtk_base_afe * afe)31*5097c0c8SAlexandre Mergnat static void mt8365_dai_disable_pcm1(struct mtk_base_afe *afe)
32*5097c0c8SAlexandre Mergnat {
33*5097c0c8SAlexandre Mergnat regmap_update_bits(afe->regmap, PCM_INTF_CON1,
34*5097c0c8SAlexandre Mergnat PCM_INTF_CON1_EN, 0x0);
35*5097c0c8SAlexandre Mergnat }
36*5097c0c8SAlexandre Mergnat
mt8365_dai_configure_pcm1(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)37*5097c0c8SAlexandre Mergnat static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream,
38*5097c0c8SAlexandre Mergnat struct snd_soc_dai *dai)
39*5097c0c8SAlexandre Mergnat {
40*5097c0c8SAlexandre Mergnat struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
41*5097c0c8SAlexandre Mergnat struct mt8365_afe_private *afe_priv = afe->platform_priv;
42*5097c0c8SAlexandre Mergnat struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
43*5097c0c8SAlexandre Mergnat bool slave_mode = pcm_priv->slave_mode;
44*5097c0c8SAlexandre Mergnat bool lrck_inv = pcm_priv->lrck_inv;
45*5097c0c8SAlexandre Mergnat bool bck_inv = pcm_priv->bck_inv;
46*5097c0c8SAlexandre Mergnat unsigned int fmt = pcm_priv->format;
47*5097c0c8SAlexandre Mergnat unsigned int bit_width = dai->sample_bits;
48*5097c0c8SAlexandre Mergnat unsigned int val = 0;
49*5097c0c8SAlexandre Mergnat
50*5097c0c8SAlexandre Mergnat if (!slave_mode) {
51*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_MASTER_MODE |
52*5097c0c8SAlexandre Mergnat PCM_INTF_CON1_BYPASS_ASRC;
53*5097c0c8SAlexandre Mergnat
54*5097c0c8SAlexandre Mergnat if (lrck_inv)
55*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_SYNC_OUT_INV;
56*5097c0c8SAlexandre Mergnat if (bck_inv)
57*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_BCLK_OUT_INV;
58*5097c0c8SAlexandre Mergnat } else {
59*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_SLAVE_MODE;
60*5097c0c8SAlexandre Mergnat
61*5097c0c8SAlexandre Mergnat if (lrck_inv)
62*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_SYNC_IN_INV;
63*5097c0c8SAlexandre Mergnat if (bck_inv)
64*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_BCLK_IN_INV;
65*5097c0c8SAlexandre Mergnat
66*5097c0c8SAlexandre Mergnat /* TODO: add asrc setting */
67*5097c0c8SAlexandre Mergnat }
68*5097c0c8SAlexandre Mergnat
69*5097c0c8SAlexandre Mergnat val |= FIELD_PREP(PCM_INTF_CON1_FORMAT_MASK, fmt);
70*5097c0c8SAlexandre Mergnat
71*5097c0c8SAlexandre Mergnat if (fmt == MT8365_PCM_FORMAT_PCMA ||
72*5097c0c8SAlexandre Mergnat fmt == MT8365_PCM_FORMAT_PCMB)
73*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_SYNC_LEN(1);
74*5097c0c8SAlexandre Mergnat else
75*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_SYNC_LEN(bit_width);
76*5097c0c8SAlexandre Mergnat
77*5097c0c8SAlexandre Mergnat switch (substream->runtime->rate) {
78*5097c0c8SAlexandre Mergnat case 48000:
79*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_FS_48K;
80*5097c0c8SAlexandre Mergnat break;
81*5097c0c8SAlexandre Mergnat case 32000:
82*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_FS_32K;
83*5097c0c8SAlexandre Mergnat break;
84*5097c0c8SAlexandre Mergnat case 16000:
85*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_FS_16K;
86*5097c0c8SAlexandre Mergnat break;
87*5097c0c8SAlexandre Mergnat case 8000:
88*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_FS_8K;
89*5097c0c8SAlexandre Mergnat break;
90*5097c0c8SAlexandre Mergnat default:
91*5097c0c8SAlexandre Mergnat return -EINVAL;
92*5097c0c8SAlexandre Mergnat }
93*5097c0c8SAlexandre Mergnat
94*5097c0c8SAlexandre Mergnat if (bit_width > 16)
95*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_24BIT | PCM_INTF_CON1_64BCK;
96*5097c0c8SAlexandre Mergnat else
97*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_16BIT | PCM_INTF_CON1_32BCK;
98*5097c0c8SAlexandre Mergnat
99*5097c0c8SAlexandre Mergnat val |= PCM_INTF_CON1_EXT_MODEM;
100*5097c0c8SAlexandre Mergnat
101*5097c0c8SAlexandre Mergnat regmap_update_bits(afe->regmap, PCM_INTF_CON1,
102*5097c0c8SAlexandre Mergnat PCM_INTF_CON1_CONFIG_MASK, val);
103*5097c0c8SAlexandre Mergnat
104*5097c0c8SAlexandre Mergnat return 0;
105*5097c0c8SAlexandre Mergnat }
106*5097c0c8SAlexandre Mergnat
mt8365_dai_pcm1_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)107*5097c0c8SAlexandre Mergnat static int mt8365_dai_pcm1_startup(struct snd_pcm_substream *substream,
108*5097c0c8SAlexandre Mergnat struct snd_soc_dai *dai)
109*5097c0c8SAlexandre Mergnat {
110*5097c0c8SAlexandre Mergnat struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
111*5097c0c8SAlexandre Mergnat
112*5097c0c8SAlexandre Mergnat if (snd_soc_dai_active(dai))
113*5097c0c8SAlexandre Mergnat return 0;
114*5097c0c8SAlexandre Mergnat
115*5097c0c8SAlexandre Mergnat mt8365_afe_enable_main_clk(afe);
116*5097c0c8SAlexandre Mergnat
117*5097c0c8SAlexandre Mergnat return 0;
118*5097c0c8SAlexandre Mergnat }
119*5097c0c8SAlexandre Mergnat
mt8365_dai_pcm1_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)120*5097c0c8SAlexandre Mergnat static void mt8365_dai_pcm1_shutdown(struct snd_pcm_substream *substream,
121*5097c0c8SAlexandre Mergnat struct snd_soc_dai *dai)
122*5097c0c8SAlexandre Mergnat {
123*5097c0c8SAlexandre Mergnat struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
124*5097c0c8SAlexandre Mergnat
125*5097c0c8SAlexandre Mergnat if (snd_soc_dai_active(dai))
126*5097c0c8SAlexandre Mergnat return;
127*5097c0c8SAlexandre Mergnat
128*5097c0c8SAlexandre Mergnat mt8365_dai_disable_pcm1(afe);
129*5097c0c8SAlexandre Mergnat mt8365_afe_disable_main_clk(afe);
130*5097c0c8SAlexandre Mergnat }
131*5097c0c8SAlexandre Mergnat
mt8365_dai_pcm1_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)132*5097c0c8SAlexandre Mergnat static int mt8365_dai_pcm1_prepare(struct snd_pcm_substream *substream,
133*5097c0c8SAlexandre Mergnat struct snd_soc_dai *dai)
134*5097c0c8SAlexandre Mergnat {
135*5097c0c8SAlexandre Mergnat struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
136*5097c0c8SAlexandre Mergnat int ret;
137*5097c0c8SAlexandre Mergnat
138*5097c0c8SAlexandre Mergnat if ((snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK) +
139*5097c0c8SAlexandre Mergnat snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)) > 1) {
140*5097c0c8SAlexandre Mergnat dev_info(afe->dev, "%s '%s' active(%u-%u) already\n",
141*5097c0c8SAlexandre Mergnat __func__, snd_pcm_stream_str(substream),
142*5097c0c8SAlexandre Mergnat snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK),
143*5097c0c8SAlexandre Mergnat snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE));
144*5097c0c8SAlexandre Mergnat return 0;
145*5097c0c8SAlexandre Mergnat }
146*5097c0c8SAlexandre Mergnat
147*5097c0c8SAlexandre Mergnat ret = mt8365_dai_configure_pcm1(substream, dai);
148*5097c0c8SAlexandre Mergnat if (ret)
149*5097c0c8SAlexandre Mergnat return ret;
150*5097c0c8SAlexandre Mergnat
151*5097c0c8SAlexandre Mergnat mt8365_dai_enable_pcm1(afe);
152*5097c0c8SAlexandre Mergnat
153*5097c0c8SAlexandre Mergnat return 0;
154*5097c0c8SAlexandre Mergnat }
155*5097c0c8SAlexandre Mergnat
mt8365_dai_pcm1_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)156*5097c0c8SAlexandre Mergnat static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
157*5097c0c8SAlexandre Mergnat {
158*5097c0c8SAlexandre Mergnat struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
159*5097c0c8SAlexandre Mergnat struct mt8365_afe_private *afe_priv = afe->platform_priv;
160*5097c0c8SAlexandre Mergnat struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
161*5097c0c8SAlexandre Mergnat
162*5097c0c8SAlexandre Mergnat switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
163*5097c0c8SAlexandre Mergnat case SND_SOC_DAIFMT_I2S:
164*5097c0c8SAlexandre Mergnat pcm_priv->format = MT8365_PCM_FORMAT_I2S;
165*5097c0c8SAlexandre Mergnat break;
166*5097c0c8SAlexandre Mergnat default:
167*5097c0c8SAlexandre Mergnat return -EINVAL;
168*5097c0c8SAlexandre Mergnat }
169*5097c0c8SAlexandre Mergnat
170*5097c0c8SAlexandre Mergnat switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
171*5097c0c8SAlexandre Mergnat case SND_SOC_DAIFMT_NB_NF:
172*5097c0c8SAlexandre Mergnat pcm_priv->bck_inv = false;
173*5097c0c8SAlexandre Mergnat pcm_priv->lrck_inv = false;
174*5097c0c8SAlexandre Mergnat break;
175*5097c0c8SAlexandre Mergnat case SND_SOC_DAIFMT_NB_IF:
176*5097c0c8SAlexandre Mergnat pcm_priv->bck_inv = false;
177*5097c0c8SAlexandre Mergnat pcm_priv->lrck_inv = true;
178*5097c0c8SAlexandre Mergnat break;
179*5097c0c8SAlexandre Mergnat case SND_SOC_DAIFMT_IB_NF:
180*5097c0c8SAlexandre Mergnat pcm_priv->bck_inv = true;
181*5097c0c8SAlexandre Mergnat pcm_priv->lrck_inv = false;
182*5097c0c8SAlexandre Mergnat break;
183*5097c0c8SAlexandre Mergnat case SND_SOC_DAIFMT_IB_IF:
184*5097c0c8SAlexandre Mergnat pcm_priv->bck_inv = true;
185*5097c0c8SAlexandre Mergnat pcm_priv->lrck_inv = true;
186*5097c0c8SAlexandre Mergnat break;
187*5097c0c8SAlexandre Mergnat default:
188*5097c0c8SAlexandre Mergnat return -EINVAL;
189*5097c0c8SAlexandre Mergnat }
190*5097c0c8SAlexandre Mergnat
191*5097c0c8SAlexandre Mergnat switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
192*5097c0c8SAlexandre Mergnat case SND_SOC_DAIFMT_CBM_CFM:
193*5097c0c8SAlexandre Mergnat pcm_priv->slave_mode = true;
194*5097c0c8SAlexandre Mergnat break;
195*5097c0c8SAlexandre Mergnat case SND_SOC_DAIFMT_CBS_CFS:
196*5097c0c8SAlexandre Mergnat pcm_priv->slave_mode = false;
197*5097c0c8SAlexandre Mergnat break;
198*5097c0c8SAlexandre Mergnat default:
199*5097c0c8SAlexandre Mergnat return -EINVAL;
200*5097c0c8SAlexandre Mergnat }
201*5097c0c8SAlexandre Mergnat
202*5097c0c8SAlexandre Mergnat return 0;
203*5097c0c8SAlexandre Mergnat }
204*5097c0c8SAlexandre Mergnat
205*5097c0c8SAlexandre Mergnat static const struct snd_soc_dai_ops mt8365_dai_pcm1_ops = {
206*5097c0c8SAlexandre Mergnat .startup = mt8365_dai_pcm1_startup,
207*5097c0c8SAlexandre Mergnat .shutdown = mt8365_dai_pcm1_shutdown,
208*5097c0c8SAlexandre Mergnat .prepare = mt8365_dai_pcm1_prepare,
209*5097c0c8SAlexandre Mergnat .set_fmt = mt8365_dai_pcm1_set_fmt,
210*5097c0c8SAlexandre Mergnat };
211*5097c0c8SAlexandre Mergnat
212*5097c0c8SAlexandre Mergnat static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
213*5097c0c8SAlexandre Mergnat {
214*5097c0c8SAlexandre Mergnat .name = "PCM1",
215*5097c0c8SAlexandre Mergnat .id = MT8365_AFE_IO_PCM1,
216*5097c0c8SAlexandre Mergnat .playback = {
217*5097c0c8SAlexandre Mergnat .stream_name = "PCM1 Playback",
218*5097c0c8SAlexandre Mergnat .channels_min = 1,
219*5097c0c8SAlexandre Mergnat .channels_max = 2,
220*5097c0c8SAlexandre Mergnat .rates = SNDRV_PCM_RATE_8000 |
221*5097c0c8SAlexandre Mergnat SNDRV_PCM_RATE_16000 |
222*5097c0c8SAlexandre Mergnat SNDRV_PCM_RATE_32000 |
223*5097c0c8SAlexandre Mergnat SNDRV_PCM_RATE_48000,
224*5097c0c8SAlexandre Mergnat .formats = SNDRV_PCM_FMTBIT_S16_LE |
225*5097c0c8SAlexandre Mergnat SNDRV_PCM_FMTBIT_S32_LE,
226*5097c0c8SAlexandre Mergnat },
227*5097c0c8SAlexandre Mergnat .capture = {
228*5097c0c8SAlexandre Mergnat .stream_name = "PCM1 Capture",
229*5097c0c8SAlexandre Mergnat .channels_min = 1,
230*5097c0c8SAlexandre Mergnat .channels_max = 2,
231*5097c0c8SAlexandre Mergnat .rates = SNDRV_PCM_RATE_8000 |
232*5097c0c8SAlexandre Mergnat SNDRV_PCM_RATE_16000 |
233*5097c0c8SAlexandre Mergnat SNDRV_PCM_RATE_32000 |
234*5097c0c8SAlexandre Mergnat SNDRV_PCM_RATE_48000,
235*5097c0c8SAlexandre Mergnat .formats = SNDRV_PCM_FMTBIT_S16_LE |
236*5097c0c8SAlexandre Mergnat SNDRV_PCM_FMTBIT_S32_LE,
237*5097c0c8SAlexandre Mergnat },
238*5097c0c8SAlexandre Mergnat .ops = &mt8365_dai_pcm1_ops,
239*5097c0c8SAlexandre Mergnat .symmetric_rate = 1,
240*5097c0c8SAlexandre Mergnat .symmetric_sample_bits = 1,
241*5097c0c8SAlexandre Mergnat }
242*5097c0c8SAlexandre Mergnat };
243*5097c0c8SAlexandre Mergnat
244*5097c0c8SAlexandre Mergnat /* DAI widget */
245*5097c0c8SAlexandre Mergnat
246*5097c0c8SAlexandre Mergnat static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
247*5097c0c8SAlexandre Mergnat SND_SOC_DAPM_OUTPUT("PCM1 Out"),
248*5097c0c8SAlexandre Mergnat SND_SOC_DAPM_INPUT("PCM1 In"),
249*5097c0c8SAlexandre Mergnat };
250*5097c0c8SAlexandre Mergnat
251*5097c0c8SAlexandre Mergnat /* DAI route */
252*5097c0c8SAlexandre Mergnat
253*5097c0c8SAlexandre Mergnat static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
254*5097c0c8SAlexandre Mergnat {"PCM1 Playback", NULL, "O07"},
255*5097c0c8SAlexandre Mergnat {"PCM1 Playback", NULL, "O08"},
256*5097c0c8SAlexandre Mergnat {"PCM1 Out", NULL, "PCM1 Playback"},
257*5097c0c8SAlexandre Mergnat
258*5097c0c8SAlexandre Mergnat {"I09", NULL, "PCM1 Capture"},
259*5097c0c8SAlexandre Mergnat {"I22", NULL, "PCM1 Capture"},
260*5097c0c8SAlexandre Mergnat {"PCM1 Capture", NULL, "PCM1 In"},
261*5097c0c8SAlexandre Mergnat };
262*5097c0c8SAlexandre Mergnat
init_pcmif_priv_data(struct mtk_base_afe * afe)263*5097c0c8SAlexandre Mergnat static int init_pcmif_priv_data(struct mtk_base_afe *afe)
264*5097c0c8SAlexandre Mergnat {
265*5097c0c8SAlexandre Mergnat struct mt8365_afe_private *afe_priv = afe->platform_priv;
266*5097c0c8SAlexandre Mergnat struct mt8365_pcm_intf_data *pcmif_priv;
267*5097c0c8SAlexandre Mergnat
268*5097c0c8SAlexandre Mergnat pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_pcm_intf_data),
269*5097c0c8SAlexandre Mergnat GFP_KERNEL);
270*5097c0c8SAlexandre Mergnat if (!pcmif_priv)
271*5097c0c8SAlexandre Mergnat return -ENOMEM;
272*5097c0c8SAlexandre Mergnat
273*5097c0c8SAlexandre Mergnat afe_priv->dai_priv[MT8365_AFE_IO_PCM1] = pcmif_priv;
274*5097c0c8SAlexandre Mergnat return 0;
275*5097c0c8SAlexandre Mergnat }
276*5097c0c8SAlexandre Mergnat
mt8365_dai_pcm_register(struct mtk_base_afe * afe)277*5097c0c8SAlexandre Mergnat int mt8365_dai_pcm_register(struct mtk_base_afe *afe)
278*5097c0c8SAlexandre Mergnat {
279*5097c0c8SAlexandre Mergnat struct mtk_base_afe_dai *dai;
280*5097c0c8SAlexandre Mergnat
281*5097c0c8SAlexandre Mergnat dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
282*5097c0c8SAlexandre Mergnat if (!dai)
283*5097c0c8SAlexandre Mergnat return -ENOMEM;
284*5097c0c8SAlexandre Mergnat
285*5097c0c8SAlexandre Mergnat list_add(&dai->list, &afe->sub_dais);
286*5097c0c8SAlexandre Mergnat dai->dai_drivers = mtk_dai_pcm_driver;
287*5097c0c8SAlexandre Mergnat dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
288*5097c0c8SAlexandre Mergnat dai->dapm_widgets = mtk_dai_pcm_widgets;
289*5097c0c8SAlexandre Mergnat dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
290*5097c0c8SAlexandre Mergnat dai->dapm_routes = mtk_dai_pcm_routes;
291*5097c0c8SAlexandre Mergnat dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
292*5097c0c8SAlexandre Mergnat return init_pcmif_priv_data(afe);
293*5097c0c8SAlexandre Mergnat }
294