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

ASoC: hdmi-codec: Add a prepare hook

The IEC958 status bit is usually set by the userspace after hw_params
has been called, so in order to use whatever is set by the userspace, we
need to implement the prepare hook. Let's add it to the hdmi_codec_ops,
and mandate that either prepare or hw_params is implemented.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20210525132354.297468-6-maxime@cerno.tech

+98 -24
+11 -1
include/sound/hdmi-codec.h
··· 65 65 66 66 /* 67 67 * Configures HDMI-encoder for audio stream. 68 - * Mandatory 68 + * Having either prepare or hw_params is mandatory. 69 69 */ 70 70 int (*hw_params)(struct device *dev, void *data, 71 71 struct hdmi_codec_daifmt *fmt, 72 72 struct hdmi_codec_params *hparms); 73 + 74 + /* 75 + * Configures HDMI-encoder for audio stream. Can be called 76 + * multiple times for each setup. 77 + * 78 + * Having either prepare or hw_params is mandatory. 79 + */ 80 + int (*prepare)(struct device *dev, void *data, 81 + struct hdmi_codec_daifmt *fmt, 82 + struct hdmi_codec_params *hparms); 73 83 74 84 /* 75 85 * Shuts down the audio stream.
+87 -23
sound/soc/codecs/hdmi-codec.c
··· 481 481 mutex_unlock(&hcp->lock); 482 482 } 483 483 484 + static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai, 485 + unsigned int sample_width, 486 + unsigned int sample_rate, 487 + unsigned int channels, 488 + struct hdmi_codec_params *hp) 489 + { 490 + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); 491 + int idx; 492 + 493 + /* Select a channel allocation that matches with ELD and pcm channels */ 494 + idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels); 495 + if (idx < 0) { 496 + dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", 497 + idx); 498 + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; 499 + return idx; 500 + } 501 + 502 + memset(hp, 0, sizeof(*hp)); 503 + 504 + hdmi_audio_infoframe_init(&hp->cea); 505 + hp->cea.channels = channels; 506 + hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; 507 + hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; 508 + hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; 509 + hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; 510 + 511 + hp->sample_width = sample_width; 512 + hp->sample_rate = sample_rate; 513 + hp->channels = channels; 514 + 515 + hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; 516 + 517 + return 0; 518 + } 519 + 484 520 static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, 485 521 struct snd_pcm_hw_params *params, 486 522 struct snd_soc_dai *dai) ··· 531 495 .dig_subframe = { 0 }, 532 496 } 533 497 }; 534 - int ret, idx; 498 + int ret; 499 + 500 + if (!hcp->hcd.ops->hw_params) 501 + return 0; 535 502 536 503 dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, 537 504 params_width(params), params_rate(params), 538 505 params_channels(params)); 506 + 507 + ret = hdmi_codec_fill_codec_params(dai, 508 + params_width(params), 509 + params_rate(params), 510 + params_channels(params), 511 + &hp); 512 + if (ret < 0) 513 + return ret; 539 514 540 515 memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status)); 541 516 ret = snd_pcm_fill_iec958_consumer_hw_params(params, hp.iec.status, ··· 557 510 return ret; 558 511 } 559 512 560 - hdmi_audio_infoframe_init(&hp.cea); 561 - hp.cea.channels = params_channels(params); 562 - hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; 563 - hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; 564 - hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; 565 - 566 - /* Select a channel allocation that matches with ELD and pcm channels */ 567 - idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels); 568 - if (idx < 0) { 569 - dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", 570 - idx); 571 - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; 572 - return idx; 573 - } 574 - hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; 575 - hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; 576 - 577 - hp.sample_width = params_width(params); 578 - hp.sample_rate = params_rate(params); 579 - hp.channels = params_channels(params); 580 - 581 513 cf->bit_fmt = params_format(params); 582 514 return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, 583 515 cf, &hp); 516 + } 517 + 518 + static int hdmi_codec_prepare(struct snd_pcm_substream *substream, 519 + struct snd_soc_dai *dai) 520 + { 521 + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); 522 + struct hdmi_codec_daifmt *cf = dai->playback_dma_data; 523 + struct snd_pcm_runtime *runtime = substream->runtime; 524 + unsigned int channels = runtime->channels; 525 + unsigned int width = snd_pcm_format_width(runtime->format); 526 + unsigned int rate = runtime->rate; 527 + struct hdmi_codec_params hp; 528 + int ret; 529 + 530 + if (!hcp->hcd.ops->prepare) 531 + return 0; 532 + 533 + dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, 534 + width, rate, channels); 535 + 536 + ret = hdmi_codec_fill_codec_params(dai, width, rate, channels, &hp); 537 + if (ret < 0) 538 + return ret; 539 + 540 + memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status)); 541 + ret = snd_pcm_fill_iec958_consumer(runtime, hp.iec.status, 542 + sizeof(hp.iec.status)); 543 + if (ret < 0) { 544 + dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", 545 + ret); 546 + return ret; 547 + } 548 + 549 + cf->bit_fmt = runtime->format; 550 + return hcp->hcd.ops->prepare(dai->dev->parent, hcp->hcd.data, 551 + cf, &hp); 584 552 } 585 553 586 554 static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, ··· 689 627 .startup = hdmi_codec_startup, 690 628 .shutdown = hdmi_codec_shutdown, 691 629 .hw_params = hdmi_codec_hw_params, 630 + .prepare = hdmi_codec_prepare, 692 631 .set_fmt = hdmi_codec_i2s_set_fmt, 693 632 .mute_stream = hdmi_codec_mute, 694 633 }; ··· 980 917 } 981 918 982 919 dai_count = hcd->i2s + hcd->spdif; 983 - if (dai_count < 1 || !hcd->ops || !hcd->ops->hw_params || 920 + if (dai_count < 1 || !hcd->ops || 921 + (!hcd->ops->hw_params && !hcd->ops->prepare) || 984 922 !hcd->ops->audio_shutdown) { 985 923 dev_err(dev, "%s: Invalid parameters\n", __func__); 986 924 return -EINVAL;