cs4265.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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. */
  11. #include <string.h>
  12. //#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
  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. #include "stdio.h"
  21. #include "math.h"
  22. #define CS4265_PULL_UP (0x4F )
  23. #define CS4265_PULL_DOWN (0x4E )
  24. #ifndef ARRAY_SIZE
  25. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  26. #endif
  27. static const char TAG[] = "CS4265";
  28. static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
  29. static void speaker(bool active);
  30. static void headset(bool active);
  31. static bool volume(unsigned left, unsigned right);
  32. static void power(adac_power_e mode);
  33. static esp_err_t cs4265_update_bit(uint8_t reg_no,uint8_t mask,uint8_t val );
  34. static esp_err_t set_clock();
  35. const struct adac_s dac_cs4265 = { "CS4265", init, adac_deinit, power, speaker, headset, volume };
  36. struct cs4265_cmd_s {
  37. uint8_t reg;
  38. uint8_t value;
  39. };
  40. struct cs4265_private {
  41. uint8_t format;
  42. uint32_t sysclk;
  43. i2s_config_t *i2s_config;
  44. int i2c_port;
  45. };
  46. struct cs4265_private cs4265;
  47. #define CS4265_CHIP_ID 0x1
  48. #define CS4265_CHIP_ID_VAL 0xD0
  49. #define CS4265_CHIP_ID_MASK 0xF0
  50. #define CS4265_REV_ID_MASK 0x0F
  51. #define CS4265_PWRCTL 0x02
  52. #define CS4265_PWRCTL_PDN (1 << 0)
  53. #define CS4265_PWRCTL_PDN_DAC (1 << 1)
  54. #define CS4265_PWRCTL_PDN_ADC (1 << 2)
  55. #define CS4265_PWRCTL_PDN_MIC (1 << 3)
  56. #define CS4265_PWRCTL_FREEZE (1 << 7)
  57. #define CS4265_PWRCTL_PDN_ALL CS4265_PWRCTL_PDN | CS4265_PWRCTL_PDN_ADC | CS4265_PWRCTL_PDN_DAC | CS4265_PWRCTL_PDN_MIC
  58. #define CS4265_DAC_CTL 0x3
  59. // De-Emphasis Control (Bit 1)
  60. // The standard 50/15 i2s digital de-emphasis filter response may be implemented for a sample
  61. // rate of 44.1 kHz when the DeEmph bit is set. NOTE: De-emphasis is available only in Single-Speed Mode.
  62. #define CS4265_DAC_CTL_DEEMPH (1 << 1)
  63. // MUTE DAC
  64. // The DAC outputs will mute and the MUTEC pin will become active when this bit is set. Though this bit is
  65. // active high, it should be noted that the MUTEC pin is active low. The common mode voltage on the outputs
  66. // will be retained when this bit is set. The muting function is effected, similar to attenuation changes, by the
  67. // DACSoft and DACZero bits in the DAC Control 2 register.
  68. #define CS4265_DAC_CTL_MUTE (1 << 2)
  69. // The required relationship between LRCK, SCLK and SDIN for the DAC is defined by the DAC Digital Interface
  70. // DAC_DIF1 DAC_DIF0 Description Format Figure
  71. // 0 0 Left Justified, up to 24-bit data (default) 0 5
  72. // 0 1 I²S, up to 24-bit data 1 6
  73. // 1 0 Right-Justified, 16-bit Data 2 7
  74. // 1 1 Right-Justified, 24-bit Data 3 7
  75. #define CS4265_DAC_CTL_DIF0 (1 << 4)
  76. // The required relationship between LRCK, SCLK and SDIN for the DAC is defined by the DAC Digital Interface
  77. // DAC_DIF1 DAC_DIF0 Description Format Figure
  78. // 0 0 Left Justified, up to 24-bit data (default) 0 5
  79. // 0 1 I²S, up to 24-bit data 1 6
  80. // 1 0 Right-Justified, 16-bit Data 2 7
  81. // 1 1 Right-Justified, 24-bit Data 3 7
  82. #define CS4265_DAC_CTL_DIF1 (1 << 5)
  83. #define CS4265_ADC_CTL 0x4
  84. #define CS4265_ADC_MASTER 1
  85. #define CS4265_ADC_CTL_MUTE (1 << 2)
  86. #define CS4265_ADC_DIF (1 << 4)
  87. #define CS4265_ADC_FM (3 << 6)
  88. //Master Clock Dividers (Bits 6:4)
  89. //Sets the frequency of the supplied MCLK signal.
  90. //
  91. //MCLK Divider MCLK Freq2 MCLK Freq1 MCLK Freq0
  92. // ÷ 1 0 0 0
  93. // ÷ 1.5 0 0 1
  94. // ÷ 2 0 1 0
  95. // ÷ 3 0 1 1
  96. // ÷ 4 1 0 0
  97. // NA 1 0 1
  98. // NA 1 1 x
  99. #define CS4265_MCLK_FREQ 0x5
  100. #define CS4265_MCLK_FREQ_1_0X (0b000<<4 )
  101. #define CS4265_MCLK_FREQ_1_5X (0b001<<4 )
  102. #define CS4265_MCLK_FREQ_2_0X (0b010<<4 )
  103. #define CS4265_MCLK_FREQ_3_0X (0b011<<4 )
  104. #define CS4265_MCLK_FREQ_4_0X (0b100<<4 )
  105. #define CS4265_MCLK_FREQ_MASK (7 << 4)
  106. #define CS4265_SIG_SEL 0x6
  107. #define CS4265_SIG_SEL_LOOP (1 << 1)
  108. #define CS4265_SIG_SEL_SDIN2 (1 << 7)
  109. #define CS4265_SIG_SEL_SDIN1 (0 << 7)
  110. // Sets the gain or attenuation for the ADC input PGA stage. The gain may be adjusted from -12 dB to
  111. // +12 dB in 0.5 dB steps. The gain bits are in two’s complement with the Gain0 bit set for a 0.5 dB step.
  112. // Register settings outside of the ±12 dB range are reserved and must not be used. See Table 13 for example settings
  113. #define CS4265_CHB_PGA_CTL 0x7
  114. // Sets the gain or attenuation for the ADC input PGA stage. The gain may be adjusted from -12 dB to
  115. // +12 dB in 0.5 dB steps. The gain bits are in two’s complement with the Gain0 bit set for a 0.5 dB step.
  116. // Register settings outside of the ±12 dB range are reserved and must not be used. See Table 13 for example settings
  117. #define CS4265_CHA_PGA_CTL 0x8
  118. // Gain[5:0] Setting
  119. // 101000 -12 dB
  120. // 000000 0 dB
  121. // 011000 +12 dB
  122. #define CS4265_ADC_CTL2 0x9
  123. // The digital volume control allows the user to attenuate the signal in 0.5 dB increments from 0 to -127 dB.
  124. // The Vol0 bit activates a 0.5 dB attenuation when set, and no attenuation when cleared. The Vol[7:1] bits
  125. // activate attenuation equal to their decimal equivalent (in dB).
  126. //Binary Code Volume Setting
  127. //00000000 0 dB
  128. //00000001 -0.5 dB
  129. //00101000 -20 dB
  130. //00101001 -20.5 dB
  131. //11111110 -127 dB
  132. //11111111 -127.5 dB
  133. #define CS4265_DAC_CHA_VOL 0xA
  134. // The digital volume control allows the user to attenuate the signal in 0.5 dB increments from 0 to -127 dB.
  135. // The Vol0 bit activates a 0.5 dB attenuation when set, and no attenuation when cleared. The Vol[7:1] bits
  136. // activate attenuation equal to their decimal equivalent (in dB).
  137. //Binary Code Volume Setting
  138. //00000000 0 dB
  139. //00000001 -0.5 dB
  140. //00101000 -20 dB
  141. //00101001 -20.5 dB
  142. //11111110 -127 dB
  143. //11111111 -127.5 dB
  144. #define CS4265_DAC_CHB_VOL 0xB
  145. #define CS4265_DAC_VOL_ATT_000_0 0b00000000
  146. #define CS4265_DAC_VOL_ATT_000_5 0b00000001
  147. #define CS4265_DAC_VOL_ATT_020_0 0b00101000
  148. #define CS4265_DAC_VOL_ATT_020_5 0b00101001
  149. #define CS4265_DAC_VOL_ATT_127_0 0b11111110
  150. #define CS4265_DAC_VOL_ATT_127_5 0b11111111
  151. // DAC Soft Ramp or Zero Cross Enable (Bits 7:6)
  152. //
  153. // Soft Ramp Enable
  154. // Soft Ramp allows level changes, both muting and attenuation, to be implemented by incrementally ramping, in 1/8 dB steps, from the current level to the new level at a rate of 1 dB per 8 left/right clock periods.
  155. // See Table 17.
  156. // Zero Cross Enable
  157. // Zero Cross Enable dictates that signal-level changes, either by attenuation changes or muting, will occur
  158. // on a signal zero crossing to minimize audible artifacts. The requested level change will occur after a timeout period between 512 and 1024 sample periods (10.7 ms to 21.3 ms at 48 kHz sample rate) if the signal
  159. // does not encounter a zero crossing. The zero cross function is independently monitored and implemented
  160. // for each channel. See Table 17.
  161. // Soft Ramp and Zero Cross Enable
  162. // Soft Ramp and Zero Cross Enable dictate that signal-level changes, either by attenuation changes or muting, will occur in 1/8 dB steps and be implemented on a signal zero crossing. The 1/8 dB level change will
  163. // occur after a time-out period between 512 and 1024 sample periods (10.7 ms to 21.3 ms at 48 kHz sample rate) if the signal does not encounter a zero crossing. The zero cross function is independently monitored and implemented for each channel
  164. // DACSoft DACZeroCross Mode
  165. // 0 0 Changes to affect immediately
  166. // 0 1 Zero Cross enabled
  167. // 1 0 Soft Ramp enabled
  168. // 1 1 Soft Ramp and Zero Cross enabled (default)
  169. #define CS4265_DAC_CTL2 0xC
  170. #define CS4265_DAC_CTL2_ZERO_CROSS_EN (uint8_t)(0b01 <<7)
  171. #define CS4265_DAC_CTL2_SOFT_RAMP_EN (uint8_t)(0b10 <<7)
  172. #define CS4265_DAC_CTL2_SOFT_RAMP_ZERO_CROSS_EN (uint8_t)(0b11 <<7)
  173. #define CS4265_INT_STATUS 0xD
  174. #define CS4265_INT_STATUS_ADC_UNDF (1<<0)
  175. #define CS4265_INT_STATUS_ADC_OVF (1<<1)
  176. #define CS4265_INT_STATUS_CLKERR (1<<3)
  177. #define CS4265_INT_MASK 0xE
  178. #define CS4265_STATUS_MODE_MSB 0xF
  179. #define CS4265_STATUS_MODE_LSB 0x10
  180. //Transmitter Control 1 - Address 11h
  181. #define CS4265_SPDIF_CTL1 0x11
  182. #define CS4265_SPDIF_CTL2 0x12
  183. // Transmitter Digital Interface Format (Bits 7:6)
  184. // Function:
  185. // The required relationship between LRCK, SCLK and SDIN for the transmitter is defined
  186. // Tx_DIF1 Tx_DIF0 Description Format Figure
  187. // 0 0 Left Justified, up to 24-bit data (default) 0 5
  188. // 0 1 I²S, up to 24-bit data 1 6
  189. // 1 0 Right-Justified, 16-bit Data 2 7
  190. // 1 1 Right-Justified, 24-bit Data 3 7
  191. #define CS4265_SPDIF_CTL2_MMTLR (1<<0)
  192. #define CS4265_SPDIF_CTL2_MMTCS (1<<1)
  193. #define CS4265_SPDIF_CTL2_MMT (1<<2)
  194. #define CS4265_SPDIF_CTL2_V (1<<3)
  195. #define CS4265_SPDIF_CTL2_TXMUTE (1<<4)
  196. #define CS4265_SPDIF_CTL2_TXOFF (1<<5)
  197. #define CS4265_SPDIF_CTL2_MUTE (1 << 4)
  198. #define CS4265_SPDIF_CTL2_DIF (3 << 6)
  199. #define CS4265_SPDIF_CTL2_DIF0 (1 << 6)
  200. #define CS4265_SPDIF_CTL2_DIF1 (1 << 7)
  201. #define CS4265_C_DATA_BUFF 0x13
  202. #define CS4265_MAX_REGISTER 0x2A
  203. struct cs4265_clk_para {
  204. uint32_t mclk;
  205. uint32_t rate;
  206. uint8_t fm_mode; /* values 1, 2, or 4 */
  207. uint8_t mclkdiv;
  208. };
  209. static const struct cs4265_clk_para clk_map_table[] = {
  210. /*32k*/
  211. {8192000, 32000, 0, 0},
  212. {12288000, 32000, 0, 1},
  213. {16384000, 32000, 0, 2},
  214. {24576000, 32000, 0, 3},
  215. {32768000, 32000, 0, 4},
  216. /*44.1k*/
  217. {11289600, 44100, 0, 0},
  218. {16934400, 44100, 0, 1},
  219. {22579200, 44100, 0, 2},
  220. {33868000, 44100, 0, 3},
  221. {45158400, 44100, 0, 4},
  222. /*48k*/
  223. {12288000, 48000, 0, 0},
  224. {18432000, 48000, 0, 1},
  225. {24576000, 48000, 0, 2},
  226. {36864000, 48000, 0, 3},
  227. {49152000, 48000, 0, 4},
  228. /*64k*/
  229. {8192000, 64000, 1, 0},
  230. {12288000, 64000, 1, 1},
  231. {16934400, 64000, 1, 2},
  232. {24576000, 64000, 1, 3},
  233. {32768000, 64000, 1, 4},
  234. /* 88.2k */
  235. {11289600, 88200, 1, 0},
  236. {16934400, 88200, 1, 1},
  237. {22579200, 88200, 1, 2},
  238. {33868000, 88200, 1, 3},
  239. {45158400, 88200, 1, 4},
  240. /* 96k */
  241. {12288000, 96000, 1, 0},
  242. {18432000, 96000, 1, 1},
  243. {24576000, 96000, 1, 2},
  244. {36864000, 96000, 1, 3},
  245. {49152000, 96000, 1, 4},
  246. /* 128k */
  247. {8192000, 128000, 2, 0},
  248. {12288000, 128000, 2, 1},
  249. {16934400, 128000, 2, 2},
  250. {24576000, 128000, 2, 3},
  251. {32768000, 128000, 2, 4},
  252. /* 176.4k */
  253. {11289600, 176400, 2, 0},
  254. {16934400, 176400, 2, 1},
  255. {22579200, 176400, 2, 2},
  256. {33868000, 176400, 2, 3},
  257. {49152000, 176400, 2, 4},
  258. /* 192k */
  259. {12288000, 192000, 2, 0},
  260. {18432000, 192000, 2, 1},
  261. {24576000, 192000, 2, 2},
  262. {36864000, 192000, 2, 3},
  263. {49152000, 192000, 2, 4},
  264. };
  265. static const struct cs4265_cmd_s cs4265_init_sequence[] = {
  266. {CS4265_PWRCTL, CS4265_PWRCTL_PDN_ADC | CS4265_PWRCTL_FREEZE | CS4265_PWRCTL_PDN_DAC | CS4265_PWRCTL_PDN_MIC},
  267. {CS4265_DAC_CTL, CS4265_DAC_CTL_DIF0 | CS4265_DAC_CTL_MUTE},
  268. {CS4265_SIG_SEL, CS4265_SIG_SEL_SDIN1},/// SDIN1
  269. {CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF0 },//
  270. {CS4265_ADC_CTL, 0x00 },// // Set the serial audio port in slave mode
  271. {CS4265_MCLK_FREQ, CS4265_MCLK_FREQ_1_0X },// // no divider
  272. {CS4265_CHB_PGA_CTL, 0x00 },// // sets the gain to 0db on channel B
  273. {CS4265_CHA_PGA_CTL, 0x00 },// // sets the gain to 0db on channel A
  274. {CS4265_ADC_CTL2, 0x19 },//
  275. {CS4265_DAC_CHA_VOL,CS4265_DAC_VOL_ATT_000_0 },// Full volume out
  276. {CS4265_DAC_CHB_VOL, CS4265_DAC_VOL_ATT_000_0 },// // Full volume out
  277. {CS4265_DAC_CTL2, CS4265_DAC_CTL2_SOFT_RAMP_ZERO_CROSS_EN },//
  278. {CS4265_SPDIF_CTL1, 0x00 },//
  279. {CS4265_INT_MASK, 0x00 },//
  280. {CS4265_STATUS_MODE_MSB, 0x00 },//
  281. {CS4265_STATUS_MODE_LSB, 0x00 },//
  282. {0xff,0xff}
  283. };
  284. // matching orders
  285. typedef enum { cs4265_ACTIVE = 0, cs4265_STANDBY, cs4265_DOWN, cs4265_ANALOGUE_OFF, cs4265_ANALOGUE_ON, cs4265_VOLUME } dac_cmd_e;
  286. static int cs4265_addr;
  287. static void dac_cmd(dac_cmd_e cmd, ...);
  288. static int cs4265_detect(void);
  289. static uint32_t calc_rnd_mclk_freq(){
  290. float m_scale = (cs4265.i2s_config->sample_rate > 96000 && cs4265.i2s_config->bits_per_sample > 16) ? 4 : 8;
  291. float num_channels = cs4265.i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1;
  292. return (uint32_t) round(cs4265.i2s_config->bits_per_sample*i2s_get_clk(cs4265.i2c_port)* m_scale*num_channels/100)*100;
  293. }
  294. static int cs4265_get_clk_index(int mclk, int rate)
  295. {
  296. for (int i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
  297. if (clk_map_table[i].rate == rate &&
  298. clk_map_table[i].mclk == mclk)
  299. return i;
  300. }
  301. return -1;
  302. }
  303. static esp_err_t set_clock(){
  304. esp_err_t err = ESP_OK;
  305. uint32_t mclk = calc_rnd_mclk_freq();
  306. int index = cs4265_get_clk_index(mclk,cs4265.i2s_config->sample_rate );
  307. if (index >= 0) {
  308. ESP_LOGD(TAG, "Setting clock for mclk %u, rate %u (fm mode:%u, clk div:%u))", mclk,cs4265.i2s_config->sample_rate,clk_map_table[index].fm_mode,clk_map_table[index].mclkdiv);
  309. err=cs4265_update_bit(CS4265_ADC_CTL,CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
  310. err|=cs4265_update_bit( CS4265_MCLK_FREQ,CS4265_MCLK_FREQ_MASK,clk_map_table[index].mclkdiv << 4);
  311. } else {
  312. ESP_LOGE(TAG,"can't get correct mclk for ");
  313. return -1;
  314. }
  315. return err;
  316. }
  317. static void get_status(){
  318. uint8_t sts1= adac_read_byte(cs4265_addr, CS4265_INT_STATUS);
  319. ESP_LOGD(TAG,"Status: %s",sts1&CS4265_INT_STATUS_CLKERR?"CLK Error":"CLK OK");
  320. }
  321. /****************************************************************************************
  322. * init
  323. */
  324. static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
  325. // find which TAS we are using (if any)
  326. cs4265_addr = adac_init(config, i2c_port);
  327. cs4265.i2s_config = i2s_config;
  328. cs4265.i2c_port=i2c_port;
  329. if (!cs4265_addr) cs4265_addr = cs4265_detect();
  330. if (!cs4265_addr) {
  331. ESP_LOGE(TAG, "No cs4265 detected");
  332. adac_deinit();
  333. return false;
  334. }
  335. #if BYTES_PER_FRAME == 8
  336. ESP_LOGE(TAG,"The CS4265 does not support 32 bits mode. ");
  337. adac_deinit();
  338. return false;
  339. #endif
  340. // configure MLK
  341. ESP_LOGD(TAG, "Configuring MCLK on GPIO0");
  342. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
  343. REG_WRITE(PIN_CTRL, 0xFFFFFFF0);
  344. i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
  345. for (int i = 0; cs4265_init_sequence[i].reg != 0xff; i++) {
  346. i2c_master_start(i2c_cmd);
  347. i2c_master_write_byte(i2c_cmd, (cs4265_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
  348. i2c_master_write_byte(i2c_cmd, cs4265_init_sequence[i].reg, I2C_MASTER_NACK);
  349. i2c_master_write_byte(i2c_cmd, cs4265_init_sequence[i].value, I2C_MASTER_NACK);
  350. ESP_LOGD(TAG, "i2c write %x at %u", cs4265_init_sequence[i].reg, cs4265_init_sequence[i].value);
  351. }
  352. i2c_master_stop(i2c_cmd);
  353. esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_RATE_MS);
  354. i2c_cmd_link_delete(i2c_cmd);
  355. if (res != ESP_OK) {
  356. ESP_LOGE(TAG, "could not intialize cs4265 %d", res);
  357. return false;
  358. }
  359. return true;
  360. }
  361. static esp_err_t cs4265_update_bit(uint8_t reg_no,uint8_t mask,uint8_t val ){
  362. esp_err_t ret=ESP_OK;
  363. uint8_t old= adac_read_byte(cs4265_addr, reg_no);
  364. uint8_t newval = (old & ~mask) | (val & mask);
  365. bool change = old != newval;
  366. if (change){
  367. ret = adac_write_byte(cs4265_addr, reg_no, newval);
  368. if(ret != ESP_OK){
  369. ESP_LOGE(TAG,"Unable to change dac register 0x%02x [0x%02x->0x%02x] from value 0x%02x, mask 0x%02x ",reg_no,old,newval,val,mask);
  370. }
  371. else {
  372. ESP_LOGD(TAG,"Changed dac register 0x%02x [0x%02x->0x%02x] from value 0x%02x, mask 0x%02x ",reg_no,old,newval,val,mask);
  373. }
  374. }
  375. return ret;
  376. }
  377. /****************************************************************************************
  378. * change volume
  379. */
  380. static bool volume(unsigned left, unsigned right) {
  381. return false;
  382. }
  383. /****************************************************************************************
  384. * power
  385. */
  386. static void power(adac_power_e mode) {
  387. switch(mode) {
  388. case ADAC_STANDBY:
  389. dac_cmd(cs4265_STANDBY);
  390. break;
  391. case ADAC_ON:
  392. dac_cmd(cs4265_ACTIVE);
  393. break;
  394. case ADAC_OFF:
  395. dac_cmd(cs4265_DOWN);
  396. break;
  397. default:
  398. ESP_LOGW(TAG, "unknown DAC command");
  399. break;
  400. }
  401. }
  402. /****************************************************************************************
  403. * speaker
  404. */
  405. static void speaker(bool active) {
  406. if (active) dac_cmd(cs4265_ANALOGUE_ON);
  407. else dac_cmd(cs4265_ANALOGUE_OFF);
  408. }
  409. /****************************************************************************************
  410. * headset
  411. */
  412. static void headset(bool active) { }
  413. /****************************************************************************************
  414. * DAC specific commands
  415. */
  416. void dac_cmd(dac_cmd_e cmd, ...) {
  417. va_list args;
  418. esp_err_t ret = ESP_OK;
  419. va_start(args, cmd);
  420. switch(cmd) {
  421. case cs4265_VOLUME:
  422. ESP_LOGE(TAG, "DAC volume not handled yet");
  423. break;
  424. case cs4265_ACTIVE:
  425. ESP_LOGD(TAG, "Activating DAC");
  426. adac_write_byte(cs4265_addr, CS4265_PWRCTL,0);
  427. cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,0);
  428. cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,0);
  429. cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,0);
  430. break;
  431. case cs4265_STANDBY:
  432. ESP_LOGD(TAG, "DAC Stand-by");
  433. cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,CS4265_SPDIF_CTL2_TXOFF);
  434. cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,CS4265_SPDIF_CTL2_TXMUTE);
  435. cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,CS4265_DAC_CTL_MUTE);
  436. break;
  437. case cs4265_DOWN:
  438. ESP_LOGD(TAG, "DAC Power Down");
  439. adac_write_byte(cs4265_addr, CS4265_PWRCTL,CS4265_PWRCTL_PDN_ALL);
  440. break;
  441. case cs4265_ANALOGUE_OFF:
  442. ESP_LOGD(TAG, "DAC Analog off");
  443. cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,CS4265_SPDIF_CTL2_TXOFF);
  444. cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,CS4265_SPDIF_CTL2_TXMUTE);
  445. cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,CS4265_DAC_CTL_MUTE);
  446. break;
  447. case cs4265_ANALOGUE_ON:
  448. ESP_LOGD(TAG, "DAC Analog on");
  449. adac_write_byte(cs4265_addr, CS4265_PWRCTL,0);
  450. cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,0);
  451. cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,0);
  452. cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,0);
  453. break;
  454. }
  455. if (ret != ESP_OK) {
  456. ESP_LOGE(TAG, "could not use cs4265 %d", ret);
  457. }
  458. get_status();
  459. // now set the clock
  460. ret=set_clock(cs4265.i2s_config,cs4265.i2c_port);
  461. if (ret != ESP_OK) {
  462. ESP_LOGE(TAG, "could not set the cs4265's clock %d", ret);
  463. }
  464. va_end(args);
  465. }
  466. /****************************************************************************************
  467. * TAS57 detection
  468. */
  469. static int cs4265_detect(void) {
  470. uint8_t addr[] = {CS4265_PULL_DOWN,CS4265_PULL_UP};
  471. for (int i = 0; i < sizeof(addr); i++) {
  472. ESP_LOGI(TAG,"Looking for CS4265 @0x%x",addr[i]);
  473. uint8_t reg=adac_read_byte(addr[i], CS4265_CHIP_ID);
  474. if(reg==255){
  475. continue;
  476. }
  477. // found a device at that address
  478. uint8_t devid = reg & CS4265_CHIP_ID_MASK;
  479. if (devid != CS4265_CHIP_ID_VAL) {
  480. ESP_LOGE(TAG,"CS4265 Device ID (%X). Expected %X",devid, CS4265_CHIP_ID);
  481. return 0;
  482. }
  483. ESP_LOGI(TAG,"Found DAC @0x%x, Version %x",addr[i], reg & CS4265_REV_ID_MASK);
  484. return addr[i];
  485. }
  486. return 0;
  487. }