| .. | .. |
|---|
| 102 | 102 | #include "rsnd.h" |
|---|
| 103 | 103 | |
|---|
| 104 | 104 | #define RSND_RATES SNDRV_PCM_RATE_8000_192000 |
|---|
| 105 | | -#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) |
|---|
| 105 | +#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\ |
|---|
| 106 | + SNDRV_PCM_FMTBIT_S16_LE |\ |
|---|
| 107 | + SNDRV_PCM_FMTBIT_S24_LE) |
|---|
| 106 | 108 | |
|---|
| 107 | 109 | static const struct of_device_id rsnd_of_match[] = { |
|---|
| 108 | 110 | { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, |
|---|
| 109 | 111 | { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, |
|---|
| 110 | 112 | { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 }, |
|---|
| 113 | + /* Special Handling */ |
|---|
| 114 | + { .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) }, |
|---|
| 111 | 115 | {}, |
|---|
| 112 | 116 | }; |
|---|
| 113 | 117 | MODULE_DEVICE_TABLE(of, rsnd_of_match); |
|---|
| .. | .. |
|---|
| 121 | 125 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
|---|
| 122 | 126 | struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 123 | 127 | |
|---|
| 124 | | - dev_warn(dev, "%s[%d] is not your expected module\n", |
|---|
| 125 | | - rsnd_mod_name(mod), rsnd_mod_id(mod)); |
|---|
| 128 | + dev_warn(dev, "%s is not your expected module\n", |
|---|
| 129 | + rsnd_mod_name(mod)); |
|---|
| 126 | 130 | } |
|---|
| 127 | 131 | } |
|---|
| 128 | 132 | |
|---|
| .. | .. |
|---|
| 135 | 139 | return mod->ops->dma_req(io, mod); |
|---|
| 136 | 140 | } |
|---|
| 137 | 141 | |
|---|
| 138 | | -u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, |
|---|
| 139 | | - struct rsnd_mod *mod, |
|---|
| 142 | +#define MOD_NAME_NUM 5 |
|---|
| 143 | +#define MOD_NAME_SIZE 16 |
|---|
| 144 | +char *rsnd_mod_name(struct rsnd_mod *mod) |
|---|
| 145 | +{ |
|---|
| 146 | + static char names[MOD_NAME_NUM][MOD_NAME_SIZE]; |
|---|
| 147 | + static int num; |
|---|
| 148 | + char *name = names[num]; |
|---|
| 149 | + |
|---|
| 150 | + num++; |
|---|
| 151 | + if (num >= MOD_NAME_NUM) |
|---|
| 152 | + num = 0; |
|---|
| 153 | + |
|---|
| 154 | + /* |
|---|
| 155 | + * Let's use same char to avoid pointlessness memory |
|---|
| 156 | + * Thus, rsnd_mod_name() should be used immediately |
|---|
| 157 | + * Don't keep pointer |
|---|
| 158 | + */ |
|---|
| 159 | + if ((mod)->ops->id_sub) { |
|---|
| 160 | + snprintf(name, MOD_NAME_SIZE, "%s[%d%d]", |
|---|
| 161 | + mod->ops->name, |
|---|
| 162 | + rsnd_mod_id(mod), |
|---|
| 163 | + rsnd_mod_id_sub(mod)); |
|---|
| 164 | + } else { |
|---|
| 165 | + snprintf(name, MOD_NAME_SIZE, "%s[%d]", |
|---|
| 166 | + mod->ops->name, |
|---|
| 167 | + rsnd_mod_id(mod)); |
|---|
| 168 | + } |
|---|
| 169 | + |
|---|
| 170 | + return name; |
|---|
| 171 | +} |
|---|
| 172 | + |
|---|
| 173 | +u32 *rsnd_mod_get_status(struct rsnd_mod *mod, |
|---|
| 174 | + struct rsnd_dai_stream *io, |
|---|
| 140 | 175 | enum rsnd_mod_type type) |
|---|
| 141 | 176 | { |
|---|
| 142 | 177 | return &mod->status; |
|---|
| 178 | +} |
|---|
| 179 | + |
|---|
| 180 | +int rsnd_mod_id_raw(struct rsnd_mod *mod) |
|---|
| 181 | +{ |
|---|
| 182 | + return mod->id; |
|---|
| 183 | +} |
|---|
| 184 | + |
|---|
| 185 | +int rsnd_mod_id(struct rsnd_mod *mod) |
|---|
| 186 | +{ |
|---|
| 187 | + if ((mod)->ops->id) |
|---|
| 188 | + return (mod)->ops->id(mod); |
|---|
| 189 | + |
|---|
| 190 | + return rsnd_mod_id_raw(mod); |
|---|
| 191 | +} |
|---|
| 192 | + |
|---|
| 193 | +int rsnd_mod_id_sub(struct rsnd_mod *mod) |
|---|
| 194 | +{ |
|---|
| 195 | + if ((mod)->ops->id_sub) |
|---|
| 196 | + return (mod)->ops->id_sub(mod); |
|---|
| 197 | + |
|---|
| 198 | + return 0; |
|---|
| 143 | 199 | } |
|---|
| 144 | 200 | |
|---|
| 145 | 201 | int rsnd_mod_init(struct rsnd_priv *priv, |
|---|
| 146 | 202 | struct rsnd_mod *mod, |
|---|
| 147 | 203 | struct rsnd_mod_ops *ops, |
|---|
| 148 | 204 | struct clk *clk, |
|---|
| 149 | | - u32* (*get_status)(struct rsnd_dai_stream *io, |
|---|
| 150 | | - struct rsnd_mod *mod, |
|---|
| 151 | | - enum rsnd_mod_type type), |
|---|
| 152 | 205 | enum rsnd_mod_type type, |
|---|
| 153 | 206 | int id) |
|---|
| 154 | 207 | { |
|---|
| .. | .. |
|---|
| 162 | 215 | mod->type = type; |
|---|
| 163 | 216 | mod->clk = clk; |
|---|
| 164 | 217 | mod->priv = priv; |
|---|
| 165 | | - mod->get_status = get_status; |
|---|
| 166 | 218 | |
|---|
| 167 | 219 | return ret; |
|---|
| 168 | 220 | } |
|---|
| .. | .. |
|---|
| 226 | 278 | struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); |
|---|
| 227 | 279 | |
|---|
| 228 | 280 | if (ctu_mod) { |
|---|
| 229 | | - u32 converted_chan = rsnd_ctu_converted_channel(ctu_mod); |
|---|
| 281 | + u32 converted_chan = rsnd_io_converted_chan(io); |
|---|
| 282 | + |
|---|
| 283 | + /* |
|---|
| 284 | + * !! Note !! |
|---|
| 285 | + * |
|---|
| 286 | + * converted_chan will be used for CTU, |
|---|
| 287 | + * or TDM Split mode. |
|---|
| 288 | + * User shouldn't use CTU with TDM Split mode. |
|---|
| 289 | + */ |
|---|
| 290 | + if (rsnd_runtime_is_tdm_split(io)) { |
|---|
| 291 | + struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); |
|---|
| 292 | + |
|---|
| 293 | + dev_err(dev, "CTU and TDM Split should be used\n"); |
|---|
| 294 | + } |
|---|
| 230 | 295 | |
|---|
| 231 | 296 | if (converted_chan) |
|---|
| 232 | 297 | return converted_chan; |
|---|
| 233 | 298 | } |
|---|
| 299 | + |
|---|
| 300 | + return chan; |
|---|
| 301 | +} |
|---|
| 302 | + |
|---|
| 303 | +int rsnd_channel_normalization(int chan) |
|---|
| 304 | +{ |
|---|
| 305 | + if (WARN_ON((chan > 8) || (chan < 0))) |
|---|
| 306 | + return 0; |
|---|
| 307 | + |
|---|
| 308 | + /* TDM Extend Mode needs 8ch */ |
|---|
| 309 | + if (chan == 6) |
|---|
| 310 | + chan = 8; |
|---|
| 234 | 311 | |
|---|
| 235 | 312 | return chan; |
|---|
| 236 | 313 | } |
|---|
| .. | .. |
|---|
| 244 | 321 | rsnd_runtime_channel_original_with_params(io, params); |
|---|
| 245 | 322 | |
|---|
| 246 | 323 | /* Use Multi SSI */ |
|---|
| 247 | | - if (rsnd_runtime_is_ssi_multi(io)) |
|---|
| 324 | + if (rsnd_runtime_is_multi_ssi(io)) |
|---|
| 248 | 325 | chan /= rsnd_rdai_ssi_lane_get(rdai); |
|---|
| 249 | 326 | |
|---|
| 250 | | - /* TDM Extend Mode needs 8ch */ |
|---|
| 251 | | - if (chan == 6) |
|---|
| 252 | | - chan = 8; |
|---|
| 253 | | - |
|---|
| 254 | | - return chan; |
|---|
| 327 | + return rsnd_channel_normalization(chan); |
|---|
| 255 | 328 | } |
|---|
| 256 | 329 | |
|---|
| 257 | | -int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) |
|---|
| 330 | +int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io) |
|---|
| 258 | 331 | { |
|---|
| 259 | 332 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
|---|
| 260 | 333 | int lane = rsnd_rdai_ssi_lane_get(rdai); |
|---|
| .. | .. |
|---|
| 265 | 338 | return (chan > 2) && (lane > 1); |
|---|
| 266 | 339 | } |
|---|
| 267 | 340 | |
|---|
| 268 | | -int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io) |
|---|
| 341 | +int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io) |
|---|
| 269 | 342 | { |
|---|
| 270 | 343 | return rsnd_runtime_channel_for_ssi(io) >= 6; |
|---|
| 344 | +} |
|---|
| 345 | + |
|---|
| 346 | +int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io) |
|---|
| 347 | +{ |
|---|
| 348 | + return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT); |
|---|
| 271 | 349 | } |
|---|
| 272 | 350 | |
|---|
| 273 | 351 | /* |
|---|
| .. | .. |
|---|
| 280 | 358 | struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 281 | 359 | |
|---|
| 282 | 360 | switch (snd_pcm_format_width(runtime->format)) { |
|---|
| 361 | + case 8: |
|---|
| 362 | + return 16 << 16; |
|---|
| 283 | 363 | case 16: |
|---|
| 284 | 364 | return 8 << 16; |
|---|
| 285 | 365 | case 24: |
|---|
| .. | .. |
|---|
| 296 | 376 | */ |
|---|
| 297 | 377 | u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) |
|---|
| 298 | 378 | { |
|---|
| 379 | + static const u32 dalign_values[8] = { |
|---|
| 380 | + 0x76543210, 0x00000032, 0x00007654, 0x00000076, |
|---|
| 381 | + 0xfedcba98, 0x000000ba, 0x0000fedc, 0x000000fe, |
|---|
| 382 | + }; |
|---|
| 383 | + int id = 0; |
|---|
| 299 | 384 | struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); |
|---|
| 300 | 385 | struct rsnd_mod *target; |
|---|
| 301 | 386 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
|---|
| 387 | + u32 dalign; |
|---|
| 302 | 388 | |
|---|
| 303 | 389 | /* |
|---|
| 304 | 390 | * *Hardware* L/R and *Software* L/R are inverted for 16bit data. |
|---|
| .. | .. |
|---|
| 331 | 417 | target = cmd ? cmd : ssiu; |
|---|
| 332 | 418 | } |
|---|
| 333 | 419 | |
|---|
| 334 | | - /* Non target mod or 24bit data needs normal DALIGN */ |
|---|
| 335 | | - if ((snd_pcm_format_width(runtime->format) != 16) || |
|---|
| 336 | | - (mod != target)) |
|---|
| 337 | | - return 0x76543210; |
|---|
| 338 | | - /* Target mod needs inverted DALIGN when 16bit */ |
|---|
| 339 | | - else |
|---|
| 340 | | - return 0x67452301; |
|---|
| 420 | + if (mod == ssiu) |
|---|
| 421 | + id = rsnd_mod_id_sub(mod); |
|---|
| 422 | + |
|---|
| 423 | + dalign = dalign_values[id]; |
|---|
| 424 | + |
|---|
| 425 | + if (mod == target && snd_pcm_format_width(runtime->format) == 16) { |
|---|
| 426 | + /* Target mod needs inverted DALIGN when 16bit */ |
|---|
| 427 | + dalign = (dalign & 0xf0f0f0f0) >> 4 | |
|---|
| 428 | + (dalign & 0x0f0f0f0f) << 4; |
|---|
| 429 | + } |
|---|
| 430 | + |
|---|
| 431 | + return dalign; |
|---|
| 341 | 432 | } |
|---|
| 342 | 433 | |
|---|
| 343 | 434 | u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) |
|---|
| .. | .. |
|---|
| 367 | 458 | * HW 24bit data is located as 0x******00 |
|---|
| 368 | 459 | * |
|---|
| 369 | 460 | */ |
|---|
| 370 | | - if (snd_pcm_format_width(runtime->format) == 16) |
|---|
| 461 | + if (snd_pcm_format_width(runtime->format) != 24) |
|---|
| 371 | 462 | return 0; |
|---|
| 372 | 463 | |
|---|
| 373 | 464 | for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { |
|---|
| .. | .. |
|---|
| 468 | 559 | enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ |
|---|
| 469 | 560 | for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ |
|---|
| 470 | 561 | int tmp = 0; \ |
|---|
| 471 | | - u32 *status = mod->get_status(io, mod, types[i]); \ |
|---|
| 562 | + u32 *status = mod->ops->get_status(mod, io, types[i]); \ |
|---|
| 472 | 563 | int func_call = rsnd_status_update(status, \ |
|---|
| 473 | 564 | __rsnd_mod_shift_##fn, \ |
|---|
| 474 | 565 | __rsnd_mod_add_##fn, \ |
|---|
| 475 | 566 | __rsnd_mod_call_##fn); \ |
|---|
| 476 | | - rsnd_dbg_dai_call(dev, "%s[%d]\t0x%08x %s\n", \ |
|---|
| 477 | | - rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \ |
|---|
| 567 | + rsnd_dbg_dai_call(dev, "%s\t0x%08x %s\n", \ |
|---|
| 568 | + rsnd_mod_name(mod), *status, \ |
|---|
| 478 | 569 | (func_call && (mod)->ops->fn) ? #fn : ""); \ |
|---|
| 479 | 570 | if (func_call && (mod)->ops->fn) \ |
|---|
| 480 | 571 | tmp = (mod)->ops->fn(mod, io, param); \ |
|---|
| 481 | 572 | if (tmp && (tmp != -EPROBE_DEFER)) \ |
|---|
| 482 | | - dev_err(dev, "%s[%d] : %s error %d\n", \ |
|---|
| 483 | | - rsnd_mod_name(mod), rsnd_mod_id(mod), \ |
|---|
| 484 | | - #fn, tmp); \ |
|---|
| 573 | + dev_err(dev, "%s : %s error %d\n", \ |
|---|
| 574 | + rsnd_mod_name(mod), #fn, tmp); \ |
|---|
| 485 | 575 | ret |= tmp; \ |
|---|
| 486 | 576 | } \ |
|---|
| 487 | 577 | ret; \ |
|---|
| .. | .. |
|---|
| 508 | 598 | |
|---|
| 509 | 599 | io->mod[type] = mod; |
|---|
| 510 | 600 | |
|---|
| 511 | | - dev_dbg(dev, "%s[%d] is connected to io (%s)\n", |
|---|
| 512 | | - rsnd_mod_name(mod), rsnd_mod_id(mod), |
|---|
| 601 | + dev_dbg(dev, "%s is connected to io (%s)\n", |
|---|
| 602 | + rsnd_mod_name(mod), |
|---|
| 513 | 603 | rsnd_io_is_play(io) ? "Playback" : "Capture"); |
|---|
| 514 | 604 | |
|---|
| 515 | 605 | return 0; |
|---|
| .. | .. |
|---|
| 538 | 628 | rdai->ssi_lane = ssi_lane; |
|---|
| 539 | 629 | |
|---|
| 540 | 630 | return rdai->ssi_lane; |
|---|
| 631 | +} |
|---|
| 632 | + |
|---|
| 633 | +int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width) |
|---|
| 634 | +{ |
|---|
| 635 | + if (width > 0) |
|---|
| 636 | + rdai->chan_width = width; |
|---|
| 637 | + |
|---|
| 638 | + return rdai->chan_width; |
|---|
| 541 | 639 | } |
|---|
| 542 | 640 | |
|---|
| 543 | 641 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) |
|---|
| .. | .. |
|---|
| 596 | 694 | static |
|---|
| 597 | 695 | struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream) |
|---|
| 598 | 696 | { |
|---|
| 599 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
|---|
| 697 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
|---|
| 600 | 698 | |
|---|
| 601 | | - return rtd->cpu_dai; |
|---|
| 699 | + return asoc_rtd_to_cpu(rtd, 0); |
|---|
| 602 | 700 | } |
|---|
| 603 | 701 | |
|---|
| 604 | 702 | static |
|---|
| .. | .. |
|---|
| 661 | 759 | { |
|---|
| 662 | 760 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| 663 | 761 | |
|---|
| 664 | | - /* set master/slave audio interface */ |
|---|
| 762 | + /* set clock master for audio interface */ |
|---|
| 665 | 763 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
|---|
| 666 | 764 | case SND_SOC_DAIFMT_CBM_CFM: |
|---|
| 667 | 765 | rdai->clk_master = 0; |
|---|
| 668 | 766 | break; |
|---|
| 669 | 767 | case SND_SOC_DAIFMT_CBS_CFS: |
|---|
| 670 | | - rdai->clk_master = 1; /* codec is slave, cpu is master */ |
|---|
| 768 | + rdai->clk_master = 1; /* cpu is master */ |
|---|
| 671 | 769 | break; |
|---|
| 672 | 770 | default: |
|---|
| 673 | 771 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 682 | 780 | rdai->frm_clk_inv = 0; |
|---|
| 683 | 781 | break; |
|---|
| 684 | 782 | case SND_SOC_DAIFMT_LEFT_J: |
|---|
| 783 | + case SND_SOC_DAIFMT_DSP_B: |
|---|
| 685 | 784 | rdai->sys_delay = 1; |
|---|
| 686 | 785 | rdai->data_alignment = 0; |
|---|
| 687 | 786 | rdai->frm_clk_inv = 1; |
|---|
| .. | .. |
|---|
| 689 | 788 | case SND_SOC_DAIFMT_RIGHT_J: |
|---|
| 690 | 789 | rdai->sys_delay = 1; |
|---|
| 691 | 790 | rdai->data_alignment = 1; |
|---|
| 791 | + rdai->frm_clk_inv = 1; |
|---|
| 792 | + break; |
|---|
| 793 | + case SND_SOC_DAIFMT_DSP_A: |
|---|
| 794 | + rdai->sys_delay = 0; |
|---|
| 795 | + rdai->data_alignment = 0; |
|---|
| 692 | 796 | rdai->frm_clk_inv = 1; |
|---|
| 693 | 797 | break; |
|---|
| 694 | 798 | } |
|---|
| .. | .. |
|---|
| 721 | 825 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| 722 | 826 | struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 723 | 827 | |
|---|
| 828 | + switch (slot_width) { |
|---|
| 829 | + case 16: |
|---|
| 830 | + case 24: |
|---|
| 831 | + case 32: |
|---|
| 832 | + break; |
|---|
| 833 | + default: |
|---|
| 834 | + /* use default */ |
|---|
| 835 | + slot_width = 32; |
|---|
| 836 | + } |
|---|
| 837 | + |
|---|
| 724 | 838 | switch (slots) { |
|---|
| 725 | 839 | case 2: |
|---|
| 840 | + /* TDM Split Mode */ |
|---|
| 726 | 841 | case 6: |
|---|
| 727 | 842 | case 8: |
|---|
| 728 | 843 | /* TDM Extend Mode */ |
|---|
| 729 | 844 | rsnd_rdai_channels_set(rdai, slots); |
|---|
| 730 | 845 | rsnd_rdai_ssi_lane_set(rdai, 1); |
|---|
| 846 | + rsnd_rdai_width_set(rdai, slot_width); |
|---|
| 731 | 847 | break; |
|---|
| 732 | 848 | default: |
|---|
| 733 | 849 | dev_err(dev, "unsupported TDM slots (%d)\n", slots); |
|---|
| .. | .. |
|---|
| 756 | 872 | 192000, |
|---|
| 757 | 873 | }; |
|---|
| 758 | 874 | |
|---|
| 759 | | -static int rsnd_soc_hw_rule(struct rsnd_priv *priv, |
|---|
| 875 | +static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, |
|---|
| 760 | 876 | unsigned int *list, int list_num, |
|---|
| 761 | 877 | struct snd_interval *baseline, struct snd_interval *iv) |
|---|
| 762 | 878 | { |
|---|
| .. | .. |
|---|
| 773 | 889 | if (!snd_interval_test(iv, list[i])) |
|---|
| 774 | 890 | continue; |
|---|
| 775 | 891 | |
|---|
| 776 | | - rate = rsnd_ssi_clk_query(priv, |
|---|
| 892 | + rate = rsnd_ssi_clk_query(rdai, |
|---|
| 777 | 893 | baseline->min, list[i], NULL); |
|---|
| 778 | 894 | if (rate > 0) { |
|---|
| 779 | 895 | p.min = min(p.min, list[i]); |
|---|
| 780 | 896 | p.max = max(p.max, list[i]); |
|---|
| 781 | 897 | } |
|---|
| 782 | 898 | |
|---|
| 783 | | - rate = rsnd_ssi_clk_query(priv, |
|---|
| 899 | + rate = rsnd_ssi_clk_query(rdai, |
|---|
| 784 | 900 | baseline->max, list[i], NULL); |
|---|
| 785 | 901 | if (rate > 0) { |
|---|
| 786 | 902 | p.min = min(p.min, list[i]); |
|---|
| .. | .. |
|---|
| 791 | 907 | return snd_interval_refine(iv, &p); |
|---|
| 792 | 908 | } |
|---|
| 793 | 909 | |
|---|
| 794 | | -static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, |
|---|
| 795 | | - struct snd_pcm_hw_rule *rule, |
|---|
| 796 | | - int is_play) |
|---|
| 910 | +static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, |
|---|
| 911 | + struct snd_pcm_hw_rule *rule) |
|---|
| 797 | 912 | { |
|---|
| 798 | 913 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
|---|
| 799 | 914 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
|---|
| 800 | 915 | struct snd_interval ic; |
|---|
| 801 | | - struct snd_soc_dai *dai = rule->private; |
|---|
| 802 | | - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| 803 | | - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
|---|
| 804 | | - struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; |
|---|
| 916 | + struct rsnd_dai_stream *io = rule->private; |
|---|
| 917 | + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
|---|
| 805 | 918 | |
|---|
| 806 | 919 | /* |
|---|
| 807 | 920 | * possible sampling rate limitation is same as |
|---|
| .. | .. |
|---|
| 812 | 925 | ic.min = |
|---|
| 813 | 926 | ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); |
|---|
| 814 | 927 | |
|---|
| 815 | | - return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, |
|---|
| 928 | + return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list, |
|---|
| 816 | 929 | ARRAY_SIZE(rsnd_soc_hw_rate_list), |
|---|
| 817 | 930 | &ic, ir); |
|---|
| 818 | 931 | } |
|---|
| 819 | 932 | |
|---|
| 820 | | -static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params, |
|---|
| 821 | | - struct snd_pcm_hw_rule *rule) |
|---|
| 822 | | -{ |
|---|
| 823 | | - return __rsnd_soc_hw_rule_rate(params, rule, 1); |
|---|
| 824 | | -} |
|---|
| 825 | | - |
|---|
| 826 | | -static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params, |
|---|
| 827 | | - struct snd_pcm_hw_rule *rule) |
|---|
| 828 | | -{ |
|---|
| 829 | | - return __rsnd_soc_hw_rule_rate(params, rule, 0); |
|---|
| 830 | | -} |
|---|
| 831 | | - |
|---|
| 832 | | -static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, |
|---|
| 833 | | - struct snd_pcm_hw_rule *rule, |
|---|
| 834 | | - int is_play) |
|---|
| 933 | +static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, |
|---|
| 934 | + struct snd_pcm_hw_rule *rule) |
|---|
| 835 | 935 | { |
|---|
| 836 | 936 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
|---|
| 837 | 937 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
|---|
| 838 | 938 | struct snd_interval ic; |
|---|
| 839 | | - struct snd_soc_dai *dai = rule->private; |
|---|
| 840 | | - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| 841 | | - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
|---|
| 842 | | - struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; |
|---|
| 939 | + struct rsnd_dai_stream *io = rule->private; |
|---|
| 940 | + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
|---|
| 843 | 941 | |
|---|
| 844 | 942 | /* |
|---|
| 845 | 943 | * possible sampling rate limitation is same as |
|---|
| .. | .. |
|---|
| 850 | 948 | ic.min = |
|---|
| 851 | 949 | ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); |
|---|
| 852 | 950 | |
|---|
| 853 | | - return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, |
|---|
| 951 | + return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list, |
|---|
| 854 | 952 | ARRAY_SIZE(rsnd_soc_hw_channels_list), |
|---|
| 855 | 953 | ir, &ic); |
|---|
| 856 | | -} |
|---|
| 857 | | - |
|---|
| 858 | | -static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params, |
|---|
| 859 | | - struct snd_pcm_hw_rule *rule) |
|---|
| 860 | | -{ |
|---|
| 861 | | - return __rsnd_soc_hw_rule_channels(params, rule, 1); |
|---|
| 862 | | -} |
|---|
| 863 | | - |
|---|
| 864 | | -static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params, |
|---|
| 865 | | - struct snd_pcm_hw_rule *rule) |
|---|
| 866 | | -{ |
|---|
| 867 | | - return __rsnd_soc_hw_rule_channels(params, rule, 0); |
|---|
| 868 | 954 | } |
|---|
| 869 | 955 | |
|---|
| 870 | 956 | static const struct snd_pcm_hardware rsnd_pcm_hardware = { |
|---|
| .. | .. |
|---|
| 883 | 969 | struct snd_soc_dai *dai) |
|---|
| 884 | 970 | { |
|---|
| 885 | 971 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| 886 | | - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
|---|
| 887 | 972 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
|---|
| 888 | 973 | struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; |
|---|
| 889 | 974 | struct snd_pcm_runtime *runtime = substream->runtime; |
|---|
| 890 | 975 | unsigned int max_channels = rsnd_rdai_channels_get(rdai); |
|---|
| 891 | | - int ret; |
|---|
| 892 | 976 | int i; |
|---|
| 893 | 977 | |
|---|
| 894 | 978 | rsnd_dai_stream_init(io, substream); |
|---|
| .. | .. |
|---|
| 923 | 1007 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
|---|
| 924 | 1008 | |
|---|
| 925 | 1009 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
|---|
| 926 | | - is_play ? rsnd_soc_hw_rule_rate_playback : |
|---|
| 927 | | - rsnd_soc_hw_rule_rate_capture, |
|---|
| 928 | | - dai, |
|---|
| 1010 | + rsnd_soc_hw_rule_rate, |
|---|
| 1011 | + is_play ? &rdai->playback : &rdai->capture, |
|---|
| 929 | 1012 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
|---|
| 930 | 1013 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
|---|
| 931 | | - is_play ? rsnd_soc_hw_rule_channels_playback : |
|---|
| 932 | | - rsnd_soc_hw_rule_channels_capture, |
|---|
| 933 | | - dai, |
|---|
| 1014 | + rsnd_soc_hw_rule_channels, |
|---|
| 1015 | + is_play ? &rdai->playback : &rdai->capture, |
|---|
| 934 | 1016 | SNDRV_PCM_HW_PARAM_RATE, -1); |
|---|
| 935 | 1017 | } |
|---|
| 936 | 1018 | |
|---|
| 937 | | - /* |
|---|
| 938 | | - * call rsnd_dai_call without spinlock |
|---|
| 939 | | - */ |
|---|
| 940 | | - ret = rsnd_dai_call(nolock_start, io, priv); |
|---|
| 941 | | - if (ret < 0) |
|---|
| 942 | | - rsnd_dai_call(nolock_stop, io, priv); |
|---|
| 943 | | - |
|---|
| 944 | | - return ret; |
|---|
| 1019 | + return 0; |
|---|
| 945 | 1020 | } |
|---|
| 946 | 1021 | |
|---|
| 947 | 1022 | static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, |
|---|
| .. | .. |
|---|
| 954 | 1029 | /* |
|---|
| 955 | 1030 | * call rsnd_dai_call without spinlock |
|---|
| 956 | 1031 | */ |
|---|
| 957 | | - rsnd_dai_call(nolock_stop, io, priv); |
|---|
| 1032 | + rsnd_dai_call(cleanup, io, priv); |
|---|
| 958 | 1033 | |
|---|
| 959 | 1034 | rsnd_dai_stream_quit(io); |
|---|
| 960 | 1035 | } |
|---|
| .. | .. |
|---|
| 977 | 1052 | .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, |
|---|
| 978 | 1053 | .prepare = rsnd_soc_dai_prepare, |
|---|
| 979 | 1054 | }; |
|---|
| 1055 | + |
|---|
| 1056 | +static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, |
|---|
| 1057 | + struct rsnd_dai_stream *io, |
|---|
| 1058 | + struct device_node *dai_np) |
|---|
| 1059 | +{ |
|---|
| 1060 | + struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 1061 | + struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); |
|---|
| 1062 | + struct device_node *np; |
|---|
| 1063 | + int is_play = rsnd_io_is_play(io); |
|---|
| 1064 | + int i, j; |
|---|
| 1065 | + |
|---|
| 1066 | + if (!ssiu_np) |
|---|
| 1067 | + return; |
|---|
| 1068 | + |
|---|
| 1069 | + /* |
|---|
| 1070 | + * This driver assumes that it is TDM Split mode |
|---|
| 1071 | + * if it includes ssiu node |
|---|
| 1072 | + */ |
|---|
| 1073 | + for (i = 0;; i++) { |
|---|
| 1074 | + struct device_node *node = is_play ? |
|---|
| 1075 | + of_parse_phandle(dai_np, "playback", i) : |
|---|
| 1076 | + of_parse_phandle(dai_np, "capture", i); |
|---|
| 1077 | + |
|---|
| 1078 | + if (!node) |
|---|
| 1079 | + break; |
|---|
| 1080 | + |
|---|
| 1081 | + j = 0; |
|---|
| 1082 | + for_each_child_of_node(ssiu_np, np) { |
|---|
| 1083 | + if (np == node) { |
|---|
| 1084 | + rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); |
|---|
| 1085 | + dev_dbg(dev, "%s is part of TDM Split\n", io->name); |
|---|
| 1086 | + } |
|---|
| 1087 | + j++; |
|---|
| 1088 | + } |
|---|
| 1089 | + |
|---|
| 1090 | + of_node_put(node); |
|---|
| 1091 | + } |
|---|
| 1092 | + |
|---|
| 1093 | + of_node_put(ssiu_np); |
|---|
| 1094 | +} |
|---|
| 1095 | + |
|---|
| 1096 | +static void rsnd_parse_connect_simple(struct rsnd_priv *priv, |
|---|
| 1097 | + struct rsnd_dai_stream *io, |
|---|
| 1098 | + struct device_node *dai_np) |
|---|
| 1099 | +{ |
|---|
| 1100 | + if (!rsnd_io_to_mod_ssi(io)) |
|---|
| 1101 | + return; |
|---|
| 1102 | + |
|---|
| 1103 | + rsnd_parse_tdm_split_mode(priv, io, dai_np); |
|---|
| 1104 | +} |
|---|
| 1105 | + |
|---|
| 1106 | +static void rsnd_parse_connect_graph(struct rsnd_priv *priv, |
|---|
| 1107 | + struct rsnd_dai_stream *io, |
|---|
| 1108 | + struct device_node *endpoint) |
|---|
| 1109 | +{ |
|---|
| 1110 | + struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 1111 | + struct device_node *remote_node; |
|---|
| 1112 | + |
|---|
| 1113 | + if (!rsnd_io_to_mod_ssi(io)) |
|---|
| 1114 | + return; |
|---|
| 1115 | + |
|---|
| 1116 | + remote_node = of_graph_get_remote_port_parent(endpoint); |
|---|
| 1117 | + |
|---|
| 1118 | + /* HDMI0 */ |
|---|
| 1119 | + if (strstr(remote_node->full_name, "hdmi@fead0000")) { |
|---|
| 1120 | + rsnd_flags_set(io, RSND_STREAM_HDMI0); |
|---|
| 1121 | + dev_dbg(dev, "%s connected to HDMI0\n", io->name); |
|---|
| 1122 | + } |
|---|
| 1123 | + |
|---|
| 1124 | + /* HDMI1 */ |
|---|
| 1125 | + if (strstr(remote_node->full_name, "hdmi@feae0000")) { |
|---|
| 1126 | + rsnd_flags_set(io, RSND_STREAM_HDMI1); |
|---|
| 1127 | + dev_dbg(dev, "%s connected to HDMI1\n", io->name); |
|---|
| 1128 | + } |
|---|
| 1129 | + |
|---|
| 1130 | + rsnd_parse_tdm_split_mode(priv, io, endpoint); |
|---|
| 1131 | + |
|---|
| 1132 | + of_node_put(remote_node); |
|---|
| 1133 | +} |
|---|
| 980 | 1134 | |
|---|
| 981 | 1135 | void rsnd_parse_connect_common(struct rsnd_dai *rdai, |
|---|
| 982 | 1136 | struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), |
|---|
| .. | .. |
|---|
| 1041 | 1195 | return ret; |
|---|
| 1042 | 1196 | } |
|---|
| 1043 | 1197 | |
|---|
| 1198 | + |
|---|
| 1199 | +#define PREALLOC_BUFFER (32 * 1024) |
|---|
| 1200 | +#define PREALLOC_BUFFER_MAX (32 * 1024) |
|---|
| 1201 | + |
|---|
| 1202 | +static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, |
|---|
| 1203 | + struct rsnd_dai_stream *io, |
|---|
| 1204 | + int stream) |
|---|
| 1205 | +{ |
|---|
| 1206 | + struct rsnd_priv *priv = rsnd_io_to_priv(io); |
|---|
| 1207 | + struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 1208 | + struct snd_pcm_substream *substream; |
|---|
| 1209 | + |
|---|
| 1210 | + /* |
|---|
| 1211 | + * use Audio-DMAC dev if we can use IPMMU |
|---|
| 1212 | + * see |
|---|
| 1213 | + * rsnd_dmaen_attach() |
|---|
| 1214 | + */ |
|---|
| 1215 | + if (io->dmac_dev) |
|---|
| 1216 | + dev = io->dmac_dev; |
|---|
| 1217 | + |
|---|
| 1218 | + for (substream = rtd->pcm->streams[stream].substream; |
|---|
| 1219 | + substream; |
|---|
| 1220 | + substream = substream->next) { |
|---|
| 1221 | + snd_pcm_set_managed_buffer(substream, |
|---|
| 1222 | + SNDRV_DMA_TYPE_DEV, |
|---|
| 1223 | + dev, |
|---|
| 1224 | + PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); |
|---|
| 1225 | + } |
|---|
| 1226 | + |
|---|
| 1227 | + return 0; |
|---|
| 1228 | +} |
|---|
| 1229 | + |
|---|
| 1230 | +static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, |
|---|
| 1231 | + struct snd_soc_dai *dai) |
|---|
| 1232 | +{ |
|---|
| 1233 | + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| 1234 | + int ret; |
|---|
| 1235 | + |
|---|
| 1236 | + ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd); |
|---|
| 1237 | + if (ret) |
|---|
| 1238 | + return ret; |
|---|
| 1239 | + |
|---|
| 1240 | + ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd); |
|---|
| 1241 | + if (ret) |
|---|
| 1242 | + return ret; |
|---|
| 1243 | + |
|---|
| 1244 | + ret = rsnd_preallocate_pages(rtd, &rdai->playback, |
|---|
| 1245 | + SNDRV_PCM_STREAM_PLAYBACK); |
|---|
| 1246 | + if (ret) |
|---|
| 1247 | + return ret; |
|---|
| 1248 | + |
|---|
| 1249 | + ret = rsnd_preallocate_pages(rtd, &rdai->capture, |
|---|
| 1250 | + SNDRV_PCM_STREAM_CAPTURE); |
|---|
| 1251 | + if (ret) |
|---|
| 1252 | + return ret; |
|---|
| 1253 | + |
|---|
| 1254 | + return 0; |
|---|
| 1255 | +} |
|---|
| 1256 | + |
|---|
| 1044 | 1257 | static void __rsnd_dai_probe(struct rsnd_priv *priv, |
|---|
| 1045 | 1258 | struct device_node *dai_np, |
|---|
| 1046 | 1259 | int dai_i) |
|---|
| .. | .. |
|---|
| 1063 | 1276 | rdai->priv = priv; |
|---|
| 1064 | 1277 | drv->name = rdai->name; |
|---|
| 1065 | 1278 | drv->ops = &rsnd_soc_dai_ops; |
|---|
| 1279 | + drv->pcm_new = rsnd_pcm_new; |
|---|
| 1066 | 1280 | |
|---|
| 1067 | | - snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE, |
|---|
| 1281 | + snprintf(io_playback->name, RSND_DAI_NAME_SIZE, |
|---|
| 1068 | 1282 | "DAI%d Playback", dai_i); |
|---|
| 1069 | 1283 | drv->playback.rates = RSND_RATES; |
|---|
| 1070 | 1284 | drv->playback.formats = RSND_FMTS; |
|---|
| 1071 | 1285 | drv->playback.channels_min = 2; |
|---|
| 1072 | 1286 | drv->playback.channels_max = 8; |
|---|
| 1073 | | - drv->playback.stream_name = rdai->playback.name; |
|---|
| 1287 | + drv->playback.stream_name = io_playback->name; |
|---|
| 1074 | 1288 | |
|---|
| 1075 | | - snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, |
|---|
| 1289 | + snprintf(io_capture->name, RSND_DAI_NAME_SIZE, |
|---|
| 1076 | 1290 | "DAI%d Capture", dai_i); |
|---|
| 1077 | 1291 | drv->capture.rates = RSND_RATES; |
|---|
| 1078 | 1292 | drv->capture.formats = RSND_FMTS; |
|---|
| 1079 | 1293 | drv->capture.channels_min = 2; |
|---|
| 1080 | 1294 | drv->capture.channels_max = 8; |
|---|
| 1081 | | - drv->capture.stream_name = rdai->capture.name; |
|---|
| 1295 | + drv->capture.stream_name = io_capture->name; |
|---|
| 1082 | 1296 | |
|---|
| 1083 | | - rdai->playback.rdai = rdai; |
|---|
| 1084 | | - rdai->capture.rdai = rdai; |
|---|
| 1297 | + io_playback->rdai = rdai; |
|---|
| 1298 | + io_capture->rdai = rdai; |
|---|
| 1085 | 1299 | rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ |
|---|
| 1086 | 1300 | rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ |
|---|
| 1301 | + rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ |
|---|
| 1087 | 1302 | |
|---|
| 1088 | 1303 | for (io_i = 0;; io_i++) { |
|---|
| 1089 | 1304 | playback = of_parse_phandle(dai_np, "playback", io_i); |
|---|
| .. | .. |
|---|
| 1093 | 1308 | break; |
|---|
| 1094 | 1309 | |
|---|
| 1095 | 1310 | rsnd_parse_connect_ssi(rdai, playback, capture); |
|---|
| 1311 | + rsnd_parse_connect_ssiu(rdai, playback, capture); |
|---|
| 1096 | 1312 | rsnd_parse_connect_src(rdai, playback, capture); |
|---|
| 1097 | 1313 | rsnd_parse_connect_ctu(rdai, playback, capture); |
|---|
| 1098 | 1314 | rsnd_parse_connect_mix(rdai, playback, capture); |
|---|
| .. | .. |
|---|
| 1149 | 1365 | if (is_graph) { |
|---|
| 1150 | 1366 | for_each_endpoint_of_node(dai_node, dai_np) { |
|---|
| 1151 | 1367 | __rsnd_dai_probe(priv, dai_np, dai_i); |
|---|
| 1152 | | - rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i); |
|---|
| 1368 | + if (rsnd_is_gen3(priv)) { |
|---|
| 1369 | + struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); |
|---|
| 1370 | + |
|---|
| 1371 | + rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); |
|---|
| 1372 | + rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); |
|---|
| 1373 | + } |
|---|
| 1153 | 1374 | dai_i++; |
|---|
| 1154 | 1375 | } |
|---|
| 1155 | 1376 | } else { |
|---|
| 1156 | | - for_each_child_of_node(dai_node, dai_np) |
|---|
| 1157 | | - __rsnd_dai_probe(priv, dai_np, dai_i++); |
|---|
| 1377 | + for_each_child_of_node(dai_node, dai_np) { |
|---|
| 1378 | + __rsnd_dai_probe(priv, dai_np, dai_i); |
|---|
| 1379 | + if (rsnd_is_gen3(priv)) { |
|---|
| 1380 | + struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); |
|---|
| 1381 | + |
|---|
| 1382 | + rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); |
|---|
| 1383 | + rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); |
|---|
| 1384 | + } |
|---|
| 1385 | + dai_i++; |
|---|
| 1386 | + } |
|---|
| 1158 | 1387 | } |
|---|
| 1159 | 1388 | |
|---|
| 1160 | 1389 | return 0; |
|---|
| .. | .. |
|---|
| 1163 | 1392 | /* |
|---|
| 1164 | 1393 | * pcm ops |
|---|
| 1165 | 1394 | */ |
|---|
| 1166 | | -static int rsnd_hw_params(struct snd_pcm_substream *substream, |
|---|
| 1167 | | - struct snd_pcm_hw_params *hw_params) |
|---|
| 1395 | +static int rsnd_hw_params(struct snd_soc_component *component, |
|---|
| 1396 | + struct snd_pcm_substream *substream, |
|---|
| 1397 | + struct snd_pcm_hw_params *hw_params) |
|---|
| 1168 | 1398 | { |
|---|
| 1169 | 1399 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); |
|---|
| 1170 | 1400 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| 1171 | 1401 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
|---|
| 1172 | | - int ret; |
|---|
| 1402 | + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); |
|---|
| 1173 | 1403 | |
|---|
| 1174 | | - ret = rsnd_dai_call(hw_params, io, substream, hw_params); |
|---|
| 1175 | | - if (ret) |
|---|
| 1176 | | - return ret; |
|---|
| 1404 | + /* |
|---|
| 1405 | + * rsnd assumes that it might be used under DPCM if user want to use |
|---|
| 1406 | + * channel / rate convert. Then, rsnd should be FE. |
|---|
| 1407 | + * And then, this function will be called *after* BE settings. |
|---|
| 1408 | + * this means, each BE already has fixuped hw_params. |
|---|
| 1409 | + * see |
|---|
| 1410 | + * dpcm_fe_dai_hw_params() |
|---|
| 1411 | + * dpcm_be_dai_hw_params() |
|---|
| 1412 | + */ |
|---|
| 1413 | + io->converted_rate = 0; |
|---|
| 1414 | + io->converted_chan = 0; |
|---|
| 1415 | + if (fe->dai_link->dynamic) { |
|---|
| 1416 | + struct rsnd_priv *priv = rsnd_io_to_priv(io); |
|---|
| 1417 | + struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 1418 | + struct snd_soc_dpcm *dpcm; |
|---|
| 1419 | + struct snd_pcm_hw_params *be_params; |
|---|
| 1420 | + int stream = substream->stream; |
|---|
| 1177 | 1421 | |
|---|
| 1178 | | - return snd_pcm_lib_malloc_pages(substream, |
|---|
| 1179 | | - params_buffer_bytes(hw_params)); |
|---|
| 1422 | + for_each_dpcm_be(fe, stream, dpcm) { |
|---|
| 1423 | + be_params = &dpcm->hw_params; |
|---|
| 1424 | + if (params_channels(hw_params) != params_channels(be_params)) |
|---|
| 1425 | + io->converted_chan = params_channels(be_params); |
|---|
| 1426 | + if (params_rate(hw_params) != params_rate(be_params)) |
|---|
| 1427 | + io->converted_rate = params_rate(be_params); |
|---|
| 1428 | + } |
|---|
| 1429 | + if (io->converted_chan) |
|---|
| 1430 | + dev_dbg(dev, "convert channels = %d\n", io->converted_chan); |
|---|
| 1431 | + if (io->converted_rate) { |
|---|
| 1432 | + /* |
|---|
| 1433 | + * SRC supports convert rates from params_rate(hw_params)/k_down |
|---|
| 1434 | + * to params_rate(hw_params)*k_up, where k_up is always 6, and |
|---|
| 1435 | + * k_down depends on number of channels and SRC unit. |
|---|
| 1436 | + * So all SRC units can upsample audio up to 6 times regardless |
|---|
| 1437 | + * its number of channels. And all SRC units can downsample |
|---|
| 1438 | + * 2 channel audio up to 6 times too. |
|---|
| 1439 | + */ |
|---|
| 1440 | + int k_up = 6; |
|---|
| 1441 | + int k_down = 6; |
|---|
| 1442 | + int channel; |
|---|
| 1443 | + struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); |
|---|
| 1444 | + |
|---|
| 1445 | + dev_dbg(dev, "convert rate = %d\n", io->converted_rate); |
|---|
| 1446 | + |
|---|
| 1447 | + channel = io->converted_chan ? io->converted_chan : |
|---|
| 1448 | + params_channels(hw_params); |
|---|
| 1449 | + |
|---|
| 1450 | + switch (rsnd_mod_id(src_mod)) { |
|---|
| 1451 | + /* |
|---|
| 1452 | + * SRC0 can downsample 4, 6 and 8 channel audio up to 4 times. |
|---|
| 1453 | + * SRC1, SRC3 and SRC4 can downsample 4 channel audio |
|---|
| 1454 | + * up to 4 times. |
|---|
| 1455 | + * SRC1, SRC3 and SRC4 can downsample 6 and 8 channel audio |
|---|
| 1456 | + * no more than twice. |
|---|
| 1457 | + */ |
|---|
| 1458 | + case 1: |
|---|
| 1459 | + case 3: |
|---|
| 1460 | + case 4: |
|---|
| 1461 | + if (channel > 4) { |
|---|
| 1462 | + k_down = 2; |
|---|
| 1463 | + break; |
|---|
| 1464 | + } |
|---|
| 1465 | + fallthrough; |
|---|
| 1466 | + case 0: |
|---|
| 1467 | + if (channel > 2) |
|---|
| 1468 | + k_down = 4; |
|---|
| 1469 | + break; |
|---|
| 1470 | + |
|---|
| 1471 | + /* Other SRC units do not support more than 2 channels */ |
|---|
| 1472 | + default: |
|---|
| 1473 | + if (channel > 2) |
|---|
| 1474 | + return -EINVAL; |
|---|
| 1475 | + } |
|---|
| 1476 | + |
|---|
| 1477 | + if (params_rate(hw_params) > io->converted_rate * k_down) { |
|---|
| 1478 | + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = |
|---|
| 1479 | + io->converted_rate * k_down; |
|---|
| 1480 | + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = |
|---|
| 1481 | + io->converted_rate * k_down; |
|---|
| 1482 | + hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; |
|---|
| 1483 | + } else if (params_rate(hw_params) * k_up < io->converted_rate) { |
|---|
| 1484 | + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = |
|---|
| 1485 | + (io->converted_rate + k_up - 1) / k_up; |
|---|
| 1486 | + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = |
|---|
| 1487 | + (io->converted_rate + k_up - 1) / k_up; |
|---|
| 1488 | + hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; |
|---|
| 1489 | + } |
|---|
| 1490 | + |
|---|
| 1491 | + /* |
|---|
| 1492 | + * TBD: Max SRC input and output rates also depend on number |
|---|
| 1493 | + * of channels and SRC unit: |
|---|
| 1494 | + * SRC1, SRC3 and SRC4 do not support more than 128kHz |
|---|
| 1495 | + * for 6 channel and 96kHz for 8 channel audio. |
|---|
| 1496 | + * Perhaps this function should return EINVAL if the input or |
|---|
| 1497 | + * the output rate exceeds the limitation. |
|---|
| 1498 | + */ |
|---|
| 1499 | + } |
|---|
| 1500 | + } |
|---|
| 1501 | + |
|---|
| 1502 | + return rsnd_dai_call(hw_params, io, substream, hw_params); |
|---|
| 1180 | 1503 | } |
|---|
| 1181 | 1504 | |
|---|
| 1182 | | -static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) |
|---|
| 1505 | +static int rsnd_hw_free(struct snd_soc_component *component, |
|---|
| 1506 | + struct snd_pcm_substream *substream) |
|---|
| 1507 | +{ |
|---|
| 1508 | + struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); |
|---|
| 1509 | + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| 1510 | + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
|---|
| 1511 | + |
|---|
| 1512 | + return rsnd_dai_call(hw_free, io, substream); |
|---|
| 1513 | +} |
|---|
| 1514 | + |
|---|
| 1515 | +static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component, |
|---|
| 1516 | + struct snd_pcm_substream *substream) |
|---|
| 1183 | 1517 | { |
|---|
| 1184 | 1518 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); |
|---|
| 1185 | 1519 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| .. | .. |
|---|
| 1190 | 1524 | |
|---|
| 1191 | 1525 | return pointer; |
|---|
| 1192 | 1526 | } |
|---|
| 1193 | | - |
|---|
| 1194 | | -static const struct snd_pcm_ops rsnd_pcm_ops = { |
|---|
| 1195 | | - .ioctl = snd_pcm_lib_ioctl, |
|---|
| 1196 | | - .hw_params = rsnd_hw_params, |
|---|
| 1197 | | - .hw_free = snd_pcm_lib_free_pages, |
|---|
| 1198 | | - .pointer = rsnd_pointer, |
|---|
| 1199 | | -}; |
|---|
| 1200 | 1527 | |
|---|
| 1201 | 1528 | /* |
|---|
| 1202 | 1529 | * snd_kcontrol |
|---|
| .. | .. |
|---|
| 1275 | 1602 | int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) |
|---|
| 1276 | 1603 | { |
|---|
| 1277 | 1604 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
|---|
| 1605 | + struct rsnd_priv *priv = rsnd_io_to_priv(io); |
|---|
| 1606 | + struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 1278 | 1607 | |
|---|
| 1279 | | - return !!runtime; |
|---|
| 1608 | + if (!runtime) { |
|---|
| 1609 | + dev_warn(dev, "Can't update kctrl when idle\n"); |
|---|
| 1610 | + return 0; |
|---|
| 1611 | + } |
|---|
| 1612 | + |
|---|
| 1613 | + return 1; |
|---|
| 1280 | 1614 | } |
|---|
| 1281 | 1615 | |
|---|
| 1282 | 1616 | struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) |
|---|
| .. | .. |
|---|
| 1383 | 1717 | /* |
|---|
| 1384 | 1718 | * snd_soc_component |
|---|
| 1385 | 1719 | */ |
|---|
| 1386 | | - |
|---|
| 1387 | | -#define PREALLOC_BUFFER (32 * 1024) |
|---|
| 1388 | | -#define PREALLOC_BUFFER_MAX (32 * 1024) |
|---|
| 1389 | | - |
|---|
| 1390 | | -static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, |
|---|
| 1391 | | - struct rsnd_dai_stream *io, |
|---|
| 1392 | | - int stream) |
|---|
| 1393 | | -{ |
|---|
| 1394 | | - struct rsnd_priv *priv = rsnd_io_to_priv(io); |
|---|
| 1395 | | - struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 1396 | | - struct snd_pcm_substream *substream; |
|---|
| 1397 | | - int err; |
|---|
| 1398 | | - |
|---|
| 1399 | | - /* |
|---|
| 1400 | | - * use Audio-DMAC dev if we can use IPMMU |
|---|
| 1401 | | - * see |
|---|
| 1402 | | - * rsnd_dmaen_attach() |
|---|
| 1403 | | - */ |
|---|
| 1404 | | - if (io->dmac_dev) |
|---|
| 1405 | | - dev = io->dmac_dev; |
|---|
| 1406 | | - |
|---|
| 1407 | | - for (substream = rtd->pcm->streams[stream].substream; |
|---|
| 1408 | | - substream; |
|---|
| 1409 | | - substream = substream->next) { |
|---|
| 1410 | | - err = snd_pcm_lib_preallocate_pages(substream, |
|---|
| 1411 | | - SNDRV_DMA_TYPE_DEV, |
|---|
| 1412 | | - dev, |
|---|
| 1413 | | - PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); |
|---|
| 1414 | | - if (err < 0) |
|---|
| 1415 | | - return err; |
|---|
| 1416 | | - } |
|---|
| 1417 | | - |
|---|
| 1418 | | - return 0; |
|---|
| 1419 | | -} |
|---|
| 1420 | | - |
|---|
| 1421 | | -static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) |
|---|
| 1422 | | -{ |
|---|
| 1423 | | - struct snd_soc_dai *dai = rtd->cpu_dai; |
|---|
| 1424 | | - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
|---|
| 1425 | | - int ret; |
|---|
| 1426 | | - |
|---|
| 1427 | | - ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd); |
|---|
| 1428 | | - if (ret) |
|---|
| 1429 | | - return ret; |
|---|
| 1430 | | - |
|---|
| 1431 | | - ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd); |
|---|
| 1432 | | - if (ret) |
|---|
| 1433 | | - return ret; |
|---|
| 1434 | | - |
|---|
| 1435 | | - ret = rsnd_preallocate_pages(rtd, &rdai->playback, |
|---|
| 1436 | | - SNDRV_PCM_STREAM_PLAYBACK); |
|---|
| 1437 | | - if (ret) |
|---|
| 1438 | | - return ret; |
|---|
| 1439 | | - |
|---|
| 1440 | | - ret = rsnd_preallocate_pages(rtd, &rdai->capture, |
|---|
| 1441 | | - SNDRV_PCM_STREAM_CAPTURE); |
|---|
| 1442 | | - if (ret) |
|---|
| 1443 | | - return ret; |
|---|
| 1444 | | - |
|---|
| 1445 | | - return 0; |
|---|
| 1446 | | -} |
|---|
| 1447 | | - |
|---|
| 1448 | 1720 | static const struct snd_soc_component_driver rsnd_soc_component = { |
|---|
| 1449 | | - .ops = &rsnd_pcm_ops, |
|---|
| 1450 | | - .pcm_new = rsnd_pcm_new, |
|---|
| 1451 | 1721 | .name = "rsnd", |
|---|
| 1722 | + .hw_params = rsnd_hw_params, |
|---|
| 1723 | + .hw_free = rsnd_hw_free, |
|---|
| 1724 | + .pointer = rsnd_pointer, |
|---|
| 1452 | 1725 | }; |
|---|
| 1453 | 1726 | |
|---|
| 1454 | 1727 | static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, |
|---|
| .. | .. |
|---|
| 1600 | 1873 | rsnd_adg_remove, |
|---|
| 1601 | 1874 | }; |
|---|
| 1602 | 1875 | int ret = 0, i; |
|---|
| 1603 | | - |
|---|
| 1604 | | - snd_soc_disconnect_sync(&pdev->dev); |
|---|
| 1605 | 1876 | |
|---|
| 1606 | 1877 | pm_runtime_disable(&pdev->dev); |
|---|
| 1607 | 1878 | |
|---|