samsung_sound.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2018 Google, LLC
  4. * Written by Simon Glass <sjg@chromium.org>
  5. */
  6. #include <common.h>
  7. #include <audio_codec.h>
  8. #include <dm.h>
  9. #include <i2s.h>
  10. #include <log.h>
  11. #include <sound.h>
  12. #include <asm/gpio.h>
  13. #include <asm/arch/power.h>
  14. static int samsung_sound_setup(struct udevice *dev)
  15. {
  16. struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
  17. struct i2s_uc_priv *i2c_priv = dev_get_uclass_priv(uc_priv->i2s);
  18. int ret;
  19. if (uc_priv->setup_done)
  20. return -EALREADY;
  21. ret = audio_codec_set_params(uc_priv->codec, i2c_priv->id,
  22. i2c_priv->samplingrate,
  23. i2c_priv->samplingrate * i2c_priv->rfs,
  24. i2c_priv->bitspersample,
  25. i2c_priv->channels);
  26. if (ret)
  27. return ret;
  28. uc_priv->setup_done = true;
  29. return 0;
  30. }
  31. static int samsung_sound_play(struct udevice *dev, void *data, uint data_size)
  32. {
  33. struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
  34. return i2s_tx_data(uc_priv->i2s, data, data_size);
  35. }
  36. static int samsung_sound_probe(struct udevice *dev)
  37. {
  38. struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
  39. struct ofnode_phandle_args args;
  40. struct gpio_desc en_gpio;
  41. ofnode node;
  42. int ret;
  43. ret = gpio_request_by_name(dev, "codec-enable-gpio", 0, &en_gpio,
  44. GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
  45. /* Turn on the GPIO which connects to the codec's "enable" line. */
  46. if (!ret)
  47. gpio_set_pull(gpio_get_number(&en_gpio), S5P_GPIO_PULL_NONE);
  48. ret = uclass_get_device_by_phandle(UCLASS_AUDIO_CODEC, dev,
  49. "samsung,audio-codec",
  50. &uc_priv->codec);
  51. if (ret) {
  52. debug("Failed to probe audio codec\n");
  53. return ret;
  54. }
  55. node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
  56. if (!ofnode_valid(node)) {
  57. debug("Failed to find /cpu subnode\n");
  58. return -EINVAL;
  59. }
  60. ret = ofnode_parse_phandle_with_args(node, "sound-dai",
  61. "#sound-dai-cells", 0, 0, &args);
  62. if (ret) {
  63. debug("Cannot find phandle: %d\n", ret);
  64. return ret;
  65. }
  66. ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
  67. if (ret) {
  68. debug("Cannot find i2s: %d\n", ret);
  69. return ret;
  70. }
  71. debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
  72. uc_priv->codec->name, uc_priv->i2s->name);
  73. /* Enable codec clock */
  74. set_xclkout();
  75. return 0;
  76. }
  77. static const struct sound_ops samsung_sound_ops = {
  78. .setup = samsung_sound_setup,
  79. .play = samsung_sound_play,
  80. };
  81. static const struct udevice_id samsung_sound_ids[] = {
  82. { .compatible = "google,snow-audio-max98095" },
  83. { .compatible = "google,spring-audio-max98088" },
  84. { .compatible = "samsung,smdk5420-audio-wm8994" },
  85. { .compatible = "google,peach-audio-max98090" },
  86. { }
  87. };
  88. U_BOOT_DRIVER(samsung_sound) = {
  89. .name = "samsung_sound",
  90. .id = UCLASS_SOUND,
  91. .of_match = samsung_sound_ids,
  92. .probe = samsung_sound_probe,
  93. .ops = &samsung_sound_ops,
  94. };