Library to control and transfer data from NXP SGTL5000. As used on the Teensy Audio Shield. It uses DMA to transfer I2S FIFO data.

The Library now supports dual codecs. Allowing all 4 channels of the Teensy I2S interface to RX and TX data to separate SGTL5000 devices.

The ISR routines that handles pointer swaps for double buffering has been fully coded in assembler to reduce overhead and now takes < 800nS per FIFO transfer when using all 4 channels.

Support added for all typical sample rates and system Clock speeds of 96Mhz or 120Mhz.

Pause and Resume functions added to allow quick and simple suppression of IRQs and stream halting and restart. This required software triggered IRQ, in order to ensure accurate word sync control.

Revision:
8:9fdf8501d14b
Parent:
7:d65476c153a4
Child:
9:40e0ff8c2ba2
diff -r d65476c153a4 -r 9fdf8501d14b sgtl5000.cpp
--- a/sgtl5000.cpp	Wed Jul 05 17:30:08 2017 +0000
+++ b/sgtl5000.cpp	Fri Jul 07 11:38:57 2017 +0000
@@ -52,7 +52,7 @@
     else i2c_addr = SGTL5000_I2C_ADDR_CS_LOW << 1;
     mI2C.frequency(i2c_freq);
     init_i2s();
-    init_codec();
+    codec_configured = false;
     SYNC_run = false;
     TX_run = false;
     RX_run = false;
@@ -61,8 +61,16 @@
     RX_attached = false;
 }
 
+int32_t SGTL5000::init(void)
+{
+    if(init_codec()) return -1;
+    else codec_configured = true;
+    return 0;
+}
+
 int32_t SGTL5000::freq(uint32_t rate)
 {
+    if(!codec_configured) return -1;
     uint32_t I2S_MCLK_M;
     uint32_t I2S_MCLK_D;
     uint32_t codec_SYS_FS;
@@ -274,114 +282,155 @@
 
 }
 
-void SGTL5000::init_codec(void)
+int32_t SGTL5000::init_codec(void)
 {
     // Default Configure Codec
-    wait(0.2);// Let codec run start-up ramp ?
-
-    write_i2c(SGTL5000_ANA_POWER,   (   (SGTL5000_ANA_POWER_DAC_MONO_MASK & (0x1 << SGTL5000_ANA_POWER_DAC_MONO_SHIFT)) |                                           // Select stereo mode for DAC
-                                        (SGTL5000_ANA_POWER_LINREG_SIMPLE_POWERUP_MASK & (0x1 << SGTL5000_ANA_POWER_LINREG_SIMPLE_POWERUP_SHIFT)) |                 // Disable simple digital lineregulator. Teensy shield has external reg but sequence requires simple linereg on for reset and power-up
-                                        (SGTL5000_ANA_POWER_STARTUP_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_STARTUP_POWERUP_SHIFT)) |                             // Disable reset and powerup circuits. Can be cleared after powerup as VDDD is external on Teensy
-                                        (SGTL5000_ANA_POWER_VDDC_CHRGPMP_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_VDDC_CHRGPMP_POWERUP_SHIFT)) |                   // Disable charge pump as VDDA & VDDIO > 3.1V
-                                        (SGTL5000_ANA_POWER_PLL_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_PLL_POWERUP_SHIFT)) |                                     // PLL disabled as codec clocking is synchronous to I2S clock.
-                                        (SGTL5000_ANA_POWER_LINREG_D_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_LINREG_D_POWERUP_SHIFT)) |                           // Disable the VDDD line regulator as Teensy externally regulated at 1.85V
-                                        (SGTL5000_ANA_POWER_VCOAMP_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_VCOAMP_POWERUP_SHIFT)) |                               // Disable the PLL VCO Amp, we don't use PLL
-                                        (SGTL5000_ANA_POWER_VAG_POWERUP_MASK & (0x1 << SGTL5000_ANA_POWER_VAG_POWERUP_SHIFT)) |                                     // Powerup VAG ref buffer. Should be enabled before powering up headphone and lineout and disabled before powering down HP and LINEOUT
-                                        (SGTL5000_ANA_POWER_ADC_MONO_MASK & (0x1 << SGTL5000_ANA_POWER_ADC_MONO_SHIFT)) |                                           // ADC in stereo mode
-                                        (SGTL5000_ANA_POWER_REFTOP_POWERUP_MASK & (0x1 << SGTL5000_ANA_POWER_REFTOP_POWERUP_SHIFT)) |                               // Enable bias currents
-                                        (SGTL5000_ANA_POWER_HEADPHONE_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_HEADPHONE_POWERUP_SHIFT)) |                         // Disable HP amp until we set the reference levels
-                                        (SGTL5000_ANA_POWER_DAC_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_DAC_POWERUP_SHIFT)) |                                     // Disable DAC until we set refs
-                                        (SGTL5000_ANA_POWER_CAPLESS_HEADPHONE_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_CAPLESS_HEADPHONE_POWERUP_SHIFT)) |         // Disable capless headphones
-                                        (SGTL5000_ANA_POWER_ADC_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_ADC_POWERUP_SHIFT)) |                                     // Disable ADC power until we set refs
-                                        (SGTL5000_ANA_POWER_LINEOUT_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_LINEOUT_POWERUP_SHIFT))                               // Disable LINEOUT power until we set refs
-                                    ));
-    write_i2c(SGTL5000_LINREG_CTRL,(      (SGTL5000_LINREG_CTRL_VDDC_MAN_ASSN_MASK & (0x0 << SGTL5000_LINREG_CTRL_VDDC_MAN_ASSN_SHIFT)) |                           // Manually assign charge pump rail (VDDC) source as VDDA.
-                                          (SGTL5000_LINREG_CTRL_VDDC_ASSN_OVRD_MASK & (0x1 << SGTL5000_LINREG_CTRL_VDDC_ASSN_OVRD_SHIFT)) |                         // chargepump source manually assigned
-                                          (SGTL5000_LINREG_CTRL_D_PROGRAMMING_MASK & (0xC << SGTL5000_LINREG_CTRL_D_PROGRAMMING_SHIFT))                             // VDDD Line Reg not used so leave default
-                                   ));
-    write_i2c(SGTL5000_REF_CTRL,        (   (SGTL5000_REF_CTRL_VAG_VAL_MASK & (0x1F << SGTL5000_REF_CTRL_VAG_VAL_SHIFT)) |                                          // Set VAG ref to 1.575V
-                                            (SGTL5000_REF_CTRL_BIAS_CTRL_MASK & (0x1 << SGTL5000_REF_CTRL_BIAS_CTRL_SHIFT)) |                                       // Set analog bias currents to +12.5%
-                                            (SGTL5000_REF_CTRL_SMALL_POP_MASK & (0x0 << SGTL5000_REF_CTRL_SMALL_POP_SHIFT))                                         // Set small pop ramp normal
-                                        ));
-    write_i2c(SGTL5000_LINE_OUT_CTRL,   (   (SGTL5000_LINE_OUT_CTRL_OUT_CURRENT_MASK & (0x3 << SGTL5000_LINE_OUT_CTRL_OUT_CURRENT_SHIFT)) |                         // Set Lineout bias curent 0.36mA
-                                            (SGTL5000_LINE_OUT_CTRL_LO_VAGCNTRL_MASK & (0x22 << SGTL5000_LINE_OUT_CTRL_LO_VAGCNTRL_SHIFT))                          // Lineout AGND = 1.65v (line out will drive between the rails, so set at VDDA/2)
-                                        ));
-    write_i2c(SGTL5000_SHORT_CTRL,      (   (SGTL5000_SHORT_CTRL_LVLADJR_MASK & (0x4 << SGTL5000_SHORT_CTRL_LVLADJR_SHIFT)) |                                       // HP R short detect 125mA
-                                            (SGTL5000_SHORT_CTRL_LVLADJL_MASK & (0x4 << SGTL5000_SHORT_CTRL_LVLADJL_SHIFT)) |                                       // HP L short detect 125mA
-                                            (SGTL5000_SHORT_CTRL_LVLADJC_MASK & (0x4 << SGTL5000_SHORT_CTRL_LVLADJC_SHIFT)) |                                       // Headphone capless short detect 250mA
-                                            (SGTL5000_SHORT_CTRL_MODE_LR_MASK & (0x1 << SGTL5000_SHORT_CTRL_MODE_LR_SHIFT)) |                                       // en short det reset 50mS
-                                            (SGTL5000_SHORT_CTRL_MODE_CM_MASK & (0x2 << SGTL5000_SHORT_CTRL_MODE_CM_SHIFT))                                         // En capless short det reset vol rise
-                                        ));
-    write_i2c(SGTL5000_ANA_CTRL,        (   (SGTL5000_ANA_CTRL_MUTE_LO_MASK & (0x1 << SGTL5000_ANA_CTRL_MUTE_LO_SHIFT)) |                                           // Mute LINEOUT
-                                            (SGTL5000_ANA_CTRL_SELECT_HP_MASK & (0x0 << SGTL5000_ANA_CTRL_SELECT_HP_SHIFT)) |                                       // Select DAC as input to HP amp
-                                            (SGTL5000_ANA_CTRL_EN_ZCD_HP_MASK & (0x1 << SGTL5000_ANA_CTRL_EN_ZCD_HP_SHIFT)) |                                       // Enable ZCD on HP
-                                            (SGTL5000_ANA_CTRL_MUTE_HP_MASK & (0x1 << SGTL5000_ANA_CTRL_MUTE_HP_SHIFT)) |                                           // Mute the headphones
-                                            (SGTL5000_ANA_CTRL_SELECT_ADC_MASK & (0x1 << SGTL5000_ANA_CTRL_SELECT_ADC_SHIFT)) |                                     // Select LINEIN as input to ADC
-                                            (SGTL5000_ANA_CTRL_EN_ZCD_ADC_MASK & (0x1 << SGTL5000_ANA_CTRL_EN_ZCD_ADC_SHIFT)) |                                     // Enable ADC ZCD
-                                            (SGTL5000_ANA_CTRL_MUTE_ADC_MASK & (0x1 << SGTL5000_ANA_CTRL_MUTE_ADC_SHIFT))                                           // Mute ADC pre-amp
-                                        ));
-    modify_i2c                              (SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_HEADPHONE_POWERUP_MASK);                                                   // Power up Headphone amp
-    modify_i2c                              (SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_DAC_POWERUP_MASK);                                                         // Power up DAC
-    modify_i2c                              (SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_CAPLESS_HEADPHONE_POWERUP_MASK);                                           // Power up capless HP block
-    modify_i2c                              (SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_ADC_POWERUP_MASK);                                                         // Power up ADC
-    modify_i2c                              (SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_LINEOUT_POWERUP_MASK);                                                     // Power up Lineout Amp
-
-    modify_i2c                              (SGTL5000_ANA_POWER, 0x0, SGTL5000_ANA_POWER_LINREG_SIMPLE_POWERUP_MASK);                                               // Turn of simple regulator now the blocks are powered-up
+    if(
+        write_i2c(SGTL5000_ANA_POWER,(
+                      (SGTL5000_ANA_POWER_DAC_MONO_MASK & (0x1 << SGTL5000_ANA_POWER_DAC_MONO_SHIFT)) |                                             // Select stereo mode for DAC
+                      (SGTL5000_ANA_POWER_LINREG_SIMPLE_POWERUP_MASK & (0x1 << SGTL5000_ANA_POWER_LINREG_SIMPLE_POWERUP_SHIFT)) |                   // Disable simple digital lineregulator. Teensy shield has external reg but sequence requires simple linereg on for reset and power-up
+                      (SGTL5000_ANA_POWER_STARTUP_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_STARTUP_POWERUP_SHIFT)) |                               // Disable reset and powerup circuits. Can be cleared after powerup as VDDD is external on Teensy
+                      (SGTL5000_ANA_POWER_VDDC_CHRGPMP_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_VDDC_CHRGPMP_POWERUP_SHIFT)) |                     // Disable charge pump as VDDA & VDDIO > 3.1V
+                      (SGTL5000_ANA_POWER_PLL_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_PLL_POWERUP_SHIFT)) |                                       // PLL disabled as codec clocking is synchronous to I2S clock.
+                      (SGTL5000_ANA_POWER_LINREG_D_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_LINREG_D_POWERUP_SHIFT)) |                             // Disable the VDDD line regulator as Teensy externally regulated at 1.85V
+                      (SGTL5000_ANA_POWER_VCOAMP_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_VCOAMP_POWERUP_SHIFT)) |                                 // Disable the PLL VCO Amp, we don't use PLL
+                      (SGTL5000_ANA_POWER_VAG_POWERUP_MASK & (0x1 << SGTL5000_ANA_POWER_VAG_POWERUP_SHIFT)) |                                       // Powerup VAG ref buffer. Should be enabled before powering up headphone and lineout and disabled before powering down HP and LINEOUT
+                      (SGTL5000_ANA_POWER_ADC_MONO_MASK & (0x1 << SGTL5000_ANA_POWER_ADC_MONO_SHIFT)) |                                             // ADC in stereo mode
+                      (SGTL5000_ANA_POWER_REFTOP_POWERUP_MASK & (0x1 << SGTL5000_ANA_POWER_REFTOP_POWERUP_SHIFT)) |                                 // Enable bias currents
+                      (SGTL5000_ANA_POWER_HEADPHONE_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_HEADPHONE_POWERUP_SHIFT)) |                           // Disable HP amp until we set the reference levels
+                      (SGTL5000_ANA_POWER_DAC_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_DAC_POWERUP_SHIFT)) |                                       // Disable DAC until we set refs
+                      (SGTL5000_ANA_POWER_CAPLESS_HEADPHONE_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_CAPLESS_HEADPHONE_POWERUP_SHIFT)) |           // Disable capless headphones
+                      (SGTL5000_ANA_POWER_ADC_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_ADC_POWERUP_SHIFT)) |                                       // Disable ADC power until we set refs
+                      (SGTL5000_ANA_POWER_LINEOUT_POWERUP_MASK & (0x0 << SGTL5000_ANA_POWER_LINEOUT_POWERUP_SHIFT))                                 // Disable LINEOUT power until we set refs
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_LINREG_CTRL,(
+                      (SGTL5000_LINREG_CTRL_VDDC_MAN_ASSN_MASK & (0x0 << SGTL5000_LINREG_CTRL_VDDC_MAN_ASSN_SHIFT)) |                               // Manually assign charge pump rail (VDDC) source as VDDA.
+                      (SGTL5000_LINREG_CTRL_VDDC_ASSN_OVRD_MASK & (0x1 << SGTL5000_LINREG_CTRL_VDDC_ASSN_OVRD_SHIFT)) |                             // chargepump source manually assigned
+                      (SGTL5000_LINREG_CTRL_D_PROGRAMMING_MASK & (0xC << SGTL5000_LINREG_CTRL_D_PROGRAMMING_SHIFT))                                 // VDDD Line Reg not used so leave default
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_REF_CTRL,(
+                      (SGTL5000_REF_CTRL_VAG_VAL_MASK & (0x1F << SGTL5000_REF_CTRL_VAG_VAL_SHIFT)) |                                                // Set VAG ref to 1.575V
+                      (SGTL5000_REF_CTRL_BIAS_CTRL_MASK & (0x1 << SGTL5000_REF_CTRL_BIAS_CTRL_SHIFT)) |                                             // Set analog bias currents to +12.5%
+                      (SGTL5000_REF_CTRL_SMALL_POP_MASK & (0x0 << SGTL5000_REF_CTRL_SMALL_POP_SHIFT))                                               // Set small pop ramp normal
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_LINE_OUT_CTRL,(
+                      (SGTL5000_LINE_OUT_CTRL_OUT_CURRENT_MASK & (0x3 << SGTL5000_LINE_OUT_CTRL_OUT_CURRENT_SHIFT)) |                               // Set Lineout bias curent 0.36mA
+                      (SGTL5000_LINE_OUT_CTRL_LO_VAGCNTRL_MASK & (0x22 << SGTL5000_LINE_OUT_CTRL_LO_VAGCNTRL_SHIFT))                                // Lineout AGND = 1.65v (line out will drive between the rails, so set at VDDA/2)
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_SHORT_CTRL,(
+                      (SGTL5000_SHORT_CTRL_LVLADJR_MASK & (0x4 << SGTL5000_SHORT_CTRL_LVLADJR_SHIFT)) |                                             // HP R short detect 125mA
+                      (SGTL5000_SHORT_CTRL_LVLADJL_MASK & (0x4 << SGTL5000_SHORT_CTRL_LVLADJL_SHIFT)) |                                             // HP L short detect 125mA
+                      (SGTL5000_SHORT_CTRL_LVLADJC_MASK & (0x4 << SGTL5000_SHORT_CTRL_LVLADJC_SHIFT)) |                                             // Headphone capless short detect 250mA
+                      (SGTL5000_SHORT_CTRL_MODE_LR_MASK & (0x1 << SGTL5000_SHORT_CTRL_MODE_LR_SHIFT)) |                                             // en short det reset 50mS
+                      (SGTL5000_SHORT_CTRL_MODE_CM_MASK & (0x2 << SGTL5000_SHORT_CTRL_MODE_CM_SHIFT))                                               // En capless short det reset vol rise
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_ANA_CTRL,(
+                      (SGTL5000_ANA_CTRL_MUTE_LO_MASK & (0x1 << SGTL5000_ANA_CTRL_MUTE_LO_SHIFT)) |                                                 // Mute LINEOUT
+                      (SGTL5000_ANA_CTRL_SELECT_HP_MASK & (0x0 << SGTL5000_ANA_CTRL_SELECT_HP_SHIFT)) |                                             // Select DAC as input to HP amp
+                      (SGTL5000_ANA_CTRL_EN_ZCD_HP_MASK & (0x1 << SGTL5000_ANA_CTRL_EN_ZCD_HP_SHIFT)) |                                             // Enable ZCD on HP
+                      (SGTL5000_ANA_CTRL_MUTE_HP_MASK & (0x1 << SGTL5000_ANA_CTRL_MUTE_HP_SHIFT)) |                                                 // Mute the headphones
+                      (SGTL5000_ANA_CTRL_SELECT_ADC_MASK & (0x1 << SGTL5000_ANA_CTRL_SELECT_ADC_SHIFT)) |                                           // Select LINEIN as input to ADC
+                      (SGTL5000_ANA_CTRL_EN_ZCD_ADC_MASK & (0x1 << SGTL5000_ANA_CTRL_EN_ZCD_ADC_SHIFT)) |                                           // Enable ADC ZCD
+                      (SGTL5000_ANA_CTRL_MUTE_ADC_MASK & (0x1 << SGTL5000_ANA_CTRL_MUTE_ADC_SHIFT))                                                 // Mute ADC pre-amp
+                  ))
+    ) return -1;
+    if(modify_i2c(SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_HEADPHONE_POWERUP_MASK)) return -1;                                                   // Power up Headphone amp
+    if(modify_i2c(SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_DAC_POWERUP_MASK)) return -1;                                                         // Power up DAC
+    if(modify_i2c(SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_CAPLESS_HEADPHONE_POWERUP_MASK)) return -1;                                           // Power up capless HP block
+    if(modify_i2c(SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_ADC_POWERUP_MASK)) return -1;                                                         // Power up ADC
+    if(modify_i2c(SGTL5000_ANA_POWER, 0x1, SGTL5000_ANA_POWER_LINEOUT_POWERUP_MASK)) return -1;                                                     // Power up Lineout Amp
+    if(modify_i2c(SGTL5000_ANA_POWER, 0x0, SGTL5000_ANA_POWER_LINREG_SIMPLE_POWERUP_MASK)) return -1;                                               // Turn of simple regulator now the blocks are powered-up
 
-    write_i2c(SGTL5000_DIG_POWER,       (   (SGTL5000_DIG_POWER_ADC_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_ADC_POWERUP_SHIFT)) |
-                                            (SGTL5000_DIG_POWER_DAC_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_DAC_POWERUP_SHIFT)) |
-                                            (SGTL5000_DIG_POWER_DAP_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_DAP_POWERUP_SHIFT)) |
-                                            (SGTL5000_DIG_POWER_I2S_OUT_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_I2S_OUT_POWERUP_SHIFT)) |                         // Keep I2S data lines disabled until config complete
-                                            (SGTL5000_DIG_POWER_I2S_IN_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_I2S_IN_POWERUP_SHIFT))
-                                        ));
-    write_i2c(SGTL5000_LINE_OUT_VOL,    (   (SGTL5000_LINE_OUT_VOL_LO_VOL_RIGHT_MASK & (0x11 << SGTL5000_LINE_OUT_VOL_LO_VOL_RIGHT_SHIFT)) |                        // Lineout Vol normalised
-                                            (SGTL5000_LINE_OUT_VOL_LO_VOL_LEFT_MASK & (0x11 << SGTL5000_LINE_OUT_VOL_LO_VOL_LEFT_SHIFT))                            // Verified with oscope at p2p = 2.82v driving ~30k load
-                                        ));
-    write_i2c(SGTL5000_PAD_STRENGTH,    (   (SGTL5000_PAD_STRENGTH_I2S_LRCLK_MASK & (0x0 << SGTL5000_PAD_STRENGTH_I2S_LRCLK_SHIFT)) |                               // I2S LR_CLK drive dissabled (codec is slave)
-                                            (SGTL5000_PAD_STRENGTH_I2S_SCLK_MASK & (0x0 << SGTL5000_PAD_STRENGTH_I2S_SCLK_SHIFT)) |                                 // I2S SCLK drive dissabled (codec is slave)
-                                            (SGTL5000_PAD_STRENGTH_I2S_DOUT_MASK & (0x1 << SGTL5000_PAD_STRENGTH_I2S_DOUT_SHIFT)) |                                 // I2S DOUT drive @ 4.02mA
-                                            (SGTL5000_PAD_STRENGTH_CTRL_DATA_MASK & (0x3 << SGTL5000_PAD_STRENGTH_CTRL_DATA_SHIFT)) |                               // I2C DATA drive @ 12.05mA.
-                                            (SGTL5000_PAD_STRENGTH_CTRL_CLK_MASK & (0x3 << SGTL5000_PAD_STRENGTH_CTRL_CLK_SHIFT))                                   // I2C CLOCK drive @ 12.05mA.
-                                        ));
-    write_i2c(SGTL5000_CLK_CTRL,        (   (SGTL5000_CLK_CTRL_RATE_MODE_MASK & (0x0 <<  SGTL5000_CLK_CTRL_RATE_MODE_SHIFT)) |                                      // Sample rate mode Fs = SYS_FS
-                                            (SGTL5000_CLK_CTRL_SYS_FS_MASK & (0x02 << SGTL5000_CLK_CTRL_SYS_FS_SHIFT)) |                                            // Set SYS_FS (sampling rate depending on mode) @ 48Khz
-                                            (SGTL5000_CLK_CTRL_MCLK_FREQ_MASK & (0x0 << SGTL5000_CLK_CTRL_MCLK_FREQ_SHIFT))                                         // Set SYS MCLK @ 256*Fs
-                                        ));
-    write_i2c(SGTL5000_I2S_CTRL,        (   (SGTL5000_I2S_CTRL_SCLKFREQ_MASK & (0x1 << SGTL5000_I2S_CTRL_SCLKFREQ_SHIFT)) |                                         // I2S SCLK 32*Fs
-                                            (SGTL5000_I2S_CTRL_MS_MASK & (0x0 << SGTL5000_I2S_CTRL_MS_SHIFT)) |                                                     // Slave
-                                            (SGTL5000_I2S_CTRL_SCLK_INV_MASK & (0x0 << SGTL5000_I2S_CTRL_SCLK_INV_SHIFT)) |                                         // Data on riseing edge
-                                            (SGTL5000_I2S_CTRL_DLEN_MASK & (0x3 << SGTL5000_I2S_CTRL_DLEN_SHIFT)) |                                                 // Data 16bits
-                                            (SGTL5000_I2S_CTRL_MODE_MASK & (0x0 << SGTL5000_I2S_CTRL_MODE_SHIFT)) |                                                 // I2S mode
-                                            (SGTL5000_I2S_CTRL_LRALIGN_MASK & (0x0 << SGTL5000_I2S_CTRL_LRALIGN_SHIFT)) |                                           // I2S format
-                                            (SGTL5000_I2S_CTRL_LRPOL_MASK & (0x0 << SGTL5000_I2S_CTRL_LRPOL_SHIFT))                                                 // Left word on LRCLK low
+    if(
+        write_i2c(SGTL5000_DIG_POWER,(
+                      (SGTL5000_DIG_POWER_ADC_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_ADC_POWERUP_SHIFT)) |
+                      (SGTL5000_DIG_POWER_DAC_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_DAC_POWERUP_SHIFT)) |
+                      (SGTL5000_DIG_POWER_DAP_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_DAP_POWERUP_SHIFT)) |
+                      (SGTL5000_DIG_POWER_I2S_OUT_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_I2S_OUT_POWERUP_SHIFT)) |                               // Keep I2S data lines disabled until config complete
+                      (SGTL5000_DIG_POWER_I2S_IN_POWERUP_MASK & (0x1 << SGTL5000_DIG_POWER_I2S_IN_POWERUP_SHIFT))
+                  ))
+    ) return -1;
+    write_i2c(SGTL5000_LINE_OUT_VOL,    (   (SGTL5000_LINE_OUT_VOL_LO_VOL_RIGHT_MASK & (0x11 << SGTL5000_LINE_OUT_VOL_LO_VOL_RIGHT_SHIFT)) |       // Lineout Vol normalised
+                                            (SGTL5000_LINE_OUT_VOL_LO_VOL_LEFT_MASK & (0x11 << SGTL5000_LINE_OUT_VOL_LO_VOL_LEFT_SHIFT))           // Verified with oscope at p2p = 2.82v driving ~30k load
                                         ));
-    write_i2c(SGTL5000_SSS_CTRL,        (   (SGTL5000_SSS_CTRL_DAP_MIX_LRSWAP_MASK & (0x0 << SGTL5000_SSS_CTRL_DAP_MIX_LRSWAP_SHIFT)) |                             // Define all inputs un-swapped
-                                            (SGTL5000_SSS_CTRL_DAP_LRSWAP_MASK & (0x0 << SGTL5000_SSS_CTRL_DAP_LRSWAP_SHIFT)) |
-                                            (SGTL5000_SSS_CTRL_DAC_LRSWAP_MASK & (0x0 << SGTL5000_SSS_CTRL_DAC_LRSWAP_SHIFT)) |
-                                            (SGTL5000_SSS_CTRL_I2S_LRSWAP_MASK & (0x0 << SGTL5000_SSS_CTRL_I2S_LRSWAP_SHIFT)) |
-                                            (SGTL5000_SSS_CTRL_DAP_MIX_SELECT_MASK & (0x0 << SGTL5000_SSS_CTRL_DAP_MIX_SELECT_SHIFT)) |                             // DAP mixer source ADC
-                                            (SGTL5000_SSS_CTRL_DAP_SELECT_MASK & (0x0 << SGTL5000_SSS_CTRL_DAP_SELECT_SHIFT)) |                                     // DAP Input source ADC
-                                            (SGTL5000_SSS_CTRL_DAC_SELECT_MASK & (0x1 << SGTL5000_SSS_CTRL_DAC_SELECT_SHIFT)) |                                     // DAC Input source I2SIN
-                                            (SGTL5000_SSS_CTRL_I2S_SELECT_MASK & (0x0 << SGTL5000_SSS_CTRL_I2S_SELECT_SHIFT))                                       // I2SOUT source ADC
-                                        ));
-    write_i2c(SGTL5000_ADCDAC_CTRL,     (   (SGTL5000_ADCDAC_CTRL_VOL_RAMP_EN_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_VOL_RAMP_EN_SHIFT)) |                             // Disable Vol ramp
-                                            (SGTL5000_ADCDAC_CTRL_VOL_EXPO_RAMP_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_VOL_EXPO_RAMP_SHIFT)) |
-                                            (SGTL5000_ADCDAC_CTRL_DAC_MUTE_RIGHT_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_DAC_MUTE_RIGHT_SHIFT)) |
-                                            (SGTL5000_ADCDAC_CTRL_DAC_MUTE_LEFT_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_DAC_MUTE_LEFT_SHIFT)) |
-                                            (SGTL5000_ADCDAC_CTRL_ADC_HPF_FREEZE_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_ADC_HPF_FREEZE_SHIFT)) |                       // ADC HPF normal operation
-                                            (SGTL5000_ADCDAC_CTRL_ADC_HPF_BYPASS_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_ADC_HPF_BYPASS_SHIFT))                         // ADC HPF enabled
-                                        ));
-    write_i2c(SGTL5000_DAC_VOL,         (   (SGTL5000_DAC_VOL_DAC_VOL_RIGHT_MASK & (0x3C << SGTL5000_DAC_VOL_DAC_VOL_RIGHT_SHIFT)) |                                // DAC R Vol 0dB
-                                            (SGTL5000_DAC_VOL_DAC_VOL_LEFT_MASK & (0x3C << SGTL5000_DAC_VOL_DAC_VOL_LEFT_SHIFT))                                    // DAC L Vol 0dB
-                                        ));
-    write_i2c(SGTL5000_ANA_HP_CTRL,     (   (SGTL5000_ANA_HP_CTRL_HP_VOL_RIGHT_MASK & (0x7F << SGTL5000_ANA_HP_CTRL_HP_VOL_RIGHT_SHIFT)) |                          // HP Vol set minimum
-                                            (SGTL5000_ANA_HP_CTRL_HP_VOL_LEFT_MASK & (0x7F << SGTL5000_ANA_HP_CTRL_HP_VOL_LEFT_SHIFT))
-                                        ));
-    modify_i2c                              (SGTL5000_ANA_CTRL, 0x0, SGTL5000_ANA_CTRL_MUTE_LO_MASK);                                                               // Un-mute Lineout
-    modify_i2c                              (SGTL5000_ANA_CTRL, 0x0, SGTL5000_ANA_CTRL_MUTE_HP_MASK);                                                               // Un-mute HP
-    modify_i2c                              (SGTL5000_ANA_CTRL, 0x0, SGTL5000_ANA_CTRL_MUTE_ADC_MASK);                                                              // Un-mute ADC pre-amp
-    modify_i2c                              (SGTL5000_DIG_POWER, 0x1, SGTL5000_DIG_POWER_I2S_OUT_POWERUP_MASK);                                                     // I2S DOUT enable
-    modify_i2c                              (SGTL5000_DIG_POWER, 0x1, SGTL5000_DIG_POWER_I2S_IN_POWERUP_MASK);                                                      // I2S DIN enable
+    if(
+        write_i2c(SGTL5000_PAD_STRENGTH,(
+                      (SGTL5000_PAD_STRENGTH_I2S_LRCLK_MASK & (0x0 << SGTL5000_PAD_STRENGTH_I2S_LRCLK_SHIFT)) |                                     // I2S LR_CLK drive dissabled (codec is slave)
+                      (SGTL5000_PAD_STRENGTH_I2S_SCLK_MASK & (0x0 << SGTL5000_PAD_STRENGTH_I2S_SCLK_SHIFT)) |                                       // I2S SCLK drive dissabled (codec is slave)
+                      (SGTL5000_PAD_STRENGTH_I2S_DOUT_MASK & (0x1 << SGTL5000_PAD_STRENGTH_I2S_DOUT_SHIFT)) |                                       // I2S DOUT drive @ 4.02mA
+                      (SGTL5000_PAD_STRENGTH_CTRL_DATA_MASK & (0x3 << SGTL5000_PAD_STRENGTH_CTRL_DATA_SHIFT)) |                                     // I2C DATA drive @ 12.05mA.
+                      (SGTL5000_PAD_STRENGTH_CTRL_CLK_MASK & (0x3 << SGTL5000_PAD_STRENGTH_CTRL_CLK_SHIFT))                                         // I2C CLOCK drive @ 12.05mA.
+                  ))
+    )return -1;
+    if(
+        write_i2c(SGTL5000_CLK_CTRL,(
+                      (SGTL5000_CLK_CTRL_RATE_MODE_MASK & (0x0 <<  SGTL5000_CLK_CTRL_RATE_MODE_SHIFT)) |                                            // Sample rate mode Fs = SYS_FS
+                      (SGTL5000_CLK_CTRL_SYS_FS_MASK & (0x02 << SGTL5000_CLK_CTRL_SYS_FS_SHIFT)) |                                                  // Set SYS_FS (sampling rate depending on mode) @ 48Khz
+                      (SGTL5000_CLK_CTRL_MCLK_FREQ_MASK & (0x0 << SGTL5000_CLK_CTRL_MCLK_FREQ_SHIFT))                                               // Set SYS MCLK @ 256*Fs
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_I2S_CTRL,(
+                      (SGTL5000_I2S_CTRL_SCLKFREQ_MASK & (0x1 << SGTL5000_I2S_CTRL_SCLKFREQ_SHIFT)) |                                               // I2S SCLK 32*Fs
+                      (SGTL5000_I2S_CTRL_MS_MASK & (0x0 << SGTL5000_I2S_CTRL_MS_SHIFT)) |                                                           // Slave
+                      (SGTL5000_I2S_CTRL_SCLK_INV_MASK & (0x0 << SGTL5000_I2S_CTRL_SCLK_INV_SHIFT)) |                                               // Data on riseing edge
+                      (SGTL5000_I2S_CTRL_DLEN_MASK & (0x3 << SGTL5000_I2S_CTRL_DLEN_SHIFT)) |                                                       // Data 16bits
+                      (SGTL5000_I2S_CTRL_MODE_MASK & (0x0 << SGTL5000_I2S_CTRL_MODE_SHIFT)) |                                                       // I2S mode
+                      (SGTL5000_I2S_CTRL_LRALIGN_MASK & (0x0 << SGTL5000_I2S_CTRL_LRALIGN_SHIFT)) |                                                 // I2S format
+                      (SGTL5000_I2S_CTRL_LRPOL_MASK & (0x0 << SGTL5000_I2S_CTRL_LRPOL_SHIFT))                                                       // Left word on LRCLK low
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_SSS_CTRL,(
+                      (SGTL5000_SSS_CTRL_DAP_MIX_LRSWAP_MASK & (0x0 << SGTL5000_SSS_CTRL_DAP_MIX_LRSWAP_SHIFT)) |                                   // Define all inputs un-swapped
+                      (SGTL5000_SSS_CTRL_DAP_LRSWAP_MASK & (0x0 << SGTL5000_SSS_CTRL_DAP_LRSWAP_SHIFT)) |
+                      (SGTL5000_SSS_CTRL_DAC_LRSWAP_MASK & (0x0 << SGTL5000_SSS_CTRL_DAC_LRSWAP_SHIFT)) |
+                      (SGTL5000_SSS_CTRL_I2S_LRSWAP_MASK & (0x0 << SGTL5000_SSS_CTRL_I2S_LRSWAP_SHIFT)) |
+                      (SGTL5000_SSS_CTRL_DAP_MIX_SELECT_MASK & (0x0 << SGTL5000_SSS_CTRL_DAP_MIX_SELECT_SHIFT)) |                                   // DAP mixer source ADC
+                      (SGTL5000_SSS_CTRL_DAP_SELECT_MASK & (0x0 << SGTL5000_SSS_CTRL_DAP_SELECT_SHIFT)) |                                           // DAP Input source ADC
+                      (SGTL5000_SSS_CTRL_DAC_SELECT_MASK & (0x1 << SGTL5000_SSS_CTRL_DAC_SELECT_SHIFT)) |                                           // DAC Input source I2SIN
+                      (SGTL5000_SSS_CTRL_I2S_SELECT_MASK & (0x0 << SGTL5000_SSS_CTRL_I2S_SELECT_SHIFT))                                             // I2SOUT source ADC
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_ADCDAC_CTRL,(
+                      (SGTL5000_ADCDAC_CTRL_VOL_RAMP_EN_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_VOL_RAMP_EN_SHIFT)) |                                   // Disable Vol ramp
+                      (SGTL5000_ADCDAC_CTRL_VOL_EXPO_RAMP_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_VOL_EXPO_RAMP_SHIFT)) |
+                      (SGTL5000_ADCDAC_CTRL_DAC_MUTE_RIGHT_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_DAC_MUTE_RIGHT_SHIFT)) |
+                      (SGTL5000_ADCDAC_CTRL_DAC_MUTE_LEFT_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_DAC_MUTE_LEFT_SHIFT)) |
+                      (SGTL5000_ADCDAC_CTRL_ADC_HPF_FREEZE_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_ADC_HPF_FREEZE_SHIFT)) |                             // ADC HPF normal operation
+                      (SGTL5000_ADCDAC_CTRL_ADC_HPF_BYPASS_MASK & (0x0 << SGTL5000_ADCDAC_CTRL_ADC_HPF_BYPASS_SHIFT))                               // ADC HPF enabled
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_DAC_VOL,(
+                      (SGTL5000_DAC_VOL_DAC_VOL_RIGHT_MASK & (0x3C << SGTL5000_DAC_VOL_DAC_VOL_RIGHT_SHIFT)) |                                      // DAC R Vol 0dB
+                      (SGTL5000_DAC_VOL_DAC_VOL_LEFT_MASK & (0x3C << SGTL5000_DAC_VOL_DAC_VOL_LEFT_SHIFT))                                          // DAC L Vol 0dB
+                  ))
+    ) return -1;
+    if(
+        write_i2c(SGTL5000_ANA_HP_CTRL,(
+                      (SGTL5000_ANA_HP_CTRL_HP_VOL_RIGHT_MASK & (0x7F << SGTL5000_ANA_HP_CTRL_HP_VOL_RIGHT_SHIFT)) |                                // HP Vol set minimum
+                      (SGTL5000_ANA_HP_CTRL_HP_VOL_LEFT_MASK & (0x7F << SGTL5000_ANA_HP_CTRL_HP_VOL_LEFT_SHIFT))
+                  ))
+    ) return -1;
+    if(modify_i2c(SGTL5000_ANA_CTRL, 0x0, SGTL5000_ANA_CTRL_MUTE_LO_MASK)) return -1;                                                               // Un-mute Lineout
+    if(modify_i2c(SGTL5000_ANA_CTRL, 0x0, SGTL5000_ANA_CTRL_MUTE_HP_MASK)) return -1;                                                               // Un-mute HP
+    if(modify_i2c(SGTL5000_ANA_CTRL, 0x0, SGTL5000_ANA_CTRL_MUTE_ADC_MASK)) return -1;                                                              // Un-mute ADC pre-amp
+    if(modify_i2c(SGTL5000_DIG_POWER, 0x1, SGTL5000_DIG_POWER_I2S_OUT_POWERUP_MASK)) return -1;                                                     // I2S DOUT enable
+    if(modify_i2c(SGTL5000_DIG_POWER, 0x1, SGTL5000_DIG_POWER_I2S_IN_POWERUP_MASK)) return -1;                                                      // I2S DIN enable
+
+    return 0;
 }
 
 
@@ -394,7 +443,7 @@
     return 0;
 }
 
-void SGTL5000::attach_SYNC_NB(uint32_t user_ISR, uint32_t irq_pri, IRQn sw_irq)
+int32_t SGTL5000::attach_SYNC_NB(uint32_t user_ISR, uint32_t irq_pri, IRQn sw_irq)
 {
     SGTL5000::SYNC_swIRQ = sw_irq;                                                                      // Assign ISR address and enable users IRQ
     NVIC_SetVector(SGTL5000::SYNC_swIRQ, user_ISR);
@@ -402,17 +451,22 @@
     NVIC_EnableIRQ(SGTL5000::SYNC_swIRQ);
     SYNC_attach_type = 1;
     SYNC_attached = true;
+    return 0;
 }
 
-void SGTL5000::detach_SYNC(void)
+int32_t SGTL5000::detach_SYNC(void)
 {
-    stop_SYNC();
-    SYNC_attached = false;
+    if(SYNC_attached) {
+        stop_SYNC();
+        SYNC_attached = false;
+    }
+    return 0;
 }
 
 int32_t SGTL5000::start_SYNC(uint32_t BufRX_L_safe, uint32_t BufRX_R_safe, uint32_t BufTX_L_safe, uint32_t BufTX_R_safe,
                              uint32_t block_size, bool _packed_RX, bool _packed_TX, bool _RX_shift, bool _TX_shift, uint32_t _RX_DMAch, uint32_t _TX_DMAch, uint32_t DMA_irq_pri)
 {
+    if(!codec_configured) return -1;
     if(!SYNC_attached && !SYNC_attach_type) return -1;                                                  // Check we have a handler if using callback
     if(SYNC_run || TX_run || RX_run ) return -1;                                                        // Check if i2s is already started
     if(_RX_DMAch > 15 || _TX_DMAch > 15) return -1;                                                     // Sanity check DMAMUX channels
@@ -472,13 +526,15 @@
     return 0;
 }
 
-void SGTL5000::stop_SYNC(void)
+int32_t SGTL5000::stop_SYNC(void)
 {
+    if(!codec_configured) return -1;
     I2S0->TCSR &= ~I2S_TCSR_FRDE_MASK;                                                                  // Disable TX FIFO IRQs based on watermark
     I2S0->RCSR &= ~I2S_RCSR_FRDE_MASK;                                                                  // Disable RX FIFO IRQs based on watermark
     I2S0->TCR3 = (I2S0->TCR3 & ~I2S_TCR3_TCE_MASK) | I2S_TCR3_TCE(0);                                   // Disable TX channels.
     I2S0->RCR3 = (I2S0->RCR3 & ~I2S_RCR3_RCE_MASK) | I2S_RCR3_RCE(0);                                   // Disable RX channels.
     SYNC_run = false;
+    return 0;
 }
 
 void SGTL5000::rx_I2S_ISR(void)
@@ -623,7 +679,7 @@
     return 0;
 }
 
-void SGTL5000::attach_TX_NB(uint32_t user_ISR, uint32_t irq_pri, IRQn sw_irq)
+int32_t SGTL5000::attach_TX_NB(uint32_t user_ISR, uint32_t irq_pri, IRQn sw_irq)
 {
     SGTL5000::TX_swIRQ = sw_irq;                                                                        // Assign ISR address and enable users IRQ
     NVIC_SetVector(SGTL5000::TX_swIRQ, user_ISR);
@@ -631,17 +687,22 @@
     NVIC_EnableIRQ(SGTL5000::TX_swIRQ);
     TX_attach_type = 1;
     TX_attached = true;
+    return 0;
 }
 
-void SGTL5000::detach_TX(void)
+int32_t SGTL5000::detach_TX(void)
 {
-    SGTL5000::stop_TX();
-    TX_attached = false;
+    if(TX_attached) {
+        SGTL5000::stop_TX();
+        TX_attached = false;
+    }
+    return 0;
 }
 
 int32_t SGTL5000::start_TX(uint32_t BufTX_L_safe, uint32_t BufTX_R_safe,
                            uint32_t block_size, bool _packed_TX, bool _TX_shift, uint32_t _TX_DMAch, uint32_t DMA_irq_pri)
 {
+    if(!codec_configured) return -1;
     if(!TX_attached && !TX_attach_type) return -1;                                                      // Check we have a handler if using callback
     if(SYNC_run || TX_run) return -1;                                                                   // Check if i2s is already started on tx
     if(_TX_DMAch > 15) return -1;                                                                       // Sanity check DMAMUX channels
@@ -674,12 +735,13 @@
     return 0;
 }
 
-void SGTL5000::stop_TX(void)
+int32_t SGTL5000::stop_TX(void)
 {
-
+    if(!codec_configured) return -1;
     I2S0->TCSR &= ~I2S_TCSR_FRDE_MASK;                                                                  // Disable TX FIFO IRQs based on watermark
     I2S0->TCR3 = (I2S0->TCR3 & ~I2S_TCR3_TCE_MASK) | I2S_TCR3_TCE(0);                                   // Disable TX channels.
     TX_run = false;
+    return 0;
 }
 
 void SGTL5000::tx_dma_ISR_NB(void)
@@ -763,7 +825,7 @@
     return 0;
 }
 
-void SGTL5000::attach_RX_NB(uint32_t user_ISR, uint32_t irq_pri, IRQn sw_irq)
+int32_t SGTL5000::attach_RX_NB(uint32_t user_ISR, uint32_t irq_pri, IRQn sw_irq)
 {
     SGTL5000::RX_swIRQ = sw_irq;                                                                        // Assign ISR address and enable users IRQ
     NVIC_SetVector(SGTL5000::RX_swIRQ, user_ISR);
@@ -771,17 +833,22 @@
     NVIC_EnableIRQ(SGTL5000::RX_swIRQ);
     RX_attach_type = 1;
     RX_attached = true;
+    return 0;
 }
 
-void SGTL5000::detach_RX(void)
+int32_t SGTL5000::detach_RX(void)
 {
-    SGTL5000::stop_RX();
-    RX_attached = false;
+    if(RX_attached) {
+        SGTL5000::stop_RX();
+        RX_attached = false;
+    }
+    return 0;
 }
 
 int32_t SGTL5000::start_RX(uint32_t BufRX_L_safe, uint32_t BufRX_R_safe,
                            uint32_t block_size, bool _packed_RX, bool _RX_shift, uint32_t _RX_DMAch, uint32_t DMA_irq_pri)
 {
+    if(!codec_configured) return -1;
     if(!RX_attached && !RX_attach_type) return -1;                                                      // Check we have a handler if using callback
     if(SYNC_run || RX_run) return -1;                                                                   // Check if i2s is already started on rx
     if(_RX_DMAch > 15) return -1;                                                                       // Sanity check DMAMUX channels
@@ -814,12 +881,13 @@
     return 0;
 }
 
-void SGTL5000::stop_RX(void)
+int32_t SGTL5000::stop_RX(void)
 {
-
+    if(!codec_configured) return -1;
     I2S0->RCSR &= ~I2S_RCSR_FRDE_MASK;                                                                  // Disable RX FIFO IRQs based on watermark
     I2S0->RCR3 = (I2S0->RCR3 & ~I2S_RCR3_RCE_MASK) | I2S_RCR3_RCE(0);                                   // Disable RX channels.
     RX_run = false;
+    return 0;
 }
 
 void SGTL5000::rx_dma_ISR_NB(void)
@@ -1026,7 +1094,7 @@
     }
 }
 
-uint32_t SGTL5000::read_debug(uint32_t index)
+int32_t SGTL5000::read_debug(uint32_t index)
 {
     //SGTL5000::debug[0] = packed_RX;
     //SGTL5000::debug[1] = packed_TX;