Files
squeezelite-esp32/components/squeezelite/cs4265/cs4265.c
2023-04-07 10:53:22 -04:00

562 lines
19 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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 twos 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 twos 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;
}