summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/sgtl5000.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/sgtl5000.c')
-rw-r--r--sound/soc/codecs/sgtl5000.c71
1 files changed, 54 insertions, 17 deletions
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 39810b713d5f..f99dd0673f57 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -35,8 +35,15 @@
#define SGTL5000_DAP_REG_OFFSET 0x0100
#define SGTL5000_MAX_REG_OFFSET 0x013A
+/*
+ * The Manual recommends a VAG ramp delay 200-400 ms.
+ * For Toradex SoM Apalis TK1 v1.2A the optimal up/down delay is 500 ms.
+ * For Toradex SoM Apalis iMX6D/Q v1.1B the optimal delay
+ * is 600 ms for ramp up and 500 ms ramp down.
+ */
+
/* Delay for the VAG ramp up */
-#define SGTL5000_VAG_POWERUP_DELAY 500 /* ms */
+#define SGTL5000_VAG_POWERUP_DELAY 600 /* ms */
/* Delay for the VAG ramp down */
#define SGTL5000_VAG_POWERDOWN_DELAY 500 /* ms */
@@ -106,6 +113,13 @@ enum sgtl5000_micbias_resistor {
SGTL5000_MICBIAS_8K = 8,
};
+enum {
+ I2S_LRCLK_STRENGTH_DISABLE,
+ I2S_LRCLK_STRENGTH_LOW,
+ I2S_LRCLK_STRENGTH_MEDIUM,
+ I2S_LRCLK_STRENGTH_HIGH,
+};
+
enum {
HP_POWER_EVENT,
DAC_POWER_EVENT,
@@ -125,6 +139,7 @@ struct sgtl5000_priv {
int revision;
u8 micbias_resistor;
u8 micbias_voltage;
+ u8 lrclk_strength;
u16 mute_state[LAST_POWER_EVENT + 1];
};
@@ -572,32 +587,42 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
.put = dac_put_volsw,
},
+ /* ADC Capture */
SOC_DOUBLE("Capture Volume", SGTL5000_CHIP_ANA_ADC_CTRL, 0, 4, 0xf, 0),
SOC_SINGLE_TLV("Capture Attenuate Switch (-6dB)",
- SGTL5000_CHIP_ANA_ADC_CTRL,
- 8, 1, 0, capture_6db_attenuate),
- SOC_SINGLE("Capture ZC Switch", SGTL5000_CHIP_ANA_CTRL, 1, 1, 0),
+ SGTL5000_CHIP_ANA_ADC_CTRL,
+ SGTL5000_ADC_VOL_M6DB, 1, 0, capture_6db_attenuate),
+ SOC_SINGLE("Capture ZC Switch", SGTL5000_CHIP_ANA_CTRL,
+ SGTL5000_ADC_ZCD_EN, 1, 0),
+ SOC_SINGLE("Capture Switch", SGTL5000_CHIP_ANA_CTRL,
+ SGTL5000_ADC_MUTE_SHIFT, 1, 1),
+
+ /* Headphone */
SOC_DOUBLE_TLV("Headphone Playback Volume",
- SGTL5000_CHIP_ANA_HP_CTRL,
- 0, 8,
- 0x7f, 1,
- headphone_volume),
+ SGTL5000_CHIP_ANA_HP_CTRL,
+ SGTL5000_HP_VOL_LEFT_SHIFT,
+ SGTL5000_HP_VOL_RIGHT_SHIFT,
+ 0x7f, 1,
+ headphone_volume),
SOC_SINGLE("Headphone Playback Switch", SGTL5000_CHIP_ANA_CTRL,
- 4, 1, 1),
+ SGTL5000_HP_MUTE_SHIFT, 1, 1),
SOC_SINGLE("Headphone Playback ZC Switch", SGTL5000_CHIP_ANA_CTRL,
- 5, 1, 0),
+ SGTL5000_HP_ZCD_EN, 1, 0),
+ /* Microphone */
SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL,
- 0, 3, 0, mic_gain_tlv),
+ SGTL5000_MIC_GAIN_SHIFT, 3, 0, mic_gain_tlv),
+ /* Lineout */
SOC_DOUBLE_TLV("Lineout Playback Volume",
SGTL5000_CHIP_LINE_OUT_VOL,
SGTL5000_LINE_OUT_VOL_LEFT_SHIFT,
SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT,
0x1f, 1,
lineout_volume),
- SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1),
+ SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL,
+ SGTL5000_LINE_MUTE_SHIFT, 1, 1),
};
/* mute the codec used by alsa core */
@@ -1277,7 +1302,9 @@ static int sgtl5000_enable_regulators(struct i2c_client *client)
static int sgtl5000_probe(struct snd_soc_codec *codec)
{
int ret;
+ u16 reg;
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+ unsigned int zcd_mask = SGTL5000_HP_ZCD_EN | SGTL5000_ADC_ZCD_EN;
/* power up sgtl5000 */
ret = sgtl5000_set_power_regs(codec);
@@ -1286,7 +1313,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
/* enable small pop, introduce 400ms delay in turning off */
snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
- SGTL5000_SMALL_POP, 1);
+ SGTL5000_SMALL_POP, SGTL5000_SMALL_POP);
/* disable short cut detector */
snd_soc_write(codec, SGTL5000_CHIP_SHORT_CTRL, 0);
@@ -1306,11 +1333,11 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
SGTL5000_DAC_MUTE_RIGHT |
SGTL5000_DAC_MUTE_LEFT);
- snd_soc_write(codec, SGTL5000_CHIP_PAD_STRENGTH, 0x015f);
+ reg = ((sgtl5000->lrclk_strength) << SGTL5000_PAD_I2S_LRCLK_SHIFT | 0x5f);
+ snd_soc_write(codec, SGTL5000_CHIP_PAD_STRENGTH, reg);
- snd_soc_write(codec, SGTL5000_CHIP_ANA_CTRL,
- SGTL5000_HP_ZCD_EN |
- SGTL5000_ADC_ZCD_EN);
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_CTRL,
+ zcd_mask, zcd_mask);
snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
SGTL5000_BIAS_R_MASK,
@@ -1341,6 +1368,9 @@ static struct snd_soc_codec_driver sgtl5000_driver = {
.probe = sgtl5000_probe,
.remove = sgtl5000_remove,
.set_bias_level = sgtl5000_set_bias_level,
+ .reg_cache_size = SGTL5000_MAX_REG_OFFSET,
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
.suspend_bias_off = true,
.component_driver = {
.controls = sgtl5000_snd_controls,
@@ -1535,6 +1565,13 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
}
}
+ sgtl5000->lrclk_strength = I2S_LRCLK_STRENGTH_LOW;
+ if (!of_property_read_u32(np, "lrclk-strength", &value)) {
+ if (value > I2S_LRCLK_STRENGTH_HIGH)
+ value = I2S_LRCLK_STRENGTH_LOW;
+ sgtl5000->lrclk_strength = value;
+ }
+
/* Ensure sgtl5000 will start with sane register values */
sgtl5000_fill_defaults(client);