| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | // |
| 3 | // MediaTek ALSA SoC Audio DAI SRC Control |
| 4 | // |
| 5 | // Copyright (c) 2022 MediaTek Inc. |
| 6 | // Author: Jiaxin Yu <jiaxin.yu@mediatek.com> |
| 7 | |
| 8 | #include <linux/regmap.h> |
| 9 | #include "mt8186-afe-common.h" |
| 10 | #include "mt8186-interconnection.h" |
| 11 | |
| 12 | struct mtk_afe_src_priv { |
| 13 | int dl_rate; |
| 14 | int ul_rate; |
| 15 | }; |
| 16 | |
| 17 | static const unsigned int src_iir_coeff_32_to_16[] = { |
| 18 | 0x0dbae6, 0xff9b0a, 0x0dbae6, 0x05e488, 0xe072b9, 0x000002, |
| 19 | 0x0dbae6, 0x000f3b, 0x0dbae6, 0x06a537, 0xe17d79, 0x000002, |
| 20 | 0x0dbae6, 0x01246a, 0x0dbae6, 0x087261, 0xe306be, 0x000002, |
| 21 | 0x0dbae6, 0x03437d, 0x0dbae6, 0x0bc16f, 0xe57c87, 0x000002, |
| 22 | 0x0dbae6, 0x072981, 0x0dbae6, 0x111dd3, 0xe94f2a, 0x000002, |
| 23 | 0x0dbae6, 0x0dc4a6, 0x0dbae6, 0x188611, 0xee85a0, 0x000002, |
| 24 | 0x0dbae6, 0x168b9a, 0x0dbae6, 0x200e8f, 0xf3ccf1, 0x000002, |
| 25 | 0x000000, 0x1b75cb, 0x1b75cb, 0x2374a2, 0x000000, 0x000001 |
| 26 | }; |
| 27 | |
| 28 | static const unsigned int src_iir_coeff_44_to_16[] = { |
| 29 | 0x09ae28, 0xf7d97d, 0x09ae28, 0x212a3d, 0xe0ac3a, 0x000002, |
| 30 | 0x09ae28, 0xf8525a, 0x09ae28, 0x216d72, 0xe234be, 0x000002, |
| 31 | 0x09ae28, 0xf980f5, 0x09ae28, 0x22a057, 0xe45a81, 0x000002, |
| 32 | 0x09ae28, 0xfc0a08, 0x09ae28, 0x24d3bd, 0xe7752d, 0x000002, |
| 33 | 0x09ae28, 0x016162, 0x09ae28, 0x27da01, 0xeb6ea8, 0x000002, |
| 34 | 0x09ae28, 0x0b67df, 0x09ae28, 0x2aca4a, 0xef34c4, 0x000002, |
| 35 | 0x000000, 0x135c50, 0x135c50, 0x2c1079, 0x000000, 0x000001 |
| 36 | }; |
| 37 | |
| 38 | static const unsigned int src_iir_coeff_44_to_32[] = { |
| 39 | 0x096966, 0x0c4d35, 0x096966, 0xedee81, 0xf05070, 0x000003, |
| 40 | 0x12d2cc, 0x193910, 0x12d2cc, 0xddbf4f, 0xe21e1d, 0x000002, |
| 41 | 0x12d2cc, 0x1a9e60, 0x12d2cc, 0xe18916, 0xe470fd, 0x000002, |
| 42 | 0x12d2cc, 0x1d06e0, 0x12d2cc, 0xe8a4a6, 0xe87b24, 0x000002, |
| 43 | 0x12d2cc, 0x207578, 0x12d2cc, 0xf4fe62, 0xef5917, 0x000002, |
| 44 | 0x12d2cc, 0x24055f, 0x12d2cc, 0x05ee2b, 0xf8b502, 0x000002, |
| 45 | 0x000000, 0x25a599, 0x25a599, 0x0fabe2, 0x000000, 0x000001 |
| 46 | }; |
| 47 | |
| 48 | static const unsigned int src_iir_coeff_48_to_16[] = { |
| 49 | 0x0296a4, 0xfd69dd, 0x0296a4, 0x209439, 0xe01ff9, 0x000002, |
| 50 | 0x0f4ff3, 0xf0d6d4, 0x0f4ff3, 0x209bc9, 0xe076c3, 0x000002, |
| 51 | 0x0e8490, 0xf1fe63, 0x0e8490, 0x20cfd6, 0xe12124, 0x000002, |
| 52 | 0x14852f, 0xed794a, 0x14852f, 0x21503d, 0xe28b32, 0x000002, |
| 53 | 0x136222, 0xf17677, 0x136222, 0x225be1, 0xe56964, 0x000002, |
| 54 | 0x0a8d85, 0xfc4a97, 0x0a8d85, 0x24310c, 0xea6952, 0x000002, |
| 55 | 0x05eff5, 0x043455, 0x05eff5, 0x4ced8f, 0xe134d6, 0x000001, |
| 56 | 0x000000, 0x3aebe6, 0x3aebe6, 0x04f3b0, 0x000000, 0x000004 |
| 57 | }; |
| 58 | |
| 59 | static const unsigned int src_iir_coeff_48_to_32[] = { |
| 60 | 0x10c1b8, 0x10a7df, 0x10c1b8, 0xe7514e, 0xe0b41f, 0x000002, |
| 61 | 0x10c1b8, 0x116257, 0x10c1b8, 0xe9402f, 0xe25aaa, 0x000002, |
| 62 | 0x10c1b8, 0x130c89, 0x10c1b8, 0xed3cc3, 0xe4dddb, 0x000002, |
| 63 | 0x10c1b8, 0x1600dd, 0x10c1b8, 0xf48000, 0xe90c55, 0x000002, |
| 64 | 0x10c1b8, 0x1a672e, 0x10c1b8, 0x00494c, 0xefa807, 0x000002, |
| 65 | 0x10c1b8, 0x1f38e6, 0x10c1b8, 0x0ee076, 0xf7c5f3, 0x000002, |
| 66 | 0x000000, 0x218370, 0x218370, 0x168b40, 0x000000, 0x000001 |
| 67 | }; |
| 68 | |
| 69 | static const unsigned int src_iir_coeff_48_to_44[] = { |
| 70 | 0x0bf71c, 0x170f3f, 0x0bf71c, 0xe3a4c8, 0xf096cb, 0x000003, |
| 71 | 0x0bf71c, 0x17395e, 0x0bf71c, 0xe58085, 0xf210c8, 0x000003, |
| 72 | 0x0bf71c, 0x1782bd, 0x0bf71c, 0xe95ef6, 0xf4c899, 0x000003, |
| 73 | 0x0bf71c, 0x17cd97, 0x0bf71c, 0xf1608a, 0xfa3b18, 0x000003, |
| 74 | 0x000000, 0x2fdc6f, 0x2fdc6f, 0xf15663, 0x000000, 0x000001 |
| 75 | }; |
| 76 | |
| 77 | static const unsigned int src_iir_coeff_96_to_16[] = { |
| 78 | 0x0805a1, 0xf21ae3, 0x0805a1, 0x3840bb, 0xe02a2e, 0x000002, |
| 79 | 0x0d5dd8, 0xe8f259, 0x0d5dd8, 0x1c0af6, 0xf04700, 0x000003, |
| 80 | 0x0bb422, 0xec08d9, 0x0bb422, 0x1bfccc, 0xf09216, 0x000003, |
| 81 | 0x08fde6, 0xf108be, 0x08fde6, 0x1bf096, 0xf10ae0, 0x000003, |
| 82 | 0x0ae311, 0xeeeda3, 0x0ae311, 0x37c646, 0xe385f5, 0x000002, |
| 83 | 0x044089, 0xfa7242, 0x044089, 0x37a785, 0xe56526, 0x000002, |
| 84 | 0x00c75c, 0xffb947, 0x00c75c, 0x378ba3, 0xe72c5f, 0x000002, |
| 85 | 0x000000, 0x0ef76e, 0x0ef76e, 0x377fda, 0x000000, 0x000001, |
| 86 | }; |
| 87 | |
| 88 | static const unsigned int src_iir_coeff_96_to_44[] = { |
| 89 | 0x08b543, 0xfd80f4, 0x08b543, 0x0e2332, 0xe06ed0, 0x000002, |
| 90 | 0x1b6038, 0xf90e7e, 0x1b6038, 0x0ec1ac, 0xe16f66, 0x000002, |
| 91 | 0x188478, 0xfbb921, 0x188478, 0x105859, 0xe2e596, 0x000002, |
| 92 | 0x13eff3, 0xffa707, 0x13eff3, 0x13455c, 0xe533b7, 0x000002, |
| 93 | 0x0dc239, 0x03d458, 0x0dc239, 0x17f120, 0xe8b617, 0x000002, |
| 94 | 0x0745f1, 0x05d790, 0x0745f1, 0x1e3d75, 0xed5f18, 0x000002, |
| 95 | 0x05641f, 0x085e2b, 0x05641f, 0x48efd0, 0xe3e9c8, 0x000001, |
| 96 | 0x000000, 0x28f632, 0x28f632, 0x273905, 0x000000, 0x000001, |
| 97 | }; |
| 98 | |
| 99 | static unsigned int mtk_get_src_freq_mode(struct mtk_base_afe *afe, int rate) |
| 100 | { |
| 101 | switch (rate) { |
| 102 | case 8000: |
| 103 | return 0x50000; |
| 104 | case 11025: |
| 105 | return 0x6e400; |
| 106 | case 12000: |
| 107 | return 0x78000; |
| 108 | case 16000: |
| 109 | return 0xa0000; |
| 110 | case 22050: |
| 111 | return 0xdc800; |
| 112 | case 24000: |
| 113 | return 0xf0000; |
| 114 | case 32000: |
| 115 | return 0x140000; |
| 116 | case 44100: |
| 117 | return 0x1b9000; |
| 118 | case 48000: |
| 119 | return 0x1e0000; |
| 120 | case 88200: |
| 121 | return 0x372000; |
| 122 | case 96000: |
| 123 | return 0x3c0000; |
| 124 | case 176400: |
| 125 | return 0x6e4000; |
| 126 | case 192000: |
| 127 | return 0x780000; |
| 128 | default: |
| 129 | dev_err(afe->dev, "%s(), rate %d invalid!!!\n" , |
| 130 | __func__, rate); |
| 131 | return 0; |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | static const unsigned int *get_iir_coeff(unsigned int rate_in, |
| 136 | unsigned int rate_out, |
| 137 | unsigned int *param_num) |
| 138 | { |
| 139 | if (rate_in == 32000 && rate_out == 16000) { |
| 140 | *param_num = ARRAY_SIZE(src_iir_coeff_32_to_16); |
| 141 | return src_iir_coeff_32_to_16; |
| 142 | } else if (rate_in == 44100 && rate_out == 16000) { |
| 143 | *param_num = ARRAY_SIZE(src_iir_coeff_44_to_16); |
| 144 | return src_iir_coeff_44_to_16; |
| 145 | } else if (rate_in == 44100 && rate_out == 32000) { |
| 146 | *param_num = ARRAY_SIZE(src_iir_coeff_44_to_32); |
| 147 | return src_iir_coeff_44_to_32; |
| 148 | } else if ((rate_in == 48000 && rate_out == 16000) || |
| 149 | (rate_in == 96000 && rate_out == 32000)) { |
| 150 | *param_num = ARRAY_SIZE(src_iir_coeff_48_to_16); |
| 151 | return src_iir_coeff_48_to_16; |
| 152 | } else if (rate_in == 48000 && rate_out == 32000) { |
| 153 | *param_num = ARRAY_SIZE(src_iir_coeff_48_to_32); |
| 154 | return src_iir_coeff_48_to_32; |
| 155 | } else if (rate_in == 48000 && rate_out == 44100) { |
| 156 | *param_num = ARRAY_SIZE(src_iir_coeff_48_to_44); |
| 157 | return src_iir_coeff_48_to_44; |
| 158 | } else if (rate_in == 96000 && rate_out == 16000) { |
| 159 | *param_num = ARRAY_SIZE(src_iir_coeff_96_to_16); |
| 160 | return src_iir_coeff_96_to_16; |
| 161 | } else if ((rate_in == 96000 && rate_out == 44100) || |
| 162 | (rate_in == 48000 && rate_out == 22050)) { |
| 163 | *param_num = ARRAY_SIZE(src_iir_coeff_96_to_44); |
| 164 | return src_iir_coeff_96_to_44; |
| 165 | } |
| 166 | |
| 167 | *param_num = 0; |
| 168 | return NULL; |
| 169 | } |
| 170 | |
| 171 | static int mtk_set_src_1_param(struct mtk_base_afe *afe, int id) |
| 172 | { |
| 173 | struct mt8186_afe_private *afe_priv = afe->platform_priv; |
| 174 | struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id]; |
| 175 | unsigned int iir_coeff_num; |
| 176 | unsigned int iir_stage; |
| 177 | int rate_in = src_priv->dl_rate; |
| 178 | int rate_out = src_priv->ul_rate; |
| 179 | unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate: rate_out); |
| 180 | unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate: rate_in); |
| 181 | |
| 182 | /* set out freq mode */ |
| 183 | regmap_update_bits(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON3, |
| 184 | G_SRC_ASM_FREQ_4_MASK_SFT, |
| 185 | val: out_freq_mode << G_SRC_ASM_FREQ_4_SFT); |
| 186 | |
| 187 | /* set in freq mode */ |
| 188 | regmap_update_bits(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON4, |
| 189 | G_SRC_ASM_FREQ_5_MASK_SFT, |
| 190 | val: in_freq_mode << G_SRC_ASM_FREQ_5_SFT); |
| 191 | |
| 192 | regmap_write(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, val: 0x3f5986); |
| 193 | regmap_write(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, val: 0x3f5987); |
| 194 | regmap_write(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON6, val: 0x1fbd); |
| 195 | regmap_write(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, val: 0); |
| 196 | |
| 197 | /* set iir if in_rate > out_rate */ |
| 198 | if (rate_in > rate_out) { |
| 199 | int i; |
| 200 | const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out, |
| 201 | param_num: &iir_coeff_num); |
| 202 | |
| 203 | if (iir_coeff_num == 0 || !iir_coeff) { |
| 204 | dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n" , |
| 205 | __func__, iir_coeff_num, iir_coeff); |
| 206 | return -EINVAL; |
| 207 | } |
| 208 | |
| 209 | /* COEFF_SRAM_CTRL */ |
| 210 | regmap_update_bits(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0, |
| 211 | G_SRC_COEFF_SRAM_CTRL_MASK_SFT, |
| 212 | BIT(G_SRC_COEFF_SRAM_CTRL_SFT)); |
| 213 | /* Clear coeff history to r/w coeff from the first position */ |
| 214 | regmap_update_bits(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON13, |
| 215 | G_SRC_COEFF_SRAM_ADR_MASK_SFT, val: 0); |
| 216 | /* Write SRC coeff, should not read the reg during write */ |
| 217 | for (i = 0; i < iir_coeff_num; i++) |
| 218 | regmap_write(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON12, |
| 219 | val: iir_coeff[i]); |
| 220 | /* disable sram access */ |
| 221 | regmap_update_bits(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0, |
| 222 | G_SRC_COEFF_SRAM_CTRL_MASK_SFT, val: 0); |
| 223 | /* CHSET_IIR_STAGE */ |
| 224 | iir_stage = (iir_coeff_num / 6) - 1; |
| 225 | regmap_update_bits(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, |
| 226 | G_SRC_CHSET_IIR_STAGE_MASK_SFT, |
| 227 | val: iir_stage << G_SRC_CHSET_IIR_STAGE_SFT); |
| 228 | /* CHSET_IIR_EN */ |
| 229 | regmap_update_bits(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, |
| 230 | G_SRC_CHSET_IIR_EN_MASK_SFT, |
| 231 | BIT(G_SRC_CHSET_IIR_EN_SFT)); |
| 232 | } else { |
| 233 | /* CHSET_IIR_EN off */ |
| 234 | regmap_update_bits(map: afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, |
| 235 | G_SRC_CHSET_IIR_EN_MASK_SFT, val: 0); |
| 236 | } |
| 237 | |
| 238 | return 0; |
| 239 | } |
| 240 | |
| 241 | static int mtk_set_src_2_param(struct mtk_base_afe *afe, int id) |
| 242 | { |
| 243 | struct mt8186_afe_private *afe_priv = afe->platform_priv; |
| 244 | struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id]; |
| 245 | unsigned int iir_coeff_num; |
| 246 | unsigned int iir_stage; |
| 247 | int rate_in = src_priv->dl_rate; |
| 248 | int rate_out = src_priv->ul_rate; |
| 249 | unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate: rate_out); |
| 250 | unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate: rate_in); |
| 251 | |
| 252 | /* set out freq mode */ |
| 253 | regmap_update_bits(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON3, |
| 254 | G_SRC_ASM_FREQ_4_MASK_SFT, |
| 255 | val: out_freq_mode << G_SRC_ASM_FREQ_4_SFT); |
| 256 | |
| 257 | /* set in freq mode */ |
| 258 | regmap_update_bits(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON4, |
| 259 | G_SRC_ASM_FREQ_5_MASK_SFT, |
| 260 | val: in_freq_mode << G_SRC_ASM_FREQ_5_SFT); |
| 261 | |
| 262 | regmap_write(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, val: 0x3f5986); |
| 263 | regmap_write(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, val: 0x3f5987); |
| 264 | regmap_write(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON6, val: 0x1fbd); |
| 265 | regmap_write(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, val: 0); |
| 266 | |
| 267 | /* set iir if in_rate > out_rate */ |
| 268 | if (rate_in > rate_out) { |
| 269 | int i; |
| 270 | const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out, |
| 271 | param_num: &iir_coeff_num); |
| 272 | |
| 273 | if (iir_coeff_num == 0 || !iir_coeff) { |
| 274 | dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n" , |
| 275 | __func__, iir_coeff_num, iir_coeff); |
| 276 | return -EINVAL; |
| 277 | } |
| 278 | |
| 279 | /* COEFF_SRAM_CTRL */ |
| 280 | regmap_update_bits(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0, |
| 281 | G_SRC_COEFF_SRAM_CTRL_MASK_SFT, |
| 282 | BIT(G_SRC_COEFF_SRAM_CTRL_SFT)); |
| 283 | /* Clear coeff history to r/w coeff from the first position */ |
| 284 | regmap_update_bits(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON13, |
| 285 | G_SRC_COEFF_SRAM_ADR_MASK_SFT, val: 0); |
| 286 | /* Write SRC coeff, should not read the reg during write */ |
| 287 | for (i = 0; i < iir_coeff_num; i++) |
| 288 | regmap_write(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON12, |
| 289 | val: iir_coeff[i]); |
| 290 | /* disable sram access */ |
| 291 | regmap_update_bits(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0, |
| 292 | G_SRC_COEFF_SRAM_CTRL_MASK_SFT, val: 0); |
| 293 | /* CHSET_IIR_STAGE */ |
| 294 | iir_stage = (iir_coeff_num / 6) - 1; |
| 295 | regmap_update_bits(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, |
| 296 | G_SRC_CHSET_IIR_STAGE_MASK_SFT, |
| 297 | val: iir_stage << G_SRC_CHSET_IIR_STAGE_SFT); |
| 298 | /* CHSET_IIR_EN */ |
| 299 | regmap_update_bits(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, |
| 300 | G_SRC_CHSET_IIR_EN_MASK_SFT, |
| 301 | BIT(G_SRC_CHSET_IIR_EN_SFT)); |
| 302 | } else { |
| 303 | /* CHSET_IIR_EN off */ |
| 304 | regmap_update_bits(map: afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, |
| 305 | G_SRC_CHSET_IIR_EN_MASK_SFT, val: 0); |
| 306 | } |
| 307 | |
| 308 | return 0; |
| 309 | } |
| 310 | |
| 311 | #define HW_SRC_1_EN_W_NAME "HW_SRC_1_Enable" |
| 312 | #define HW_SRC_2_EN_W_NAME "HW_SRC_2_Enable" |
| 313 | |
| 314 | static int mtk_hw_src_event(struct snd_soc_dapm_widget *w, |
| 315 | struct snd_kcontrol *kcontrol, |
| 316 | int event) |
| 317 | { |
| 318 | struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(dapm: w->dapm); |
| 319 | struct mtk_base_afe *afe = snd_soc_component_get_drvdata(c: cmpnt); |
| 320 | struct mt8186_afe_private *afe_priv = afe->platform_priv; |
| 321 | int id; |
| 322 | struct mtk_afe_src_priv *src_priv; |
| 323 | unsigned int reg; |
| 324 | |
| 325 | if (snd_soc_dapm_widget_name_cmp(widget: w, HW_SRC_1_EN_W_NAME) == 0) |
| 326 | id = MT8186_DAI_SRC_1; |
| 327 | else |
| 328 | id = MT8186_DAI_SRC_2; |
| 329 | |
| 330 | src_priv = afe_priv->dai_priv[id]; |
| 331 | |
| 332 | dev_dbg(afe->dev, |
| 333 | "%s(), name %s, event 0x%x, id %d, src_priv %p, dl_rate %d, ul_rate %d\n" , |
| 334 | __func__, w->name, event, id, src_priv, |
| 335 | src_priv->dl_rate, src_priv->ul_rate); |
| 336 | |
| 337 | switch (event) { |
| 338 | case SND_SOC_DAPM_PRE_PMU: |
| 339 | if (id == MT8186_DAI_SRC_1) |
| 340 | mtk_set_src_1_param(afe, id); |
| 341 | else |
| 342 | mtk_set_src_2_param(afe, id); |
| 343 | break; |
| 344 | case SND_SOC_DAPM_POST_PMU: |
| 345 | reg = (id == MT8186_DAI_SRC_1) ? |
| 346 | AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0; |
| 347 | /* ASM_ON */ |
| 348 | regmap_update_bits(map: afe->regmap, reg, |
| 349 | G_SRC_ASM_ON_MASK_SFT, |
| 350 | BIT(G_SRC_ASM_ON_SFT)); |
| 351 | /* CHSET_ON */ |
| 352 | regmap_update_bits(map: afe->regmap, reg, |
| 353 | G_SRC_CHSET_ON_MASK_SFT, |
| 354 | BIT(G_SRC_CHSET_ON_SFT)); |
| 355 | /* CHSET_STR_CLR */ |
| 356 | regmap_update_bits(map: afe->regmap, reg, |
| 357 | G_SRC_CHSET_STR_CLR_MASK_SFT, |
| 358 | BIT(G_SRC_CHSET_STR_CLR_SFT)); |
| 359 | break; |
| 360 | case SND_SOC_DAPM_PRE_PMD: |
| 361 | reg = (id == MT8186_DAI_SRC_1) ? |
| 362 | AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0; |
| 363 | /* ASM_OFF */ |
| 364 | regmap_update_bits(map: afe->regmap, reg, G_SRC_ASM_ON_MASK_SFT, val: 0); |
| 365 | /* CHSET_OFF */ |
| 366 | regmap_update_bits(map: afe->regmap, reg, G_SRC_CHSET_ON_MASK_SFT, val: 0); |
| 367 | /* CHSET_STR_CLR */ |
| 368 | regmap_update_bits(map: afe->regmap, reg, G_SRC_CHSET_STR_CLR_MASK_SFT, val: 0); |
| 369 | break; |
| 370 | default: |
| 371 | break; |
| 372 | } |
| 373 | |
| 374 | return 0; |
| 375 | } |
| 376 | |
| 377 | /* dai component */ |
| 378 | static const struct snd_kcontrol_new mtk_hw_src_1_in_ch1_mix[] = { |
| 379 | SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch" , AFE_CONN40, |
| 380 | I_DL1_CH1, 1, 0), |
| 381 | SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch" , AFE_CONN40, |
| 382 | I_DL2_CH1, 1, 0), |
| 383 | SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch" , AFE_CONN40, |
| 384 | I_DL3_CH1, 1, 0), |
| 385 | SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch" , AFE_CONN40_1, |
| 386 | I_DL4_CH1, 1, 0), |
| 387 | SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch" , AFE_CONN40_1, |
| 388 | I_DL6_CH1, 1, 0), |
| 389 | SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch" , AFE_CONN40, |
| 390 | I_I2S0_CH1, 1, 0), |
| 391 | SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch" , AFE_CONN40_1, |
| 392 | I_DL5_CH1, 1, 0), |
| 393 | }; |
| 394 | |
| 395 | static const struct snd_kcontrol_new mtk_hw_src_1_in_ch2_mix[] = { |
| 396 | SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch" , AFE_CONN41, |
| 397 | I_DL1_CH2, 1, 0), |
| 398 | SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch" , AFE_CONN41, |
| 399 | I_DL2_CH2, 1, 0), |
| 400 | SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch" , AFE_CONN41, |
| 401 | I_DL3_CH2, 1, 0), |
| 402 | SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch" , AFE_CONN41_1, |
| 403 | I_DL4_CH2, 1, 0), |
| 404 | SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch" , AFE_CONN41_1, |
| 405 | I_DL6_CH2, 1, 0), |
| 406 | SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch" , AFE_CONN41, |
| 407 | I_I2S0_CH2, 1, 0), |
| 408 | SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch" , AFE_CONN41_1, |
| 409 | I_DL5_CH2, 1, 0), |
| 410 | }; |
| 411 | |
| 412 | static const struct snd_kcontrol_new mtk_hw_src_2_in_ch1_mix[] = { |
| 413 | SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch" , AFE_CONN42, |
| 414 | I_DL1_CH1, 1, 0), |
| 415 | SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch" , AFE_CONN42, |
| 416 | I_DL2_CH1, 1, 0), |
| 417 | SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch" , AFE_CONN42, |
| 418 | I_DL3_CH1, 1, 0), |
| 419 | SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch" , AFE_CONN42, |
| 420 | I_DL4_CH1, 1, 0), |
| 421 | SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch" , AFE_CONN42_1, |
| 422 | I_DL5_CH1, 1, 0), |
| 423 | SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch" , AFE_CONN42_1, |
| 424 | I_DL6_CH1, 1, 0), |
| 425 | SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH1 Switch" , AFE_CONN42, |
| 426 | I_GAIN2_OUT_CH1, 1, 0), |
| 427 | }; |
| 428 | |
| 429 | static const struct snd_kcontrol_new mtk_hw_src_2_in_ch2_mix[] = { |
| 430 | SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch" , AFE_CONN43, |
| 431 | I_DL1_CH2, 1, 0), |
| 432 | SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch" , AFE_CONN43, |
| 433 | I_DL2_CH2, 1, 0), |
| 434 | SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch" , AFE_CONN43, |
| 435 | I_DL3_CH2, 1, 0), |
| 436 | SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch" , AFE_CONN43, |
| 437 | I_DL4_CH2, 1, 0), |
| 438 | SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch" , AFE_CONN43_1, |
| 439 | I_DL5_CH2, 1, 0), |
| 440 | SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch" , AFE_CONN43_1, |
| 441 | I_DL6_CH2, 1, 0), |
| 442 | SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH2 Switch" , AFE_CONN43, |
| 443 | I_GAIN2_OUT_CH2, 1, 0), |
| 444 | }; |
| 445 | |
| 446 | static const struct snd_soc_dapm_widget mtk_dai_src_widgets[] = { |
| 447 | /* inter-connections */ |
| 448 | SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH1" , SND_SOC_NOPM, 0, 0, |
| 449 | mtk_hw_src_1_in_ch1_mix, |
| 450 | ARRAY_SIZE(mtk_hw_src_1_in_ch1_mix)), |
| 451 | SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH2" , SND_SOC_NOPM, 0, 0, |
| 452 | mtk_hw_src_1_in_ch2_mix, |
| 453 | ARRAY_SIZE(mtk_hw_src_1_in_ch2_mix)), |
| 454 | SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH1" , SND_SOC_NOPM, 0, 0, |
| 455 | mtk_hw_src_2_in_ch1_mix, |
| 456 | ARRAY_SIZE(mtk_hw_src_2_in_ch1_mix)), |
| 457 | SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH2" , SND_SOC_NOPM, 0, 0, |
| 458 | mtk_hw_src_2_in_ch2_mix, |
| 459 | ARRAY_SIZE(mtk_hw_src_2_in_ch2_mix)), |
| 460 | |
| 461 | SND_SOC_DAPM_SUPPLY(HW_SRC_1_EN_W_NAME, |
| 462 | GENERAL_ASRC_EN_ON, GENERAL1_ASRC_EN_ON_SFT, 0, |
| 463 | mtk_hw_src_event, |
| 464 | SND_SOC_DAPM_PRE_PMU | |
| 465 | SND_SOC_DAPM_POST_PMU | |
| 466 | SND_SOC_DAPM_PRE_PMD), |
| 467 | |
| 468 | SND_SOC_DAPM_SUPPLY(HW_SRC_2_EN_W_NAME, |
| 469 | GENERAL_ASRC_EN_ON, GENERAL2_ASRC_EN_ON_SFT, 0, |
| 470 | mtk_hw_src_event, |
| 471 | SND_SOC_DAPM_PRE_PMU | |
| 472 | SND_SOC_DAPM_POST_PMU | |
| 473 | SND_SOC_DAPM_PRE_PMD), |
| 474 | |
| 475 | SND_SOC_DAPM_INPUT("HW SRC 1 Out Endpoint" ), |
| 476 | SND_SOC_DAPM_INPUT("HW SRC 2 Out Endpoint" ), |
| 477 | SND_SOC_DAPM_OUTPUT("HW SRC 1 In Endpoint" ), |
| 478 | SND_SOC_DAPM_OUTPUT("HW SRC 2 In Endpoint" ), |
| 479 | }; |
| 480 | |
| 481 | static int mtk_afe_src_en_connect(struct snd_soc_dapm_widget *source, |
| 482 | struct snd_soc_dapm_widget *sink) |
| 483 | { |
| 484 | struct snd_soc_dapm_widget *w = source; |
| 485 | struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(dapm: w->dapm); |
| 486 | struct mtk_base_afe *afe = snd_soc_component_get_drvdata(c: cmpnt); |
| 487 | struct mt8186_afe_private *afe_priv = afe->platform_priv; |
| 488 | struct mtk_afe_src_priv *src_priv; |
| 489 | |
| 490 | if (snd_soc_dapm_widget_name_cmp(widget: w, HW_SRC_1_EN_W_NAME) == 0) |
| 491 | src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_1]; |
| 492 | else |
| 493 | src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_2]; |
| 494 | |
| 495 | dev_dbg(afe->dev, |
| 496 | "%s(), source %s, sink %s, dl_rate %d, ul_rate %d\n" , |
| 497 | __func__, source->name, sink->name, |
| 498 | src_priv->dl_rate, src_priv->ul_rate); |
| 499 | |
| 500 | return (src_priv->dl_rate > 0 && src_priv->ul_rate > 0) ? 1 : 0; |
| 501 | } |
| 502 | |
| 503 | static const struct snd_soc_dapm_route mtk_dai_src_routes[] = { |
| 504 | {"HW_SRC_1_IN_CH1" , "DL1_CH1 Switch" , "DL1" }, |
| 505 | {"HW_SRC_1_IN_CH2" , "DL1_CH2 Switch" , "DL1" }, |
| 506 | {"HW_SRC_2_IN_CH1" , "DL1_CH1 Switch" , "DL1" }, |
| 507 | {"HW_SRC_2_IN_CH2" , "DL1_CH2 Switch" , "DL1" }, |
| 508 | {"HW_SRC_1_IN_CH1" , "DL2_CH1 Switch" , "DL2" }, |
| 509 | {"HW_SRC_1_IN_CH2" , "DL2_CH2 Switch" , "DL2" }, |
| 510 | {"HW_SRC_2_IN_CH1" , "DL2_CH1 Switch" , "DL2" }, |
| 511 | {"HW_SRC_2_IN_CH2" , "DL2_CH2 Switch" , "DL2" }, |
| 512 | {"HW_SRC_1_IN_CH1" , "DL3_CH1 Switch" , "DL3" }, |
| 513 | {"HW_SRC_1_IN_CH2" , "DL3_CH2 Switch" , "DL3" }, |
| 514 | {"HW_SRC_2_IN_CH1" , "DL3_CH1 Switch" , "DL3" }, |
| 515 | {"HW_SRC_2_IN_CH2" , "DL3_CH2 Switch" , "DL3" }, |
| 516 | {"HW_SRC_1_IN_CH1" , "DL6_CH1 Switch" , "DL6" }, |
| 517 | {"HW_SRC_1_IN_CH2" , "DL6_CH2 Switch" , "DL6" }, |
| 518 | {"HW_SRC_2_IN_CH1" , "DL6_CH1 Switch" , "DL6" }, |
| 519 | {"HW_SRC_2_IN_CH2" , "DL6_CH2 Switch" , "DL6" }, |
| 520 | {"HW_SRC_1_IN_CH1" , "DL5_CH1 Switch" , "DL5" }, |
| 521 | {"HW_SRC_1_IN_CH2" , "DL5_CH2 Switch" , "DL5" }, |
| 522 | {"HW_SRC_2_IN_CH1" , "DL5_CH1 Switch" , "DL5" }, |
| 523 | {"HW_SRC_2_IN_CH2" , "DL5_CH2 Switch" , "DL5" }, |
| 524 | {"HW_SRC_1_IN_CH1" , "DL4_CH1 Switch" , "DL4" }, |
| 525 | {"HW_SRC_1_IN_CH2" , "DL4_CH2 Switch" , "DL4" }, |
| 526 | {"HW_SRC_2_IN_CH1" , "DL4_CH1 Switch" , "DL4" }, |
| 527 | {"HW_SRC_2_IN_CH2" , "DL4_CH2 Switch" , "DL4" }, |
| 528 | |
| 529 | {"HW_SRC_1_In" , NULL, "HW_SRC_1_IN_CH1" }, |
| 530 | {"HW_SRC_1_In" , NULL, "HW_SRC_1_IN_CH2" }, |
| 531 | |
| 532 | {"HW_SRC_2_In" , NULL, "HW_SRC_2_IN_CH1" }, |
| 533 | {"HW_SRC_2_In" , NULL, "HW_SRC_2_IN_CH2" }, |
| 534 | |
| 535 | {"HW_SRC_1_In" , NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect}, |
| 536 | {"HW_SRC_1_Out" , NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect}, |
| 537 | {"HW_SRC_2_In" , NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect}, |
| 538 | {"HW_SRC_2_Out" , NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect}, |
| 539 | |
| 540 | {"HW SRC 1 In Endpoint" , NULL, "HW_SRC_1_In" }, |
| 541 | {"HW SRC 2 In Endpoint" , NULL, "HW_SRC_2_In" }, |
| 542 | {"HW_SRC_1_Out" , NULL, "HW SRC 1 Out Endpoint" }, |
| 543 | {"HW_SRC_2_Out" , NULL, "HW SRC 2 Out Endpoint" }, |
| 544 | }; |
| 545 | |
| 546 | /* dai ops */ |
| 547 | static int mtk_dai_src_hw_params(struct snd_pcm_substream *substream, |
| 548 | struct snd_pcm_hw_params *params, |
| 549 | struct snd_soc_dai *dai) |
| 550 | { |
| 551 | struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
| 552 | struct mt8186_afe_private *afe_priv = afe->platform_priv; |
| 553 | int id = dai->id; |
| 554 | struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id]; |
| 555 | unsigned int sft, mask; |
| 556 | unsigned int rate = params_rate(p: params); |
| 557 | unsigned int rate_reg = mt8186_rate_transform(dev: afe->dev, rate, aud_blk: id); |
| 558 | |
| 559 | dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n" , |
| 560 | __func__, id, substream->stream, rate); |
| 561 | |
| 562 | /* rate */ |
| 563 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 564 | src_priv->dl_rate = rate; |
| 565 | if (id == MT8186_DAI_SRC_1) { |
| 566 | sft = GENERAL1_ASRCIN_MODE_SFT; |
| 567 | mask = GENERAL1_ASRCIN_MODE_MASK; |
| 568 | } else { |
| 569 | sft = GENERAL2_ASRCIN_MODE_SFT; |
| 570 | mask = GENERAL2_ASRCIN_MODE_MASK; |
| 571 | } |
| 572 | } else { |
| 573 | src_priv->ul_rate = rate; |
| 574 | if (id == MT8186_DAI_SRC_1) { |
| 575 | sft = GENERAL1_ASRCOUT_MODE_SFT; |
| 576 | mask = GENERAL1_ASRCOUT_MODE_MASK; |
| 577 | } else { |
| 578 | sft = GENERAL2_ASRCOUT_MODE_SFT; |
| 579 | mask = GENERAL2_ASRCOUT_MODE_MASK; |
| 580 | } |
| 581 | } |
| 582 | |
| 583 | regmap_update_bits(map: afe->regmap, GENERAL_ASRC_MODE, mask: mask << sft, val: rate_reg << sft); |
| 584 | |
| 585 | return 0; |
| 586 | } |
| 587 | |
| 588 | static int mtk_dai_src_hw_free(struct snd_pcm_substream *substream, |
| 589 | struct snd_soc_dai *dai) |
| 590 | { |
| 591 | struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
| 592 | struct mt8186_afe_private *afe_priv = afe->platform_priv; |
| 593 | int id = dai->id; |
| 594 | struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id]; |
| 595 | |
| 596 | dev_dbg(afe->dev, "%s(), id %d, stream %d\n" , |
| 597 | __func__, id, substream->stream); |
| 598 | |
| 599 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 600 | src_priv->dl_rate = 0; |
| 601 | else |
| 602 | src_priv->ul_rate = 0; |
| 603 | |
| 604 | return 0; |
| 605 | } |
| 606 | |
| 607 | static const struct snd_soc_dai_ops mtk_dai_src_ops = { |
| 608 | .hw_params = mtk_dai_src_hw_params, |
| 609 | .hw_free = mtk_dai_src_hw_free, |
| 610 | }; |
| 611 | |
| 612 | /* dai driver */ |
| 613 | #define MTK_SRC_RATES (SNDRV_PCM_RATE_8000_48000 |\ |
| 614 | SNDRV_PCM_RATE_88200 |\ |
| 615 | SNDRV_PCM_RATE_96000 |\ |
| 616 | SNDRV_PCM_RATE_176400 |\ |
| 617 | SNDRV_PCM_RATE_192000) |
| 618 | |
| 619 | #define MTK_SRC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ |
| 620 | SNDRV_PCM_FMTBIT_S24_LE |\ |
| 621 | SNDRV_PCM_FMTBIT_S32_LE) |
| 622 | |
| 623 | static struct snd_soc_dai_driver mtk_dai_src_driver[] = { |
| 624 | { |
| 625 | .name = "HW_SRC_1" , |
| 626 | .id = MT8186_DAI_SRC_1, |
| 627 | .playback = { |
| 628 | .stream_name = "HW_SRC_1_In" , |
| 629 | .channels_min = 1, |
| 630 | .channels_max = 2, |
| 631 | .rates = MTK_SRC_RATES, |
| 632 | .formats = MTK_SRC_FORMATS, |
| 633 | }, |
| 634 | .capture = { |
| 635 | .stream_name = "HW_SRC_1_Out" , |
| 636 | .channels_min = 1, |
| 637 | .channels_max = 2, |
| 638 | .rates = MTK_SRC_RATES, |
| 639 | .formats = MTK_SRC_FORMATS, |
| 640 | }, |
| 641 | .ops = &mtk_dai_src_ops, |
| 642 | }, |
| 643 | { |
| 644 | .name = "HW_SRC_2" , |
| 645 | .id = MT8186_DAI_SRC_2, |
| 646 | .playback = { |
| 647 | .stream_name = "HW_SRC_2_In" , |
| 648 | .channels_min = 1, |
| 649 | .channels_max = 2, |
| 650 | .rates = MTK_SRC_RATES, |
| 651 | .formats = MTK_SRC_FORMATS, |
| 652 | }, |
| 653 | .capture = { |
| 654 | .stream_name = "HW_SRC_2_Out" , |
| 655 | .channels_min = 1, |
| 656 | .channels_max = 2, |
| 657 | .rates = MTK_SRC_RATES, |
| 658 | .formats = MTK_SRC_FORMATS, |
| 659 | }, |
| 660 | .ops = &mtk_dai_src_ops, |
| 661 | }, |
| 662 | }; |
| 663 | |
| 664 | int mt8186_dai_src_register(struct mtk_base_afe *afe) |
| 665 | { |
| 666 | struct mtk_base_afe_dai *dai; |
| 667 | int ret; |
| 668 | |
| 669 | dai = devm_kzalloc(dev: afe->dev, size: sizeof(*dai), GFP_KERNEL); |
| 670 | if (!dai) |
| 671 | return -ENOMEM; |
| 672 | |
| 673 | list_add(new: &dai->list, head: &afe->sub_dais); |
| 674 | |
| 675 | dai->dai_drivers = mtk_dai_src_driver; |
| 676 | dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_src_driver); |
| 677 | |
| 678 | dai->dapm_widgets = mtk_dai_src_widgets; |
| 679 | dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_src_widgets); |
| 680 | dai->dapm_routes = mtk_dai_src_routes; |
| 681 | dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_src_routes); |
| 682 | |
| 683 | /* set dai priv */ |
| 684 | ret = mt8186_dai_set_priv(afe, id: MT8186_DAI_SRC_1, |
| 685 | priv_size: sizeof(struct mtk_afe_src_priv), NULL); |
| 686 | if (ret) |
| 687 | return ret; |
| 688 | |
| 689 | ret = mt8186_dai_set_priv(afe, id: MT8186_DAI_SRC_2, |
| 690 | priv_size: sizeof(struct mtk_afe_src_priv), NULL); |
| 691 | if (ret) |
| 692 | return ret; |
| 693 | |
| 694 | return 0; |
| 695 | } |
| 696 | |