pcm_drm_eld.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /*
  2. * PCM DRM helpers
  3. *
  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.
  7. */
  8. #include <linux/export.h>
  9. #include <drm/drm_edid.h>
  10. #include <sound/pcm.h>
  11. #include <sound/pcm_drm_eld.h>
  12. static const unsigned int eld_rates[] = {
  13. 32000,
  14. 44100,
  15. 48000,
  16. 88200,
  17. 96000,
  18. 176400,
  19. 192000,
  20. };
  21. static unsigned int sad_max_channels(const u8 *sad)
  22. {
  23. return 1 + (sad[0] & 7);
  24. }
  25. static int eld_limit_rates(struct snd_pcm_hw_params *params,
  26. struct snd_pcm_hw_rule *rule)
  27. {
  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;
  32. sad = drm_eld_sad(eld);
  33. if (sad) {
  34. c = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  35. for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) {
  36. unsigned max_channels = sad_max_channels(sad);
  37. /*
  38. * Exclude SADs which do not include the
  39. * requested number of channels.
  40. */
  41. if (c->min <= max_channels)
  42. rate_mask |= sad[1];
  43. }
  44. }
  45. return snd_interval_list(r, ARRAY_SIZE(eld_rates), eld_rates,
  46. rate_mask);
  47. }
  48. static int eld_limit_channels(struct snd_pcm_hw_params *params,
  49. struct snd_pcm_hw_rule *rule)
  50. {
  51. struct snd_interval *c = hw_param_interval(params, rule->var);
  52. const struct snd_interval *r;
  53. struct snd_interval t = { .min = 1, .max = 2, .integer = 1, };
  54. unsigned int i;
  55. const u8 *sad, *eld = rule->private;
  56. sad = drm_eld_sad(eld);
  57. if (sad) {
  58. unsigned int rate_mask = 0;
  59. /* Convert the rate interval to a mask */
  60. r = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
  61. for (i = 0; i < ARRAY_SIZE(eld_rates); i++)
  62. if (r->min <= eld_rates[i] && r->max >= eld_rates[i])
  63. rate_mask |= BIT(i);
  64. for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
  65. if (rate_mask & sad[1])
  66. t.max = max(t.max, sad_max_channels(sad));
  67. }
  68. return snd_interval_refine(c, &t);
  69. }
  70. int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld)
  71. {
  72. int ret;
  73. ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
  74. eld_limit_rates, eld,
  75. SNDRV_PCM_HW_PARAM_CHANNELS, -1);
  76. if (ret < 0)
  77. return ret;
  78. ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
  79. eld_limit_channels, eld,
  80. SNDRV_PCM_HW_PARAM_RATE, -1);
  81. return ret;
  82. }
  83. EXPORT_SYMBOL_GPL(snd_pcm_hw_constraint_eld);