~aleteoryx/muditaos

8d9719e8b9d3aa0f99af6f7405e63154e46a8d16 — Szymon Mroczek 5 years ago 998ceac
[EGD-3510] audio codec configuration for headset microphone (#1004)

[EGD-3510] Audio stereo outputs fixed. Microphone bias handling for headset. Headset microphone gain adjusted.

M changelog.md => changelog.md +1 -0
@@ 9,6 9,7 @@
* `[file indexer db]` Added messages for File Indexer db.
* `[settings]` Added Torch window (front-end only).
* `[audio]` Added support for Bluetooth audio profiles
* `[audio]` Added support for headset microphone.
* `[filesystem]` Added support for standard file IO library.
* [`[messages]`] Added fetching text messages at phone startup.


M module-audio/Audio/Operation/RouterOperation.cpp => module-audio/Audio/Operation/RouterOperation.cpp +1 -1
@@ 104,7 104,7 @@ namespace audio
        constexpr audio::Volume defaultRoutingEarspeakerVolume   = 10;
        constexpr audio::Gain defaultRoutingSpeakerphoneGain     = 20;
        constexpr audio::Volume defaultRoutingSpeakerphoneVolume = 10;
        constexpr audio::Gain defaultRoutingHeadphonesGain       = 50;
        constexpr audio::Gain defaultRoutingHeadphonesGain       = 0;
        constexpr audio::Volume defaultRoutingHeadphonesVolume   = 10;

        const auto dbRoutingEarspeakerGainPath =

M module-audio/Audio/Profiles/ProfilePlaybackHeadphones.hpp => module-audio/Audio/Profiles/ProfilePlaybackHeadphones.hpp +0 -1
@@ 1,6 1,5 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Profile.hpp"

M module-audio/Audio/Profiles/ProfileRecordingHeadphones.hpp => module-audio/Audio/Profiles/ProfileRecordingHeadphones.hpp +0 -1
@@ 1,6 1,5 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Profile.hpp"

M module-audio/Audio/Profiles/ProfileRecordingOnBoardMic.hpp => module-audio/Audio/Profiles/ProfileRecordingOnBoardMic.hpp +0 -1
@@ 1,6 1,5 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Profile.hpp"

M module-audio/Audio/Profiles/ProfileRoutingEarspeaker.hpp => module-audio/Audio/Profiles/ProfileRoutingEarspeaker.hpp +0 -1
@@ 1,6 1,5 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Profile.hpp"

M module-audio/Audio/Profiles/ProfileRoutingHeadphones.hpp => module-audio/Audio/Profiles/ProfileRoutingHeadphones.hpp +1 -2
@@ 1,6 1,5 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Profile.hpp"


@@ 23,7 22,7 @@ namespace audio
                          .outputVolume = static_cast<float>(volume),
                          .inputGain    = static_cast<float>(gain),
                          .inputPath    = bsp::AudioDevice::InputPath::Headphones,
                          .outputPath   = bsp::AudioDevice::OutputPath::Headphones},
                          .outputPath   = bsp::AudioDevice::OutputPath::HeadphonesMono},
                      bsp::AudioDevice::Type::Audiocodec,
                      callback)
        {}

M module-audio/Audio/Profiles/ProfileRoutingLoudspeaker.hpp => module-audio/Audio/Profiles/ProfileRoutingLoudspeaker.hpp +1 -2
@@ 1,6 1,5 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Profile.hpp"


@@ 23,7 22,7 @@ namespace audio
                          .outputVolume = static_cast<float>(volume),
                          .inputGain    = static_cast<float>(gain),
                          .inputPath    = bsp::AudioDevice::InputPath::Microphone,
                          .outputPath   = bsp::AudioDevice::OutputPath::Loudspeaker},
                          .outputPath   = bsp::AudioDevice::OutputPath::LoudspeakerMono},
                      bsp::AudioDevice::Type::Audiocodec,
                      callback)
        {}

M module-bsp/board/rt1051/bsp/audio/CodecMAX98090.cpp => module-bsp/board/rt1051/bsp/audio/CodecMAX98090.cpp +130 -128
@@ 80,31 80,34 @@ CodecRetCode CodecMAX98090::Start(const CodecParams &param)

    // OUT configuration
    if (params.outputPath != bsp::AudioDevice::OutputPath::None) {
        // Set output route
        max98090_reg_playback_quick_setup_t q_playback_setup = {0};

        // Control HP performance
        max98090_reg_dachp_perfmode_t dacperf = {0};
        dacperf.dachp                         = 1;
        dacperf.perfmode                      = 0;
        i2cAddr.subAddress                    = MAX98090_REG_DACHP_PERF_MODE;
        i2c->Write(i2cAddr, (uint8_t *)&dacperf, 1);

        switch (params.outputPath) {

        case bsp::AudioDevice::OutputPath::HeadphonesMono: {
            max98090_reg_playback_quick_setup_t q_playback_setup = {0};
            q_playback_setup.dig2hp                              = 1;
            i2cAddr.subAddress                                   = MAX98090_REG_PLAYBACK_QUICK_SETUP;
            i2c->Write(i2cAddr, (uint8_t *)&q_playback_setup, 1);

            // Mix left DAC channel to left&right HP output
            max98090_reg_lhp_mixer_t lmixconf = {0};
            max98090_reg_rhp_mixer_t rmixconf = {0};
            lmixconf.mixhpl                   = 1;
            rmixconf.mixhpr                   = 1;

            i2cAddr.subAddress = MAX98090_REG_LHP_MIXER_CONF;
            i2c->Write(i2cAddr, (uint8_t *)&lmixconf, 1);

            max98090_reg_rhp_mixer_t rmixconf = {0};
            rmixconf.mixhpr                   = 1;
            i2cAddr.subAddress = MAX98090_REG_RHP_MIXER_CONF;
            i2c->Write(i2cAddr, (uint8_t *)&rmixconf, 1);

            q_playback_setup.dig2hp = 1;
            i2cAddr.subAddress      = MAX98090_REG_PLAYBACK_QUICK_SETUP;
            i2c->Write(i2cAddr, (uint8_t *)&q_playback_setup, 1);

            // Use mixer outputs instead of direct DAC outputs
            max98090_reg_hpmix_conf_t mixconf = {0};
            mixconf.mixhplsel                 = 1;
            mixconf.mixhprsel                 = 1;


@@ 114,110 117,58 @@ CodecRetCode CodecMAX98090::Start(const CodecParams &param)
        } break;

        case bsp::AudioDevice::OutputPath::Headphones: {
            // Set DAC headphones output to high performance mode, increasing power consumption but providing the
            // highest quality
            dacperf.dachp           = 1;
            dacperf.perfmode        = 1;
            q_playback_setup.dig2hp = 1;

            max98090_reg_playback_quick_setup_t q_playback_setup = {0};
            q_playback_setup.dig2hp                              = 1;
            i2cAddr.subAddress = MAX98090_REG_PLAYBACK_QUICK_SETUP;
            i2c->Write(i2cAddr, (uint8_t *)&q_playback_setup, 1);
            i2cAddr.subAddress = MAX98090_REG_DACHP_PERF_MODE;
            i2c->Write(i2cAddr, (uint8_t *)&dacperf, 1);

        } break;

        case bsp::AudioDevice::OutputPath::Earspeaker: {
            max98090_reg_playback_quick_setup_t q_playback_setup = {0};
            q_playback_setup.dig2ear = 1;
            i2cAddr.subAddress       = MAX98090_REG_PLAYBACK_QUICK_SETUP;
            i2c->Write(i2cAddr, (uint8_t *)&q_playback_setup, 1);

            qfilter_coefficients_t band1_filter = {0};
            qfilter_coefficients_t band2_filter = {0};
            qfilter_coefficients_t band3_filter = {0};

            // Highpass,lowpass & flat filters don't use Gain parameter
            qfilter_CalculateCoeffs(FilterHighPass, 800, currentParams.GetSampleRateVal(), 0.707, 1, &band1_filter);
            qfilter_CalculateCoeffs(FilterLowPass, 6000, currentParams.GetSampleRateVal(), 0.707, 1, &band2_filter);
            qfilter_CalculateCoeffs(FilterFlat, 0, currentParams.GetSampleRateVal(), 0.707, 1, &band3_filter);

            // BAND1
            WriteFilterCoeff(band1_filter.b0, 0x46);
            WriteFilterCoeff(band1_filter.b1, 0x49);
            WriteFilterCoeff(band1_filter.b2, 0x4C);
            WriteFilterCoeff(band1_filter.a1, 0x4F);
            WriteFilterCoeff(band1_filter.a2, 0x52);

            // BAND2
            WriteFilterCoeff(band2_filter.b0, 0x55);
            WriteFilterCoeff(band2_filter.b1, 0x58);
            WriteFilterCoeff(band2_filter.b2, 0x5B);
            WriteFilterCoeff(band2_filter.a1, 0x5E);
            WriteFilterCoeff(band2_filter.a2, 0x61);

            // BAND3
            WriteFilterCoeff(band3_filter.b0, 0x64);
            WriteFilterCoeff(band3_filter.b1, 0x67);
            WriteFilterCoeff(band3_filter.b2, 0x6A);
            WriteFilterCoeff(band3_filter.a1, 0x6D);
            WriteFilterCoeff(band3_filter.a2, 0x70);

            // Enable 3-band filter
            max98090_reg_dsp_biquadfilter_enable_t filter = {0};
            filter.eq3banden                              = 1;
            i2cAddr.subAddress                            = MAX98090_REG_DSP_BIQUAD_FILTER_ENABLE;
            i2c->Write(i2cAddr, (uint8_t *)&filter, 1);
            SetupEarspeakerEqualizer();

        } break;

        case bsp::AudioDevice::OutputPath::Loudspeaker: {
            max98090_reg_playback_quick_setup_t q_playback_setup = {0};
            q_playback_setup.dig2spk = 1;
            i2cAddr.subAddress                                   = MAX98090_REG_PLAYBACK_QUICK_SETUP;
            i2c->Write(i2cAddr, (uint8_t *)&q_playback_setup, 1);

            uint8_t mask       = 0x08; // Set 3th bit (dmono on)
            i2cAddr.subAddress = MAX98090_REG_INOUT_PATH_CONF;
            i2c->Modify(i2cAddr, mask, true, 1);

            // TODO: Turn off/mute right speaker
            // Turn off right speaker path
            max98090_reg_outputenable_t outputenable = {0};
            outputenable.dalen                       = 1;
            outputenable.splen                       = 1;
            i2cAddr.subAddress                       = MAX98090_REG_OUTPUT_ENABLE;
            i2c->Write(i2cAddr, (uint8_t *)&outputenable, 1);

            SetupLoudspeakerEqualizer();

        } break;

        case bsp::AudioDevice::OutputPath::LoudspeakerMono: {
            max98090_reg_playback_quick_setup_t q_playback_setup = {0};
            q_playback_setup.dig2spk                             = 1;
            i2cAddr.subAddress = MAX98090_REG_PLAYBACK_QUICK_SETUP;
            i2c->Write(i2cAddr, (uint8_t *)&q_playback_setup, 1);

            qfilter_coefficients_t band1_filter = {0};
            qfilter_coefficients_t band2_filter = {0};
            qfilter_coefficients_t band3_filter = {0};

            // Highpass,lowpass & flat filters don't use Gain parameter
            qfilter_CalculateCoeffs(FilterHighPass, 500, currentParams.GetSampleRateVal(), 0.707, 1, &band1_filter);
            qfilter_CalculateCoeffs(FilterFlat, 0, currentParams.GetSampleRateVal(), 0.707, 1, &band2_filter);
            qfilter_CalculateCoeffs(FilterFlat, 0, currentParams.GetSampleRateVal(), 0.707, 1, &band3_filter);

            // BAND1
            WriteFilterCoeff(band1_filter.b0, 0x46);
            WriteFilterCoeff(band1_filter.b1, 0x49);
            WriteFilterCoeff(band1_filter.b2, 0x4C);
            WriteFilterCoeff(band1_filter.a1, 0x4F);
            WriteFilterCoeff(band1_filter.a2, 0x52);

            // BAND2
            WriteFilterCoeff(band2_filter.b0, 0x55);
            WriteFilterCoeff(band2_filter.b1, 0x58);
            WriteFilterCoeff(band2_filter.b2, 0x5B);
            WriteFilterCoeff(band2_filter.a1, 0x5E);
            WriteFilterCoeff(band2_filter.a2, 0x61);

            // BAND3
            WriteFilterCoeff(band3_filter.b0, 0x64);
            WriteFilterCoeff(band3_filter.b1, 0x67);
            WriteFilterCoeff(band3_filter.b2, 0x6A);
            WriteFilterCoeff(band3_filter.a1, 0x6D);
            WriteFilterCoeff(band3_filter.a2, 0x70);

            // Enable 3-band filter
            max98090_reg_dsp_biquadfilter_enable_t filter = {0};
            filter.eq3banden                              = 1;
            i2cAddr.subAddress                            = MAX98090_REG_DSP_BIQUAD_FILTER_ENABLE;
            i2c->Write(i2cAddr, (uint8_t *)&filter, 1);
            // Turn off right speaker path
            max98090_reg_outputenable_t outputenable = {0};
            outputenable.dalen                       = 1;
            outputenable.splen                       = 1;
            i2cAddr.subAddress                       = MAX98090_REG_OUTPUT_ENABLE;
            i2c->Write(i2cAddr, (uint8_t *)&outputenable, 1);

            SetupLoudspeakerEqualizer();
        } break;

        default:


@@ 229,34 180,16 @@ CodecRetCode CodecMAX98090::Start(const CodecParams &param)
    if (params.inputPath != bsp::AudioDevice::InputPath::None) {
        // Set input path
        switch (params.inputPath) {
        case bsp::AudioDevice::InputPath::Headphones: {
            /* 			max98090_reg_analog_to_record_quick_t q_analog_setup = {0};

                        q_analog_setup.in34mic2 = 1;
                        bsp_i2c_Send(i2CInst,DeviceAddr,
               MAX98090_REG_ANALOG_MIC_TO_RECORD_QUICK,(uint8_t*)&q_analog_setup,1);

                        max98090_reg_radc_mix_input_t radcmix = {0};
                        bsp_i2c_Send(i2CInst,DeviceAddr, MAX98090_REG_RADC_MIXER_INPUT,(uint8_t*)&radcmix);

                        max98090_reg_ladc_mix_input_t ladcmix = {0};
                        ladcmix.mixadl = 0x40;
                        bsp_i2c_Send(i2CInst,DeviceAddr, MAX98090_REG_LADC_MIXER_INPUT,(uint8_t*)&ladcmix); */
        case bsp::AudioDevice::InputPath::Headphones: {
            max98090_reg_input_to_record_quick_t q_input_setup = {0};
            q_input_setup.in34dan                              = 1;
            i2cAddr.subAddress                                 = MAX98090_REG_LINE_INPUT_TO_RECORD_QUICK;
            i2c->Write(i2cAddr, (uint8_t *)&q_input_setup, 1);

            uint8_t mask       = 0x10; // Set 4th bit (mic bias enable)
            i2cAddr.subAddress = MAX98090_REG_INPUT_ENABLE;
            i2c->Modify(i2cAddr, mask, true, 1);

        } break;

        case bsp::AudioDevice::InputPath::Microphone: {
            max98090_reg_input_to_record_quick_t q_input_setup   = {0};
            max98090_reg_analog_to_record_quick_t q_analog_setup = {0};
            max98090_reg_digmic_enable_t digena                  = {0};
            max98090_reg_digmic_enable_t digena = {0};

            // Enable left and right digital mic interface
            digena.digmicl = 1;


@@ 266,32 199,18 @@ CodecRetCode CodecMAX98090::Start(const CodecParams &param)

            i2cAddr.subAddress = MAX98090_REG_DIG_MIC_ENABLE;
            i2c->Write(i2cAddr, (uint8_t *)&digena, 1);

            // It seems that for digital mics it doesn't matter if digitial or analog input is chosen
            q_input_setup.in12sab = 1;

            i2cAddr.subAddress = MAX98090_REG_LINE_INPUT_TO_RECORD_QUICK;
            i2c->Write(i2cAddr, (uint8_t *)&q_input_setup, 1);

            // q_analog_setup.in12mic1 = 1;
            // bsp_i2c_Send(i2CInst,DeviceAddr, MAX98090_REG_ANALOG_MIC_TO_RECORD_QUICK,(uint8_t*)&q_analog_setup,1);

            uint8_t mask       = 0x10; // Clr 4th bit (mic bias disable)
            i2cAddr.subAddress = MAX98090_REG_INPUT_ENABLE;
            i2c->Modify(i2cAddr, mask, false, 1);

        } break;

        default:
            return CodecRetCode::InvalidInputPath;
        }

        // Turn on DC blocking filters
        uint8_t mask       = (1 << 6) | (1 << 5); // set 6th and 7th bit (AHPF and DHPF)
        i2cAddr.subAddress = MAX98090_REG_PLAYBACK_DSP_FILTER_CONF;
        i2c->Modify(i2cAddr, mask, true, 1);
    }

    // Turn on DC blocking filters
    uint8_t mask       = (1 << 6) | (1 << 5); // set 6th and 7th bit (AHPF and DHPF)
    i2cAddr.subAddress = MAX98090_REG_PLAYBACK_DSP_FILTER_CONF;
    i2c->Modify(i2cAddr, mask, true, 1);

    // Store param configuration
    currentParams = params;



@@ 417,7 336,8 @@ CodecRetCode CodecMAX98090::SetOutputVolume(const float vol)
        i2c->Write(i2cAddr, (uint8_t *)&vol, 1);
    } break;

    case bsp::AudioDevice::OutputPath::Loudspeaker: {
    case bsp::AudioDevice::OutputPath::Loudspeaker:
    case bsp::AudioDevice::OutputPath::LoudspeakerMono: {
        // Scale input volume(range 0 - 100) to MAX98090 range(decibels hardcoded as specific hex values)
        constexpr float scale_factor = .39f * 10.f;
        uint8_t volume               = static_cast<float>(vol * scale_factor) + 0x18;


@@ 515,6 435,88 @@ CodecRetCode CodecMAX98090::MicBias(const bool enable)
    return CodecRetCode::Success;
}

CodecRetCode CodecMAX98090::SetupEarspeakerEqualizer()
{
    qfilter_coefficients_t band1_filter = {0};
    qfilter_coefficients_t band2_filter = {0};
    qfilter_coefficients_t band3_filter = {0};

    // Highpass,lowpass & flat filters don't use Gain parameter
    qfilter_CalculateCoeffs(FilterHighPass, 800, currentParams.GetSampleRateVal(), 0.707, 1, &band1_filter);
    qfilter_CalculateCoeffs(FilterLowPass, 6000, currentParams.GetSampleRateVal(), 0.707, 1, &band2_filter);
    qfilter_CalculateCoeffs(FilterFlat, 0, currentParams.GetSampleRateVal(), 0.707, 1, &band3_filter);

    // BAND1
    WriteFilterCoeff(band1_filter.b0, 0x46);
    WriteFilterCoeff(band1_filter.b1, 0x49);
    WriteFilterCoeff(band1_filter.b2, 0x4C);
    WriteFilterCoeff(band1_filter.a1, 0x4F);
    WriteFilterCoeff(band1_filter.a2, 0x52);

    // BAND2
    WriteFilterCoeff(band2_filter.b0, 0x55);
    WriteFilterCoeff(band2_filter.b1, 0x58);
    WriteFilterCoeff(band2_filter.b2, 0x5B);
    WriteFilterCoeff(band2_filter.a1, 0x5E);
    WriteFilterCoeff(band2_filter.a2, 0x61);

    // BAND3
    WriteFilterCoeff(band3_filter.b0, 0x64);
    WriteFilterCoeff(band3_filter.b1, 0x67);
    WriteFilterCoeff(band3_filter.b2, 0x6A);
    WriteFilterCoeff(band3_filter.a1, 0x6D);
    WriteFilterCoeff(band3_filter.a2, 0x70);

    // Enable 3-band filter
    max98090_reg_dsp_biquadfilter_enable_t filter = {0};
    filter.eq3banden                              = 1;
    i2cAddr.subAddress                            = MAX98090_REG_DSP_BIQUAD_FILTER_ENABLE;
    i2c->Write(i2cAddr, (uint8_t *)&filter, 1);

    return CodecRetCode::Success;
}

CodecRetCode CodecMAX98090::SetupLoudspeakerEqualizer()
{
    qfilter_coefficients_t band1_filter = {0};
    qfilter_coefficients_t band2_filter = {0};
    qfilter_coefficients_t band3_filter = {0};

    // Highpass,lowpass & flat filters don't use Gain parameter
    qfilter_CalculateCoeffs(FilterHighPass, 500, currentParams.GetSampleRateVal(), 0.707, 1, &band1_filter);
    qfilter_CalculateCoeffs(FilterFlat, 0, currentParams.GetSampleRateVal(), 0.707, 1, &band2_filter);
    qfilter_CalculateCoeffs(FilterFlat, 0, currentParams.GetSampleRateVal(), 0.707, 1, &band3_filter);

    // BAND1
    WriteFilterCoeff(band1_filter.b0, 0x46);
    WriteFilterCoeff(band1_filter.b1, 0x49);
    WriteFilterCoeff(band1_filter.b2, 0x4C);
    WriteFilterCoeff(band1_filter.a1, 0x4F);
    WriteFilterCoeff(band1_filter.a2, 0x52);

    // BAND2
    WriteFilterCoeff(band2_filter.b0, 0x55);
    WriteFilterCoeff(band2_filter.b1, 0x58);
    WriteFilterCoeff(band2_filter.b2, 0x5B);
    WriteFilterCoeff(band2_filter.a1, 0x5E);
    WriteFilterCoeff(band2_filter.a2, 0x61);

    // BAND3
    WriteFilterCoeff(band3_filter.b0, 0x64);
    WriteFilterCoeff(band3_filter.b1, 0x67);
    WriteFilterCoeff(band3_filter.b2, 0x6A);
    WriteFilterCoeff(band3_filter.a1, 0x6D);
    WriteFilterCoeff(band3_filter.a2, 0x70);

    // Enable 3-band filter
    max98090_reg_dsp_biquadfilter_enable_t filter = {0};
    filter.eq3banden                              = 1;
    i2cAddr.subAddress                            = MAX98090_REG_DSP_BIQUAD_FILTER_ENABLE;
    i2c->Write(i2cAddr, (uint8_t *)&filter, 1);

    return CodecRetCode::Success;
}

CodecRetCode CodecMAX98090::Reset()
{


M module-bsp/board/rt1051/bsp/audio/CodecMAX98090.hpp => module-bsp/board/rt1051/bsp/audio/CodecMAX98090.hpp +2 -0
@@ 120,6 120,8 @@ class CodecMAX98090 : public Codec
    CodecRetCode SetInputPath(const bsp::AudioDevice::InputPath path);
    CodecRetCode SetOutputPath(const bsp::AudioDevice::OutputPath path);
    CodecRetCode MicBias(const bool enable);
    CodecRetCode SetupEarspeakerEqualizer();
    CodecRetCode SetupLoudspeakerEqualizer();
    CodecRetCode WriteFilterCoeff(const float coeff, const uint8_t basereg);
    CodecRetCode Reset();
};

M module-bsp/board/rt1051/bsp/audio/max98090_regs.hpp => module-bsp/board/rt1051/bsp/audio/max98090_regs.hpp +29 -65
@@ 37,7 37,7 @@ typedef struct

// Device Status Interrupt Mask Register
// Check Table 86. for more info.
#define MAX98090_REG_DEVICE_STATUS_MASK 0x01
#define MAX98090_REG_DEVICE_STATUS_MASK 0x03
typedef struct
{
    uint8_t idrcclp : 1;


@@ 74,24 74,25 @@ typedef struct
#define MAX98090_REG_OUTPUT_ENABLE 0x3F
typedef struct
{
    uint8_t hpren : 1;
    uint8_t hplen : 1;
    uint8_t spren : 1;
    uint8_t splen : 1;
    uint8_t rcvlen : 1;
    uint8_t rcvren : 1;
    uint8_t daren : 1;
    uint8_t dalen : 1;
    uint8_t daren : 1;
    uint8_t rcvren : 1;
    uint8_t rcvlen : 1;
    uint8_t splen : 1;
    uint8_t spren : 1;
    uint8_t hplen : 1;
    uint8_t hpren : 1;
} max98090_reg_outputenable_t;

// Output enable register
#define MAX98090_REG_DAC_HP_PERF 0x43
// Line Input Level Configuration Register
#define MAX98090_REG_LINE_INPUT_LEVEL_CONF 0x0E
typedef struct
{
    uint8_t dachp : 1;
    uint8_t perfmode : 1;
    uint8_t unused : 6;
} max98090_reg_dac_hp_perf_t;
    uint8_t linbpga : 3;
    uint8_t linapga : 3;
    uint8_t mixg246 : 1;
    uint8_t mixg135 : 1;
} max98090_reg_line_inp_lvl_t;

// Microphone 1 enable and level configuration register
#define MAX98090_REG_MIC1_ENABLE_LEVEL_CONF 0x10


@@ 99,6 100,7 @@ typedef struct
{
    uint8_t pgam : 5;
    uint8_t pa1en : 2;
    uint8_t unused : 1;
} max98090_reg_mic1ena_lvlctl_t;

// Microphone 2 enable and level configuration register


@@ 107,6 109,7 @@ typedef struct
{
    uint8_t pgam : 5;
    uint8_t pa2en : 2;
    uint8_t unused : 1;
} max98090_reg_mic2ena_lvlctl_t;

// Microphone Bias Level Configuration Register


@@ 125,7 128,7 @@ typedef struct
    uint8_t digmicl : 1;
    uint8_t digmicr : 1;
    uint8_t unused : 2;
    uint8_t dmicclk : 2;
    uint8_t dmicclk : 3;
    uint8_t unused2 : 1;
} max98090_reg_digmic_enable_t;



@@ 154,6 157,7 @@ typedef struct
typedef struct
{
    uint8_t mixadl : 7;
    uint8_t unused : 1;
} max98090_reg_ladc_mix_input_t;

/*  Right ADC Mixer Input Configuration Register


@@ 169,6 173,7 @@ typedef struct
typedef struct
{
    uint8_t mixadr : 7;
    uint8_t unused : 1;
} max98090_reg_radc_mix_input_t;

/*  Left Record Path Digital Gain Configuration Register


@@ 193,46 198,6 @@ typedef struct
    uint8_t unused : 1;
} max98090_reg_rrec_dig_gain_t;

// Record DSP Filter Configuration Register
#define MAX98090_REG_REC_DSP_FILTER_CONF 0x14
typedef struct
{

    uint8_t unused : 4;

    /*
    Enables the DAC High Sample Rate Mode (LRCLK > 48kHz, FIR Only)
    0: LRCLK is less than 48kHz. 8x FIR interpolation filter used.
    1: LRCLK is greater than 48kHz. 4x FIR interpolation filter used.
     */
    uint8_t dhf : 1;

    /*
    Enables the Playback Path DC-Blocking Filter
    0: DC-blocking filter disabled.
    1: DC-blocking filter enabled
     */
    uint8_t dhpf : 1;

    /*
    Enables the Record Path DC-Blocking Filter
    0: DC-blocking filter disabled.
    1: DC-blocking filter enabled.
     */
    uint8_t ahpf : 1;

    /*
    Enables the Codec DSP FIR Music Filters (Default IIR Voice Filters)
    0: The codec DSP filters operate in IIR voice mode with stop band frequencies below
    the fS/2 Nyquist rate. The voice mode filters are optimized for 8kHz or 16kHz voice
    application use.
    1: The codec DSP filters operate in a linear phase FIR audio mode optimized to
    maintain stereo imaging and operate at higher fS rates while utilizing lower power
     */
    uint8_t mode : 1;

} max98090_reg_rec_dspfilter_conf_t;

// System Master Clock (MCLK) Prescaler Configuration Register
// Check MAX98090 datasheet Table 34 for available configurations
#define MAX98090_REG_SYSTEM_MASTER_CLOCK 0x1B


@@ 260,7 225,7 @@ typedef struct
#define MAX98090_REG_CLOCK_MODE 0x1C
typedef struct
{
    uint8_t usemi : 4;
    uint8_t usemi : 1;
    uint8_t unused : 3;
    uint8_t freq : 4;
} max98090_reg_clock_mode_t;


@@ 270,7 235,8 @@ typedef struct
#define MAX98090_REG_NI_MSB 0x1D
typedef struct
{
    uint8_t ni;
    uint8_t ni : 7;
    uint8_t unused : 1;
} max98090_reg_manual_clock_ratio_NI_MSB_t;

// Manual Clock Ratio Configuration Register (NI LSB)


@@ 405,7 371,6 @@ typedef struct
    uint8_t dhpf : 1;
    uint8_t ahpf : 1;
    uint8_t mode : 1;

} max98090_reg_playback_dspfilter_conf_t;

// Master Clock Quick Setup Register


@@ 501,8 466,8 @@ typedef struct
#define MAX98090_REG_LHP_VOL_CTRL 0x2C
typedef struct
{
    uint8_t hpvoll : 6;
    uint8_t unused : 1;
    uint8_t hpvoll : 5;
    uint8_t unused : 2;
    uint8_t hplm : 1;

} max98090_reg_lhp_vol_ctrl_t;


@@ 512,8 477,8 @@ typedef struct
#define MAX98090_REG_RHP_VOL_CTRL 0x2D
typedef struct
{
    uint8_t hpvolr : 6;
    uint8_t unused : 1;
    uint8_t hpvolr : 5;
    uint8_t unused : 2;
    uint8_t hprm : 1;

} max98090_reg_rhp_vol_ctrl_t;


@@ 545,8 510,8 @@ typedef struct
#define MAX98090_REG_RECV_VOL_CTRL 0x39
typedef struct
{
    uint8_t rcvlvol : 6;
    uint8_t unused : 1;
    uint8_t rcvlvol : 5;
    uint8_t unused : 2;
    uint8_t rcvlm : 1;

} max98090_reg_recv_vol_ctrl_t;


@@ 581,7 546,6 @@ typedef struct
    uint8_t adcdither : 1;
    uint8_t osr128 : 1;
    uint8_t unused : 5;

} max98090_reg_adcperf_mode_t;

#define MAX98090_I2C_ADDR 0x10

M module-bsp/board/rt1051/bsp/headset/headset.cpp => module-bsp/board/rt1051/bsp/headset/headset.cpp +35 -3
@@ 5,6 5,7 @@

#include "BoardDefinitions.hpp"
#include "DriverI2C.hpp"
#include "DriverGPIO.hpp"
#include "fsl_common.h"
#include "timers.h"



@@ 32,9 33,10 @@ namespace bsp
        static constexpr uint8_t HEADSET_DEV_SET_DET_EN = 1 << 5;
        static constexpr uint8_t HEADSET_DEV_SET_DEB_1S = 0x06;

        static constexpr uint16_t HEADSET_POLL_INTERVAL_MS = 500;
        static constexpr uint16_t HEADSET_POLL_INTERVAL_MS = 2500;

        static std::shared_ptr<drivers::DriverI2C> i2c;
        static std::shared_ptr<drivers::DriverGPIO> gpio;
        static drivers::I2CAddress i2cAddr = {.deviceAddress = HEADSET_I2C_ADDR, .subAddressSize = 0x01};
        static TimerHandle_t timerHandle;



@@ 55,12 57,27 @@ namespace bsp
            if (((reg & 0x08) == 0) && (HeadsetInserted == true)) {
                HeadsetInserted = false;
                LOG_INFO("Headset removed");
                gpio->WritePin(static_cast<uint32_t>(BoardDefinitions::MIC_BIAS_DRIVER_EN), 0);

                ret = true;
            }

            if (((reg & 0x08) != 0) && (HeadsetInserted == false)) {
                HeadsetInserted = true;
                LOG_INFO("Headset inserted");

                if ((reg & 0x01) != 0) {
                    LOG_INFO("Headset 3-pole detected");
                    gpio->WritePin(static_cast<uint32_t>(BoardDefinitions::MIC_BIAS_DRIVER_EN), 0);
                }
                if ((reg & 0x02) != 0) {
                    LOG_INFO("Headset 4-pole OMTP detected");
                    gpio->WritePin(static_cast<uint32_t>(BoardDefinitions::MIC_BIAS_DRIVER_EN), 1);
                }
                if ((reg & 0x04) != 0) {
                    LOG_INFO("Headset 4-pole Standard detected");
                    gpio->WritePin(static_cast<uint32_t>(BoardDefinitions::MIC_BIAS_DRIVER_EN), 1);
                }
                ret = true;
            }



@@ 81,8 98,20 @@ namespace bsp
                static_cast<I2CInstances>(BoardDefinitions::HEADSET_I2C),
                DriverI2CParams{.baudrate = static_cast<uint32_t>(BoardDefinitions::HEADSET_I2C_BAUDRATE)});

            gpio = DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::MIC_BIAS_DRIVER_GPIO),
                                      DriverGPIOParams{});

            gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                              .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                              .defLogic = 0,
                                              .pin      = static_cast<uint32_t>(BoardDefinitions::MIC_BIAS_DRIVER_EN)});

            qHandleIrq = qHandle;

            HeadsetInserted = false;

            gpio->WritePin(static_cast<uint32_t>(BoardDefinitions::MIC_BIAS_DRIVER_EN), 0);

            uint8_t reg =
                HEADSET_INT_DIS_INT_ENA | HEADSET_INT_DIS_ADC_ENA | HEADSET_INT_DIS_DC_ENA | HEADSET_INT_DIS_INS_ENA;
            i2cAddr.subAddress = HEADSET_INT_DIS_ADDR;


@@ 101,7 130,7 @@ namespace bsp
                }
            }

            xTimerStart(timerHandle, 0);
            xTimerStart(timerHandle, HEADSET_POLL_INTERVAL_MS);

            return kStatus_Success;
        }


@@ 122,10 151,13 @@ namespace bsp

        status_t Deinit()
        {
            qHandleIrq = nullptr;
            qHandleIrq      = nullptr;
            HeadsetInserted = false;

            i2c.reset();

            gpio->WritePin(static_cast<uint32_t>(BoardDefinitions::MIC_BIAS_DRIVER_EN), 0);

            return kStatus_Success;
        }
    } // namespace headset

M module-bsp/board/rt1051/common/board.h => module-bsp/board/rt1051/common/board.h +8 -2
@@ 189,8 189,8 @@
#define BSP_CELLULAR_AP_RDY_PAD  GPIO_B1_00

#define BSP_CELLULAR_WAKEUP_PORT GPIO2
#define BSP_CELLULAR_WAKEUP_PIN  19
#define BSP_CELLULAR_WAKEUP_PAD  GPIO_B1_03
#define BSP_CELLULAR_WAKEUP_PIN  22
#define BSP_CELLULAR_WAKEUP_PAD  GPIO_B1_06

#define BSP_CELLULAR_SIM_TRAY_INSERTED_PORT   GPIO2
#define BSP_CELLULAR_SIM_TRAY_INSERTED_PIN    11


@@ 294,6 294,12 @@
#define BOARD_JACKDET_IRQ_GPIO     GPIO2
#define BOARD_JACKDET_IRQ_GPIO_PIN (30U)

/**
 * MICROPHONE BIAS DEFINITIONS
 */
#define BOARD_MIC_LDO_EN_GPIO GPIO2
#define BOARD_MIC_LDO_EN_PIN  19

#define DMA_MAX_SINGLE_TRANSACTION_PAYLOAD 32767

/**

M module-bsp/board/rt1051/common/pin_mux.c => module-bsp/board/rt1051/common/pin_mux.c +7 -2
@@ 305,7 305,7 @@ void PINMUX_InitBootPins(void)
    PINMUX_InitBatteryCharger();
    PINMUX_InitALS();
    PINMUX_InitPowerSW();
    PINMUX_InitJACKDET();
    PINMUX_InitHeadset();
    PINMUX_InitVibrator();
    PINMUX_InitTorch();
    PINMUX_InitMagnetometer();


@@ 1381,7 1381,7 @@ void PINMUX_InitBluetoothPins(void)
                            PAD_CONFIG_HYSTERESIS_DISABLED);
}

void PINMUX_InitJACKDET(void)
void PINMUX_InitHeadset(void)
{
    CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */



@@ 1390,6 1390,11 @@ void PINMUX_InitJACKDET(void)

    IOMUXC_SetPinConfig(PINMUX_JACKDET_IRQ, /* GPIO_AD_B0_02 PAD functional properties : */
                        PAD_CONFIG_PULL_UP_100kOhm | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_KEEPER_ENABLED);

    IOMUXC_SetPinMux(PINMUX_MIC_LDO_EN, 1);
    IOMUXC_SetPinConfig(PINMUX_MIC_LDO_EN,
                        PAD_CONFIG_PULL_UP_22kOhm | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_KEEPER_DISABLED |
                            PAD_CONFIG_DRIVER_STRENGTH_LVL_4 | PAD_CONFIG_SLEW_RATE_SLOW | PAD_CONFIG_SPEED_SLOW_50MHz);
}

void PINMUX_InitBatteryCharger(void)

M module-bsp/board/rt1051/common/pin_mux.h => module-bsp/board/rt1051/common/pin_mux.h +3 -2
@@ 183,10 183,11 @@ extern "C"
    void PINMUX_InitLEDDRIVER(void);

/**
 * JACK DETECTION PINMUX DEFINITIONS
 * HEADSET (JACK DETECTION, MIC BIAS) PINMUX DEFINITIONS
 */
#define PINMUX_JACKDET_IRQ IOMUXC_GPIO_B1_14_GPIO2_IO30
    void PINMUX_InitJACKDET(void);
#define PINMUX_MIC_LDO_EN  IOMUXC_GPIO_B1_03_GPIO2_IO19
    void PINMUX_InitHeadset(void);

/**
 * BATTERY CHARGER PINMUX DEFINITIONS

M module-bsp/bsp/audio/bsp_audio.hpp => module-bsp/bsp/audio/bsp_audio.hpp +1 -0
@@ 33,6 33,7 @@ namespace bsp {
            HeadphonesMono,
            Earspeaker,
            Loudspeaker,
            LoudspeakerMono,
            BluetoothA2DP,
            BluetoothHSP,
            None

M module-services/service-audio/ServiceAudio.cpp => module-services/service-audio/ServiceAudio.cpp +1 -1
@@ 69,7 69,7 @@ sys::ReturnCodes ServiceAudio::InitHandler()
        // ROUTING
        {dbPath(Setting::Gain, PlaybackType::None, Profile::Type::RoutingBluetoothHSP), "20"},
        {dbPath(Setting::Gain, PlaybackType::None, Profile::Type::RoutingEarspeaker), "20"},
        {dbPath(Setting::Gain, PlaybackType::None, Profile::Type::RoutingHeadphones), "20"},
        {dbPath(Setting::Gain, PlaybackType::None, Profile::Type::RoutingHeadphones), "0"},
        {dbPath(Setting::Gain, PlaybackType::None, Profile::Type::RoutingLoudspeaker), "20"},
        {dbPath(Setting::Gain, PlaybackType::None, Profile::Type::RoutingHeadphones), "50"},