Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: imx-audmix: Split capture device to be a new

Merge series from Shengjiu Wang <shengjiu.wang@nxp.com>:

The transmitter and receiver part of the SAI interface need to be
configured with different master/slave mode, especially to work
with the audiomix module.

The SAI1 TX is in master mode, but SAI1 RX is in slave mode.
So add another two DAIs for TX and RX separately in fsl_sai driver.

There will be three devices for audiomix sound card, hw:x,0 is
the playback device for one SAI, hw:x,1 is the playback device
for another SAI, hw:x,2 is the capture device for audmix
output.

+155 -85
+6 -10
sound/soc/fsl/fsl_audmix.c
··· 326 326 .rates = SNDRV_PCM_RATE_8000_96000, 327 327 .formats = FSL_AUDMIX_FORMATS, 328 328 }, 329 - .capture = { 330 - .stream_name = "AUDMIX-Capture-0", 331 - .channels_min = 8, 332 - .channels_max = 8, 333 - .rate_min = 8000, 334 - .rate_max = 96000, 335 - .rates = SNDRV_PCM_RATE_8000_96000, 336 - .formats = FSL_AUDMIX_FORMATS, 337 - }, 338 329 .ops = &fsl_audmix_dai_ops, 339 330 }, 340 331 { ··· 340 349 .rates = SNDRV_PCM_RATE_8000_96000, 341 350 .formats = FSL_AUDMIX_FORMATS, 342 351 }, 352 + .ops = &fsl_audmix_dai_ops, 353 + }, 354 + { 355 + .id = 2, 356 + .name = "audmix-2", 343 357 .capture = { 344 - .stream_name = "AUDMIX-Capture-1", 358 + .stream_name = "AUDMIX-Capture-0", 345 359 .channels_min = 8, 346 360 .channels_max = 8, 347 361 .rate_min = 8000,
+102 -39
sound/soc/fsl/fsl_sai.c
··· 357 357 case SND_SOC_DAIFMT_BP_FP: 358 358 val_cr2 |= FSL_SAI_CR2_BCD_MSTR; 359 359 val_cr4 |= FSL_SAI_CR4_FSD_MSTR; 360 - sai->is_consumer_mode = false; 360 + sai->is_consumer_mode[tx] = false; 361 361 break; 362 362 case SND_SOC_DAIFMT_BC_FC: 363 - sai->is_consumer_mode = true; 363 + sai->is_consumer_mode[tx] = true; 364 364 break; 365 365 case SND_SOC_DAIFMT_BP_FC: 366 366 val_cr2 |= FSL_SAI_CR2_BCD_MSTR; 367 - sai->is_consumer_mode = false; 367 + sai->is_consumer_mode[tx] = false; 368 368 break; 369 369 case SND_SOC_DAIFMT_BC_FP: 370 370 val_cr4 |= FSL_SAI_CR4_FSD_MSTR; 371 - sai->is_consumer_mode = true; 371 + sai->is_consumer_mode[tx] = true; 372 372 break; 373 373 default: 374 374 return -EINVAL; ··· 400 400 return ret; 401 401 } 402 402 403 + static int fsl_sai_set_dai_fmt_tx(struct snd_soc_dai *cpu_dai, unsigned int fmt) 404 + { 405 + return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, true); 406 + } 407 + 408 + static int fsl_sai_set_dai_fmt_rx(struct snd_soc_dai *cpu_dai, unsigned int fmt) 409 + { 410 + return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, false); 411 + } 412 + 403 413 static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) 404 414 { 405 415 struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); ··· 422 412 bool support_1_1_ratio = sai->verid.version >= 0x0301; 423 413 424 414 /* Don't apply to consumer mode */ 425 - if (sai->is_consumer_mode) 415 + if (sai->is_consumer_mode[tx]) 426 416 return 0; 427 417 428 418 /* ··· 585 575 } 586 576 } 587 577 588 - if (!sai->is_consumer_mode) { 578 + if (!sai->is_consumer_mode[tx]) { 589 579 ret = fsl_sai_set_bclk(cpu_dai, tx, bclk); 590 580 if (ret) 591 581 return ret; ··· 623 613 * RCR5(TCR5) for playback(capture), or there will be sync error. 624 614 */ 625 615 626 - if (!sai->is_consumer_mode && fsl_sai_dir_is_synced(sai, adir)) { 616 + if (!sai->is_consumer_mode[tx] && fsl_sai_dir_is_synced(sai, adir)) { 627 617 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs), 628 618 FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | 629 619 FSL_SAI_CR4_CHMOD_MASK, ··· 693 683 * FSD_MSTR bit for this specific case. 694 684 */ 695 685 if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && 696 - !sai->is_consumer_mode) 686 + !sai->is_consumer_mode[tx]) 697 687 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), 698 688 FSL_SAI_CR4_FSD_MSTR, 0); 699 689 ··· 707 697 708 698 /* Enable FSD_MSTR after configuring word width */ 709 699 if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && 710 - !sai->is_consumer_mode) 700 + !sai->is_consumer_mode[tx]) 711 701 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), 712 702 FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR); 713 703 ··· 730 720 regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), 731 721 FSL_SAI_CR3_TRCE_MASK, 0); 732 722 733 - if (!sai->is_consumer_mode && 734 - sai->mclk_streams & BIT(substream->stream)) { 723 + if (!sai->is_consumer_mode[tx] && 724 + sai->mclk_streams & BIT(substream->stream)) { 735 725 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); 736 726 sai->mclk_streams &= ~BIT(substream->stream); 737 727 } ··· 769 759 * This is a hardware bug, and will be fix in the 770 760 * next sai version. 771 761 */ 772 - if (!sai->is_consumer_mode) { 762 + if (!sai->is_consumer_mode[tx]) { 773 763 /* Software Reset */ 774 764 regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); 775 765 /* Clear SR bit to finish the reset */ ··· 924 914 .startup = fsl_sai_startup, 925 915 }; 926 916 917 + static const struct snd_soc_dai_ops fsl_sai_pcm_dai_tx_ops = { 918 + .probe = fsl_sai_dai_probe, 919 + .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, 920 + .set_sysclk = fsl_sai_set_dai_sysclk, 921 + .set_fmt = fsl_sai_set_dai_fmt_tx, 922 + .set_tdm_slot = fsl_sai_set_dai_tdm_slot, 923 + .hw_params = fsl_sai_hw_params, 924 + .hw_free = fsl_sai_hw_free, 925 + .trigger = fsl_sai_trigger, 926 + .startup = fsl_sai_startup, 927 + }; 928 + 929 + static const struct snd_soc_dai_ops fsl_sai_pcm_dai_rx_ops = { 930 + .probe = fsl_sai_dai_probe, 931 + .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, 932 + .set_sysclk = fsl_sai_set_dai_sysclk, 933 + .set_fmt = fsl_sai_set_dai_fmt_rx, 934 + .set_tdm_slot = fsl_sai_set_dai_tdm_slot, 935 + .hw_params = fsl_sai_hw_params, 936 + .hw_free = fsl_sai_hw_free, 937 + .trigger = fsl_sai_trigger, 938 + .startup = fsl_sai_startup, 939 + }; 940 + 927 941 static int fsl_sai_dai_resume(struct snd_soc_component *component) 928 942 { 929 943 struct fsl_sai *sai = snd_soc_component_get_drvdata(component); ··· 965 931 return 0; 966 932 } 967 933 968 - static struct snd_soc_dai_driver fsl_sai_dai_template = { 969 - .playback = { 970 - .stream_name = "CPU-Playback", 971 - .channels_min = 1, 972 - .channels_max = 32, 973 - .rate_min = 8000, 974 - .rate_max = 2822400, 975 - .rates = SNDRV_PCM_RATE_KNOT, 976 - .formats = FSL_SAI_FORMATS, 934 + static struct snd_soc_dai_driver fsl_sai_dai_template[] = { 935 + { 936 + .name = "sai-tx-rx", 937 + .playback = { 938 + .stream_name = "CPU-Playback", 939 + .channels_min = 1, 940 + .channels_max = 32, 941 + .rate_min = 8000, 942 + .rate_max = 2822400, 943 + .rates = SNDRV_PCM_RATE_KNOT, 944 + .formats = FSL_SAI_FORMATS, 945 + }, 946 + .capture = { 947 + .stream_name = "CPU-Capture", 948 + .channels_min = 1, 949 + .channels_max = 32, 950 + .rate_min = 8000, 951 + .rate_max = 2822400, 952 + .rates = SNDRV_PCM_RATE_KNOT, 953 + .formats = FSL_SAI_FORMATS, 954 + }, 955 + .ops = &fsl_sai_pcm_dai_ops, 977 956 }, 978 - .capture = { 979 - .stream_name = "CPU-Capture", 980 - .channels_min = 1, 981 - .channels_max = 32, 982 - .rate_min = 8000, 983 - .rate_max = 2822400, 984 - .rates = SNDRV_PCM_RATE_KNOT, 985 - .formats = FSL_SAI_FORMATS, 957 + { 958 + .name = "sai-tx", 959 + .playback = { 960 + .stream_name = "CPU-Playback", 961 + .channels_min = 1, 962 + .channels_max = 32, 963 + .rate_min = 8000, 964 + .rate_max = 2822400, 965 + .rates = SNDRV_PCM_RATE_KNOT, 966 + .formats = FSL_SAI_FORMATS, 967 + }, 968 + .ops = &fsl_sai_pcm_dai_tx_ops, 986 969 }, 987 - .ops = &fsl_sai_pcm_dai_ops, 970 + { 971 + .name = "sai-rx", 972 + .capture = { 973 + .stream_name = "CPU-Capture", 974 + .channels_min = 1, 975 + .channels_max = 32, 976 + .rate_min = 8000, 977 + .rate_max = 2822400, 978 + .rates = SNDRV_PCM_RATE_KNOT, 979 + .formats = FSL_SAI_FORMATS, 980 + }, 981 + .ops = &fsl_sai_pcm_dai_rx_ops, 982 + }, 988 983 }; 989 984 990 985 static const struct snd_soc_component_driver fsl_component = { ··· 1462 1399 return ret; 1463 1400 } 1464 1401 1465 - memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template, 1466 - sizeof(fsl_sai_dai_template)); 1402 + memcpy(&sai->cpu_dai_drv, fsl_sai_dai_template, 1403 + sizeof(*fsl_sai_dai_template) * ARRAY_SIZE(fsl_sai_dai_template)); 1467 1404 1468 1405 /* Sync Tx with Rx as default by following old DT binding */ 1469 1406 sai->synchronous[RX] = true; 1470 1407 sai->synchronous[TX] = false; 1471 - sai->cpu_dai_drv.symmetric_rate = 1; 1472 - sai->cpu_dai_drv.symmetric_channels = 1; 1473 - sai->cpu_dai_drv.symmetric_sample_bits = 1; 1408 + sai->cpu_dai_drv[0].symmetric_rate = 1; 1409 + sai->cpu_dai_drv[0].symmetric_channels = 1; 1410 + sai->cpu_dai_drv[0].symmetric_sample_bits = 1; 1474 1411 1475 1412 if (of_property_read_bool(np, "fsl,sai-synchronous-rx") && 1476 1413 of_property_read_bool(np, "fsl,sai-asynchronous")) { ··· 1487 1424 /* Discard all settings for asynchronous mode */ 1488 1425 sai->synchronous[RX] = false; 1489 1426 sai->synchronous[TX] = false; 1490 - sai->cpu_dai_drv.symmetric_rate = 0; 1491 - sai->cpu_dai_drv.symmetric_channels = 0; 1492 - sai->cpu_dai_drv.symmetric_sample_bits = 0; 1427 + sai->cpu_dai_drv[0].symmetric_rate = 0; 1428 + sai->cpu_dai_drv[0].symmetric_channels = 0; 1429 + sai->cpu_dai_drv[0].symmetric_sample_bits = 0; 1493 1430 } 1494 1431 1495 1432 sai->mclk_direction_output = of_property_read_bool(np, "fsl,sai-mclk-direction-output"); ··· 1568 1505 } 1569 1506 1570 1507 ret = devm_snd_soc_register_component(dev, &fsl_component, 1571 - &sai->cpu_dai_drv, 1); 1508 + sai->cpu_dai_drv, ARRAY_SIZE(fsl_sai_dai_template)); 1572 1509 if (ret) 1573 1510 goto err_pm_get_sync; 1574 1511
+2 -2
sound/soc/fsl/fsl_sai.h
··· 282 282 struct clk *pll11k_clk; 283 283 struct resource *res; 284 284 285 - bool is_consumer_mode; 285 + bool is_consumer_mode[2]; 286 286 bool is_lsb_first; 287 287 bool is_dsp_mode; 288 288 bool is_pdm_mode; ··· 299 299 unsigned int bclk_ratio; 300 300 301 301 const struct fsl_sai_soc_data *soc_data; 302 - struct snd_soc_dai_driver cpu_dai_drv; 302 + struct snd_soc_dai_driver cpu_dai_drv[3]; 303 303 struct snd_dmaengine_dai_dma_data dma_params_rx; 304 304 struct snd_dmaengine_dai_dma_data dma_params_tx; 305 305 struct fsl_sai_verid verid;
+45 -34
sound/soc/fsl/imx-audmix.c
··· 140 140 .hw_params = imx_audmix_be_hw_params, 141 141 }; 142 142 143 + static const char *name[][3] = { 144 + {"HiFi-AUDMIX-FE-0", "HiFi-AUDMIX-FE-1", "HiFi-AUDMIX-FE-2"}, 145 + {"sai-tx", "sai-tx", "sai-rx"}, 146 + {"AUDMIX-Playback-0", "AUDMIX-Playback-1", "CPU-Capture"}, 147 + {"CPU-Playback", "CPU-Playback", "AUDMIX-Capture-0"}, 148 + }; 149 + 143 150 static int imx_audmix_probe(struct platform_device *pdev) 144 151 { 145 152 struct device_node *np = pdev->dev.of_node; ··· 157 150 struct imx_audmix *priv; 158 151 int i, num_dai, ret; 159 152 const char *fe_name_pref = "HiFi-AUDMIX-FE-"; 160 - char *be_name, *be_pb, *be_cp, *dai_name, *capture_dai_name; 153 + char *be_name, *dai_name; 161 154 162 155 if (pdev->dev.parent) { 163 156 audmix_np = pdev->dev.parent->of_node; ··· 190 183 if (!priv) 191 184 return -ENOMEM; 192 185 186 + num_dai += 1; 193 187 priv->num_dai = 2 * num_dai; 194 188 priv->dai = devm_kcalloc(&pdev->dev, priv->num_dai, 195 189 sizeof(struct snd_soc_dai_link), GFP_KERNEL); ··· 204 196 if (!priv->dai_conf) 205 197 return -ENOMEM; 206 198 207 - priv->num_dapm_routes = 3 * num_dai; 199 + priv->num_dapm_routes = num_dai; 208 200 priv->dapm_routes = devm_kcalloc(&pdev->dev, priv->num_dapm_routes, 209 201 sizeof(struct snd_soc_dapm_route), 210 202 GFP_KERNEL); ··· 219 211 if (!dlc) 220 212 return -ENOMEM; 221 213 222 - ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i, 223 - &args); 214 + if (i == num_dai - 1) 215 + ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, 0, 216 + &args); 217 + else 218 + ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i, 219 + &args); 224 220 if (ret < 0) { 225 221 dev_err(&pdev->dev, "of_parse_phandle_with_args failed\n"); 226 222 return ret; ··· 238 226 put_device(&cpu_pdev->dev); 239 227 240 228 dai_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%s", 241 - fe_name_pref, args.np->full_name + 1); 229 + fe_name_pref, args.np->full_name); 242 230 if (!dai_name) 243 231 return -ENOMEM; 244 232 245 233 dev_info(pdev->dev.parent, "DAI FE name:%s\n", dai_name); 246 234 247 - if (i == 0) { 235 + if (i == num_dai - 1) 248 236 out_cpu_np = args.np; 249 - capture_dai_name = 250 - devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s", 251 - dai_name, "CPU-Capture"); 252 - if (!capture_dai_name) 253 - return -ENOMEM; 254 - } 255 237 256 238 /* 257 239 * CPU == Platform ··· 258 252 priv->dai[i].num_cpus = 1; 259 253 priv->dai[i].num_codecs = 1; 260 254 priv->dai[i].num_platforms = 1; 261 - 262 - priv->dai[i].name = dai_name; 255 + priv->dai[i].name = name[0][i]; 263 256 priv->dai[i].stream_name = "HiFi-AUDMIX-FE"; 264 257 priv->dai[i].cpus->of_node = args.np; 265 - priv->dai[i].cpus->dai_name = dev_name(&cpu_pdev->dev); 258 + priv->dai[i].cpus->dai_name = name[1][i]; 259 + 266 260 priv->dai[i].dynamic = 1; 267 261 priv->dai[i].dpcm_playback = 1; 268 - priv->dai[i].dpcm_capture = (i == 0 ? 1 : 0); 262 + if (i == num_dai - 1) { 263 + priv->dai[i].dpcm_capture = 1; 264 + priv->dai[i].dpcm_playback = 0; 265 + } 269 266 priv->dai[i].ignore_pmdown_time = 1; 270 267 priv->dai[i].ops = &imx_audmix_fe_ops; 271 268 272 269 /* Add AUDMIX Backend */ 273 270 be_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, 274 271 "audmix-%d", i); 275 - be_pb = devm_kasprintf(&pdev->dev, GFP_KERNEL, 276 - "AUDMIX-Playback-%d", i); 277 - be_cp = devm_kasprintf(&pdev->dev, GFP_KERNEL, 278 - "AUDMIX-Capture-%d", i); 279 - if (!be_name || !be_pb || !be_cp) 280 - return -ENOMEM; 281 - 282 272 priv->dai[num_dai + i].cpus = &dlc[1]; 283 273 priv->dai[num_dai + i].codecs = &snd_soc_dummy_dlc; 284 274 ··· 286 284 priv->dai[num_dai + i].cpus->dai_name = be_name; 287 285 priv->dai[num_dai + i].no_pcm = 1; 288 286 priv->dai[num_dai + i].dpcm_playback = 1; 289 - priv->dai[num_dai + i].dpcm_capture = 1; 287 + if (i == num_dai - 1) { 288 + priv->dai[num_dai + i].dpcm_capture = 1; 289 + priv->dai[num_dai + i].dpcm_playback = 0; 290 + } 290 291 priv->dai[num_dai + i].ignore_pmdown_time = 1; 291 292 priv->dai[num_dai + i].ops = &imx_audmix_be_ops; 292 293 293 294 priv->dai_conf[i].dlc.of_node = args.np; 294 295 priv->dai_conf[i].name_prefix = dai_name; 295 296 296 - priv->dapm_routes[i].source = 297 - devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s", 298 - dai_name, "CPU-Playback"); 299 - if (!priv->dapm_routes[i].source) 300 - return -ENOMEM; 297 + if (i == num_dai - 1) { 298 + priv->dapm_routes[i].sink = 299 + devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s", 300 + dai_name, name[2][i]); 301 + if (!priv->dapm_routes[i].sink) 302 + return -ENOMEM; 301 303 302 - priv->dapm_routes[i].sink = be_pb; 303 - priv->dapm_routes[num_dai + i].source = be_pb; 304 - priv->dapm_routes[num_dai + i].sink = be_cp; 305 - priv->dapm_routes[2 * num_dai + i].source = be_cp; 306 - priv->dapm_routes[2 * num_dai + i].sink = capture_dai_name; 304 + priv->dapm_routes[i].source = name[3][i]; 305 + } else { 306 + priv->dapm_routes[i].source = 307 + devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s", 308 + dai_name, name[3][i]); 309 + if (!priv->dapm_routes[i].source) 310 + return -ENOMEM; 311 + 312 + priv->dapm_routes[i].sink = name[2][i]; 313 + } 307 314 } 308 315 309 316 cpu_pdev = of_find_device_by_node(out_cpu_np);