1 // SPDX-License-Identifier: GPL-2.0-only
5 #include <linux/export.h>
6 #include <drm/drm_edid.h>
8 #include <sound/pcm_drm_eld.h>
10 static const unsigned int eld_rates
[] = {
20 static unsigned int sad_max_channels(const u8
*sad
)
22 return 1 + (sad
[0] & 7);
25 static int eld_limit_rates(struct snd_pcm_hw_params
*params
,
26 struct snd_pcm_hw_rule
*rule
)
28 struct snd_interval
*r
= hw_param_interval(params
, rule
->var
);
29 const struct snd_interval
*c
;
30 unsigned int rate_mask
= 7, i
;
31 const u8
*sad
, *eld
= rule
->private;
33 sad
= drm_eld_sad(eld
);
35 c
= hw_param_interval_c(params
, SNDRV_PCM_HW_PARAM_CHANNELS
);
37 for (i
= drm_eld_sad_count(eld
); i
> 0; i
--, sad
+= 3) {
38 unsigned max_channels
= sad_max_channels(sad
);
41 * Exclude SADs which do not include the
42 * requested number of channels.
44 if (c
->min
<= max_channels
)
49 return snd_interval_list(r
, ARRAY_SIZE(eld_rates
), eld_rates
,
53 static int eld_limit_channels(struct snd_pcm_hw_params
*params
,
54 struct snd_pcm_hw_rule
*rule
)
56 struct snd_interval
*c
= hw_param_interval(params
, rule
->var
);
57 const struct snd_interval
*r
;
58 struct snd_interval t
= { .min
= 1, .max
= 2, .integer
= 1, };
60 const u8
*sad
, *eld
= rule
->private;
62 sad
= drm_eld_sad(eld
);
64 unsigned int rate_mask
= 0;
66 /* Convert the rate interval to a mask */
67 r
= hw_param_interval_c(params
, SNDRV_PCM_HW_PARAM_RATE
);
68 for (i
= 0; i
< ARRAY_SIZE(eld_rates
); i
++)
69 if (r
->min
<= eld_rates
[i
] && r
->max
>= eld_rates
[i
])
72 for (i
= drm_eld_sad_count(eld
); i
> 0; i
--, sad
+= 3)
73 if (rate_mask
& sad
[1])
74 t
.max
= max(t
.max
, sad_max_channels(sad
));
77 return snd_interval_refine(c
, &t
);
80 int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime
*runtime
, void *eld
)
84 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_RATE
,
86 SNDRV_PCM_HW_PARAM_CHANNELS
, -1);
90 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_CHANNELS
,
91 eld_limit_channels
, eld
,
92 SNDRV_PCM_HW_PARAM_RATE
, -1);
96 EXPORT_SYMBOL_GPL(snd_pcm_hw_constraint_eld
);