4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 #include <linux/export.h>
9 #include <drm/drm_edid.h>
10 #include <sound/pcm.h>
11 #include <sound/pcm_drm_eld.h>
13 static const unsigned int eld_rates
[] = {
23 static unsigned int sad_max_channels(const u8
*sad
)
25 return 1 + (sad
[0] & 7);
28 static int eld_limit_rates(struct snd_pcm_hw_params
*params
,
29 struct snd_pcm_hw_rule
*rule
)
31 struct snd_interval
*r
= hw_param_interval(params
, rule
->var
);
32 struct snd_interval
*c
;
33 unsigned int rate_mask
= 7, i
;
34 const u8
*sad
, *eld
= rule
->private;
36 sad
= drm_eld_sad(eld
);
38 c
= hw_param_interval(params
, SNDRV_PCM_HW_PARAM_CHANNELS
);
40 for (i
= drm_eld_sad_count(eld
); i
> 0; i
--, sad
+= 3) {
41 unsigned max_channels
= sad_max_channels(sad
);
44 * Exclude SADs which do not include the
45 * requested number of channels.
47 if (c
->min
<= max_channels
)
52 return snd_interval_list(r
, ARRAY_SIZE(eld_rates
), eld_rates
,
56 static int eld_limit_channels(struct snd_pcm_hw_params
*params
,
57 struct snd_pcm_hw_rule
*rule
)
59 struct snd_interval
*c
= hw_param_interval(params
, rule
->var
);
60 struct snd_interval
*r
;
61 struct snd_interval t
= { .min
= 1, .max
= 2, .integer
= 1, };
63 const u8
*sad
, *eld
= rule
->private;
65 sad
= drm_eld_sad(eld
);
67 unsigned int rate_mask
= 0;
69 /* Convert the rate interval to a mask */
70 r
= hw_param_interval(params
, SNDRV_PCM_HW_PARAM_RATE
);
71 for (i
= 0; i
< ARRAY_SIZE(eld_rates
); i
++)
72 if (r
->min
<= eld_rates
[i
] && r
->max
>= eld_rates
[i
])
75 for (i
= drm_eld_sad_count(eld
); i
> 0; i
--, sad
+= 3)
76 if (rate_mask
& sad
[1])
77 t
.max
= max(t
.max
, sad_max_channels(sad
));
80 return snd_interval_refine(c
, &t
);
83 int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime
*runtime
, void *eld
)
87 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_RATE
,
89 SNDRV_PCM_HW_PARAM_CHANNELS
, -1);
93 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_CHANNELS
,
94 eld_limit_channels
, eld
,
95 SNDRV_PCM_HW_PARAM_RATE
, -1);
99 EXPORT_SYMBOL_GPL(snd_pcm_hw_constraint_eld
);