dac_5713.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * Squeezelite for esp32
  3. *
  4. * (c) Sebastien 2019
  5. * Philippe G. 2019, philippe_44@outlook.com
  6. *
  7. * This software is released under the MIT License.
  8. * https://opensource.org/licenses/MIT
  9. *
  10. * (c) C. Rohs 2020 added support for the tas5713 (eg. HiFiBerry AMP+)
  11. */
  12. #include <string.h>
  13. #include "freertos/FreeRTOS.h"
  14. #include "freertos/task.h"
  15. #include "driver/i2s.h"
  16. #include "driver/i2c.h"
  17. #include "driver/gpio.h"
  18. #include "esp_log.h"
  19. #include "adac.h"
  20. #define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
  21. #define TAS5713 0x36 /* i2c address of TAS5713 */
  22. // TAS5713 I2C-bus register addresses
  23. #define TAS5713_CLOCK_CTRL 0x00
  24. #define TAS5713_DEVICE_ID 0x01
  25. #define TAS5713_ERROR_STATUS 0x02
  26. #define TAS5713_SYSTEM_CTRL1 0x03
  27. #define TAS5713_SERIAL_DATA_INTERFACE 0x04
  28. #define TAS5713_SYSTEM_CTRL2 0x05
  29. #define TAS5713_SOFT_MUTE 0x06
  30. #define TAS5713_VOL_MASTER 0x07
  31. #define TAS5713_VOL_CH1 0x08
  32. #define TAS5713_VOL_CH2 0x09
  33. #define TAS5713_VOL_HEADPHONE 0x0A
  34. #define TAS5713_OSC_TRIM 0x1B
  35. static const char TAG[] = "TAS5713";
  36. static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
  37. static void deinit(void);
  38. static void speaker(bool active) { };
  39. static void headset(bool active) { } ;
  40. static bool volume(unsigned left, unsigned right);
  41. static void power(adac_power_e mode) { };
  42. const struct adac_s dac_tas5713 = {"TAS5713", init, deinit, power, speaker, headset, volume};
  43. struct tas5713_cmd_s {
  44. uint8_t reg;
  45. uint8_t value;
  46. };
  47. // matching orders
  48. typedef enum {
  49. TAS57_ACTIVE = 0,
  50. TAS57_STANDBY,
  51. TAS57_DOWN,
  52. TAS57_ANALOGUE_OFF,
  53. TAS57_ANALOGUE_ON,
  54. TAS57_VOLUME
  55. } dac_cmd_e;
  56. static int i2c_port;
  57. static void tas5713_set(uint8_t reg, uint8_t val);
  58. static uint8_t tas5713_get(uint8_t reg);
  59. /****************************************************************************************
  60. * init
  61. */
  62. static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config) {
  63. char *p;
  64. i2c_port = i2c_port_num;
  65. // configure i2c
  66. i2c_config_t i2c_config = {
  67. .mode = I2C_MODE_MASTER,
  68. .sda_io_num = -1,
  69. .sda_pullup_en = GPIO_PULLUP_ENABLE,
  70. .scl_io_num = -1,
  71. .scl_pullup_en = GPIO_PULLUP_ENABLE,
  72. .master.clk_speed = 250000,
  73. };
  74. if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
  75. if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
  76. i2c_param_config(i2c_port, &i2c_config);
  77. esp_err_t res = i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
  78. /* find if there is a tas5713 attached. Reg 0 should read non-zero if so */
  79. if (!tas5713_get(0x00)) {
  80. ESP_LOGW(TAG, "No TAS5713 detected");
  81. i2c_driver_delete(i2c_port);
  82. return 0;
  83. }
  84. ESP_LOGI(TAG, "TAS5713 uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num);
  85. /* do the init sequence */
  86. tas5713_set(TAS5713_OSC_TRIM, 0x00); /* a delay is required after this */
  87. vTaskDelay(50 / portTICK_PERIOD_MS);
  88. tas5713_set(TAS5713_SERIAL_DATA_INTERFACE, 0x03); /* I2S LJ 16 bit */
  89. tas5713_set(TAS5713_SYSTEM_CTRL2, 0x00); /* exit all channel shutdown */
  90. tas5713_set(TAS5713_SOFT_MUTE, 0x00); /* unmute */
  91. tas5713_set(TAS5713_VOL_MASTER, 0x20);
  92. tas5713_set(TAS5713_VOL_CH1, 0x30);
  93. tas5713_set(TAS5713_VOL_CH2, 0x30);
  94. tas5713_set(TAS5713_VOL_HEADPHONE, 0xFF);
  95. /* The tas5713 typically has the mclk connected to the sclk. In this
  96. configuration, mclk must be a multiple of the sclk. The lowest workable
  97. multiple is 64x. To achieve this, 32 bits per channel on must be sent
  98. over I2S. Reconfigure the I2S for that here, and expand the I2S stream
  99. when it is sent */
  100. i2s_config->bits_per_sample = 32;
  101. if (res != ESP_OK) {
  102. ESP_LOGE(TAG, "could not intialize TAS5713 %d", res);
  103. return false;
  104. }
  105. return true;
  106. }
  107. /****************************************************************************************
  108. * init
  109. */
  110. static void deinit(void) {
  111. i2c_driver_delete(i2c_port);
  112. }
  113. /****************************************************************************************
  114. * change volume
  115. */
  116. static bool volume(unsigned left, unsigned right) {
  117. return false;
  118. }
  119. /****************************************************************************************
  120. * DAC specific commands
  121. */
  122. void tas5713_set(uint8_t reg, uint8_t val) {
  123. esp_err_t ret = ESP_OK;
  124. ESP_LOGI(TAG,"TAS5713 send %x %x", reg, val);
  125. i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
  126. i2c_master_start(i2c_cmd);
  127. i2c_master_write_byte(i2c_cmd,
  128. TAS5713 | I2C_MASTER_WRITE,
  129. I2C_MASTER_NACK);
  130. i2c_master_write_byte(i2c_cmd, reg, I2C_MASTER_NACK);
  131. i2c_master_write_byte(i2c_cmd, val, I2C_MASTER_NACK);
  132. i2c_master_stop(i2c_cmd);
  133. ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
  134. i2c_cmd_link_delete(i2c_cmd);
  135. if (ret != ESP_OK) {
  136. ESP_LOGE(TAG, "Could not send command to TAS5713 %d", ret);
  137. }
  138. }
  139. /*************************************************************************
  140. * Read from i2c for the tas5713. This doubles as tas5713 detect. This function
  141. * returns zero on error, so read register 0x00 for tas detect, which will be
  142. * non-zero in this application.
  143. */
  144. static uint8_t tas5713_get(uint8_t reg) {
  145. int ret;
  146. uint8_t data = 0;
  147. i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
  148. i2c_master_start(i2c_cmd);
  149. i2c_master_write_byte(i2c_cmd, TAS5713 | I2C_MASTER_WRITE, I2C_MASTER_NACK);
  150. i2c_master_write_byte(i2c_cmd, reg, I2C_MASTER_NACK);
  151. i2c_master_start(i2c_cmd);
  152. i2c_master_write_byte(i2c_cmd, TAS5713 | I2C_MASTER_READ, I2C_MASTER_NACK);
  153. i2c_master_read_byte(i2c_cmd, &data, I2C_MASTER_NACK);
  154. i2c_master_stop(i2c_cmd);
  155. ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_RATE_MS);
  156. i2c_cmd_link_delete(i2c_cmd);
  157. if (ret == ESP_OK) {
  158. ESP_LOGI(TAG,"TAS5713 reg 0x%x is 0x%x", reg, data);
  159. }
  160. return data;
  161. }