aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/codecs/ab3550.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/ab3550.c')
-rwxr-xr-xsound/soc/codecs/ab3550.c1652
1 files changed, 1046 insertions, 606 deletions
diff --git a/sound/soc/codecs/ab3550.c b/sound/soc/codecs/ab3550.c
index 5ee08672792..de51ca963c2 100755
--- a/sound/soc/codecs/ab3550.c
+++ b/sound/soc/codecs/ab3550.c
@@ -1,7 +1,9 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
- * Author: Xie Xiaolei <xie.xiaolei@etericsson.com>
+ * Author: Xie Xiaolei <xie.xiaolei@etericsson.com>,
+ * Ola Lilja ola.o.lilja@stericsson.com,
+ * Roger Nilsson roger.xr.nilsson@stericsson.com
* for ST-Ericsson.
*
* License terms:
@@ -25,34 +27,102 @@
#include <sound/soc-dapm.h>
#include <linux/mfd/abx500.h>
#include <linux/bitops.h>
+#include <asm/atomic.h>
#include "ab3550.h"
-#include "../u8500/u8500_pcm.h"
-#include "../u8500/u8500_msp_dai.h"
#define I2C_BANK 0
static struct device *ab3550_dev = NULL;
+// Registers -----------------------------------------------------------------------------------------------------------------------
+
+struct ab3550_register {
+ const char* name;
+ u8 address;
+};
+
+struct ab3550_register ab3550_registers[] = {
+ {"IDX_MIC_BIAS1", 0x31},
+ {"IDX_MIC_BIAS2", 0x32},
+ {"IDX_MIC_BIAS2_VAD", 0x33},
+ {"IDX_MIC1_GAIN", 0x34},
+ {"IDX_MIC2_GAIN", 0x35},
+ {"IDX_MIC1_INPUT_SELECT", 0x36},
+ {"IDX_MIC2_INPUT_SELECT", 0x37},
+ {"IDX_MIC1_VMID_SELECT", 0x38},
+ {"IDX_MIC2_VMID_SELECT", 0x39},
+ {"IDX_MIC2_TO_MIC1", 0x3A},
+ {"IDX_ANALOG_LOOP_PGA1", 0x3B},
+ {"IDX_ANALOG_LOOP_PGA2", 0x3C},
+ {"IDX_APGA_VMID_SELECT", 0x3D},
+ {"IDX_EAR", 0x3E},
+ {"IDX_AUXO1", 0x3F},
+ {"IDX_AUXO2", 0x40},
+ {"IDX_AUXO_PWR_MODE", 0x41},
+ {"IDX_OFFSET_CANCEL", 0x42},
+ {"IDX_SPKR", 0x43},
+ {"IDX_LINE1", 0x44},
+ {"IDX_LINE2", 0x45},
+ {"IDX_APGA1_ADDER", 0x46},
+ {"IDX_APGA2_ADDER", 0x47},
+ {"IDX_EAR_ADDER", 0x48},
+ {"IDX_AUXO1_ADDER", 0x49},
+ {"IDX_AUXO2_ADDER", 0x4A},
+ {"IDX_SPKR_ADDER", 0x4B},
+ {"IDX_LINE1_ADDER", 0x4C},
+ {"IDX_LINE2_ADDER", 0x4D},
+ {"IDX_EAR_TO_MIC2", 0x4E},
+ {"IDX_SPKR_TO_MIC2", 0x4F},
+ {"IDX_NEGATIVE_CHARGE_PUMP", 0x50},
+ {"IDX_TX1", 0x51},
+ {"IDX_TX2", 0x52},
+ {"IDX_RX1", 0x53},
+ {"IDX_RX2", 0x54},
+ {"IDX_RX3", 0x55},
+ {"IDX_TX_DIGITAL_PGA1", 0X56},
+ {"IDX_TX_DIGITAL_PGA2", 0X57},
+ {"IDX_RX1_DIGITAL_PGA", 0x58},
+ {"IDX_RX2_DIGITAL_PGA", 0x59},
+ {"IDX_RX3_DIGITAL_PGA", 0x5A},
+ {"IDX_SIDETONE1_PGA", 0x5B},
+ {"IDX_SIDETONE2_PGA", 0x5C},
+ {"IDX_CLOCK", 0x5D},
+ {"IDX_INTERFACE0", 0x5E},
+ {"IDX_INTERFACE1", 0x60},
+ {"IDX_INTERFACE0_DATA", 0x5F},
+ {"IDX_INTERFACE1_DATA", 0x61},
+ {"IDX_INTERFACE_LOOP", 0x62},
+ {"IDX_INTERFACE_SWAP", 0x63}
+};
+
#define SET_REG(reg, val) abx500_set_register_interruptible( \
- ab3550_dev, I2C_BANK, (reg), (val))
+ ab3550_dev, I2C_BANK, (reg), (val)); \
+ printk(KERN_DEBUG "REG = 0x%02x, VAL = 0x%02x.\n", (reg), (val))
-#define MASK_SET_REG(reg, mask, val) \
- abx500_mask_and_set_register_interruptible( \
- ab3550_dev, I2C_BANK, (reg), (mask), (val))
+#define MASK_SET_REG(reg, mask, val) abx500_mask_and_set_register_interruptible( \
+ ab3550_dev, I2C_BANK, (reg), (mask), (val)); \
+ printk(KERN_DEBUG "REG = 0x%02x, MASK = 0x%02x, VAL = 0x%02x.\n", (reg), (mask), (val))
#define GET_REG(reg, val) abx500_get_register_interruptible( \
ab3550_dev, I2C_BANK, (reg), (val))
-#define AB3550_SUPPORTED_RATE (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+static enum enum_register outamp_indices[] = {
+ IDX_LINE1, IDX_LINE2, IDX_SPKR, IDX_EAR, IDX_AUXO1, IDX_AUXO2
+};
-#define AB3550_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S24_LE)
+static enum enum_control outamp_gain_controls[] = {
+ IDX_LINE1_Gain, IDX_LINE2_Gain, IDX_SPKR_Gain, IDX_EAR_Gain, IDX_AUXO1_Gain, IDX_AUXO2_Gain
+};
-static const u8 outamp_reg[] = {
- LINE1, LINE2, SPKR, EAR, AUXO1, AUXO2
+static enum enum_register outamp_adder_indices[] = {
+ IDX_LINE1_ADDER, IDX_LINE2_ADDER, IDX_SPKR_ADDER, IDX_EAR_ADDER, IDX_AUXO1_ADDER, IDX_AUXO2_ADDER
};
+
+//static const char* outamp_name[] = {
+// "LINE1", "LINE2", "SPKR", "EAR", "AUXO1", "AUXO2"
+//};
+
static const u8 outamp_gain_shift[] = {
LINEx_GAIN_SHIFT, LINEx_GAIN_SHIFT,
SPKR_GAIN_SHIFT, EAR_GAIN_SHIFT,
@@ -74,402 +144,268 @@ static const u8 outamp_pwr_mask[] = {
AUXOx_PWR_MASK, AUXOx_PWR_MASK
};
-static int ab3550_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai* dai);
-static int ab3550_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai* dai);
-static void ab3550_pcm_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai* dai);
+struct codec_dai_private {
+ atomic_t substream_count;
+} privates[] = {
+ {ATOMIC_INIT(0)},
+ {ATOMIC_INIT(0)},
+};
-static int ab3550_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
- unsigned int freq, int dir);
-static int ab3550_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt);
+/* TODO: Add a clock use count.
+ Turn off the clock is there is no audio activity in the system.
+ */
-struct snd_soc_dai ab3550_codec_dai[] = {
- {
- .name = "ab3550_0",
- .playback = {
- .stream_name = "ab3550_0",
- .channels_min = 2,
- .channels_max = 2,
- .rates = AB3550_SUPPORTED_RATE,
- .formats = AB3550_SUPPORTED_FMT,
- },
- .capture = {
- .stream_name = "ab3550_0",
- .channels_min = 2,
- .channels_max = 2,
- .rates = AB3550_SUPPORTED_RATE,
- .formats = AB3550_SUPPORTED_FMT,
- },
- .ops = {
- .prepare = ab3550_pcm_prepare,
- .hw_params = ab3550_pcm_hw_params,
- .shutdown = ab3550_pcm_shutdown,
- .set_sysclk = ab3550_set_dai_sysclk,
- .set_fmt = ab3550_set_dai_fmt
- },
- },
- {
- .name = "ab3550_1",
- .playback = {
- .stream_name = "ab3550_1",
- .channels_min = 2,
- .channels_max = 2,
- .rates = AB3550_SUPPORTED_RATE,
- .formats = AB3550_SUPPORTED_FMT,
- },
- .capture = {
- .stream_name = "ab3550_1",
- .channels_min = 2,
- .channels_max = 2,
- .rates = AB3550_SUPPORTED_RATE,
- .formats = AB3550_SUPPORTED_FMT,
- },
- .ops = {
- .prepare = ab3550_pcm_prepare,
- .hw_params = ab3550_pcm_hw_params,
- .shutdown = ab3550_pcm_shutdown,
- .set_sysclk = ab3550_set_dai_sysclk,
- .set_fmt = ab3550_set_dai_fmt
- },
- }
-};
-EXPORT_SYMBOL_GPL(ab3550_codec_dai);
+
+
+// Controls -----------------------------------------------------------------------------------------------------------------------
struct ab3550_control {
const char *name;
u8 value;
- int is_enum;
+ enum enum_register reg_idx;
+ u8 reg_mask;
+ u8 reg_shift;
+ bool is_enum;
+ bool changed;
};
-/* When AB3550 starts up, these registers are initialized to 0 */
struct ab3550_control ab3550_ctl[] = {
- {"RX2 Select", 0, 1},
- {"DAC1 Routing", 0, 0},
- {"DAC2 Routing", 0, 0},
- {"DAC3 Routing", 0, 0},
- {"MIC1 Input Select", 0, 0},
- {"MIC2 Input Select", 0, 0},
- {"I2S0 TX", 0, 1},
- {"I2S1 TX", 0, 1},
- {"APGA1 Source", 0, 1},
- {"APGA2 Source", 0, 1},
- {"APGA1 Destination", 0, 0},
- {"APGA2 Destination", 0, 0},
- {"DAC1 Side Tone", 0, 1},
- {"DAC2 Side Tone", 0, 1},
- {"RX-DPGA1 Gain", 0x3D, 0},
- {"RX-DPGA2 Gain", 0x3D, 0},
- {"RX-DPGA3 Gain", 0x3D, 0},
- {"LINE1 Gain", 0x0A, 0},
- {"LINE2 Gain", 0x0A, 0},
- {"SPKR Gain", 0x0A, 0},
- {"EAR Gain", 0x0A, 0},
- {"AUXO1 Gain", 0x0A, 0},
- {"AUXO2 Gain", 0x0A, 0},
- {"MIC1 Gain", 0, 0},
- {"MIC2 Gain", 0, 0},
- {"TX-DPGA1 Gain", 0, 0},
- {"TX-DPGA2 Gain", 0, 0},
- {"ST-PGA1 Gain", 0, 0},
- {"ST-PGA2 Gain", 0, 0},
- {"APGA1 Gain", 0, 0},
- {"APGA2 Gain", 0, 0},
- {"DAC1 Power Mode", 0, 1},
- {"DAC2 Power Mode", 0, 1},
- {"DAC3 Power Mode", 0, 1},
- {"EAR Power Mode", 0, 1},
- {"AUXO Power Mode", 0, 1},
- {"LINE1 Inverse", 0, 0},
- {"LINE2 Inverse", 0, 0},
- {"AUXO1 Inverse", 0, 0},
- {"AUXO2 Inverse", 0, 0},
- {"AUXO1 Pulldown", 0, 0},
- {"AUXO2 Pulldown", 0, 0},
- {"VMID1", 0, 0},
- {"VMID2", 0, 0},
- {"MIC1-1 MBias", 0, 1},
- {"MIC1-2 MBias", 0, 1},
- {"MIC2-1 MBias", 0, 1},
- {"MIC2-2 MBias", 0, 1},
- {"MBIAS1 HiZ Option", 0, 1},
- {"MBIAS2 HiZ Option", 0, 1},
- {"MBIAS2 Output Voltage", 0, 1},
- {"MBIAS2 Internal Resistor", 0, 1},
- {"MIC1 Input Impedance", 0, 1},
- {"MIC2 Input Impedance", 0, 1},
- {"TX1 HP Filter", 0, 1},
- {"TX2 HP Filter", 0, 1},
- {"LINEIN1 Pre-charge", 0, 0},
- {"LINEIN2 Pre-charge", 0, 0},
- {"MIC1P1 Pre-charge", 0, 0},
- {"MIC1P2 Pre-charge", 0, 0},
- {"MIC1N1 Pre-charge", 0, 0},
- {"MIC1N2 Pre-charge", 0, 0},
- {"MIC2P1 Pre-charge", 0, 0},
- {"MIC2P2 Pre-charge", 0, 0},
- {"MIC2N1 Pre-charge", 0, 0},
- {"MIC2N2 Pre-charge", 0, 0},
- {"ST1 HP Filter", 0, 1},
- {"ST2 HP Filter", 0, 1},
- {"I2S0 Word Length", 0, 1},
- {"I2S1 Word Length", 0, 1},
- {"I2S0 Mode", 0, 1},
- {"I2S1 Mode", 0, 1},
- {"I2S0 Tri-state", 0, 1},
- {"I2S1 Tri-state", 0, 1},
- {"I2S0 Pulldown", 0, 1},
- {"I2S1 Pulldown", 0, 1},
- {"I2S0 Sample Rate", 0, 1},
- {"I2S1 Sample Rate", 0, 1},
- {"Interface Loop", 0, 0},
- {"Interface Swap", 0, 0},
- {"Commit", 0, 0},
+// name value reg_idx reg_mask reg_shift is_enum changed
+ {"RX2 Select", 0, IDX_RX2, RX2_IF_SELECT_MASK, RX2_IF_SELECT_SHIFT,true, false},
+ {"DAC1 Routing", 0x05, IDX_RX1, DACx_PWR_MASK, DACx_PWR_SHIFT, false, false}, // DAC1 -> AUXO1, SPKR
+ {"DAC2 Routing", 0x06, IDX_RX2, DACx_PWR_MASK, DACx_PWR_SHIFT, false, false}, // DAC2 -> AUXO1, SPKR
+ {"DAC3 Routing", 0x00, IDX_RX3, DACx_PWR_MASK, DACx_PWR_SHIFT, false, false},
+ {"MIC1 Input Select", 0x30, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC2 Input Select", 0x00, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"I2S0 Input Select", 0x11, IDX_TX1, 0x00, 0x00, true, false},
+ {"I2S1 Input Select", 0x22, IDX_TX2, 0x00, 0x00, true, false},
+ {"APGA1 Source", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"APGA2 Source", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"APGA1 Destination", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"APGA2 Destination", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"DAC1 Side Tone", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"DAC2 Side Tone", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"RX-DPGA1 Gain", 0x3A, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"RX-DPGA2 Gain", 0x3A, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"RX-DPGA3 Gain", 0x00, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"LINE1 Gain", 0x4, IDX_UNKNOWN, 0x00, 0x00, false, false}, // -6 dB
+ {"LINE2 Gain", 0x4, IDX_UNKNOWN, 0x00, 0x00, false, false}, // -6 dB
+ {"SPKR Gain", 0x4, IDX_UNKNOWN, 0x00, 0x00, false, false}, // -6 dB
+ {"EAR Gain", 0x4, IDX_UNKNOWN, 0x00, 0x00, false, false}, // -6 dB
+ {"AUXO1 Gain", 0x4, IDX_UNKNOWN, 0x00, 0x00, false, false}, // -6 dB
+ {"AUXO2 Gain", 0x4, IDX_UNKNOWN, 0x00, 0x00, false, false}, // -6 dB
+ {"MIC1 Gain", 0x2, IDX_MIC1_GAIN, MICx_GAIN_MASK, MICx_GAIN_SHIFT, false, false},
+ {"MIC2 Gain", 0x2, IDX_MIC2_GAIN, MICx_GAIN_MASK, MICx_GAIN_SHIFT, false, false},
+ {"TX-DPGA1 Gain", 0x06, IDX_TX_DIGITAL_PGA1, TXDPGAx_MASK, TXDPGAx_SHIFT, false, false},
+ {"TX-DPGA2 Gain", 0x06, IDX_TX_DIGITAL_PGA2, TXDPGAx_MASK, TXDPGAx_SHIFT, false, false},
+ {"ST-PGA1 Gain", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"ST-PGA2 Gain", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"APGA1 Gain", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"APGA2 Gain", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"DAC1 Power Mode", 0x0, IDX_UNKNOWN, 0x00, 0x00, true, false}, // 100%
+ {"DAC2 Power Mode", 0x0, IDX_UNKNOWN, 0x00, 0x00, true, false}, // 100%
+ {"DAC3 Power Mode", 0x3, IDX_UNKNOWN, 0x00, 0x00, true, false}, // Do not use
+ {"EAR Power Mode", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"AUXO Power Mode", 0x4, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"LINE1 Inverse", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"LINE2 Inverse", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"AUXO1 Inverse", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"AUXO2 Inverse", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"AUXO1 Pulldown", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"AUXO2 Pulldown", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"VMID1", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"VMID2", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC1 MBias", 0x01, IDX_UNKNOWN, 0x00, 0x00, true, false}, // MBias 1 On
+ {"MIC2 MBias", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"MBIAS1 HiZ Option", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"MBIAS2 HiZ Option", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"MBIAS2 Output Voltage", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"MBIAS2 Internal Resistor",0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"MIC1 Input Impedance", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"MIC2 Input Impedance", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"TX1 HP Filter", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"TX2 HP Filter", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"LINEIN1 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"LINEIN2 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC1P1 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC1P2 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC1N1 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC1N2 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC2P1 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC2P2 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC2N1 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"MIC2N2 Pre-charge", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"ST1 HP Filter", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"ST2 HP Filter", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S0 Word Length", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S1 Word Length", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S0 Mode", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S1 Mode", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S0 Tri-state", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S1 Tri-state", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S0 Pulldown", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S1 Pulldown", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S0 Sample Rate", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"I2S1 Sample Rate", 0, IDX_UNKNOWN, 0x00, 0x00, true, false},
+ {"Interface Loop", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"Interface Swap", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"Voice Call", 0, IDX_UNKNOWN, 0x00, 0x00, false, false},
+ {"Commit", 0, IDX_UNKNOWN, 0x00, 0x00, false, false}
};
/* control No. 0 correpsonds to bit No. 0 in this array.
If a control value has been changed, but not commited
to the AB3550. Its corresponding bit is set.
*/
-static unsigned long control_changed[] = {
- 0, 0, 0, 0
-};
+//static unsigned long changed_controls[BIT_WORD(ARRAY_SIZE(ab3550_ctl)) + 1];
static const char *enum_rx2_select[] = {"I2S0", "I2S1"};
-static const char *enum_i2s_tx[] =
-{"TX1", "TX2", "tri-state", "mute"};
-
-static const char *enum_apga1_source[] =
-{"None", "LINEIN1", "MIC1", "MIC2"};
-
-static const char *enum_apga2_source[] =
-{"None", "LINEIN2", "MIC1", "MIC2"};
-
-static const char *enum_dac1_side_tone[] =
-{"None", "TX1", "TX2"};
-
-static const char *enum_dac1_power_mode[] =
-{"100%", "75%", "50%"};
-
-static const char *enum_ear_power_mode[] =
-{"100%", "75%"};
-
-static const char *enum_auxo_power_mode[] =
-{"100%", "75%", "50%", "25%"};
-
-static const char *enum_mic_bias_connection[] =
-{"MIC Bias 1", "MIC Bias 2"};
-
-static const char *enum_mbias1_hiz_option[] =
-{"GND", "HiZ"};
-
-static const char *enum_mbias2_output_voltage[] =
-{"2.0v", "2.2v"};
-
-static const char *enum_mbias2_internal_resistor[] =
-{"connected", "bypassed"};
-
-static const char *enum_mic1_input_impedance[] =
-{"12.5 kohm", "25 kohm", "50 kohm"};
-
-static const char *enum_tx1_hp_filter[] =
-{"HP3", "HP1", "bypass"};
-
-static const char *enum_i2s_word_length[] =
-{"16 bits", "24 bits"};
-
-static const char *enum_i2s_mode[] =
-{"Master Mode", "Slave Mode"};
-
-static const char *enum_i2s_tristate[] =
-{"Normal", "Tri-state"};
-
-static const char *enum_i2s_pulldown[] =
-{"disconnected", "connected"};
-
-static const char *enum_i2s_sample_rate[] =
-{"8 kHz", "16 kHz", "44.1 kHz", "48 kHz"};
-
-
-static struct soc_enum ab3550_enum[] = {
- /* RX2 Select */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_rx2_select), enum_rx2_select),
- /* I2S0 TX */
- SOC_ENUM_DOUBLE(0, 0, 4, ARRAY_SIZE(enum_i2s_tx), enum_i2s_tx),
- /* I2S1 TX */
- SOC_ENUM_DOUBLE(0, 0, 4, ARRAY_SIZE(enum_i2s_tx), enum_i2s_tx),
- /* APGA1 Source */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_apga1_source),
- enum_apga1_source),
- /* APGA2 Source */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_apga2_source),
- enum_apga2_source),
- /* DAC1 Side Tone */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac1_side_tone),
- enum_dac1_side_tone),
- /* DAC2 Side Tone */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac1_side_tone),
- enum_dac1_side_tone),
- /* DAC1 Power Mode */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac1_power_mode),
- enum_dac1_power_mode),
- /* DAC2 Power Mode */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac1_power_mode),
- enum_dac1_power_mode),
- /* DAC3 Power Mode */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac1_power_mode),
- enum_dac1_power_mode),
- /* EAR Power Mode */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_ear_power_mode),
- enum_ear_power_mode),
- /* AUXO Power Mode */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_auxo_power_mode),
- enum_auxo_power_mode),
- /* MIC Bias Connection */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mic_bias_connection),
- enum_mic_bias_connection),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mic_bias_connection),
- enum_mic_bias_connection),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mic_bias_connection),
- enum_mic_bias_connection),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mic_bias_connection),
- enum_mic_bias_connection),
- /* MBIAS1 HiZ Option */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias1_hiz_option),
- enum_mbias1_hiz_option),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias1_hiz_option),
- enum_mbias1_hiz_option),
- /* MBIAS2 Output voltage */
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias2_output_voltage),
- enum_mbias2_output_voltage),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias2_internal_resistor),
- enum_mbias2_internal_resistor),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mic1_input_impedance),
- enum_mic1_input_impedance),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mic1_input_impedance),
- enum_mic1_input_impedance),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_tx1_hp_filter),
- enum_tx1_hp_filter),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_tx1_hp_filter),
- enum_tx1_hp_filter),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_tx1_hp_filter),
- enum_tx1_hp_filter),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_tx1_hp_filter),
- enum_tx1_hp_filter),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_word_length),
- enum_i2s_word_length),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_word_length),
- enum_i2s_word_length),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_mode),
- enum_i2s_mode),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_mode),
- enum_i2s_mode),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_tristate),
- enum_i2s_tristate),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_tristate),
- enum_i2s_tristate),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_pulldown),
- enum_i2s_pulldown),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_pulldown),
- enum_i2s_pulldown),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_sample_rate),
- enum_i2s_sample_rate),
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_sample_rate),
- enum_i2s_sample_rate),
-
-};
+static const char *enum_i2s_input_select[] = {"tri-state", "MIC1", "MIC2", "mute"};
+static const char *enum_apga1_source[] = {"None", "LINEIN1", "MIC1", "MIC2"};
+static const char *enum_apga2_source[] = {"None", "LINEIN2", "MIC1", "MIC2"};
+static const char *enum_dac_side_tone[] = {"None", "TX1", "TX2"};
+static const char *enum_dac_power_mode[] = {"100%", "75%", "50%"};
+static const char *enum_ear_power_mode[] = {"100%", "75%"};
+static const char *enum_auxo_power_mode[] = {"100%", "75%", "50%", "25%"};
+static const char *enum_mbias[] = {"Off", "On"};
+static const char *enum_mbias_hiz_option[] = {"GND", "HiZ"};
+static const char *enum_mbias2_output_voltage[] = {"2.0v", "2.2v"};
+static const char *enum_mbias2_internal_resistor[] = {"connected", "bypassed"};
+static const char *enum_mic_input_impedance[] = {"12.5 kohm", "25 kohm", "50 kohm"};
+static const char *enum_hp_filter[] = {"HP3", "HP1", "bypass"};
+static const char *enum_i2s_word_length[] = {"16 bits", "24 bits"};
+static const char *enum_i2s_mode[] = {"Master Mode", "Slave Mode"};
+static const char *enum_i2s_tristate[] = {"Normal", "Tri-state"};
+static const char *enum_i2s_pulldown[] = {"disconnected", "connected"};
+static const char *enum_i2s_sample_rate[] = {"8 kHz", "16 kHz", "44.1 kHz", "48 kHz"};
+
+static struct soc_enum soc_enum_rx2_select = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_rx2_select), enum_rx2_select); // RX2 Select
+static struct soc_enum soc_enum_i2s0_input_select = SOC_ENUM_DOUBLE(0, 0, 4, ARRAY_SIZE(enum_i2s_input_select), enum_i2s_input_select); // I2S0 Input Select
+static struct soc_enum soc_enum_i2s1_input_select = SOC_ENUM_DOUBLE(0, 0, 4, ARRAY_SIZE(enum_i2s_input_select), enum_i2s_input_select); // I2S1 Input Select
+static struct soc_enum soc_enum_apga1_source = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_apga1_source), enum_apga1_source); // APGA1 Source
+static struct soc_enum soc_enum_apga2_source = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_apga2_source), enum_apga2_source); // APGA2 Source
+static struct soc_enum soc_enum_dac1_side_tone = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac_side_tone), enum_dac_side_tone); // DAC1 Side Tone
+static struct soc_enum soc_enum_dac2_side_tone = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac_side_tone), enum_dac_side_tone); // DAC2 Side Tone
+static struct soc_enum soc_enum_dac1_power_mode = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac_power_mode), enum_dac_power_mode); // DAC1 Power Mode
+static struct soc_enum soc_enum_dac2_power_mode = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac_power_mode), enum_dac_power_mode); // DAC2 Power Mode
+static struct soc_enum soc_enum_dac3_power_mode = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_dac_power_mode), enum_dac_power_mode); // DAC3 Power Mode
+static struct soc_enum soc_enum_ear_power_mode = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_ear_power_mode), enum_ear_power_mode); // EAR Power Mode
+static struct soc_enum soc_enum_auxo_power_mode = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_auxo_power_mode), enum_auxo_power_mode); // AUXO Power Mode
+static struct soc_enum soc_enum_mic1_mbias = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias), enum_mbias); // MIC Bias Connection
+static struct soc_enum soc_enum_mic2_mbias = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias), enum_mbias); // MIC Bias Connection
+static struct soc_enum soc_enum_mbias1_hiz_option = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias_hiz_option), enum_mbias_hiz_option); // MBIAS1 HiZ Option
+static struct soc_enum soc_enum_mbias2_hiz_option = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias_hiz_option), enum_mbias_hiz_option); // MBIAS1 HiZ Option
+static struct soc_enum soc_enum_mbias2_output_voltage = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias2_output_voltage), enum_mbias2_output_voltage); // MBIAS2 Output voltage
+static struct soc_enum soc_enum_mbias2_internal_resistor = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mbias2_internal_resistor), enum_mbias2_internal_resistor); //
+static struct soc_enum soc_enum_mic1_input_impedance = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mic_input_impedance), enum_mic_input_impedance); //
+static struct soc_enum soc_enum_mic2_input_impedance = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_mic_input_impedance), enum_mic_input_impedance); //
+static struct soc_enum soc_enum_tx1_hp_filter = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_hp_filter), enum_hp_filter); //
+static struct soc_enum soc_enum_tx2_hp_filter = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_hp_filter), enum_hp_filter); //
+static struct soc_enum soc_enum_st1_hp_filter = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_hp_filter), enum_hp_filter); //
+static struct soc_enum soc_enum_st2_hp_filter = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_hp_filter), enum_hp_filter); //
+static struct soc_enum soc_enum_i2s0_word_length = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_word_length), enum_i2s_word_length); //
+static struct soc_enum soc_enum_i2s1_word_length = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_word_length), enum_i2s_word_length); //
+static struct soc_enum soc_enum_i2s0_mode = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_mode), enum_i2s_mode); //
+static struct soc_enum soc_enum_i2s1_mode = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_mode), enum_i2s_mode); //
+static struct soc_enum soc_enum_i2s0_tristate = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_tristate), enum_i2s_tristate); //
+static struct soc_enum soc_enum_i2s1_tristate = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_tristate), enum_i2s_tristate); //
+static struct soc_enum soc_enum_i2s0_pulldown = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_pulldown), enum_i2s_pulldown); //
+static struct soc_enum soc_enum_i2s1_pulldown = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_pulldown), enum_i2s_pulldown); //
+static struct soc_enum soc_enum_i2s0_sample_rate = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_sample_rate), enum_i2s_sample_rate); //
+static struct soc_enum soc_enum_i2s1_sample_rate = SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(enum_i2s_sample_rate), enum_i2s_sample_rate); //
static struct snd_kcontrol_new ab3550_snd_controls[] = {
/* RX Routing */
- SOC_ENUM("RX2 Select", ab3550_enum[0]),
- SOC_SINGLE("DAC1 Routing", 0, 0, 0x3f, 0),
- SOC_SINGLE("DAC2 Routing", 0, 0, 0x3f, 0),
- SOC_SINGLE("DAC3 Routing", 0, 0, 0x3f, 0),
+ SOC_ENUM( "RX2 Select", soc_enum_rx2_select),
+ SOC_SINGLE( "DAC1 Routing", 0, 0, 0x3f, 0),
+ SOC_SINGLE( "DAC2 Routing", 0, 0, 0x3f, 0),
+ SOC_SINGLE( "DAC3 Routing", 0, 0, 0x3f, 0),
/* TX Routing */
- SOC_SINGLE("MIC1 Input Select", 0, 0, 0xff, 0),
- SOC_SINGLE("MIC2 Input Select", 0, 0, 0x3f, 0),
- SOC_ENUM("I2S0 TX", ab3550_enum[1]),
- SOC_ENUM("I2S1 TX", ab3550_enum[2]),
+ SOC_SINGLE( "MIC1 Input Select", 0, 0, 0xff, 0),
+ SOC_SINGLE( "MIC2 Input Select", 0, 0, 0x3f, 0),
+ SOC_ENUM( "I2S0 Input Select", soc_enum_i2s0_input_select),
+ SOC_ENUM( "I2S1 Input Select", soc_enum_i2s1_input_select),
/* Routing of Side Tone and Analop Loop */
- SOC_ENUM("APGA1 Source", ab3550_enum[3]),
- SOC_ENUM("APGA2 Source", ab3550_enum[4]),
- SOC_SINGLE("APGA1 Destination", 0, 0, 0x3f, 0),
- SOC_SINGLE("APGA2 Destination", 0, 0, 0x3f, 0),
- SOC_ENUM("DAC1 Side Tone", ab3550_enum[5]),
- SOC_ENUM("DAC2 Side Tone", ab3550_enum[5]),
+ SOC_ENUM( "APGA1 Source", soc_enum_apga1_source),
+ SOC_ENUM( "APGA2 Source", soc_enum_apga2_source),
+ SOC_SINGLE( "APGA1 Destination", 0, 0, 0x3f, 0),
+ SOC_SINGLE( "APGA2 Destination", 0, 0, 0x3f, 0),
+ SOC_ENUM( "DAC1 Side Tone", soc_enum_dac1_side_tone),
+ SOC_ENUM( "DAC2 Side Tone", soc_enum_dac2_side_tone),
/* RX Volume Control */
- SOC_SINGLE("RX-DPGA1 Gain", 0, 0, 66, 0),
- SOC_SINGLE("RX-DPGA2 Gain", 0, 0, 66, 0),
- SOC_SINGLE("RX-DPGA3 Gain", 0, 0, 66, 0),
- SOC_SINGLE("LINE1 Gain", 0, 0, 10, 0),
- SOC_SINGLE("LINE2 Gain", 0, 0, 10, 0),
- SOC_SINGLE("SPKR Gain", 0, 0, 22, 0),
- SOC_SINGLE("EAR Gain", 0, 0, 14, 0),
- SOC_SINGLE("AUXO1 Gain", 0, 0, 12, 0),
- SOC_SINGLE("AUXO2 Gain", 0, 0, 12, 0),
+ SOC_SINGLE( "RX-DPGA1 Gain", 0, 0, 66, 0),
+ SOC_SINGLE( "RX-DPGA2 Gain", 0, 0, 66, 0),
+ SOC_SINGLE( "RX-DPGA3 Gain", 0, 0, 66, 0),
+ SOC_SINGLE( "LINE1 Gain", 0, 0, 10, 0),
+ SOC_SINGLE( "LINE2 Gain", 0, 0, 10, 0),
+ SOC_SINGLE( "SPKR Gain", 0, 0, 22, 0),
+ SOC_SINGLE( "EAR Gain", 0, 0, 14, 0),
+ SOC_SINGLE( "AUXO1 Gain", 0, 0, 12, 0),
+ SOC_SINGLE( "AUXO2 Gain", 0, 0, 12, 0),
/* TX Volume Control */
- SOC_SINGLE("MIC1 Gain", 0, 0, 10, 0),
- SOC_SINGLE("MIC2 Gain", 0, 0, 10, 0),
- SOC_SINGLE("TX-DPGA1 Gain", 0, 0, 15, 0),
- SOC_SINGLE("TX-DPGA2 Gain", 0, 0, 15, 0),
+ SOC_SINGLE( "MIC1 Gain", 0, 0, 10, 0),
+ SOC_SINGLE( "MIC2 Gain", 0, 0, 10, 0),
+ SOC_SINGLE( "TX-DPGA1 Gain", 0, 0, 15, 0),
+ SOC_SINGLE( "TX-DPGA2 Gain", 0, 0, 15, 0),
/* Volume Control of Side Tone and Analog Loop */
- SOC_SINGLE("ST-PGA1 Gain", 0, 0, 10, 0),
- SOC_SINGLE("ST-PGA2 Gain", 0, 0, 10, 0),
- SOC_SINGLE("APGA1 Gain", 0, 0, 28, 0),
- SOC_SINGLE("APGA2 Gain", 0, 0, 28, 0),
+ SOC_SINGLE( "ST-PGA1 Gain", 0, 0, 10, 0),
+ SOC_SINGLE( "ST-PGA2 Gain", 0, 0, 10, 0),
+ SOC_SINGLE( "APGA1 Gain", 0, 0, 28, 0),
+ SOC_SINGLE( "APGA2 Gain", 0, 0, 28, 0),
/* RX Properties */
- SOC_ENUM("DAC1 Power Mode", ab3550_enum[6]),
- SOC_ENUM("DAC2 Power Mode", ab3550_enum[7]),
- SOC_ENUM("DAC3 Power Mode", ab3550_enum[8]),
- SOC_ENUM("EAR Power Mode", ab3550_enum[9]),
- SOC_ENUM("AUXO Power Mode", ab3550_enum[10]),
- SOC_SINGLE("LINE1 Inverse", 0, 0, 1, 0),
- SOC_SINGLE("LINE2 Inverse", 0, 0, 1, 0),
- SOC_SINGLE("AUXO1 Inverse", 0, 0, 1, 0),
- SOC_SINGLE("AUXO2 Inverse", 0, 0, 1, 0),
- SOC_SINGLE("AUXO1 Pulldown", 0, 0, 1, 0),
- SOC_SINGLE("AUXO2 Pulldown", 0, 0, 1, 0),
+ SOC_ENUM( "DAC1 Power Mode", soc_enum_dac1_power_mode),
+ SOC_ENUM( "DAC2 Power Mode", soc_enum_dac2_power_mode),
+ SOC_ENUM( "DAC3 Power Mode", soc_enum_dac3_power_mode),
+ SOC_ENUM( "EAR Power Mode", soc_enum_ear_power_mode),
+ SOC_ENUM( "AUXO Power Mode", soc_enum_auxo_power_mode),
+ SOC_SINGLE( "LINE1 Inverse", 0, 0, 1, 0),
+ SOC_SINGLE( "LINE2 Inverse", 0, 0, 1, 0),
+ SOC_SINGLE( "AUXO1 Inverse", 0, 0, 1, 0),
+ SOC_SINGLE( "AUXO2 Inverse", 0, 0, 1, 0),
+ SOC_SINGLE( "AUXO1 Pulldown", 0, 0, 1, 0),
+ SOC_SINGLE( "AUXO2 Pulldown", 0, 0, 1, 0),
/* TX Properties */
- SOC_SINGLE("VMID1", 0, 0, 0xff, 0),
- SOC_SINGLE("VMID2", 0, 0, 0xff, 0),
- SOC_ENUM("MIC1-1 MBias", ab3550_enum[11]),
- SOC_ENUM("MIC1-2 MBias", ab3550_enum[12]),
- SOC_ENUM("MIC2-1 MBias", ab3550_enum[13]),
- SOC_ENUM("MIC2-2 MBias", ab3550_enum[14]),
- SOC_ENUM("MBIAS1 HiZ Option", ab3550_enum[15]),
- SOC_ENUM("MBIAS2 HiZ Option", ab3550_enum[16]),
- SOC_ENUM("MBIAS2 Output Voltage", ab3550_enum[17]),
- SOC_ENUM("MBIAS2 Internal Resistor", ab3550_enum[18]),
- SOC_ENUM("MIC1 Input Impedance", ab3550_enum[19]),
- SOC_ENUM("MIC2 Input Impedance", ab3550_enum[20]),
- SOC_ENUM("TX1 HP Filter", ab3550_enum[21]),
- SOC_ENUM("TX2 HP Filter", ab3550_enum[22]),
- SOC_SINGLE("LINEIN1 Pre-charge", 0, 0, 100, 0),
- SOC_SINGLE("LINEIN2 Pre-charge", 0, 0, 100, 0),
- SOC_SINGLE("MIC1P1 Pre-charge", 0, 0, 100, 0),
- SOC_SINGLE("MIC1P2 Pre-charge", 0, 0, 100, 0),
- SOC_SINGLE("MIC1N1 Pre-charge", 0, 0, 100, 0),
- SOC_SINGLE("MIC1N2 Pre-charge", 0, 0, 100, 0),
- SOC_SINGLE("MIC2P1 Pre-charge", 0, 0, 100, 0),
- SOC_SINGLE("MIC2P2 Pre-charge", 0, 0, 100, 0),
- SOC_SINGLE("MIC2N1 Pre-charge", 0, 0, 100, 0),
- SOC_SINGLE("MIC2N2 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "VMID1", 0, 0, 0xff, 0),
+ SOC_SINGLE( "VMID2", 0, 0, 0xff, 0),
+ SOC_ENUM( "MIC1 MBias", soc_enum_mic1_mbias),
+ SOC_ENUM( "MIC2 MBias", soc_enum_mic2_mbias),
+ SOC_ENUM( "MBIAS1 HiZ Option", soc_enum_mbias1_hiz_option),
+ SOC_ENUM( "MBIAS2 HiZ Option", soc_enum_mbias2_hiz_option),
+ SOC_ENUM( "MBIAS2 Output Voltage", soc_enum_mbias2_output_voltage),
+ SOC_ENUM( "MBIAS2 Internal Resistor", soc_enum_mbias2_internal_resistor),
+ SOC_ENUM( "MIC1 Input Impedance", soc_enum_mic1_input_impedance),
+ SOC_ENUM( "MIC2 Input Impedance", soc_enum_mic2_input_impedance),
+ SOC_ENUM( "TX1 HP Filter", soc_enum_tx1_hp_filter),
+ SOC_ENUM( "TX2 HP Filter", soc_enum_tx2_hp_filter),
+ SOC_SINGLE( "LINEIN1 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "LINEIN2 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "MIC1P1 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "MIC1P2 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "MIC1N1 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "MIC1N2 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "MIC2P1 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "MIC2P2 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "MIC2N1 Pre-charge", 0, 0, 100, 0),
+ SOC_SINGLE( "MIC2N2 Pre-charge", 0, 0, 100, 0),
/* Side Tone and Analog Loop Properties */
- SOC_ENUM("ST1 HP Filter", ab3550_enum[23]),
- SOC_ENUM("ST2 HP Filter", ab3550_enum[24]),
+ SOC_ENUM( "ST1 HP Filter", soc_enum_st1_hp_filter),
+ SOC_ENUM( "ST2 HP Filter", soc_enum_st2_hp_filter),
/* I2S Interface Properties */
- SOC_ENUM("I2S0 Word Length", ab3550_enum[25]),
- SOC_ENUM("I2S1 Word Length", ab3550_enum[26]),
- SOC_ENUM("I2S0 Mode", ab3550_enum[27]),
- SOC_ENUM("I2S1 Mode", ab3550_enum[28]),
- SOC_ENUM("I2S0 tri-state", ab3550_enum[29]),
- SOC_ENUM("I2S1 tri-state", ab3550_enum[30]),
- SOC_ENUM("I2S0 pulldown", ab3550_enum[31]),
- SOC_ENUM("I2S1 pulldown", ab3550_enum[32]),
- SOC_ENUM("I2S0 Sample Rate", ab3550_enum[33]),
- SOC_ENUM("I2S1 Sample Rate", ab3550_enum[34]),
- SOC_SINGLE("Interface Loop", 0, 0, 0x0f, 0),
- SOC_SINGLE("Interface Swap", 0, 0, 0x1f, 0),
+ SOC_ENUM( "I2S0 Word Length", soc_enum_i2s0_word_length),
+ SOC_ENUM( "I2S1 Word Length", soc_enum_i2s1_word_length),
+ SOC_ENUM( "I2S0 Mode", soc_enum_i2s0_mode),
+ SOC_ENUM( "I2S1 Mode", soc_enum_i2s1_mode),
+ SOC_ENUM( "I2S0 tri-state", soc_enum_i2s0_tristate),
+ SOC_ENUM( "I2S1 tri-state", soc_enum_i2s1_tristate),
+ SOC_ENUM( "I2S0 pulldown", soc_enum_i2s0_pulldown),
+ SOC_ENUM( "I2S1 pulldown", soc_enum_i2s1_pulldown),
+ SOC_ENUM( "I2S0 Sample Rate", soc_enum_i2s0_sample_rate),
+ SOC_ENUM( "I2S1 Sample Rate", soc_enum_i2s1_sample_rate),
+ SOC_SINGLE( "Interface Loop", 0, 0, 0x0f, 0),
+ SOC_SINGLE( "Interface Swap", 0, 0, 0x1f, 0),
/* Miscellaneous */
- SOC_SINGLE("Commit", 0, 0, 1, 0)
+ SOC_SINGLE( "Voice Call", 0, 0, 1, 0),
+ SOC_SINGLE( "Commit", 0, 0, 1, 0)
};
static const struct snd_soc_dapm_widget ab3550_dapm_widgets[] = {
@@ -478,11 +414,12 @@ static const struct snd_soc_dapm_widget ab3550_dapm_widgets[] = {
static const struct snd_soc_dapm_route intercon[] = {
};
-static unsigned int ab3550_get_control_value(struct snd_soc_codec *codec,
- unsigned int ctl)
+static unsigned int ab3550_get_control_value(struct snd_soc_codec *codec, unsigned int ctl)
{
if (ctl >= ARRAY_SIZE(ab3550_ctl))
return -EINVAL;
+ //printk(KERN_DEBUG "%s: returning value of control %s: 0x%02x.\n",
+ // __func__, ab3550_ctl[ctl].name, ab3550_ctl[ctl].value);
return ab3550_ctl[ctl].value;
}
@@ -498,25 +435,27 @@ static unsigned int get_control_index(const char *name)
static unsigned int get_control_value_by_name(const char *name)
{
- int i, n;
- for(i = 0, n = ARRAY_SIZE(ab3550_ctl); i < n; i++) {
- if (strcmp(ab3550_ctl[i].name, name) == 0)
- break;
- }
+ int i = get_control_index(name);
return ab3550_ctl[i].value;
}
+static unsigned int get_control_changed_by_name(const char *name)
+{
+ int i = get_control_index(name);
+ return ab3550_ctl[i].changed;
+}
+
static int gain_ramp(u8 reg, u8 target, int shift, u8 mask)
{
- u8 curr, step;
+// u8 curr;
int ret = 0;
// printk(KERN_DEBUG "%s invoked.\n", __func__);
- if ((ret = GET_REG(reg, &curr))) {
- return ret;
- }
- if (curr == target)
- return 0;
+// if ((ret = GET_REG(reg, &curr))) {
+// return ret;
+// }
+// if (curr == target)
+// return 0;
// step = curr < target ? 1 : -1;
// while (!ret && curr != target) {
/* At least 15ms are required, so I take 16ms :-) */
@@ -527,125 +466,79 @@ static int gain_ramp(u8 reg, u8 target, int shift, u8 mask)
return ret;
}
-static int ab3550_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
- unsigned int freq, int dir)
+static void ab3550_print_registers(int stream_dir)
{
- printk(KERN_DEBUG "%s: %s called\n", __FILE__, __func__);
- return 0;
+ int i;
+ u8 val;
+ for (i = 0; i < ARRAY_SIZE(ab3550_registers); i++) {
+ GET_REG(ab3550_registers[i].address, &val);
+ printk(KERN_DEBUG "REGISTERS: %s = 0x%02x\n", ab3550_registers[i].name, val);
+ }
}
-static int ab3550_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
-{
- printk(KERN_DEBUG "%s: %s called.\n", __FILE__, __func__);
- return 0;
+static void ab3550_toggle_output_amp(int idx_amp, u8 val) {
+ struct ab3550_register* reg = &(ab3550_registers[(int)outamp_indices[idx_amp]]);
+ MASK_SET_REG(reg->address,
+ outamp_pwr_mask[idx_amp],
+ val << outamp_pwr_shift[idx_amp]);
+
+ printk(KERN_DEBUG "DORIANO: %s turned %s.\n", reg->name, val == 0 ? "off" : "on");
}
-static int ab3550_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai* dai)
+static void ab3550_toggle_mic_amp(int idx, u8 val) {
+ enum enum_register idx_reg_mic_amp[] = {IDX_MIC1_GAIN, IDX_MIC2_GAIN}; // PWR is in located in the gain regs.
+ struct ab3550_register* reg = &(ab3550_registers[(int)idx_reg_mic_amp[idx]]);
+ MASK_SET_REG(reg->address,
+ MICx_PWR_MASK,
+ val << MICx_PWR_SHIFT);
+
+ printk(KERN_DEBUG "DORIANO: %s turned %s.\n", reg->name, val == 0 ? "off" : "on");
+}
+
+static void ab3550_toggle_DAC(int idx_DAC, u8 val)
{
- u8 val;
- printk(KERN_DEBUG "%s: %s called.\n", __FILE__, __func__);
- MASK_SET_REG(CLOCK, CLOCK_ENABLE_MASK, 1 << CLOCK_ENABLE_SHIFT);
- /* Turn on the master generator */
- MASK_SET_REG(INTERFACE0, MASTER_GENx_PWR_MASK,
- 1 << MASTER_GENx_PWR_SHIFT);
- GET_REG(CLOCK, &val);
- printk(KERN_DEBUG "%s: CLOCK = %02x.\n", __func__, val);
- GET_REG(INTERFACE0, &val);
- printk(KERN_DEBUG "%s: INTERFACE0 = %02x.\n", __func__, val);
- GET_REG(RX1, &val);
- printk(KERN_DEBUG "%s: RX1 = %02x.\n", __func__, val);
- GET_REG(RX2, &val);
- printk(KERN_DEBUG "%s: RX2 = %02x.\n", __func__, val);
- GET_REG(SPKR_ADDER, &val);
- printk(KERN_DEBUG "%s: SPKR_ADDER = %02x.\n", __func__, val);
- GET_REG(AUXO1_ADDER, &val);
- printk(KERN_DEBUG "%s: AUXO1_ADDER = %02x.\n", __func__, val);
- GET_REG(AUXO2_ADDER, &val);
- printk(KERN_DEBUG "%s: AUXO2_ADDER = %02x.\n", __func__, val);
- GET_REG(SPKR, &val);
- printk(KERN_DEBUG "%s: SPKR = %02x.\n", __func__, val);
- GET_REG(AUXO1, &val);
- printk(KERN_DEBUG "%s: AUXO1 = %02x.\n", __func__, val);
- GET_REG(AUXO2, &val);
- printk(KERN_DEBUG "%s: AUXO2 = %02x.\n", __func__, val);
- GET_REG(RX1_DIGITAL_PGA, &val);
- printk(KERN_DEBUG "%s: RX1_DIGITAL_PGA = %02x.\n", __func__, val);
- GET_REG(RX2_DIGITAL_PGA, &val);
- printk(KERN_DEBUG "%s: RX2_DIGITAL_PGA = %02x.\n", __func__, val);
- return 0;
+ enum enum_register idx_reg_DAC[] = {IDX_RX1, IDX_RX2, IDX_RX3};
+ struct ab3550_register* reg = &(ab3550_registers[(int)idx_reg_DAC[idx_DAC]]);
+ MASK_SET_REG(reg->address,
+ DACx_PWR_MASK | RXx_PWR_MASK,
+ (val << RXx_PWR_SHIFT | val << DACx_PWR_SHIFT));
+
+ printk(KERN_DEBUG "DORIANO: DAC%d turned %s.\n", idx_DAC + 1, val == 0 ? "off" : "on");
}
-static void ab3550_pcm_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai* dai)
+static void ab3550_toggle_output_adder(int idx_adder, u8 val)
{
int i;
- printk(KERN_DEBUG "%s: %s called.\n", __FILE__, __func__);
- MASK_SET_REG(INTERFACE0, MASTER_GENx_PWR_MASK, 0);
- MASK_SET_REG(CLOCK, CLOCK_ENABLE_MASK, 0);
- for (i = 0; i < ARRAY_SIZE(outamp_reg); i++) {
- MASK_SET_REG(outamp_reg[i], outamp_pwr_mask[i], 0);
- }
+ struct ab3550_register* reg = &(ab3550_registers[(int)outamp_adder_indices[idx_adder]]);
+
+ MASK_SET_REG(reg->address,
+ DAC1_TO_ADDER_MASK | DAC2_TO_ADDER_MASK | DAC3_TO_ADDER_MASK,
+ val);
+
+ for (i = 0; i < 3; i++)
+ printk(KERN_DEBUG "DORIANO: DAC%d -> %s: %s.\n", i + 1, reg->name, (val & 1 << i) ? "on" : "off");
}
-static int set_up_speaker_playback(void)
+static void ab3550_toggle_ADC(int idx_ADC, u8 val)
{
- printk(KERN_DEBUG "%s: %s called.\n", __FILE__, __func__);
- MASK_SET_REG(CLOCK, CLOCK_REF_SELECT_MASK,
- 1 << CLOCK_REF_SELECT_SHIFT);
+ enum enum_register idx_reg_ADC[] = {IDX_TX1, IDX_TX2};
+ struct ab3550_register* reg = &(ab3550_registers[(int)idx_reg_ADC[idx_ADC]]);
+ MASK_SET_REG(reg->address,
+ ADCx_PWR_MASK | TXx_PWR_MASK,
+ ( val << ADCx_PWR_SHIFT | val << TXx_PWR_SHIFT));
- /* Sample rate 48 kHz */
- SET_REG(INTERFACE0, 0x03);
- printk(KERN_DEBUG "%s: interface 0 is setup", __func__);
-
- MASK_SET_REG(RX2, RX2_IF_SELECT_MASK, 0);
- SET_REG(SPKR_ADDER, 1 << DAC1_TO_ADDER_SHIFT |
- 1 << DAC2_TO_ADDER_SHIFT);
-/* SET_REG(AUXO1_ADDER, 1 << DAC1_TO_ADDER_SHIFT); */
-/* SET_REG(AUXO2_ADDER, 1 << DAC2_TO_ADDER_SHIFT); */
- printk(KERN_DEBUG "%s: Routes to the speaker and the AUXO are setup.\n",
- __func__);
-
- /* Mute the outamps first */
- MASK_SET_REG(RX1_DIGITAL_PGA, RXx_PGA_GAIN_MASK, 0);
- MASK_SET_REG(RX2_DIGITAL_PGA, RXx_PGA_GAIN_MASK, 0);
-/* MASK_SET_REG(AUXO1, AUXOx_GAIN_MASK, 0); */
-/* MASK_SET_REG(AUXO2, AUXOx_GAIN_MASK, 0); */
- MASK_SET_REG(SPKR, SPKR_GAIN_MASK, 0);
-
- MASK_SET_REG(RX1, RX1_PWR_MASK | DAC1_PWR_MASK | DAC1_PWR_MODE_MASK,
- 1 << RX1_PWR_SHIFT | 1 << DAC1_PWR_SHIFT |
- 1 << DAC1_PWR_MODE_SHIFT);
- MASK_SET_REG(RX2, RX2_PWR_MASK | DAC2_PWR_MASK | DAC2_PWR_MODE_MASK,
- 1 << RX2_PWR_SHIFT | 1 << DAC2_PWR_SHIFT |
- 1 << DAC2_PWR_MODE_SHIFT);
- printk(KERN_DEBUG "%s: DAC1, DAC2 and RX2 are now powered up.\n",
- __func__);
-
- MASK_SET_REG(SPKR, SPKR_PWR_MASK, 1 << SPKR_PWR_SHIFT);
-/* MASK_SET_REG(AUXO1, AUXOx_PWR_MASK, 1 << AUXOx_PWR_SHIFT); */
-/* MASK_SET_REG(AUXO2, AUXOx_PWR_MASK, 1 << AUXOx_PWR_SHIFT); */
- printk(KERN_DEBUG "%s: The speaker and the AUXO are now powered up.\n",
- __func__);
-
- gain_ramp(RX1_DIGITAL_PGA, get_control_value_by_name("RX-DPGA1 Gain"),
- RXx_PGA_GAIN_SHIFT, RXx_PGA_GAIN_MASK);
-
- gain_ramp(RX2_DIGITAL_PGA, get_control_value_by_name("RX-DPGA2 Gain"),
- RXx_PGA_GAIN_SHIFT, RXx_PGA_GAIN_MASK);
- gain_ramp(SPKR, get_control_value_by_name("SPKR Gain"),
- SPKR_GAIN_SHIFT, SPKR_GAIN_MASK);
-/* gain_ramp(AUXO1, get_control_value_by_name("AUXO1 Gain"), */
-/* AUXOx_GAIN_SHIFT, AUXOx_GAIN_MASK); */
-/* gain_ramp(AUXO2, get_control_value_by_name("AUXO1 Gain"), */
-/* AUXOx_GAIN_SHIFT, AUXOx_GAIN_MASK); */
- printk(KERN_DEBUG "%s: return 0.\n", __func__);
- return 0;
+ printk(KERN_DEBUG "DORIANO: ADC%d turned %s.\n", idx_ADC + 1, val == 0 ? "off" : "on");
}
-static int ab3550_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai* dai)
+static void ab3550_set_ADC_filter(int idx_ADC, u8 val)
{
- printk(KERN_DEBUG "%s: %s called.\n", __FILE__, __func__);
- set_up_speaker_playback();
- return 0;
+ enum enum_register idx_reg_ADC[] = {IDX_TX1, IDX_TX2};
+ struct ab3550_register* reg = &(ab3550_registers[(int)idx_reg_ADC[idx_ADC]]);
+ MASK_SET_REG(reg->address,
+ TXx_HP_FILTER_MASK,
+ val << TXx_HP_FILTER_SHIFT);
+
+ printk(KERN_DEBUG "DORIANO: ADC%d filter set to %s.\n", idx_ADC + 1, enum_hp_filter[val]);
}
static int ab3550_add_widgets(struct snd_soc_codec *codec)
@@ -659,35 +552,150 @@ static int ab3550_add_widgets(struct snd_soc_codec *codec)
return 0;
}
+
+
+static void ab3550_init_registers_startup(int ifSel)
+{
+ u8 val;
+ u8 iface = (ifSel == 0) ? INTERFACE0 : INTERFACE1;
+
+ // Configure CLOCK register
+ val = 1 << CLOCK_REF_SELECT_SHIFT | // 32kHz RTC
+ 1 << CLOCK_ENABLE_SHIFT; // Enable clock
+ SET_REG(CLOCK, val);
+
+ // Enable Master Generator I2Sx
+ MASK_SET_REG(iface, MASTER_GENx_PWR_MASK | I2Sx_TRISTATE_MASK | I2Sx_PULLDOWN_MASK, 1 << MASTER_GENx_PWR_SHIFT);
+
+ // Configure INTERFACEx_DATA register
+ val = 1 << I2Sx_L_DATA_SHIFT |// TX1 to I2Sx_L
+ 1 << I2Sx_R_DATA_SHIFT; // TX1 to I2Sx_R
+ SET_REG(ifSel == 0 ? INTERFACE0_DATA : INTERFACE1_DATA, val);
+
+ GET_REG(CLOCK, &val);
+ printk(KERN_DEBUG "AB: CLOCK = 0x%02x\n", val);
+ GET_REG(iface, &val);
+ printk(KERN_DEBUG "AB: INTERFACE%d = 0x%02x\n", ifSel, val);
+ GET_REG(ifSel == 0 ? INTERFACE0_DATA : INTERFACE1_DATA, &val);
+ printk(KERN_DEBUG "AB: INTERFACE%d_DATA = 0x%02x\n", ifSel, val);
+}
+
+static void ab3550_init_registers_playback(int ifSel) {
+
+ int i, routing_left, routing_right, idx_RX_left, idx_RX_right;
+ u8 val;
+
+ // Get indices to active DACs
+ idx_RX_left = idx_RX_right = -1;
+ val = get_control_value_by_name("RX2 Select");
+ if (ifSel == 0) {
+ if (!(val & RX2_IF_SELECT_MASK))
+ idx_RX_right = 1;
+ idx_RX_left = 0;
+ } else {
+ if (val & RX2_IF_SELECT_MASK)
+ idx_RX_right = 1;
+ idx_RX_left = 2;
+ }
+printk(KERN_DEBUG "DORIANO: idx_RX_left = %d, idx_RX_right = %d\n", idx_RX_left, idx_RX_right);
+
+ // Toggle DACs
+ routing_left = ab3550_ctl[IDX_DAC1_Routing].value;
+printk(KERN_DEBUG "DORIANO: routing_left = %d\n", routing_left);
+ if (routing_left)
+ ab3550_toggle_DAC(idx_RX_left, 1);
+ routing_right = 0;
+ if (idx_RX_right > -1)
+ {
+ routing_right = ab3550_ctl[IDX_DAC2_Routing].value;
+printk(KERN_DEBUG "DORIANO: routing_right = %d\n", routing_right);
+ if (routing_right)
+ ab3550_toggle_DAC(idx_RX_right, 1);
+ }
+
+ // Toggle adders
+ for (i = 0; i < ARRAY_SIZE(outamp_indices); i++) {
+ val = 0;
+ val |= (routing_left & 1 << i) ? 1 << idx_RX_left : 0;
+ if (idx_RX_right > -1)
+ val |= (routing_right & 1 << i) ? 1 << idx_RX_right : 0;
+ ab3550_toggle_output_adder(i, val);
+ }
+
+ /* TODO: DC cancellation */
+
+ // Toggle amplifiers
+ val = routing_left | routing_right;
+ for (i = 0; i < ARRAY_SIZE(outamp_indices); i++) {
+printk(KERN_DEBUG "DORIANO: val & 1 << i = %d\n", val & 1 << i);
+ if (val & 1 << i)
+ ab3550_toggle_output_amp(i, 1);
+ }
+}
+
+static void ab3550_init_registers_capture(int ifSel)
+{
+ enum enum_control idx = (ifSel == 0) ? IDX_I2S0_Input_Select : IDX_I2S1_Input_Select;
+
+printk(KERN_DEBUG "DORIANO: ab3550_ctl[idx].value = 0x%02x\n", ab3550_ctl[idx].value);
+
+ // Toggle ADC (RXx) and amplifiers (MICx_GAIN)
+ if ((ab3550_ctl[idx].value & 0x0F) < 3) { // value = 3 => mute
+ int idx_ADC = (ab3550_ctl[idx].value & 0x0F) - 1; // value = 0xX1 => MIC1, value = 0xX2 => MIC2
+ ab3550_toggle_ADC(idx_ADC, 1);
+ ab3550_toggle_mic_amp(idx_ADC, 1);
+ }
+}
+
+
+
+// Commit ---------------------------------------------------------------------------------------------------------------
+
+static void printCommit(int idx) {
+ printk(KERN_DEBUG "%s: %s committed to 0x%02x.\n", __func__, ab3550_ctl[idx].name, ab3550_ctl[idx].value);
+}
+
+static bool commit_if_changed(enum enum_control idx_ctl)
+{
+ bool changed = false;
+
+ if (ab3550_ctl[idx_ctl].changed) {
+ MASK_SET_REG(ab3550_registers[ab3550_ctl[idx_ctl].reg_idx].address,
+ ab3550_ctl[idx_ctl].reg_mask,
+ ab3550_ctl[idx_ctl].value << ab3550_ctl[idx_ctl].reg_shift);
+ ab3550_ctl[idx_ctl].changed = false;
+ changed = true;
+
+ printCommit(idx_ctl);
+ }
+
+ return changed;
+}
+
static int commit_outamps_routing(void)
{
- unsigned long idx;
- int adjust = 0;
static const char *control_names[] = {
"DAC1 Routing", "DAC2 Routing", "DAC3 Routing",
"APGA1 Destination", "APGA2 Destination"
};
- static const u8 outamp_adder_reg[] = {
- LINE1_ADDER, LINE2_ADDER, SPKR_ADDER,
- EAR_ADDER, AUXO1_ADDER, AUXO2_ADDER
- };
+
static const u8 outamp_0db_gain[] = {
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
};
- for_each_bit(idx, control_changed, ARRAY_SIZE(ab3550_ctl)) {
- if (strcmp(ab3550_ctl[idx].name, "DAC1 Routing") == 0 ||
- strcmp(ab3550_ctl[idx].name, "DAC2 Routing") == 0 ||
- strcmp(ab3550_ctl[idx].name, "DAC3 Routing") == 0 ||
- strcmp(ab3550_ctl[idx].name, "APGA1 Destination") == 0 ||
- strcmp(ab3550_ctl[idx].name, "APGA2 Destination") == 0
- ) {
- adjust = 1;
- }
- }
- if (adjust) {
+ struct ab3550_register* reg;
+
+ printk(KERN_DEBUG "%s: Enter.\n", __func__);
+
+ if ((get_control_changed_by_name("DAC1 Routing")) ||
+ (get_control_changed_by_name("DAC2 Routing")) ||
+ (get_control_changed_by_name("DAC3 Routing")) ||
+ (get_control_changed_by_name("APGA1 Destination")) ||
+ (get_control_changed_by_name("APGA2 Destination"))) {
+
int i;
- for (i = 0; i < ARRAY_SIZE(outamp_reg); i++) {
+
+ for (i = 0; i < ARRAY_SIZE(outamp_indices); i++) {
unsigned int connect = 0;
int j;
for (j = 0; j < ARRAY_SIZE(control_names); j++) {
@@ -700,17 +708,19 @@ static int commit_outamps_routing(void)
nothing is to be disconnected to it */
if (!connect) {
u8 val = 0;
- GET_REG(outamp_reg[i], &val);
+ reg = &(ab3550_registers[(int)outamp_indices[i]]);
+ GET_REG(reg->address, &val);
if (! (val & 1 << outamp_pwr_shift[i]))
continue;
- gain_ramp(outamp_reg[i], 0,
+ gain_ramp(reg->address, 0,
outamp_gain_shift[i],
outamp_gain_mask[i]);
- MASK_SET_REG(outamp_reg[i],
+ MASK_SET_REG(reg->address,
outamp_pwr_mask[i], 0);
continue;
}
- MASK_SET_REG(outamp_adder_reg[i],
+ reg = &(ab3550_registers[(int)outamp_adder_indices[i]]);
+ MASK_SET_REG(reg->address,
DAC3_TO_ADDER_MASK |
DAC2_TO_ADDER_MASK |
DAC3_TO_ADDER_MASK,
@@ -718,88 +728,270 @@ static int commit_outamps_routing(void)
if (connect & 1 << 3) {
/* Connect APGA1 */
MASK_SET_REG(APGA1_ADDER,
- 1 << (ARRAY_SIZE(outamp_reg) - i),
- 1 << (ARRAY_SIZE(outamp_reg) - i));
+ 1 << (ARRAY_SIZE(outamp_indices) - i),
+ 1 << (ARRAY_SIZE(outamp_indices) - i));
}
if (connect & 1 << 4) {
/* Connect APGA2 */
MASK_SET_REG(APGA2_ADDER,
- 1 << (ARRAY_SIZE(outamp_reg) - i),
- 1 << (ARRAY_SIZE(outamp_reg) - i));
+ 1 << (ARRAY_SIZE(outamp_indices) - i),
+ 1 << (ARRAY_SIZE(outamp_indices) - i));
}
- MASK_SET_REG(outamp_reg[i],
+ reg = &(ab3550_registers[(int)outamp_indices[i]]);
+ MASK_SET_REG(reg->address,
outamp_pwr_mask[i],
1 << outamp_pwr_shift[i]);
- gain_ramp(outamp_reg[i], outamp_0db_gain[i],
+ gain_ramp(reg->address, outamp_0db_gain[i],
outamp_gain_shift[i],
outamp_gain_mask[i]);
}
+
+ for (i = 0; i < ARRAY_SIZE(control_names); i++)
+ ab3550_ctl[get_control_index(control_names[i])].changed = 0;
}
return 0;
}
-static int commit_gain(void)
-{
- unsigned long idx;
- for_each_bit(idx, control_changed, ARRAY_SIZE(ab3550_ctl)) {
- if (strcmp(ab3550_ctl[idx].name, "LINE1 Gain") == 0 ||
- strcmp(ab3550_ctl[idx].name, "LINE2 Gain") == 0 ||
- strcmp(ab3550_ctl[idx].name, "SPKR Gain") == 0 ||
- strcmp(ab3550_ctl[idx].name, "EAR Gain") == 0 ||
- strcmp(ab3550_ctl[idx].name, "AUXO1 Gain") == 0 ||
- strcmp(ab3550_ctl[idx].name, "AUXO2 Gain") == 0
- ) {
- /* Ramping is needed if powered up */
- int i = idx - get_control_index("LINE1 Gain");
- u8 val = GET_REG(outamp_reg[i], &val);
- if (val & 1 << outamp_pwr_shift[i]) {
- gain_ramp(outamp_reg[i], ab3550_ctl[idx].value,
- outamp_gain_shift[i],
- outamp_gain_mask[i]);
- continue;
- }
- /* Othwise set directly */
- MASK_SET_REG(outamp_reg[i], outamp_gain_mask[i],
+static int commit_rx_routing(void)
+{
+ int idx;
+
+ printk(KERN_DEBUG "%s: Enter.\n", __func__);
+
+ idx = get_control_index("RX2 Select");
+ if (ab3550_ctl[idx].changed) {
+ u8 val = ab3550_ctl[idx].value;
+ if (val & RXx_PWR_MASK)
+ MASK_SET_REG(RX2, RXx_PWR_MASK, 0);
+ MASK_SET_REG(RX2, RX2_IF_SELECT_MASK, ab3550_ctl[idx].value);
+ if (val & RXx_PWR_MASK)
+ MASK_SET_REG(RX2, RXx_PWR_MASK, 1 << RXx_PWR_SHIFT);
+ ab3550_ctl[idx].changed = false;
+
+ printCommit(idx);
+ }
+
+ commit_outamps_routing();
+
+ return 0;
+}
+
+static int commit_rx_gain(void)
+{
+ int i, idx_ctl;
+ //u8 val;
+ struct ab3550_register* reg;
+
+ printk(KERN_DEBUG "%s: Enter.\n", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(outamp_gain_controls); i++) {
+ idx_ctl = (int)outamp_gain_controls[i];
+ reg = &(ab3550_registers[ab3550_ctl[idx_ctl].reg_idx]);
+ if (ab3550_ctl[idx_ctl].changed) {
+ //val = GET_REG(reg->address, &val);
+ // if (ab3550_ctl[idx_ctl].value & 1 << outamp_pwr_shift[i]) // Ramping is needed if amp is powered up
+ // gain_ramp(outamp_reg[i], ab3550_ctl[idx_ctl].value, outamp_gain_shift[i], outamp_gain_mask[i]);
+ // else // Set directly if amp is not powered up
+ MASK_SET_REG(reg->address, outamp_gain_mask[i], ab3550_ctl[idx_ctl].value);
+ ab3550_ctl[idx_ctl].changed = false;
+
+ printCommit(idx_ctl);
+ }
+ }
+
+ idx_ctl = get_control_index("RX-DPGA1 Gain");
+ if (ab3550_ctl[idx_ctl].changed) {
+ gain_ramp(RX1_DIGITAL_PGA, ab3550_ctl[idx_ctl].value, RXx_PGA_GAIN_SHIFT, RXx_PGA_GAIN_MASK);
+ ab3550_ctl[idx_ctl].changed = false;
+
+ printCommit(idx_ctl);
+
+ }
+
+ idx_ctl = get_control_index("RX-DPGA2 Gain");
+ if (ab3550_ctl[idx_ctl].changed) {
+ gain_ramp(RX2_DIGITAL_PGA, ab3550_ctl[idx_ctl].value, RXx_PGA_GAIN_SHIFT, RXx_PGA_GAIN_MASK);
+ ab3550_ctl[idx_ctl].changed = false;
+
+ printCommit(idx_ctl);
+ }
+
+ idx_ctl = get_control_index("RX-DPGA3 Gain");
+ if (ab3550_ctl[idx_ctl].changed) {
+ gain_ramp(RX3_DIGITAL_PGA, ab3550_ctl[idx_ctl].value, RXx_PGA_GAIN_SHIFT, RXx_PGA_GAIN_MASK);
+ ab3550_ctl[idx_ctl].changed = false;
+
+ printCommit(idx_ctl);
+ }
+
+ return 0;
+}
+
+static int commit_tx_routing(void)
+{
+ int idx;
+
+ printk(KERN_DEBUG "%s: Enter.\n", __func__);
+
+ idx = get_control_index("MIC1 Input Select");
+ if (ab3550_ctl[idx].changed) {
+ MASK_SET_REG(MIC1_INPUT_SELECT,
+ MICxP1_SEL_MASK | MICxN1_SEL_MASK | MICxP2_SEL_MASK | MICxN2_SEL_MASK | LINEIN_SEL_MASK,
+ ab3550_ctl[idx].value);
+ MASK_SET_REG(MIC2_TO_MIC1,
+ MIC2P1_MIC1P_SEL_MASK | MIC2N1_MIC1N_SEL_MASK,
+ ab3550_ctl[idx].value >> 2);
+ ab3550_ctl[idx].changed = false;
+
+ printCommit(idx);
+ }
+
+ idx = get_control_index("MIC2 Input Select");
+ if (ab3550_ctl[idx].changed) {
+ MASK_SET_REG(MIC2_INPUT_SELECT,
+ MICxP1_SEL_MASK | MICxN1_SEL_MASK | MICxP2_SEL_MASK | MICxN2_SEL_MASK | LINEIN_SEL_MASK,
ab3550_ctl[idx].value);
- } else if (strcmp(ab3550_ctl[idx].name, "RX-DPGA1 Gain") == 0) {
- gain_ramp(RX1_DIGITAL_PGA,
- get_control_value_by_name("RX-DPGA1 Gain"),
- RXx_PGA_GAIN_SHIFT, RXx_PGA_GAIN_MASK);
+ ab3550_ctl[idx].changed = false;
+
+ printCommit(idx);
+ }
+
+ idx = get_control_index("I2S0 Input Select");
+ if (ab3550_ctl[idx].changed) {
+ MASK_SET_REG(INTERFACE0_DATA,
+ I2Sx_L_DATA_MASK,
+ ab3550_ctl[idx].value << I2Sx_L_DATA_SHIFT);
+ MASK_SET_REG(INTERFACE0_DATA,
+ I2Sx_R_DATA_MASK,
+ ab3550_ctl[idx].value << I2Sx_R_DATA_SHIFT);
+ ab3550_ctl[idx].changed = false;
+
+ printCommit(idx);
+ }
+
+ idx = get_control_index("I2S1 Input Select");
+ if (ab3550_ctl[idx].changed) {
+ MASK_SET_REG(INTERFACE1_DATA,
+ I2Sx_L_DATA_MASK,
+ ab3550_ctl[idx].value << I2Sx_L_DATA_SHIFT);
+ MASK_SET_REG(INTERFACE1_DATA,
+ I2Sx_R_DATA_MASK,
+ ab3550_ctl[idx].value << I2Sx_R_DATA_SHIFT);
+ ab3550_ctl[idx].changed = false;
+
+ printCommit(idx);
+ }
+
+ return 0;
+}
+
+static int commit_tx_gain(void)
+{
+ printk(KERN_DEBUG "%s: Enter.\n", __func__);
+
+ commit_if_changed(IDX_MIC1_Gain);
+ commit_if_changed(IDX_MIC2_Gain);
+ commit_if_changed(IDX_TX_DPGA1_Gain);
+ commit_if_changed(IDX_TX_DPGA2_Gain);
+
+ return 0;
+}
+
+static int commit_others(void)
+{
+ int idx;
+
+ printk(KERN_DEBUG "%s: Enter.\n", __func__);
+
+ idx = get_control_index("I2S0 Sample Rate");
+ if (ab3550_ctl[idx].changed) {
+ // TODO?
+ ab3550_ctl[idx].changed = false;
+ }
+
+ idx = get_control_index("I2S1 Sample Rate");
+ if (ab3550_ctl[idx].changed) {
+ // TODO?
+ ab3550_ctl[idx].changed = false;
+ }
+
+ idx = get_control_index("MIC1 MBias");
+ if (ab3550_ctl[idx].changed) {
+ MASK_SET_REG(MIC_BIAS1,
+ MBIAS_PWR_MASK,
+ ab3550_ctl[idx].value << MBIAS_PWR_SHIFT);
+ ab3550_ctl[idx].changed = false;
+ }
+
+ idx = get_control_index("MIC1 MBias");
+ if (ab3550_ctl[idx].changed) {
+ MASK_SET_REG(MIC_BIAS2,
+ MBIAS_PWR_MASK,
+ ab3550_ctl[idx].value << MBIAS_PWR_SHIFT);
+ ab3550_ctl[idx].changed = false;
+ }
- } else if (strcmp(ab3550_ctl[idx].name, "RX-DPGA2 Gain") == 0) {
- gain_ramp(RX2_DIGITAL_PGA,
- get_control_value_by_name("RX-DPGA2 Gain"),
- RXx_PGA_GAIN_SHIFT, RXx_PGA_GAIN_MASK);
+ idx = get_control_index("TX1 HP Filter");
+ if (ab3550_ctl[idx].changed) {
+ ab3550_set_ADC_filter(0, ab3550_ctl[idx].value);
+ ab3550_ctl[idx].changed = false;
+ }
- } else if (strcmp(ab3550_ctl[idx].name, "RX-DPGA3 Gain") == 0) {
- gain_ramp(RX3_DIGITAL_PGA,
- get_control_value_by_name("RX-DPGA3 Gain"),
- RXx_PGA_GAIN_SHIFT, RXx_PGA_GAIN_MASK);
+ idx = get_control_index("TX2 HP Filter");
+ if (ab3550_ctl[idx].changed) {
+ ab3550_set_ADC_filter(1, ab3550_ctl[idx].value);
+ ab3550_ctl[idx].changed = false;
+ }
+ idx = get_control_index("Voice Call");
+ if (ab3550_ctl[idx].changed) {
+ printk(KERN_DEBUG "%s: commiting 'Voice Call'.\n", __func__);
+ if (ab3550_ctl[idx].value) {
+ MASK_SET_REG(MIC_BIAS1,
+ MBIAS_PWR_MASK,
+ 1 << MBIAS_PWR_SHIFT);
+ MASK_SET_REG(MIC_BIAS2,
+ MBIAS_PWR_MASK,
+ 1 << MBIAS_PWR_SHIFT);
+ //turn_on_interface_tx(INTERFACE1);
+ MASK_SET_REG(INTERFACE1,
+ MASTER_GENx_PWR_MASK,
+ 1 << MASTER_GENx_PWR_SHIFT);
+
+ printCommit(idx);
}
+ ab3550_ctl[idx].changed = false;
}
+
return 0;
}
+void commit_all(void)
+{
+ commit_rx_routing();
+ commit_rx_gain();
+ commit_tx_routing();
+ commit_tx_gain();
+ commit_others();
+}
+
static int ab3550_set_control_value(struct snd_soc_codec *codec,
unsigned int ctl, unsigned int value)
{
- int ret = 0;
-
if (ctl >= ARRAY_SIZE(ab3550_ctl))
return -EINVAL;
- if (ab3550_ctl[ctl].value == value)
- return 0;
- ab3550_ctl[ctl].value = value;
- if (strcmp(ab3550_ctl[ctl].name, "Commit") != 0)
- return 0;
- /* Commit the changes */
- commit_outamps_routing();
- commit_gain();
- memset(control_changed, 0, sizeof(control_changed));
+ if (strcmp(ab3550_ctl[ctl].name, "Commit") == 0) {
+ commit_all();
- return ret;
+ } else if (ab3550_ctl[ctl].value != value) {
+ printk(KERN_DEBUG "%s: Ctl %d changed from 0x%02x to 0x%02x\n", __func__, ctl, ab3550_ctl[ctl].value, value);
+
+ ab3550_ctl[ctl].value = value;
+ ab3550_ctl[ctl].changed = true;
+ }
+
+ return 0;
}
static int ab3550_add_controls(struct snd_soc_codec *codec)
@@ -810,11 +1002,11 @@ static int ab3550_add_controls(struct snd_soc_codec *codec)
for (i = 0; i < n; i++) {
/* Initialize the control indice */
if (! ab3550_ctl[i].is_enum) {
- ab3550_snd_controls[i].private_value |= i;
+ ((struct soc_mixer_control *)
+ ab3550_snd_controls[i].private_value)->reg = i;
} else {
- struct soc_enum *p = (struct soc_enum *)
- ab3550_snd_controls[i].private_value;
- p->reg = i;
+ ((struct soc_enum *)
+ ab3550_snd_controls[i].private_value)->reg = i;
}
printk(KERN_DEBUG "%s: %s.reg = %d\n", __func__,
ab3550_ctl[i].name, i);
@@ -831,6 +1023,232 @@ static int ab3550_add_controls(struct snd_soc_codec *codec)
return err;
}
+
+
+// snd_soc_dai ---------------------------------------------------------------------------------------------------------
+
+static int ab3550_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai* dai)
+{
+ struct codec_dai_private *priv = (struct codec_dai_private*)dai->private_data;
+
+ printk(KERN_DEBUG "%s: %s called.\n", __FILE__, __func__);
+ /* TODO: consult the clock use count */
+
+
+ // Configure registers on startup
+ if (atomic_read(&priv->substream_count) == 0)
+ ab3550_init_registers_startup(dai->id);
+
+ atomic_inc(&priv->substream_count);
+
+ // Configure registers for either playback or capture
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ab3550_init_registers_playback(dai->id);
+ else
+ ab3550_init_registers_capture(dai->id);
+
+ ab3550_print_registers(substream->stream);
+
+ return 0;
+}
+
+static int ab3550_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params,
+ struct snd_soc_dai* dai)
+{
+
+ u8 val;
+ const char *reg_name;
+
+ printk(KERN_DEBUG "%s: %s called\n", __FILE__, __func__);
+
+ reg_name = dai->id == 0 ? "I2S0 Sample Rate" : "I2S1 Sample Rate";
+
+ switch(params_rate(hw_params))
+ {
+ case 8000:
+ val=0;
+ break;
+
+ case 16000:
+ val=1;
+ break;
+
+ case 44100:
+ val=2;
+ break;
+
+ case 48000:
+ val=3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ab3550_ctl[get_control_index(reg_name)].value = val;
+
+ MASK_SET_REG(dai->id == 0 ? INTERFACE0 : INTERFACE1,
+ I2Sx_SR_MASK,
+ val);
+
+ return 0;
+}
+
+static void ab3550_pcm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai* dai)
+{
+ int i;
+ u8 iface;
+ const char *mode_ctl_name;
+ printk(KERN_DEBUG "%s: %s called.\n", __FILE__, __func__);
+ if (dai->id == 0) {
+ iface = INTERFACE0;
+ mode_ctl_name = "I2S0 Mode";
+ } else {
+ iface = INTERFACE1;
+ mode_ctl_name = "I2S1 Mode";
+ }
+ if (get_control_value_by_name(mode_ctl_name) == 0) {
+ struct codec_dai_private *priv =
+ (struct codec_dai_private *)dai->private_data;
+ if (atomic_dec_and_test(&priv->substream_count))
+ MASK_SET_REG(iface, MASTER_GENx_PWR_MASK, 0);
+ }
+ /*TODO: consult the clock use count */
+/* MASK_SET_REG(CLOCK, CLOCK_ENABLE_MASK, 0); */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ struct ab3550_register* reg;
+ /* TODO: Turn off the outamps only used by this I2S */
+ for (i = 0; i < ARRAY_SIZE(outamp_indices); i++) {
+ reg = &(ab3550_registers[(int)outamp_indices[i]]);
+ MASK_SET_REG(reg->address, outamp_pwr_mask[i], 0);
+ }
+ } else {
+ /* TODO: Turn off the inactive components */
+ }
+}
+
+static int ab3550_set_dai_sysclk(struct snd_soc_dai* dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ /*
+ u8 val;
+ const char *reg_name;
+ printk(KERN_DEBUG "%s: %s called\n", __FILE__, __func__);
+ switch(freq) {
+ case 8000:
+ val = 0;
+ break;
+ case 16000:
+ val = 1;
+ break;
+ case 44100:
+ val = 2;
+ break;
+ case 48000:
+ val = 3;
+ break;
+ default:
+ printk(KERN_ERR "%s: invalid frequency %u.\n",
+ __func__, freq);
+ return -EINVAL;
+ }
+
+ reg_name = dai->id == 0 ? "I2S0 Sample Rate" : "I2S1 Sample Rate";
+ ab3550_ctl[get_control_index(reg_name)].value = val;
+ return MASK_SET_REG(dai->id == 0 ? INTERFACE0 : INTERFACE1,
+ I2Sx_SR_MASK,
+ val << I2Sx_SR_SHIFT);
+ */
+ return 0;
+}
+
+static int ab3550_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ u8 iface = (codec_dai->id == 0) ? INTERFACE0 : INTERFACE1;
+ u8 val=0;
+ printk(KERN_DEBUG "%s: %s called\n", __FILE__, __func__);
+
+ switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
+
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+ val |= 1 << I2Sx_MODE_SHIFT;
+ break;
+
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+ break;
+
+ default:
+ printk(KERN_WARNING "AB3550_dai: unsupported DAI format 0x%x\n",fmt);
+ return -EINVAL;
+ }
+
+ return MASK_SET_REG(iface,I2Sx_MODE_MASK | I2Sx_WORDLENGTH_MASK, val);
+}
+
+struct snd_soc_dai ab3550_codec_dai[] = {
+ {
+ .name = "ab3550_0",
+ .id = 0,
+ .playback = {
+ .stream_name = "ab3550_0",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AB3550_SUPPORTED_RATE,
+ .formats = AB3550_SUPPORTED_FMT,
+ },
+ .capture = {
+ .stream_name = "ab3550_0",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AB3550_SUPPORTED_RATE,
+ .formats = AB3550_SUPPORTED_FMT,
+ },
+ .ops = {
+ .prepare = ab3550_pcm_prepare,
+ .hw_params = ab3550_pcm_hw_params,
+ .shutdown = ab3550_pcm_shutdown,
+ .set_sysclk = ab3550_set_dai_sysclk,
+ .set_fmt = ab3550_set_dai_fmt
+ },
+ .private_data = &privates[0]
+ },
+ {
+ .name = "ab3550_1",
+ .id = 1,
+ .playback = {
+ .stream_name = "ab3550_1",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AB3550_SUPPORTED_RATE,
+ .formats = AB3550_SUPPORTED_FMT,
+ },
+ .capture = {
+ .stream_name = "ab3550_1",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AB3550_SUPPORTED_RATE,
+ .formats = AB3550_SUPPORTED_FMT,
+ },
+ .ops = {
+ .prepare = ab3550_pcm_prepare,
+ .hw_params = ab3550_pcm_hw_params,
+ .shutdown = ab3550_pcm_shutdown,
+ .set_sysclk = ab3550_set_dai_sysclk,
+ .set_fmt = ab3550_set_dai_fmt
+ },
+ .private_data = &privates[1]
+ }
+};
+EXPORT_SYMBOL_GPL(ab3550_codec_dai);
+
+
+
+
+
+// snd_soc_codec_device ---------------------------------------------------------------------------------------------------
+
static int ab3550_codec_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -843,7 +1261,6 @@ static int ab3550_codec_probe(struct platform_device *pdev)
return -ENOMEM;
codec->name = "AB3550";
codec->owner = THIS_MODULE;
- /* TODO: add codec dai */
codec->dai = ab3550_codec_dai;
codec->num_dai = 2;
codec->read = ab3550_get_control_value;
@@ -911,38 +1328,31 @@ struct snd_soc_codec_device soc_codec_dev_ab3550 = {
EXPORT_SYMBOL_GPL(soc_codec_dev_ab3550);
-/* struct snd_soc_dai ab3550_codec_dai = { */
-/* .name = "AB3550", */
-/* .playback = { */
-/* .stream_name = "Playback", */
-/* .channels_min = 1, */
-/* .channels_max = 2, */
-/* .rates = AB3550_RATES, */
-/* .formats = AB3550_FORMATS,}, */
-/* .capture = { */
-/* .stream_name = "Capture", */
-/* .channels_min = 1, */
-/* .channels_max = 2, */
-/* .rates = AB3550_RATES, */
-/* .formats = AB3550_FORMATS,}, */
-/* .ops = { */
-/* .prepare = ab3550_pcm_prepare, */
-/* .hw_params = ab3550_hw_params, */
-/* .shutdown = ab3550_shutdown, */
-/* }, */
-/* .dai_ops = { */
-/* .digital_mute = ab3550_mute, */
-/* .set_sysclk = ab3550_set_dai_sysclk, */
-/* .set_fmt = ab3550_set_dai_fmt, */
-/* } */
-/* }; */
-/* EXPORT_SYMBOL_GPL(ab3550_codec_dai); */
static int ab3550_platform_probe(struct platform_device *pdev)
{
int ret = 0;
-
+ u8 reg, val;
+ unsigned long i;
printk(KERN_DEBUG "%s invoked with pdev = %p.\n", __func__, pdev);
ab3550_dev = &pdev->dev;
+
+ /* Initialize the codec registers */
+ for (reg = MIC_BIAS1; reg < INTERFACE_SWAP; reg++) {
+ SET_REG(reg, 0);
+ }
+ MASK_SET_REG(CLOCK, CLOCK_REF_SELECT_MASK,
+ 1 << CLOCK_REF_SELECT_SHIFT);
+ MASK_SET_REG(CLOCK, CLOCK_ENABLE_MASK,
+ 1 << CLOCK_ENABLE_SHIFT);
+ val = GET_REG(CLOCK, &val);
+ printk(KERN_DEBUG "%s: CLOCK = 0x%02x.\n", __func__, val);
+
+ // Init all registers from default control values
+ for (i = 0; i < ARRAY_SIZE(ab3550_ctl); i++)
+ if (ab3550_ctl[i].value)
+ ab3550_ctl[i].changed = true;
+ commit_all();
+
return ret;
}
@@ -950,6 +1360,7 @@ static int ab3550_platform_remove(struct platform_device *pdev)
{
int ret;
printk(KERN_DEBUG "%s called.\n", __func__);
+ MASK_SET_REG(CLOCK, CLOCK_ENABLE_MASK, 0);
if ((ret = soc_codec_dev_ab3550.remove(NULL)))
printk(KERN_ERR "%s failed with error code %d.\n",
__func__, ret);
@@ -991,18 +1402,47 @@ static struct platform_driver ab3550_platform_driver = {
static int __devinit ab3550_init(void)
{
- int ret;
+ int i, ret1;
+ int ret2 = 0;
+
printk(KERN_DEBUG "%s called.\n", __func__);
- ret= platform_driver_register(&ab3550_platform_driver);
- printk(KERN_DEBUG "%s finished with error code %d.\n",
- __func__, ret);
- return ret;
+
+ // Register codec platform driver.
+ ret1 = platform_driver_register(&ab3550_platform_driver);
+ if (ret1 < 0) {
+ printk(KERN_DEBUG "%s: Error %d: Failed to register codec platform driver.\n", __func__, ret1);
+ ret2 = -1;
+ }
+
+ // Register codec-dai.
+ printk(KERN_DEBUG "%s: Register codec-dai.\n", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(ab3550_codec_dai); i++) {
+ printk(KERN_DEBUG "%s: Register codec-dai %d.\n", __func__, i);
+ ret1 = snd_soc_register_dai(&ab3550_codec_dai[i]);
+ if (ret1 < 0) {
+ printk(KERN_DEBUG "MOP500_AB3550: Error: Failed to register codec-dai %d.\n", i);
+ ret2 = -1;
+ }
+ }
+
+ return ret2;
}
static void ab3550_exit(void)
{
- printk(KERN_DEBUG "%s called.\n", __func__);
+ int i;
+
+ printk(KERN_DEBUG "u8500_ab3550_init: Enter.\n");
+
+ // Register codec platform driver.
+ printk(KERN_DEBUG "%s: Un-register codec platform driver.\n", __func__);
platform_driver_unregister(&ab3550_platform_driver);
+
+ for (i = 0; i < ARRAY_SIZE(ab3550_codec_dai); i++) {
+ printk(KERN_DEBUG "%s: Un-register codec-dai %d.\n", __func__, i);
+ snd_soc_unregister_dai(&ab3550_codec_dai[i]);
+ }
}
module_init(ab3550_init);