sound-uclass.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2018 Google LLC
  4. * Written by Simon Glass <sjg@chromium.org>
  5. */
  6. #define LOG_CATEGORY UCLASS_SOUND
  7. #include <common.h>
  8. #include <dm.h>
  9. #include <i2s.h>
  10. #include <log.h>
  11. #include <malloc.h>
  12. #include <sound.h>
  13. #include <linux/delay.h>
  14. #define SOUND_BITS_IN_BYTE 8
  15. int sound_setup(struct udevice *dev)
  16. {
  17. struct sound_ops *ops = sound_get_ops(dev);
  18. if (!ops->setup)
  19. return 0;
  20. return ops->setup(dev);
  21. }
  22. int sound_play(struct udevice *dev, void *data, uint data_size)
  23. {
  24. struct sound_ops *ops = sound_get_ops(dev);
  25. if (!ops->play)
  26. return -ENOSYS;
  27. return ops->play(dev, data, data_size);
  28. }
  29. int sound_stop_play(struct udevice *dev)
  30. {
  31. struct sound_ops *ops = sound_get_ops(dev);
  32. if (!ops->play)
  33. return -ENOSYS;
  34. return ops->stop_play(dev);
  35. }
  36. int sound_start_beep(struct udevice *dev, int frequency_hz)
  37. {
  38. struct sound_ops *ops = sound_get_ops(dev);
  39. if (!ops->start_beep)
  40. return -ENOSYS;
  41. return ops->start_beep(dev, frequency_hz);
  42. }
  43. int sound_stop_beep(struct udevice *dev)
  44. {
  45. struct sound_ops *ops = sound_get_ops(dev);
  46. if (!ops->stop_beep)
  47. return -ENOSYS;
  48. return ops->stop_beep(dev);
  49. }
  50. int sound_beep(struct udevice *dev, int msecs, int frequency_hz)
  51. {
  52. struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
  53. struct i2s_uc_priv *i2s_uc_priv;
  54. unsigned short *data;
  55. uint data_size;
  56. int ret;
  57. ret = sound_setup(dev);
  58. if (ret && ret != -EALREADY)
  59. return ret;
  60. /* Try using the beep interface if available */
  61. ret = sound_start_beep(dev, frequency_hz);
  62. if (ret != -ENOSYS) {
  63. if (ret)
  64. return ret;
  65. mdelay(msecs);
  66. ret = sound_stop_beep(dev);
  67. return ret;
  68. }
  69. /* Buffer length computation */
  70. i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s);
  71. data_size = i2s_uc_priv->samplingrate * i2s_uc_priv->channels;
  72. data_size *= (i2s_uc_priv->bitspersample / SOUND_BITS_IN_BYTE);
  73. data = malloc(data_size);
  74. if (!data) {
  75. debug("%s: malloc failed\n", __func__);
  76. return -ENOMEM;
  77. }
  78. sound_create_square_wave(i2s_uc_priv->samplingrate, data, data_size,
  79. frequency_hz, i2s_uc_priv->channels);
  80. ret = 0;
  81. while (msecs >= 1000) {
  82. ret = sound_play(dev, data, data_size);
  83. if (ret)
  84. break;
  85. msecs -= 1000;
  86. }
  87. if (!ret && msecs) {
  88. unsigned long size =
  89. (data_size * msecs) / (sizeof(int) * 1000);
  90. ret = sound_play(dev, data, size);
  91. }
  92. sound_stop_play(dev);
  93. free(data);
  94. return ret;
  95. }
  96. int sound_find_codec_i2s(struct udevice *dev)
  97. {
  98. struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
  99. struct ofnode_phandle_args args;
  100. ofnode node;
  101. int ret;
  102. /* First the codec */
  103. node = ofnode_find_subnode(dev_ofnode(dev), "codec");
  104. if (!ofnode_valid(node)) {
  105. debug("Failed to find /cpu subnode\n");
  106. return -EINVAL;
  107. }
  108. ret = ofnode_parse_phandle_with_args(node, "sound-dai",
  109. "#sound-dai-cells", 0, 0, &args);
  110. if (ret) {
  111. debug("Cannot find phandle: %d\n", ret);
  112. return ret;
  113. }
  114. ret = uclass_get_device_by_ofnode(UCLASS_AUDIO_CODEC, args.node,
  115. &uc_priv->codec);
  116. if (ret) {
  117. debug("Cannot find codec: %d\n", ret);
  118. return ret;
  119. }
  120. /* Now the i2s */
  121. node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
  122. if (!ofnode_valid(node)) {
  123. debug("Failed to find /cpu subnode\n");
  124. return -EINVAL;
  125. }
  126. ret = ofnode_parse_phandle_with_args(node, "sound-dai",
  127. "#sound-dai-cells", 0, 0, &args);
  128. if (ret) {
  129. debug("Cannot find phandle: %d\n", ret);
  130. return ret;
  131. }
  132. ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
  133. if (ret) {
  134. debug("Cannot find i2s: %d\n", ret);
  135. return ret;
  136. }
  137. debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
  138. uc_priv->codec->name, uc_priv->i2s->name);
  139. return 0;
  140. }
  141. UCLASS_DRIVER(sound) = {
  142. .id = UCLASS_SOUND,
  143. .name = "sound",
  144. .per_device_auto = sizeof(struct sound_uc_priv),
  145. };