Skip to content

Commit 971cd56

Browse files
committed
Support for wm8960
1 parent 7cfc6d3 commit 971cd56

File tree

8 files changed

+2153
-13
lines changed

8 files changed

+2153
-13
lines changed

src/Driver.h

Lines changed: 186 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "Driver/es8374/es8374.h"
1212
#include "Driver/es8388/es8388.h"
1313
#include "Driver/tas5805m/tas5805m.h"
14+
#include "Driver/wm8960/mtb_wm8960.h"
1415
#include "Driver/wm8994/wm8994.h"
1516

1617
#include "DriverPins.h"
@@ -205,7 +206,7 @@ class AudioDriver {
205206
/// make sure that value is in range
206207
/// @param volume
207208
/// @return
208-
int limitVolume(int volume, int min = 0, int max = 100) {
209+
int limitValue(int volume, int min = 0, int max = 100) {
209210
if (volume > max)
210211
volume = max;
211212
if (volume < min)
@@ -223,7 +224,7 @@ class AudioDriverAC101Class : public AudioDriver {
223224
public:
224225
bool setMute(bool mute) { return ac101_set_voice_mute(mute); }
225226
bool setVolume(int volume) {
226-
return ac101_set_voice_volume(limitVolume(volume));
227+
return ac101_set_voice_volume(limitValue(volume));
227228
};
228229
int getVolume() {
229230
int vol;
@@ -345,7 +346,7 @@ class AudioDriverES7210Class : public AudioDriver {
345346
bool setMute(bool mute) { return es7210_set_mute(mute) == RESULT_OK; }
346347
bool setVolume(int volume) {
347348
this->volume = volume;
348-
return es7210_adc_set_volume(limitVolume(volume)) == RESULT_OK;
349+
return es7210_adc_set_volume(limitValue(volume)) == RESULT_OK;
349350
}
350351
int getVolume() { return volume; }
351352

@@ -380,7 +381,7 @@ class AudioDriverES7243Class : public AudioDriver {
380381
return es7243_adc_set_voice_mute(mute) == RESULT_OK;
381382
}
382383
bool setVolume(int volume) {
383-
return es7243_adc_set_voice_volume(limitVolume(volume)) == RESULT_OK;
384+
return es7243_adc_set_voice_volume(limitValue(volume)) == RESULT_OK;
384385
}
385386
int getVolume() {
386387
int vol;
@@ -420,7 +421,7 @@ class AudioDriverES7243eClass : public AudioDriver {
420421
}
421422
bool setVolume(int volume) {
422423
this->volume = volume;
423-
return es7243e_adc_set_voice_volume(limitVolume(volume)) == RESULT_OK;
424+
return es7243e_adc_set_voice_volume(limitValue(volume)) == RESULT_OK;
424425
}
425426
int getVolume() {
426427
int vol;
@@ -460,7 +461,7 @@ class AudioDriverES8156Class : public AudioDriver {
460461
}
461462
bool setVolume(int volume) {
462463
AD_LOGD("volume %d", volume);
463-
return es8156_codec_set_voice_volume(limitVolume(volume)) == RESULT_OK;
464+
return es8156_codec_set_voice_volume(limitValue(volume)) == RESULT_OK;
464465
}
465466
int getVolume() {
466467
int vol;
@@ -496,7 +497,7 @@ class AudioDriverES8311Class : public AudioDriver {
496497
public:
497498
bool setMute(bool mute) { return es8311_set_voice_mute(mute) == RESULT_OK; }
498499
bool setVolume(int volume) {
499-
return es8311_codec_set_voice_volume(limitVolume(volume)) == RESULT_OK;
500+
return es8311_codec_set_voice_volume(limitValue(volume)) == RESULT_OK;
500501
}
501502
int getVolume() {
502503
int vol;
@@ -536,7 +537,7 @@ class AudioDriverES8374Class : public AudioDriver {
536537
bool setMute(bool mute) { return es8374_set_voice_mute(mute) == RESULT_OK; }
537538
bool setVolume(int volume) {
538539
AD_LOGD("volume %d", volume);
539-
return es8374_codec_set_voice_volume(limitVolume(volume)) == RESULT_OK;
540+
return es8374_codec_set_voice_volume(limitValue(volume)) == RESULT_OK;
540541
}
541542
int getVolume() {
542543
int vol;
@@ -574,7 +575,7 @@ class AudioDriverES8388Class : public AudioDriver {
574575
bool setMute(bool mute) { return es8388_set_voice_mute(mute) == RESULT_OK; }
575576
bool setVolume(int volume) {
576577
AD_LOGD("volume %d", volume);
577-
return es8388_set_voice_volume(limitVolume(volume)) == RESULT_OK;
578+
return es8388_set_voice_volume(limitValue(volume)) == RESULT_OK;
578579
}
579580
int getVolume() {
580581
int vol;
@@ -584,7 +585,7 @@ class AudioDriverES8388Class : public AudioDriver {
584585

585586
bool setInputVolume(int volume) {
586587
// map values from 0 - 100 to 0 to 10
587-
es_mic_gain_t gain = (es_mic_gain_t)(limitVolume(volume) / 10);
588+
es_mic_gain_t gain = (es_mic_gain_t)(limitValue(volume) / 10);
588589
AD_LOGD("input volume: %d -> gain %d", volume, gain);
589590
return setMicrophoneGain(gain);
590591
}
@@ -618,7 +619,7 @@ class AudioDriverTAS5805MClass : public AudioDriver {
618619
bool setMute(bool mute) { return tas5805m_set_mute(mute) == RESULT_OK; }
619620
bool setVolume(int volume) {
620621
AD_LOGD("volume %d", volume);
621-
return tas5805m_set_volume(limitVolume(volume)) == RESULT_OK;
622+
return tas5805m_set_volume(limitValue(volume)) == RESULT_OK;
622623
}
623624
int getVolume() {
624625
int vol;
@@ -638,6 +639,179 @@ class AudioDriverTAS5805MClass : public AudioDriver {
638639
bool deinit() { return tas5805m_deinit() == RESULT_OK; }
639640
};
640641

642+
/**
643+
* @brief Driver API for WM8990 codec chip
644+
* @author Phil Schatzmann
645+
* @copyright GPLv3
646+
*/
647+
class AudioDriverWM8960Class : public AudioDriver {
648+
public:
649+
bool begin(CodecConfig codecCfg, DriverPins &pins) {
650+
codec_cfg = codecCfg;
651+
652+
auto i2c = pins.getI2CPins(CODEC);
653+
if (!i2c) {
654+
AD_LOGE("i2c pins not defined");
655+
return false;
656+
}
657+
// define wire object
658+
mtb_wm8960_set_wire(i2c.value().p_wire);
659+
660+
// setup wm8960
661+
if (!init(codecCfg)) {
662+
AD_LOGE("init");
663+
return false;
664+
}
665+
setVolume(DRIVER_DEFAULT_VOLUME);
666+
if (!mtb_wm8960_activate()) {
667+
AD_LOGE("mtb_wm8960_activate");
668+
return false;
669+
}
670+
if (!configure_clocking()) {
671+
AD_LOGE("configure_clocking");
672+
return false;
673+
}
674+
return true;
675+
}
676+
bool end(void) {
677+
mtb_wm8960_deactivate();
678+
mtb_wm8960_free();
679+
return true;
680+
}
681+
bool setMute(bool enable) { return setVolume(enable ? 0 : volume_out); }
682+
/// Defines the Volume (in %) if volume is 0, mute is enabled,range is 0-100.
683+
bool setVolume(int volume) {
684+
setOutputVolume(volume);
685+
return true;
686+
};
687+
int getVolume() { return volume_out; }
688+
bool setInputVolume(int volume) {
689+
adjustInputVolume(volume);
690+
return true;
691+
}
692+
bool isVolumeSupported() { return true; }
693+
bool isInputVolumeSupported() { return true; }
694+
695+
protected:
696+
int volume_in;
697+
int volume_out;
698+
int i2c_retry_count = 5;
699+
int vs1053_mclk_hz = 0;
700+
bool vs1053_enable_pll = true;
701+
702+
void adjustInputVolume(int vol) {
703+
volume_in = limitValue(vol, 0, 100);
704+
int vol_int = map(volume_in, 0, 100, 0, 30);
705+
mtb_wm8960_adjust_input_volume(vol_int);
706+
}
707+
708+
void setOutputVolume(int vol) {
709+
volume_out = limitValue(vol, 0, 100);
710+
int vol_int = volume_out == 0.0 ? 0 : map(volume_out, 0, 100, 30, 0x7F);
711+
mtb_wm8960_set_output_volume(vol_int);
712+
}
713+
714+
bool init(CodecConfig cfg) {
715+
mtb_wm8960_set_write_retry_count(i2c_retry_count);
716+
int features = 0;
717+
switch (cfg.dac_output) {
718+
case DAC_OUTPUT_LINE1:
719+
features = features | WM8960_FEATURE_SPEAKER;
720+
break;
721+
case DAC_OUTPUT_LINE2:
722+
features = features | WM8960_FEATURE_HEADPHONE;
723+
break;
724+
case DAC_OUTPUT_ALL:
725+
features = features | WM8960_FEATURE_SPEAKER | WM8960_FEATURE_HEADPHONE;
726+
break;
727+
default:
728+
break;
729+
}
730+
switch (cfg.adc_input) {
731+
case ADC_INPUT_LINE1:
732+
features = features | WM8960_FEATURE_MICROPHONE1;
733+
break;
734+
case ADC_INPUT_LINE2:
735+
features = features | WM8960_FEATURE_MICROPHONE2;
736+
break;
737+
case ADC_INPUT_ALL:
738+
features = features | WM8960_FEATURE_MICROPHONE1 |
739+
WM8960_FEATURE_MICROPHONE2 | WM8960_FEATURE_MICROPHONE3;
740+
break;
741+
default:
742+
break;
743+
}
744+
AD_LOGW("Setup features: %d", features);
745+
return mtb_wm8960_init(features);
746+
}
747+
748+
bool configure_clocking() {
749+
if (vs1053_mclk_hz == 0) {
750+
// just pick a multiple of the sample rate
751+
vs1053_mclk_hz = 512 * codec_cfg.getRateNumeric();
752+
}
753+
if (!mtb_wm8960_configure_clocking(
754+
vs1053_mclk_hz, vs1053_enable_pll, sampleRate(codec_cfg.getRateNumeric()),
755+
wordLength(codec_cfg.getBitsNumeric()),
756+
modeMasterSlave(codec_cfg.i2s.mode == MODE_MASTER))) {
757+
AD_LOGE("mtb_wm8960_configure_clocking");
758+
return false;
759+
}
760+
return true;
761+
}
762+
763+
mtb_wm8960_adc_dac_sample_rate_t sampleRate(int rate) {
764+
switch (rate) {
765+
case 48000:
766+
return WM8960_ADC_DAC_SAMPLE_RATE_48_KHZ;
767+
case 44100:
768+
return WM8960_ADC_DAC_SAMPLE_RATE_44_1_KHZ;
769+
case 32000:
770+
return WM8960_ADC_DAC_SAMPLE_RATE_32_KHZ;
771+
case 24000:
772+
return WM8960_ADC_DAC_SAMPLE_RATE_24_KHZ;
773+
case 22050:
774+
return WM8960_ADC_DAC_SAMPLE_RATE_22_05_KHZ;
775+
case 16000:
776+
return WM8960_ADC_DAC_SAMPLE_RATE_16_KHZ;
777+
case 12000:
778+
return WM8960_ADC_DAC_SAMPLE_RATE_12_KHZ;
779+
case 11025:
780+
return WM8960_ADC_DAC_SAMPLE_RATE_11_025_KHZ;
781+
case 8018:
782+
return WM8960_ADC_DAC_SAMPLE_RATE_8_018_KHZ;
783+
case 8000:
784+
return WM8960_ADC_DAC_SAMPLE_RATE_8_KHZ;
785+
default:
786+
AD_LOGE("Unsupported rate: %d", rate);
787+
return WM8960_ADC_DAC_SAMPLE_RATE_44_1_KHZ;
788+
}
789+
}
790+
791+
mtb_wm8960_word_length_t wordLength(int bits) {
792+
switch (bits) {
793+
case 16:
794+
return WM8960_WL_16BITS;
795+
case 20:
796+
return WM8960_WL_20BITS;
797+
case 24:
798+
return WM8960_WL_24BITS;
799+
case 32:
800+
return WM8960_WL_32BITS;
801+
default:
802+
AD_LOGE("Unsupported bits: %d", bits);
803+
return WM8960_WL_16BITS;
804+
}
805+
}
806+
807+
/// if microcontroller is master then module is slave
808+
mtb_wm8960_mode_t modeMasterSlave(bool microcontroller_is_master) {
809+
return microcontroller_is_master ? WM8960_MODE_SLAVE : WM8960_MODE_MASTER;
810+
}
811+
812+
void volumeError(float vol) { AD_LOGE("Invalid volume %f", vol); }
813+
};
814+
641815
/**
642816
* @brief Driver API for the wm8994 codec chip
643817
* @author Phil Schatzmann
@@ -658,7 +832,7 @@ class AudioDriverWM8994Class : public AudioDriver {
658832
delay(10);
659833
p_pins = &pins;
660834
int vol = map(volume, 0, 100, DEFAULT_VOLMIN, DEFAULT_VOLMAX);
661-
uint32_t freq = codecCfg.getRateNumeric();
835+
uint32_t freq = codecCfg.getRateNumeric();
662836
uint16_t outputDevice = getOutput(codec_cfg.dac_output);
663837

664838
auto i2c = pins.getI2CPins(CODEC);
@@ -694,7 +868,6 @@ class AudioDriverWM8994Class : public AudioDriver {
694868
return cnt == 0;
695869
}
696870

697-
698871
uint16_t getOutput(dac_output_t dac_output) {
699872
switch (dac_output) {
700873
case DAC_OUTPUT_NONE:

0 commit comments

Comments
 (0)