wm8978.c 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * Squeezelite for esp32
  3. *
  4. * (c) Wizmo 2021
  5. * Sebastien 2019
  6. * Philippe G. 2019, philippe_44@outlook.com
  7. *
  8. * This software is released under the MIT License.
  9. * https://opensource.org/licenses/MIT
  10. *
  11. */
  12. #include <freertos/FreeRTOS.h>
  13. #include <freertos/task.h>
  14. #include <driver/i2s.h>
  15. #include "driver/i2c.h"
  16. #include "esp_log.h"
  17. #include "adac.h"
  18. static const char TAG[] = "WM8978";
  19. static void speaker(bool active) { }
  20. static void headset(bool active) { }
  21. static bool volume(unsigned left, unsigned right) { return false; }
  22. static void power(adac_power_e mode);
  23. static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
  24. static esp_err_t i2c_write_shadow(uint8_t reg, uint16_t val);
  25. static uint16_t i2c_read_shadow(uint8_t reg);
  26. static int WM8978;
  27. const struct adac_s dac_wm8978 = { "WM8978", init, adac_deinit, power, speaker, headset, volume };
  28. // initiation table for non-readbale 9-bit i2c registers
  29. static uint16_t WM8978_REGVAL_TBL[58] = {
  30. 0X0000, 0X0000, 0X0000, 0X0000, 0X0050, 0X0000, 0X0140, 0X0000,
  31. 0X0000, 0X0000, 0X0000, 0X00FF, 0X00FF, 0X0000, 0X0100, 0X00FF,
  32. 0X00FF, 0X0000, 0X012C, 0X002C, 0X002C, 0X002C, 0X002C, 0X0000,
  33. 0X0032, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  34. 0X0038, 0X000B, 0X0032, 0X0000, 0X0008, 0X000C, 0X0093, 0X00E9,
  35. 0X0000, 0X0000, 0X0000, 0X0000, 0X0003, 0X0010, 0X0010, 0X0100,
  36. 0X0100, 0X0002, 0X0001, 0X0001, 0X0039, 0X0039, 0X0039, 0X0039,
  37. 0X0001, 0X0001
  38. };
  39. /****************************************************************************************
  40. * init
  41. */
  42. static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
  43. WM8978 = adac_init(config, i2c_port);
  44. if (!WM8978) WM8978 = 0x1a;
  45. ESP_LOGI(TAG, "WM8978 detected @%d", WM8978);
  46. // init sequence
  47. i2c_write_shadow(0, 0);
  48. i2c_write_shadow(4, 16);
  49. i2c_write_shadow(6, 0);
  50. i2c_write_shadow(10, 8);
  51. i2c_write_shadow(43, 16);
  52. i2c_write_shadow(49, 102);
  53. // Configure system clk to GPIO0 for DAC MCLK input
  54. ESP_LOGI(TAG, "Configuring MCLK on GPIO0");
  55. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
  56. REG_WRITE(PIN_CTRL, 0xFFFFFFF0);
  57. return true;
  58. }
  59. /****************************************************************************************
  60. * power
  61. */
  62. static void power(adac_power_e mode) {
  63. uint16_t *data, off[] = {0, 0, 0}, on[] = {11, 384, 111};
  64. data = (mode == ADAC_STANDBY || mode == ADAC_OFF) ? off : on;
  65. i2c_write_shadow(1, data[0]);
  66. i2c_write_shadow(2, data[1]);
  67. i2c_write_shadow(3, data[2]);
  68. }
  69. /****************************************************************************************
  70. * Write with custom reg/value structure
  71. */
  72. static esp_err_t i2c_write_shadow(uint8_t reg, uint16_t val) {
  73. WM8978_REGVAL_TBL[reg] = val;
  74. reg = (reg << 1) | ((val >> 8) & 0x01);
  75. val &= 0xff;
  76. return adac_write_byte(WM8978, reg, val);
  77. }
  78. /****************************************************************************************
  79. * Return local register value
  80. */
  81. static uint16_t i2c_read_shadow(uint8_t reg) {
  82. return WM8978_REGVAL_TBL[reg];
  83. }