diff --git a/components/platform_console/cmd_config.c b/components/platform_console/cmd_config.c index fef747b4..f7f2d2e9 100644 --- a/components/platform_console/cmd_config.c +++ b/components/platform_console/cmd_config.c @@ -71,7 +71,7 @@ typedef enum { } parse_state_t; static const char *TAG = "cmd_config"; extern struct arg_end *getParmsEnd(struct arg_hdr * * argtable); -//bck=,ws=,do=[,mute=[:0|1][,model=TAS57xx|TAS5713|AC101|I2S][,sda=,scl=gpio[,i2c=]] +//bck=,ws=,do=[,mute=[:0|1][,model=TAS57xx|TAS5713|AC101|WM8978|I2S][,sda=,scl=gpio[,i2c=]] static struct { struct arg_str *model_name; struct arg_int *clock; @@ -861,7 +861,7 @@ static char * get_log_level_options(const char * longname){ return options; } static void register_i2s_config(void){ - i2s_args.model_name = arg_str1(NULL,"model_name","TAS57xx|TAS5713|AC101|I2S","DAC Model Name"); + i2s_args.model_name = arg_str1(NULL,"model_name","TAS57xx|TAS5713|AC101|WM8978|I2S","DAC Model Name"); i2s_args.clear = arg_lit0(NULL, "clear", "Clear configuration"); i2s_args.clock = arg_int1(NULL,"clock","","Clock GPIO. e.g. 33"); i2s_args.wordselect = arg_int1(NULL,"wordselect","","Word Select GPIO. e.g. 25"); diff --git a/components/squeezelite/CMakeLists.txt b/components/squeezelite/CMakeLists.txt index ce1d38f0..2af25280 100644 --- a/components/squeezelite/CMakeLists.txt +++ b/components/squeezelite/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register( SRC_DIRS . external ac101 tas57xx +idf_component_register( SRC_DIRS . external ac101 tas57xx wm8978 INCLUDE_DIRS . ac101 PRIV_REQUIRES codecs diff --git a/components/squeezelite/adac.h b/components/squeezelite/adac.h index eeaa5d9c..4a61ad10 100644 --- a/components/squeezelite/adac.h +++ b/components/squeezelite/adac.h @@ -28,6 +28,7 @@ struct adac_s { extern const struct adac_s dac_tas57xx; extern const struct adac_s dac_tas5713; extern const struct adac_s dac_ac101; +extern const struct adac_s dac_wm8978; extern const struct adac_s dac_external; int adac_init(char *config, int i2c_port); diff --git a/components/squeezelite/component.mk b/components/squeezelite/component.mk index 718baf19..9e896be7 100644 --- a/components/squeezelite/component.mk +++ b/components/squeezelite/component.mk @@ -20,7 +20,7 @@ CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ON # -I$(COMPONENT_PATH)/../codecs/inc/faad2 -COMPONENT_SRCDIRS := . tas57xx ac101 external +COMPONENT_SRCDIRS := . tas57xx ac101 external wm8978 COMPONENT_ADD_INCLUDEDIRS := . ./tas57xx ./ac101 COMPONENT_EMBED_FILES := vu.data diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index d554a3f6..60fd0f90 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -79,7 +79,7 @@ extern struct buffer *streambuf; extern struct buffer *outputbuf; extern u8_t *silencebuf; -const struct adac_s *dac_set[] = { &dac_tas57xx, &dac_tas5713, &dac_ac101, NULL }; +const struct adac_s *dac_set[] = { &dac_tas57xx, &dac_tas5713, &dac_ac101, &dac_wm8978, NULL }; const struct adac_s *adac = &dac_external; static log_level loglevel; diff --git a/components/squeezelite/tas57xx/dac_57xx.c b/components/squeezelite/tas57xx/dac_57xx.c index b585ede4..5fd47343 100644 --- a/components/squeezelite/tas57xx/dac_57xx.c +++ b/components/squeezelite/tas57xx/dac_57xx.c @@ -59,7 +59,6 @@ static const struct tas57xx_cmd_s tas57xx_cmd[] = { }; static uint8_t tas57_addr; - int i2c_port_x; static void dac_cmd(dac_cmd_e cmd, ...); static int tas57_detect(void); @@ -69,10 +68,9 @@ static int tas57_detect(void); */ static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) { // find which TAS we are using (if any) -i2c_port_x = i2c_port; - adac_init(config, i2c_port); - tas57_addr = tas57_detect(); - + tas57_addr = adac_init(config, i2c_port); + if (!tas57_addr) tas57_addr = tas57_detect(); + if (!tas57_addr) { ESP_LOGW(TAG, "No TAS57xx detected"); adac_deinit(); diff --git a/components/squeezelite/wm8978/wm8978.c b/components/squeezelite/wm8978/wm8978.c new file mode 100644 index 00000000..b55b8b6f --- /dev/null +++ b/components/squeezelite/wm8978/wm8978.c @@ -0,0 +1,98 @@ +/* + * Squeezelite for esp32 + * + * (c) Wizmo 2021 + * Sebastien 2019 + * Philippe G. 2019, philippe_44@outlook.com + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + * + */ + +#include +#include +#include +#include "driver/i2c.h" +#include "esp_log.h" +#include "adac.h" + +static const char TAG[] = "WM8978"; + +static void speaker(bool active) { } +static void headset(bool active) { } +static bool volume(unsigned left, unsigned right) { return false; } +static void power(adac_power_e mode); +static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config); + +static esp_err_t i2c_write_shadow(uint8_t reg, uint16_t val); +static uint16_t i2c_read_shadow(uint8_t reg); + +static int WM8978; + +const struct adac_s dac_wm8978 = { "WM8978", init, adac_deinit, power, speaker, headset, volume }; + +// initiation table for non-readbale 9-bit i2c registers +static uint16_t WM8978_REGVAL_TBL[58] = { + 0X0000, 0X0000, 0X0000, 0X0000, 0X0050, 0X0000, 0X0140, 0X0000, + 0X0000, 0X0000, 0X0000, 0X00FF, 0X00FF, 0X0000, 0X0100, 0X00FF, + 0X00FF, 0X0000, 0X012C, 0X002C, 0X002C, 0X002C, 0X002C, 0X0000, + 0X0032, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, + 0X0038, 0X000B, 0X0032, 0X0000, 0X0008, 0X000C, 0X0093, 0X00E9, + 0X0000, 0X0000, 0X0000, 0X0000, 0X0003, 0X0010, 0X0010, 0X0100, + 0X0100, 0X0002, 0X0001, 0X0001, 0X0039, 0X0039, 0X0039, 0X0039, + 0X0001, 0X0001 +}; + +/**************************************************************************************** + * init + */ +static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) { + WM8978 = adac_init(config, i2c_port); + + if (!WM8978) WM8978 = 0x1a; + ESP_LOGI(TAG, "WM8978 detected @%d", WM8978); + + // init sequence + i2c_write_shadow(0, 0); + i2c_write_shadow(4, 16); + i2c_write_shadow(6, 0); + i2c_write_shadow(10, 8); + i2c_write_shadow(43, 16); + i2c_write_shadow(49, 102); + + // Configure system clk to GPIO0 for DAC MCLK input + ESP_LOGI(TAG, "Configuring MCLK on pin:%d", 0); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); + REG_WRITE(PIN_CTRL, 0xFFFFFFF0); + + return true; +} + +/**************************************************************************************** + * power + */ +static void power(adac_power_e mode) { + uint16_t *data, off[] = {0, 0, 0}, on[] = {11, 384, 111}; + data = (mode == ADAC_STANDBY || mode == ADAC_OFF) ? off : on; + i2c_write_shadow(1, data[0]); + i2c_write_shadow(2, data[1]); + i2c_write_shadow(3, data[2]); +} + +/**************************************************************************************** + * Write with custom reg/value structure + */ + static esp_err_t i2c_write_shadow(uint8_t reg, uint16_t val) { + WM8978_REGVAL_TBL[reg] = val; + reg = (reg << 1) | ((val >> 8) & 0x01); + val &= 0xff; + return adac_write_byte(WM8978, reg, val); +} + +/**************************************************************************************** + * Return local register value + */ +static uint16_t i2c_read_shadow(uint8_t reg) { + return WM8978_REGVAL_TBL[reg]; +} diff --git a/components/wifi-manager/webapp/mock/commands.json b/components/wifi-manager/webapp/mock/commands.json index b34e51a4..35cb07a3 100644 --- a/components/wifi-manager/webapp/mock/commands.json +++ b/components/wifi-manager/webapp/mock/commands.json @@ -124,7 +124,7 @@ "help": "DAC Options", "hascb": true, "argtable": [{ - "datatype": "TAS57xx|TAS5713|AC101|I2S", + "datatype": "TAS57xx|TAS5713|AC101|WM8978|I2S", "glossary": "DAC Model Name", "longopts": "model_name", "checkbox": false, @@ -202,7 +202,7 @@ "mincount": 0, "maxcount": 1 }], - "hint": " --model_name=TAS57xx|TAS5713|AC101|I2S --clock= --wordselect= --data= [--mute_gpio=] [--mute_level] [--dac_sda=] [--dac_scl=] [--dac_i2c=] [--clear]", + "hint": " --model_name=TAS57xx|TAS5713|AC101|WM8978|I2S --clock= --wordselect= --data= [--mute_gpio=] [--mute_level] [--dac_sda=] [--dac_scl=] [--dac_i2c=] [--clear]", "name": "cfg-hw-dac" }, { "help": "SPDIF Options",