| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561 | 
							- /* 
 
-  *  Squeezelite for esp32
 
-  *
 
-  *  (c) Sebastien 2019
 
-  *      Philippe G. 2019, philippe_44@outlook.com
 
-  *
 
-  *  This software is released under the MIT License.
 
-  *  https://opensource.org/licenses/MIT
 
-  *
 
-  */
 
-  
 
- #include <string.h>
 
- //#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
 
- #include "freertos/FreeRTOS.h"
 
- #include "freertos/task.h"
 
- #include "driver/i2s.h"
 
- #include "driver/i2c.h"
 
- #include "driver/gpio.h"
 
- #include "esp_log.h"
 
- #include "adac.h"
 
- #include "stdio.h"
 
- #include "math.h"
 
- #define CS4265_PULL_UP (0x4F )
 
- #define CS4265_PULL_DOWN (0x4E )
 
- #ifndef ARRAY_SIZE
 
- #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
- #endif
 
- static const char TAG[] = "CS4265";
 
- static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
 
- static void speaker(bool active);
 
- static void headset(bool active);
 
- static bool volume(unsigned left, unsigned right);
 
- static void power(adac_power_e mode);
 
- static esp_err_t cs4265_update_bit(uint8_t reg_no,uint8_t mask,uint8_t val );
 
- static esp_err_t set_clock();
 
- const struct adac_s dac_cs4265 = { "CS4265", init, adac_deinit, power, speaker, headset, volume };
 
- struct cs4265_cmd_s {
 
- 	uint8_t reg;
 
- 	uint8_t value;
 
- };
 
- struct cs4265_private {
 
- 	uint8_t format;
 
- 	uint32_t sysclk;
 
- 	i2s_config_t *i2s_config;
 
- 	int i2c_port;
 
- };
 
- struct cs4265_private cs4265;
 
- #define CS4265_CHIP_ID				0x1
 
- #define CS4265_CHIP_ID_VAL			0xD0
 
- #define CS4265_CHIP_ID_MASK			0xF0
 
- #define CS4265_REV_ID_MASK			0x0F
 
- #define CS4265_PWRCTL				0x02
 
- #define CS4265_PWRCTL_PDN			(1 << 0)
 
- #define CS4265_PWRCTL_PDN_DAC       (1 << 1)
 
- #define CS4265_PWRCTL_PDN_ADC       (1 << 2)
 
- #define CS4265_PWRCTL_PDN_MIC       (1 << 3)
 
- #define CS4265_PWRCTL_FREEZE        (1 << 7)
 
- #define CS4265_PWRCTL_PDN_ALL   	CS4265_PWRCTL_PDN | CS4265_PWRCTL_PDN_ADC | CS4265_PWRCTL_PDN_DAC | CS4265_PWRCTL_PDN_MIC
 
- #define CS4265_DAC_CTL				0x3
 
- // De-Emphasis Control (Bit 1)
 
- // The standard 50/15 i2s digital de-emphasis filter response may be implemented for a sample
 
- // rate of 44.1 kHz when the DeEmph bit is set.  NOTE: De-emphasis is available only in Single-Speed Mode.
 
- #define CS4265_DAC_CTL_DEEMPH		(1 << 1)
 
- // MUTE DAC
 
- // The DAC outputs will mute and the MUTEC pin will become active when this bit is set. Though this bit is
 
- // active high, it should be noted that the MUTEC pin is active low. The common mode voltage on the outputs
 
- // will be retained when this bit is set. The muting function is effected, similar to attenuation changes, by the
 
- // DACSoft and DACZero bits in the DAC Control 2 register.
 
- #define CS4265_DAC_CTL_MUTE			(1 << 2)
 
- // The required relationship between LRCK, SCLK and SDIN for the DAC is defined by the DAC Digital Interface
 
- // DAC_DIF1 DAC_DIF0 Description                                    Format Figure
 
- // 0        0        Left Justified, up to 24-bit data (default)    0       5
 
- // 0        1        I²S, up to 24-bit data                         1       6
 
- // 1        0        Right-Justified, 16-bit Data                   2       7
 
- // 1        1        Right-Justified, 24-bit Data                   3       7
 
- #define CS4265_DAC_CTL_DIF0			(1 << 4)
 
- // The required relationship between LRCK, SCLK and SDIN for the DAC is defined by the DAC Digital Interface
 
- // DAC_DIF1 DAC_DIF0 Description                                    Format Figure
 
- // 0        0        Left Justified, up to 24-bit data (default)    0       5
 
- // 0        1        I²S, up to 24-bit data                         1       6
 
- // 1        0        Right-Justified, 16-bit Data                   2       7
 
- // 1        1        Right-Justified, 24-bit Data                   3       7
 
- #define CS4265_DAC_CTL_DIF1			(1 << 5)
 
- #define CS4265_ADC_CTL				0x4
 
- #define CS4265_ADC_MASTER			1
 
- #define CS4265_ADC_CTL_MUTE   		(1 << 2)
 
- #define CS4265_ADC_DIF				(1 << 4)
 
- #define CS4265_ADC_FM				(3 << 6)
 
- //Master Clock Dividers (Bits 6:4)
 
- //Sets the frequency of the supplied MCLK signal. 
 
- //
 
- //MCLK Divider MCLK Freq2 MCLK Freq1 MCLK Freq0
 
- // ÷   1 	   0          0           0
 
- // ÷   1.5 	   0          0           1
 
- // ÷   2 	   0          1           0
 
- // ÷   3 	   0          1           1
 
- // ÷   4 	   1          0           0
 
- // NA          1          0           1
 
- // NA 		   1          1           x 
 
- #define CS4265_MCLK_FREQ			0x5
 
- #define CS4265_MCLK_FREQ_1_0X	(0b000<<4 )
 
- #define CS4265_MCLK_FREQ_1_5X	(0b001<<4 )
 
- #define CS4265_MCLK_FREQ_2_0X	(0b010<<4 )
 
- #define CS4265_MCLK_FREQ_3_0X	(0b011<<4 )
 
- #define CS4265_MCLK_FREQ_4_0X	(0b100<<4 )
 
- #define CS4265_MCLK_FREQ_MASK			(7 << 4)
 
- #define CS4265_SIG_SEL				0x6
 
- #define CS4265_SIG_SEL_LOOP			(1 << 1)
 
- #define CS4265_SIG_SEL_SDIN2		(1 << 7)
 
- #define CS4265_SIG_SEL_SDIN1		(0 << 7)
 
- // Sets the gain or attenuation for the ADC input PGA stage. The gain may be adjusted from -12 dB to
 
- // +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.
 
- // Register settings outside of the ±12 dB range are reserved and must not be used. See Table 13 for example settings
 
- #define CS4265_CHB_PGA_CTL			0x7
 
- // Sets the gain or attenuation for the ADC input PGA stage. The gain may be adjusted from -12 dB to
 
- // +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.
 
- // Register settings outside of the ±12 dB range are reserved and must not be used. See Table 13 for example settings
 
- #define CS4265_CHA_PGA_CTL			0x8
 
- // Gain[5:0]    Setting
 
- // 101000       -12 dB
 
- // 000000       0 dB
 
- // 011000       +12 dB
 
- #define CS4265_ADC_CTL2				0x9
 
- // The digital volume control allows the user to attenuate the signal in 0.5 dB increments from 0 to -127 dB.
 
- // The Vol0 bit activates a 0.5 dB attenuation when set, and no attenuation when cleared. The Vol[7:1] bits
 
- // activate attenuation equal to their decimal equivalent (in dB). 
 
- //Binary Code 	Volume Setting
 
- //00000000 		0 dB
 
- //00000001 		-0.5 dB
 
- //00101000 		-20 dB
 
- //00101001 		-20.5 dB
 
- //11111110 		-127 dB
 
- //11111111 		-127.5 dB
 
- #define CS4265_DAC_CHA_VOL			0xA
 
- // The digital volume control allows the user to attenuate the signal in 0.5 dB increments from 0 to -127 dB.
 
- // The Vol0 bit activates a 0.5 dB attenuation when set, and no attenuation when cleared. The Vol[7:1] bits
 
- // activate attenuation equal to their decimal equivalent (in dB). 
 
- //Binary Code 	Volume Setting
 
- //00000000 		0 dB
 
- //00000001 		-0.5 dB
 
- //00101000 		-20 dB
 
- //00101001 		-20.5 dB
 
- //11111110 		-127 dB
 
- //11111111 		-127.5 dB
 
- #define CS4265_DAC_CHB_VOL			0xB
 
- #define CS4265_DAC_VOL_ATT_000_0		0b00000000
 
- #define CS4265_DAC_VOL_ATT_000_5		0b00000001
 
- #define CS4265_DAC_VOL_ATT_020_0		0b00101000
 
- #define CS4265_DAC_VOL_ATT_020_5		0b00101001
 
- #define CS4265_DAC_VOL_ATT_127_0		0b11111110
 
- #define CS4265_DAC_VOL_ATT_127_5		0b11111111
 
- // DAC Soft Ramp or Zero Cross Enable (Bits 7:6)
 
- //
 
- // Soft Ramp Enable
 
- // 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.
 
- // See Table 17.
 
- // Zero Cross Enable
 
- // Zero Cross Enable dictates that signal-level changes, either by attenuation changes or muting, will occur
 
- // 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
 
- // does not encounter a zero crossing. The zero cross function is independently monitored and implemented
 
- // for each channel. See Table 17.
 
- // Soft Ramp and Zero Cross Enable
 
- // 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
 
- // 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
 
- // DACSoft DACZeroCross Mode
 
- // 0 0 Changes to affect immediately
 
- // 0 1 Zero Cross enabled
 
- // 1 0 Soft Ramp enabled
 
- // 1 1 Soft Ramp and Zero Cross enabled (default)
 
- #define CS4265_DAC_CTL2								0xC
 
- #define CS4265_DAC_CTL2_ZERO_CROSS_EN  				(uint8_t)(0b01 <<7)
 
- #define CS4265_DAC_CTL2_SOFT_RAMP_EN  				(uint8_t)(0b10 <<7)
 
- #define CS4265_DAC_CTL2_SOFT_RAMP_ZERO_CROSS_EN  	(uint8_t)(0b11 <<7)
 
- #define CS4265_INT_STATUS			0xD
 
- #define CS4265_INT_STATUS_ADC_UNDF  (1<<0)
 
- #define CS4265_INT_STATUS_ADC_OVF   (1<<1)
 
- #define CS4265_INT_STATUS_CLKERR    (1<<3)
 
- #define CS4265_INT_MASK				0xE
 
- #define CS4265_STATUS_MODE_MSB			0xF
 
- #define CS4265_STATUS_MODE_LSB			0x10
 
- //Transmitter Control 1 - Address 11h
 
- #define CS4265_SPDIF_CTL1			0x11
 
- #define CS4265_SPDIF_CTL2			0x12
 
- // Transmitter Digital Interface Format (Bits 7:6)
 
- // Function:
 
- // The required relationship between LRCK, SCLK and SDIN for the transmitter is defined
 
- // Tx_DIF1 Tx_DIF0 Description Format Figure
 
- // 0 0 Left Justified, up to 24-bit data (default) 0 5
 
- // 0 1 I²S, up to 24-bit data 1 6
 
- // 1 0 Right-Justified, 16-bit Data 2 7
 
- // 1 1 Right-Justified, 24-bit Data 3 7
 
- #define CS4265_SPDIF_CTL2_MMTLR         (1<<0)
 
- #define CS4265_SPDIF_CTL2_MMTCS         (1<<1)
 
- #define CS4265_SPDIF_CTL2_MMT           (1<<2)
 
- #define CS4265_SPDIF_CTL2_V             (1<<3)
 
- #define CS4265_SPDIF_CTL2_TXMUTE        (1<<4)
 
- #define CS4265_SPDIF_CTL2_TXOFF         (1<<5)
 
- #define CS4265_SPDIF_CTL2_MUTE			(1 << 4)
 
- #define CS4265_SPDIF_CTL2_DIF			(3 << 6)
 
- #define CS4265_SPDIF_CTL2_DIF0			(1 << 6)
 
- #define CS4265_SPDIF_CTL2_DIF1			(1 << 7)
 
- #define CS4265_C_DATA_BUFF			0x13
 
- #define CS4265_MAX_REGISTER			0x2A
 
- struct cs4265_clk_para {
 
- 	uint32_t mclk;
 
- 	uint32_t rate;
 
- 	uint8_t fm_mode; /* values 1, 2, or 4 */
 
- 	uint8_t mclkdiv;
 
- };
 
- static const struct cs4265_clk_para clk_map_table[] = {
 
- 	/*32k*/
 
- 	{8192000, 32000, 0, 0},
 
- 	{12288000, 32000, 0, 1},
 
- 	{16384000, 32000, 0, 2},
 
- 	{24576000, 32000, 0, 3},
 
- 	{32768000, 32000, 0, 4},
 
- 	/*44.1k*/
 
- 	{11289600, 44100, 0, 0},
 
- 	{16934400, 44100, 0, 1},
 
- 	{22579200, 44100, 0, 2},
 
- 	{33868000, 44100, 0, 3},
 
- 	{45158400, 44100, 0, 4},
 
- 	/*48k*/
 
- 	{12288000, 48000, 0, 0},
 
- 	{18432000, 48000, 0, 1},
 
- 	{24576000, 48000, 0, 2},
 
- 	{36864000, 48000, 0, 3},
 
- 	{49152000, 48000, 0, 4},
 
- 	/*64k*/
 
- 	{8192000, 64000, 1, 0},
 
- 	{12288000, 64000, 1, 1},
 
- 	{16934400, 64000, 1, 2},
 
- 	{24576000, 64000, 1, 3},
 
- 	{32768000, 64000, 1, 4},
 
- 	/* 88.2k */
 
- 	{11289600, 88200, 1, 0},
 
- 	{16934400, 88200, 1, 1},
 
- 	{22579200, 88200, 1, 2},
 
- 	{33868000, 88200, 1, 3},
 
- 	{45158400, 88200, 1, 4},
 
- 	/* 96k */
 
- 	{12288000, 96000, 1, 0},
 
- 	{18432000, 96000, 1, 1},
 
- 	{24576000, 96000, 1, 2},
 
- 	{36864000, 96000, 1, 3},
 
- 	{49152000, 96000, 1, 4},
 
- 	/* 128k */
 
- 	{8192000, 128000, 2, 0},
 
- 	{12288000, 128000, 2, 1},
 
- 	{16934400, 128000, 2, 2},
 
- 	{24576000, 128000, 2, 3},
 
- 	{32768000, 128000, 2, 4},
 
- 	/* 176.4k */
 
- 	{11289600, 176400, 2, 0},
 
- 	{16934400, 176400, 2, 1},
 
- 	{22579200, 176400, 2, 2},
 
- 	{33868000, 176400, 2, 3},
 
- 	{49152000, 176400, 2, 4},
 
- 	/* 192k */
 
- 	{12288000, 192000, 2, 0},
 
- 	{18432000, 192000, 2, 1},
 
- 	{24576000, 192000, 2, 2},
 
- 	{36864000, 192000, 2, 3},
 
- 	{49152000, 192000, 2, 4},
 
- };
 
- static const struct cs4265_cmd_s cs4265_init_sequence[] = {
 
- 	{CS4265_PWRCTL, CS4265_PWRCTL_PDN_ADC | CS4265_PWRCTL_FREEZE | CS4265_PWRCTL_PDN_DAC | CS4265_PWRCTL_PDN_MIC},
 
-  	{CS4265_DAC_CTL, CS4265_DAC_CTL_DIF0 | CS4265_DAC_CTL_MUTE}, 
 
-  	{CS4265_SIG_SEL, CS4265_SIG_SEL_SDIN1},/// SDIN1
 
-  	{CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF0 },//
 
-  	{CS4265_ADC_CTL, 0x00 },// // Set the serial audio port in slave mode
 
-  	{CS4265_MCLK_FREQ, CS4265_MCLK_FREQ_1_0X },// // no divider 
 
-  	{CS4265_CHB_PGA_CTL, 0x00 },// // sets the gain to 0db on channel B
 
-  	{CS4265_CHA_PGA_CTL, 0x00 },// // sets the gain to 0db on channel A
 
-  	{CS4265_ADC_CTL2, 0x19 },//
 
-  	{CS4265_DAC_CHA_VOL,CS4265_DAC_VOL_ATT_000_0   },// Full volume out 
 
-  	{CS4265_DAC_CHB_VOL, CS4265_DAC_VOL_ATT_000_0 },// // Full volume out 
 
-  	{CS4265_DAC_CTL2, CS4265_DAC_CTL2_SOFT_RAMP_ZERO_CROSS_EN },//
 
-  	{CS4265_SPDIF_CTL1, 0x00 },//
 
-  	{CS4265_INT_MASK, 0x00 },//
 
-  	{CS4265_STATUS_MODE_MSB, 0x00 },//
 
-  	{CS4265_STATUS_MODE_LSB, 0x00 },//
 
- 	{0xff,0xff}
 
- };
 
- // matching orders
 
- typedef enum { cs4265_ACTIVE = 0, cs4265_STANDBY, cs4265_DOWN, cs4265_ANALOGUE_OFF, cs4265_ANALOGUE_ON, cs4265_VOLUME } dac_cmd_e;
 
- static int cs4265_addr;
 
- static void dac_cmd(dac_cmd_e cmd, ...);
 
- static int cs4265_detect(void);
 
- static uint32_t calc_rnd_mclk_freq(){
 
- 	float m_scale = (cs4265.i2s_config->sample_rate > 96000 && cs4265.i2s_config->bits_per_sample > 16) ? 4 : 8;
 
- 	float num_channels = cs4265.i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1;
 
-      return (uint32_t) round(cs4265.i2s_config->bits_per_sample*i2s_get_clk(cs4265.i2c_port)* m_scale*num_channels/100)*100;
 
- }
 
- static int cs4265_get_clk_index(int mclk, int rate)
 
- {
 
- 	for (int i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
 
- 		if (clk_map_table[i].rate == rate &&
 
- 				clk_map_table[i].mclk == mclk)
 
- 			return i;
 
- 	}
 
- 	return -1;
 
- }
 
- static esp_err_t set_clock(){
 
-     esp_err_t err = ESP_OK;
 
- 	uint32_t mclk = calc_rnd_mclk_freq();
 
-     int index = cs4265_get_clk_index(mclk,cs4265.i2s_config->sample_rate );
 
- 	if (index >= 0) {
 
-         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);
 
- 		err=cs4265_update_bit(CS4265_ADC_CTL,CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
 
- 		err|=cs4265_update_bit( CS4265_MCLK_FREQ,CS4265_MCLK_FREQ_MASK,clk_map_table[index].mclkdiv << 4);
 
- 	} else {
 
- 		ESP_LOGE(TAG,"can't get correct mclk for ");
 
- 		return -1;
 
- 	}
 
-     return err;
 
- }
 
- static void get_status(){
 
-     uint8_t sts1= adac_read_byte(cs4265_addr, CS4265_INT_STATUS);	
 
-     ESP_LOGD(TAG,"Status: %s",sts1&CS4265_INT_STATUS_CLKERR?"CLK Error":"CLK OK");
 
- }
 
- /****************************************************************************************
 
-  * init
 
-  */
 
- static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {	 
 
- 	// find which TAS we are using (if any)
 
- 	cs4265_addr = adac_init(config, i2c_port);
 
- 	cs4265.i2s_config = i2s_config;
 
- 	cs4265.i2c_port=i2c_port;
 
- 	if (!cs4265_addr) cs4265_addr = cs4265_detect();
 
- 	if (!cs4265_addr) {
 
- 		ESP_LOGE(TAG, "No cs4265 detected");
 
- 		adac_deinit();
 
- 		return false;
 
- 	}
 
- 	#if BYTES_PER_FRAME == 8
 
- 		ESP_LOGE(TAG,"The CS4265 does not support 32 bits mode. ");
 
- 		adac_deinit();
 
- 		return false;
 
- 	#endif	
 
- 	// configure MLK
 
-     ESP_LOGD(TAG, "Configuring MCLK on GPIO0");
 
- 	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
 
-    	REG_WRITE(PIN_CTRL, 0xFFFFFFF0);
 
- 	i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
 
- 	for (int i = 0; cs4265_init_sequence[i].reg != 0xff; i++) {
 
- 		i2c_master_start(i2c_cmd);
 
- 		i2c_master_write_byte(i2c_cmd, (cs4265_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
 
- 		i2c_master_write_byte(i2c_cmd, cs4265_init_sequence[i].reg, I2C_MASTER_NACK);
 
- 		i2c_master_write_byte(i2c_cmd, cs4265_init_sequence[i].value, I2C_MASTER_NACK);
 
- 		ESP_LOGD(TAG, "i2c write %x at %u", cs4265_init_sequence[i].reg, cs4265_init_sequence[i].value);
 
- 	}
 
- 	i2c_master_stop(i2c_cmd);	
 
- 	esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_RATE_MS);
 
-     i2c_cmd_link_delete(i2c_cmd);
 
- 	if (res != ESP_OK) {
 
- 		ESP_LOGE(TAG, "could not intialize cs4265 %d", res);
 
- 		return false;
 
- 	}	
 
- 	
 
- 	return true;
 
- }	
 
- static esp_err_t cs4265_update_bit(uint8_t reg_no,uint8_t mask,uint8_t val ){
 
-     esp_err_t ret=ESP_OK;
 
-     uint8_t old= adac_read_byte(cs4265_addr, reg_no);
 
-     uint8_t newval = (old & ~mask) | (val & mask);
 
- 	bool change = old != newval;
 
- 	if (change){
 
- 		ret = adac_write_byte(cs4265_addr, reg_no, newval);
 
- 		if(ret != ESP_OK){
 
-         	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);
 
-     	}
 
-     	else {
 
- 	        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);
 
- 	    }
 
- 	}
 
- 	
 
-     return ret;
 
- }
 
- /****************************************************************************************
 
-  * change volume
 
-  */
 
- static bool volume(unsigned left, unsigned right) { 
 
- 	return false; 
 
- }
 
- /****************************************************************************************
 
-  * power
 
-  */
 
- static void power(adac_power_e mode) {
 
- 	switch(mode) {
 
- 	case ADAC_STANDBY:
 
- 		dac_cmd(cs4265_STANDBY);
 
- 		break;
 
- 	case ADAC_ON:
 
- 		dac_cmd(cs4265_ACTIVE);
 
- 		break;		
 
- 	case ADAC_OFF:
 
- 		dac_cmd(cs4265_DOWN);
 
- 		break;				
 
- 	default:
 
- 		ESP_LOGW(TAG, "unknown DAC command");
 
- 		break;
 
- 	}
 
- }
 
- /****************************************************************************************
 
-  * speaker
 
-  */
 
- static void speaker(bool active) {
 
- 	if (active) dac_cmd(cs4265_ANALOGUE_ON);
 
- 	else dac_cmd(cs4265_ANALOGUE_OFF);
 
- } 
 
- /****************************************************************************************
 
-  * headset
 
-  */
 
- static void headset(bool active) { } 
 
-  
 
- /****************************************************************************************
 
-  * DAC specific commands
 
-  */
 
- void dac_cmd(dac_cmd_e cmd, ...) {
 
- 	va_list args;
 
- 	esp_err_t ret = ESP_OK;
 
- 	
 
- 	va_start(args, cmd);
 
- 	switch(cmd) {
 
- 	case cs4265_VOLUME:
 
- 		ESP_LOGE(TAG, "DAC volume not handled yet");
 
- 		break;
 
-     case cs4265_ACTIVE:
 
- 		ESP_LOGD(TAG, "Activating DAC");
 
-         adac_write_byte(cs4265_addr, CS4265_PWRCTL,0);
 
-         cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,0);
 
-         cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,0);
 
- 		cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,0);				
 
- 		break;
 
-     case cs4265_STANDBY:
 
- 		ESP_LOGD(TAG, "DAC Stand-by");
 
-         cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,CS4265_SPDIF_CTL2_TXOFF);
 
-         cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,CS4265_SPDIF_CTL2_TXMUTE);
 
- 		cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,CS4265_DAC_CTL_MUTE);
 
- 		break;
 
-     case cs4265_DOWN:
 
- 		ESP_LOGD(TAG, "DAC Power Down");
 
-         adac_write_byte(cs4265_addr, CS4265_PWRCTL,CS4265_PWRCTL_PDN_ALL);
 
- 		break;
 
-     case cs4265_ANALOGUE_OFF:
 
- 		ESP_LOGD(TAG, "DAC Analog off");
 
-         cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,CS4265_SPDIF_CTL2_TXOFF);
 
-         cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,CS4265_SPDIF_CTL2_TXMUTE);
 
- 		cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,CS4265_DAC_CTL_MUTE);
 
- 		break;
 
-     case cs4265_ANALOGUE_ON:
 
- 		ESP_LOGD(TAG, "DAC Analog on");
 
- 		adac_write_byte(cs4265_addr, CS4265_PWRCTL,0);
 
-         cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,0);
 
-         cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,0);
 
- 		cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,0);		
 
- 		break;
 
- 	}
 
- 	
 
-   	if (ret != ESP_OK) {
 
- 		ESP_LOGE(TAG, "could not use cs4265 %d", ret);
 
- 	}
 
-     get_status();
 
- 	// now set the clock
 
- 	ret=set_clock(cs4265.i2s_config,cs4265.i2c_port);
 
- 	if (ret != ESP_OK) {
 
- 		ESP_LOGE(TAG, "could not set the cs4265's clock %d", ret);
 
- 	}	
 
- 	va_end(args);
 
- }
 
- /****************************************************************************************
 
-  * TAS57 detection
 
-  */
 
- static int cs4265_detect(void) {
 
- 	uint8_t addr[] = {CS4265_PULL_DOWN,CS4265_PULL_UP};
 
- 	
 
- 	for (int i = 0; i < sizeof(addr); i++) {
 
- 		ESP_LOGI(TAG,"Looking for CS4265 @0x%x",addr[i]);
 
- 		uint8_t reg=adac_read_byte(addr[i], CS4265_CHIP_ID);
 
- 		if(reg==255){
 
- 			continue;
 
- 		}
 
- 			// found a device at that address
 
- 		uint8_t devid = reg & CS4265_CHIP_ID_MASK;
 
- 		if (devid != CS4265_CHIP_ID_VAL) {
 
- 			ESP_LOGE(TAG,"CS4265 Device ID (%X). Expected %X",devid, CS4265_CHIP_ID);
 
- 			return 0;
 
- 		}
 
- 		ESP_LOGI(TAG,"Found DAC @0x%x, Version %x",addr[i], reg & CS4265_REV_ID_MASK);
 
- 		return addr[i];	
 
- 	}
 
- 	return 0;
 
- }
 
 
  |