Skip to content

Commit

Permalink
ALSA: hda: Honor subformat when querying PCMs
Browse files Browse the repository at this point in the history
Update mechanism for querying supported PCMs to allow for granular
format selection when container size is 32 bits. Currently always the
highest bit depth is selected, regardless of how many actual formats
codec in question supports.

Acked-by: Mark Brown <broonie@kernel.org>
Co-developed-by: Jaroslav Kysela <perex@perex.cz>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20231117120610.1755254-3-cezary.rojewski@intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
crojewsk-intel authored and tiwai committed Nov 27, 2023
1 parent 2112aa0 commit a7fc8b8
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 24 deletions.
5 changes: 3 additions & 2 deletions include/sound/hda_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ struct hda_pcm_stream {
hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */
u32 rates; /* supported rates */
u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */
u32 subformats; /* for S32_LE format, SNDRV_PCM_SUBFMTBIT_* */
unsigned int maxbps; /* supported max. bit per sample */
const struct snd_pcm_chmap_elem *chmap; /* chmap to override */
struct hda_pcm_ops ops;
Expand Down Expand Up @@ -448,8 +449,8 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
#define snd_hda_codec_cleanup_stream(codec, nid) \
__snd_hda_codec_cleanup_stream(codec, nid, 0)

#define snd_hda_query_supported_pcm(codec, nid, ratesp, fmtsp, bpsp) \
snd_hdac_query_supported_pcm(&(codec)->core, nid, ratesp, fmtsp, bpsp)
#define snd_hda_query_supported_pcm(codec, nid, ratesp, fmtsp, subfmtp, bpsp) \
snd_hdac_query_supported_pcm(&(codec)->core, nid, ratesp, fmtsp, subfmtp, bpsp)
#define snd_hda_is_supported_format(codec, nid, fmt) \
snd_hdac_is_supported_format(&(codec)->core, nid, fmt)

Expand Down
3 changes: 2 additions & 1 deletion include/sound/hdaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ unsigned int snd_hdac_calc_stream_format(unsigned int rate,
unsigned int maxbps,
unsigned short spdif_ctls);
int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
u32 *ratesp, u64 *formatsp, u32 *subformatsp,
unsigned int *bpsp);
bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid,
unsigned int format);

Expand Down
45 changes: 25 additions & 20 deletions sound/hda/hdac_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -817,15 +817,17 @@ static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid)
* @nid: NID to query
* @ratesp: the pointer to store the detected rate bitflags
* @formatsp: the pointer to store the detected formats
* @subformatsp: the pointer to store the detected subformats for S32_LE format
* @bpsp: the pointer to store the detected format widths
*
* Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp
* or @bsps argument is ignored.
* Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp,
* @subformatsp or @bpsp argument is ignored.
*
* Returns 0 if successful, otherwise a negative error code.
*/
int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
u32 *ratesp, u64 *formatsp, u32 *subformatsp,
unsigned int *bpsp)
{
unsigned int i, val, wcaps;

Expand All @@ -848,9 +850,10 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
*ratesp = rates;
}

if (formatsp || bpsp) {
u64 formats = 0;
if (formatsp || subformatsp || bpsp) {
unsigned int streams, bps;
u32 subformats = 0;
u64 formats = 0;

streams = query_stream_param(codec, nid);
if (!streams)
Expand All @@ -866,24 +869,24 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
formats |= SNDRV_PCM_FMTBIT_S16_LE;
bps = 16;
}
if (wcaps & AC_WCAP_DIGITAL) {
if (val & AC_SUPPCM_BITS_32)
if (val & AC_SUPPCM_BITS_20) {
formats |= SNDRV_PCM_FMTBIT_S32_LE;
subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_20;
bps = 20;
}
if (val & AC_SUPPCM_BITS_24) {
formats |= SNDRV_PCM_FMTBIT_S32_LE;
subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_24;
bps = 24;
}
if (val & AC_SUPPCM_BITS_32) {
if (wcaps & AC_WCAP_DIGITAL) {
formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24))
} else {
formats |= SNDRV_PCM_FMTBIT_S32_LE;
if (val & AC_SUPPCM_BITS_24)
bps = 24;
else if (val & AC_SUPPCM_BITS_20)
bps = 20;
} else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24|
AC_SUPPCM_BITS_32)) {
formats |= SNDRV_PCM_FMTBIT_S32_LE;
if (val & AC_SUPPCM_BITS_32)
subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_MAX;
bps = 32;
else if (val & AC_SUPPCM_BITS_24)
bps = 24;
else if (val & AC_SUPPCM_BITS_20)
bps = 20;
}
}
}
#if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */
Expand Down Expand Up @@ -911,6 +914,8 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
}
if (formatsp)
*formatsp = formats;
if (subformatsp)
*subformatsp = subformats;
if (bpsp)
*bpsp = bps;
}
Expand Down
2 changes: 2 additions & 0 deletions sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -3163,6 +3163,7 @@ static int set_pcm_default_values(struct hda_codec *codec,
err = snd_hda_query_supported_pcm(codec, info->nid,
info->rates ? NULL : &info->rates,
info->formats ? NULL : &info->formats,
info->subformats ? NULL : &info->subformats,
info->maxbps ? NULL : &info->maxbps);
if (err < 0)
return err;
Expand Down Expand Up @@ -3757,6 +3758,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
snd_hda_query_supported_pcm(codec, mout->dig_out_nid,
&mout->spdif_rates,
&mout->spdif_formats,
NULL,
&mout->spdif_maxbps);
}
mutex_lock(&codec->spdif_mutex);
Expand Down
1 change: 1 addition & 0 deletions sound/pci/hda/patch_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1977,6 +1977,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
err = snd_hda_query_supported_pcm(codec, cvt_nid,
&per_cvt->rates,
&per_cvt->formats,
NULL,
&per_cvt->maxbps);
if (err < 0)
return err;
Expand Down
3 changes: 2 additions & 1 deletion sound/soc/codecs/hdac_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt)
err = snd_hdac_query_supported_pcm(hdev, cvt->nid,
&cvt->params.rates,
&cvt->params.formats,
NULL,
&cvt->params.maxbps);
if (err < 0)
dev_err(&hdev->dev,
Expand Down Expand Up @@ -1577,7 +1578,7 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev,

list_for_each_entry(cvt, &hdmi->cvt_list, head) {
ret = snd_hdac_query_supported_pcm(hdev, cvt->nid,
&rates, &formats, &bps);
&rates, &formats, NULL, &bps);
if (ret)
return ret;

Expand Down

0 comments on commit a7fc8b8

Please sign in to comment.