1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * MediaTek ALSA SoC Audio DAI PCM I/F Control 4 * 5 * Copyright (c) 2022 MediaTek Inc. 6 * Author: Bicycle Tsai <bicycle.tsai@mediatek.com> 7 * Trevor Wu <trevor.wu@mediatek.com> 8 * Chun-Chia Chiu <chun-chia.chiu@mediatek.com> 9 */ 10 11 #include <linux/bitfield.h> 12 #include <linux/regmap.h> 13 #include <sound/pcm_params.h> 14 #include "mt8188-afe-clk.h" 15 #include "mt8188-afe-common.h" 16 #include "mt8188-reg.h" 17 18 enum { 19 MTK_DAI_PCM_FMT_I2S, 20 MTK_DAI_PCM_FMT_EIAJ, 21 MTK_DAI_PCM_FMT_MODEA, 22 MTK_DAI_PCM_FMT_MODEB, 23 }; 24 25 enum { 26 MTK_DAI_PCM_CLK_A1SYS, 27 MTK_DAI_PCM_CLK_A2SYS, 28 MTK_DAI_PCM_CLK_26M_48K, 29 MTK_DAI_PCM_CLK_26M_441K, 30 }; 31 32 struct mtk_dai_pcm_rate { 33 unsigned int rate; 34 unsigned int reg_value; 35 }; 36 37 struct mtk_dai_pcmif_priv { 38 unsigned int slave_mode; 39 unsigned int lrck_inv; 40 unsigned int bck_inv; 41 unsigned int format; 42 }; 43 44 static const struct mtk_dai_pcm_rate mtk_dai_pcm_rates[] = { 45 { .rate = 8000, .reg_value = 0, }, 46 { .rate = 16000, .reg_value = 1, }, 47 { .rate = 32000, .reg_value = 2, }, 48 { .rate = 48000, .reg_value = 3, }, 49 { .rate = 11025, .reg_value = 1, }, 50 { .rate = 22050, .reg_value = 2, }, 51 { .rate = 44100, .reg_value = 3, }, 52 }; 53 54 static int mtk_dai_pcm_mode(unsigned int rate) 55 { 56 int i; 57 58 for (i = 0; i < ARRAY_SIZE(mtk_dai_pcm_rates); i++) 59 if (mtk_dai_pcm_rates[i].rate == rate) 60 return mtk_dai_pcm_rates[i].reg_value; 61 62 return -EINVAL; 63 } 64 65 static const struct snd_kcontrol_new mtk_dai_pcm_o000_mix[] = { 66 SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN0, 0, 1, 0), 67 SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN0_2, 6, 1, 0), 68 }; 69 70 static const struct snd_kcontrol_new mtk_dai_pcm_o001_mix[] = { 71 SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN1, 1, 1, 0), 72 SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN1_2, 7, 1, 0), 73 }; 74 75 static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = { 76 SND_SOC_DAPM_MIXER("I002", SND_SOC_NOPM, 0, 0, NULL, 0), 77 SND_SOC_DAPM_MIXER("I003", SND_SOC_NOPM, 0, 0, NULL, 0), 78 SND_SOC_DAPM_MIXER("O000", SND_SOC_NOPM, 0, 0, 79 mtk_dai_pcm_o000_mix, 80 ARRAY_SIZE(mtk_dai_pcm_o000_mix)), 81 SND_SOC_DAPM_MIXER("O001", SND_SOC_NOPM, 0, 0, 82 mtk_dai_pcm_o001_mix, 83 ARRAY_SIZE(mtk_dai_pcm_o001_mix)), 84 85 SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, 0, 0, NULL, 0), 86 87 SND_SOC_DAPM_INPUT("PCM1_INPUT"), 88 SND_SOC_DAPM_OUTPUT("PCM1_OUTPUT"), 89 90 SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc11"), 91 SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc12"), 92 SND_SOC_DAPM_CLOCK_SUPPLY("aud_pcmif"), 93 }; 94 95 static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = { 96 {"I002", NULL, "PCM1 Capture"}, 97 {"I003", NULL, "PCM1 Capture"}, 98 99 {"O000", "I000 Switch", "I000"}, 100 {"O001", "I001 Switch", "I001"}, 101 102 {"O000", "I070 Switch", "I070"}, 103 {"O001", "I071 Switch", "I071"}, 104 105 {"PCM1 Playback", NULL, "O000"}, 106 {"PCM1 Playback", NULL, "O001"}, 107 108 {"PCM1 Playback", NULL, "PCM_1_EN"}, 109 {"PCM1 Playback", NULL, "aud_asrc12"}, 110 {"PCM1 Playback", NULL, "aud_pcmif"}, 111 112 {"PCM1 Capture", NULL, "PCM_1_EN"}, 113 {"PCM1 Capture", NULL, "aud_asrc11"}, 114 {"PCM1 Capture", NULL, "aud_pcmif"}, 115 116 {"PCM1_OUTPUT", NULL, "PCM1 Playback"}, 117 {"PCM1 Capture", NULL, "PCM1_INPUT"}, 118 }; 119 120 static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, 121 struct snd_soc_dai *dai) 122 { 123 struct snd_pcm_runtime * const runtime = substream->runtime; 124 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 125 struct mt8188_afe_private *afe_priv = afe->platform_priv; 126 struct mtk_dai_pcmif_priv *pcmif_priv = NULL; 127 unsigned int slave_mode; 128 unsigned int lrck_inv; 129 unsigned int bck_inv; 130 unsigned int fmt; 131 unsigned int bit_width = dai->sample_bits; 132 unsigned int val = 0; 133 unsigned int mask = 0; 134 int fs = 0; 135 int mode = 0; 136 137 if (dai->id < 0) 138 return -EINVAL; 139 140 pcmif_priv = afe_priv->dai_priv[dai->id]; 141 slave_mode = pcmif_priv->slave_mode; 142 lrck_inv = pcmif_priv->lrck_inv; 143 bck_inv = pcmif_priv->bck_inv; 144 fmt = pcmif_priv->format; 145 146 /* sync freq mode */ 147 fs = mt8188_afe_fs_timing(runtime->rate); 148 if (fs < 0) 149 return -EINVAL; 150 151 val |= FIELD_PREP(PCM_INTF_CON2_SYNC_FREQ_MODE_MASK, fs); 152 mask |= PCM_INTF_CON2_SYNC_FREQ_MODE_MASK; 153 154 /* clk domain sel */ 155 if (runtime->rate % 8000) 156 val |= FIELD_PREP(PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK, 157 MTK_DAI_PCM_CLK_26M_441K); 158 else 159 val |= FIELD_PREP(PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK, 160 MTK_DAI_PCM_CLK_26M_48K); 161 mask |= PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK; 162 163 regmap_update_bits(afe->regmap, PCM_INTF_CON2, mask, val); 164 165 val = 0; 166 mask = 0; 167 168 /* pcm mode */ 169 mode = mtk_dai_pcm_mode(runtime->rate); 170 if (mode < 0) 171 return -EINVAL; 172 173 val |= FIELD_PREP(PCM_INTF_CON1_PCM_MODE_MASK, mode); 174 mask |= PCM_INTF_CON1_PCM_MODE_MASK; 175 176 /* pcm format */ 177 val |= FIELD_PREP(PCM_INTF_CON1_PCM_FMT_MASK, fmt); 178 mask |= PCM_INTF_CON1_PCM_FMT_MASK; 179 180 /* pcm sync length */ 181 if (fmt == MTK_DAI_PCM_FMT_MODEA || 182 fmt == MTK_DAI_PCM_FMT_MODEB) 183 val |= FIELD_PREP(PCM_INTF_CON1_SYNC_LENGTH_MASK, 1); 184 else 185 val |= FIELD_PREP(PCM_INTF_CON1_SYNC_LENGTH_MASK, bit_width); 186 mask |= PCM_INTF_CON1_SYNC_LENGTH_MASK; 187 188 /* pcm bits, word length */ 189 if (bit_width > 16) { 190 val |= PCM_INTF_CON1_PCM_24BIT; 191 val |= PCM_INTF_CON1_PCM_WLEN_64BCK; 192 } else { 193 val |= PCM_INTF_CON1_PCM_16BIT; 194 val |= PCM_INTF_CON1_PCM_WLEN_32BCK; 195 } 196 mask |= PCM_INTF_CON1_PCM_BIT_MASK; 197 mask |= PCM_INTF_CON1_PCM_WLEN_MASK; 198 199 /* master/slave */ 200 if (!slave_mode) { 201 val |= PCM_INTF_CON1_PCM_MASTER; 202 203 if (lrck_inv) 204 val |= PCM_INTF_CON1_SYNC_OUT_INV; 205 if (bck_inv) 206 val |= PCM_INTF_CON1_BCLK_OUT_INV; 207 mask |= PCM_INTF_CON1_CLK_OUT_INV_MASK; 208 } else { 209 val |= PCM_INTF_CON1_PCM_SLAVE; 210 211 if (lrck_inv) 212 val |= PCM_INTF_CON1_SYNC_IN_INV; 213 if (bck_inv) 214 val |= PCM_INTF_CON1_BCLK_IN_INV; 215 mask |= PCM_INTF_CON1_CLK_IN_INV_MASK; 216 217 // TODO: add asrc setting for slave mode 218 } 219 mask |= PCM_INTF_CON1_PCM_M_S_MASK; 220 221 regmap_update_bits(afe->regmap, PCM_INTF_CON1, mask, val); 222 223 return 0; 224 } 225 226 /* dai ops */ 227 static int mtk_dai_pcm_prepare(struct snd_pcm_substream *substream, 228 struct snd_soc_dai *dai) 229 { 230 if (snd_soc_dai_get_widget_playback(dai)->active || 231 snd_soc_dai_get_widget_capture(dai)->active) 232 return 0; 233 234 return mtk_dai_pcm_configure(substream, dai); 235 } 236 237 static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 238 { 239 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 240 struct mt8188_afe_private *afe_priv = afe->platform_priv; 241 struct mtk_dai_pcmif_priv *pcmif_priv = NULL; 242 243 dev_dbg(dai->dev, "%s fmt 0x%x\n", __func__, fmt); 244 245 if (dai->id < 0) 246 return -EINVAL; 247 248 pcmif_priv = afe_priv->dai_priv[dai->id]; 249 250 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 251 case SND_SOC_DAIFMT_I2S: 252 pcmif_priv->format = MTK_DAI_PCM_FMT_I2S; 253 break; 254 case SND_SOC_DAIFMT_DSP_A: 255 pcmif_priv->format = MTK_DAI_PCM_FMT_MODEA; 256 break; 257 case SND_SOC_DAIFMT_DSP_B: 258 pcmif_priv->format = MTK_DAI_PCM_FMT_MODEB; 259 break; 260 default: 261 return -EINVAL; 262 } 263 264 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 265 case SND_SOC_DAIFMT_NB_NF: 266 pcmif_priv->bck_inv = 0; 267 pcmif_priv->lrck_inv = 0; 268 break; 269 case SND_SOC_DAIFMT_NB_IF: 270 pcmif_priv->bck_inv = 0; 271 pcmif_priv->lrck_inv = 1; 272 break; 273 case SND_SOC_DAIFMT_IB_NF: 274 pcmif_priv->bck_inv = 1; 275 pcmif_priv->lrck_inv = 0; 276 break; 277 case SND_SOC_DAIFMT_IB_IF: 278 pcmif_priv->bck_inv = 1; 279 pcmif_priv->lrck_inv = 1; 280 break; 281 default: 282 return -EINVAL; 283 } 284 285 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 286 case SND_SOC_DAIFMT_BC_FC: 287 pcmif_priv->slave_mode = 1; 288 break; 289 case SND_SOC_DAIFMT_BP_FP: 290 pcmif_priv->slave_mode = 0; 291 break; 292 default: 293 return -EINVAL; 294 } 295 296 return 0; 297 } 298 299 static const struct snd_soc_dai_ops mtk_dai_pcm_ops = { 300 .prepare = mtk_dai_pcm_prepare, 301 .set_fmt = mtk_dai_pcm_set_fmt, 302 }; 303 304 /* dai driver */ 305 #define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000) 306 307 #define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 308 SNDRV_PCM_FMTBIT_S24_LE |\ 309 SNDRV_PCM_FMTBIT_S32_LE) 310 311 static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = { 312 { 313 .name = "PCM1", 314 .id = MT8188_AFE_IO_PCM, 315 .playback = { 316 .stream_name = "PCM1 Playback", 317 .channels_min = 1, 318 .channels_max = 2, 319 .rates = MTK_PCM_RATES, 320 .formats = MTK_PCM_FORMATS, 321 }, 322 .capture = { 323 .stream_name = "PCM1 Capture", 324 .channels_min = 1, 325 .channels_max = 2, 326 .rates = MTK_PCM_RATES, 327 .formats = MTK_PCM_FORMATS, 328 }, 329 .ops = &mtk_dai_pcm_ops, 330 .symmetric_rate = 1, 331 .symmetric_sample_bits = 1, 332 }, 333 }; 334 335 static int init_pcmif_priv_data(struct mtk_base_afe *afe) 336 { 337 struct mt8188_afe_private *afe_priv = afe->platform_priv; 338 struct mtk_dai_pcmif_priv *pcmif_priv; 339 340 pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_pcmif_priv), 341 GFP_KERNEL); 342 if (!pcmif_priv) 343 return -ENOMEM; 344 345 afe_priv->dai_priv[MT8188_AFE_IO_PCM] = pcmif_priv; 346 return 0; 347 } 348 349 int mt8188_dai_pcm_register(struct mtk_base_afe *afe) 350 { 351 struct mtk_base_afe_dai *dai; 352 353 dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); 354 if (!dai) 355 return -ENOMEM; 356 357 list_add(&dai->list, &afe->sub_dais); 358 359 dai->dai_drivers = mtk_dai_pcm_driver; 360 dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver); 361 362 dai->dapm_widgets = mtk_dai_pcm_widgets; 363 dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets); 364 dai->dapm_routes = mtk_dai_pcm_routes; 365 dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes); 366 367 return init_pcmif_priv_data(afe); 368 } 369