summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/sgtl5000.c63
-rw-r--r--sound/soc/fsl/Kconfig5
-rw-r--r--sound/soc/fsl/Makefile3
-rw-r--r--sound/soc/fsl/fsl_spdif.c4
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c45
5 files changed, 100 insertions, 20 deletions
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 3dba5550a665..d55fdff55e62 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -99,6 +99,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,
+};
+
/* sgtl5000 private structure in codec */
struct sgtl5000_priv {
int sysclk; /* sysclk rate */
@@ -111,6 +118,7 @@ struct sgtl5000_priv {
int revision;
u8 micbias_resistor;
u8 micbias_voltage;
+ u8 lrclk_strength;
};
/*
@@ -164,6 +172,13 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_PRE_PMD:
/*
+ * Don't clear VAG_POWERUP when there is a local loop
+ * from LINE_IN to the HP.
+ */
+ if (snd_soc_read(codec, SGTL5000_CHIP_ANA_CTRL) &
+ SGTL5000_HP_SEL_MASK)
+ break;
+ /*
* Don't clear VAG_POWERUP, when both DAC and ADC are
* operational to prevent inadvertently starving the
* other one of them.
@@ -182,6 +197,39 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
return 0;
}
+/*
+ * If we mux a direct path from LINE_IN to HP, VAG must be powered up.
+ * With the SND_SOC_DAPM_POST_REG event the new state of the headphone mux is
+ * available.
+ */
+static int headphone_mux_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ /*
+ * switch on VAG unconditionally on any change of the headphone muxer
+ * early to lessen pop.
+ */
+ switch (event) {
+ case SND_SOC_DAPM_PRE_REG:
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
+ break;
+ /*
+ * The call to power_vag_event() switches VAG off again, if VAG need
+ * not be switched on.
+ */
+ case SND_SOC_DAPM_POST_REG:
+ power_vag_event(w, kcontrol, SND_SOC_DAPM_PRE_PMD);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
/* input sources for ADC */
static const char *adc_mux_text[] = {
"MIC_IN", "LINE_IN"
@@ -221,7 +269,9 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux),
- SND_SOC_DAPM_MUX("Headphone Mux", SND_SOC_NOPM, 0, 0, &dac_mux),
+ SND_SOC_DAPM_MUX_E("Headphone Mux", SND_SOC_NOPM, 0, 0, &dac_mux,
+ headphone_mux_event,
+ SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG),
/* aif for i2s input */
SND_SOC_DAPM_AIF_IN("AIFIN", "Playback",
@@ -1100,6 +1150,7 @@ 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);
/* power up sgtl5000 */
@@ -1129,7 +1180,8 @@ 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 |
@@ -1358,6 +1410,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);
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 48f795dfc3ed..887af25f7367 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -55,6 +55,7 @@ config SND_SOC_FSL_SSI
config SND_SOC_FSL_SPDIF
tristate "Sony/Philips Digital Interface (S/PDIF) module support"
select REGMAP_MMIO
+ select SND_SOC_FSL_DMA_WORKAROUND
select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC)
help
@@ -66,6 +67,7 @@ config SND_SOC_FSL_SPDIF
config SND_SOC_FSL_ESAI
tristate "Enhanced Serial Audio Interface (ESAI) module support"
select REGMAP_MMIO
+ select SND_SOC_FSL_DMA_WORKAROUND
select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
help
Say Y if you want to add Enhanced Synchronous Audio Interface
@@ -99,6 +101,9 @@ config SND_SOC_FSL_DSP
This option is only useful for out-of-tree drivers since
in-tree drivers select it automatically.
+config SND_SOC_FSL_DMA_WORKAROUND
+ tristate
+
config SND_SOC_FSL_UTILS
tristate
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 3e41fd9abfbd..ed0fe428464f 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -20,7 +20,7 @@ snd-soc-fsl-sai-objs := fsl_sai.o
snd-soc-fsl-ssi-y := fsl_ssi.o
snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o
snd-soc-fsl-spdif-objs := fsl_spdif.o
-snd-soc-fsl-esai-objs := fsl_esai.o fsl_dma_workaround.o
+snd-soc-fsl-esai-objs := fsl_esai.o
snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
snd-soc-fsl-rpmsg-i2s-objs := fsl_rpmsg_i2s.o
@@ -31,6 +31,7 @@ snd-soc-fsl-micfil-objs := fsl_micfil.o
obj-$(CONFIG_SND_SOC_FSL_ACM) += snd-soc-fsl-acm.o
obj-$(CONFIG_SND_SOC_FSL_AMIX) += snd-soc-fsl-amix.o
obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o
+obj-$(CONFIG_SND_SOC_FSL_DMA_WORKAROUND) += snd-soc-fsl-dma-workaround.o
obj-$(CONFIG_SND_SOC_FSL_DSP) += snd-soc-fsl-dsp.o
obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index a7a3639e50b2..5149912ae22f 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -548,10 +548,10 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
scr = SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL |
SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP |
- SCR_TXFIFO_FSEL_IF8;
+ SCR_TXFIFO_FSEL_IF8 | SCR_VAL_CLEAR;
mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
- SCR_TXFIFO_FSEL_MASK;
+ SCR_TXFIFO_FSEL_MASK | SCR_VAL_MASK;
} else {
scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC;
mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index b99e0b5e00e9..de5691b3cc10 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012, 2014 Freescale Semiconductor, Inc.
* Copyright 2012 Linaro Ltd.
*
* The code contained herein is licensed under the GNU General Public
@@ -55,13 +55,9 @@ static const struct snd_soc_dapm_widget imx_sgtl5000_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Ext Spk", NULL),
};
-static int imx_sgtl5000_probe(struct platform_device *pdev)
+static int imx_sgtl5000_audmux_config(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct device_node *ssi_np, *codec_np;
- struct platform_device *ssi_pdev;
- struct i2c_client *codec_dev;
- struct imx_sgtl5000_data *data = NULL;
int int_port, ext_port;
int ret;
@@ -101,16 +97,33 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
return ret;
}
- ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
+ return 0;
+}
+
+static int imx_sgtl5000_probe(struct platform_device *pdev)
+{
+ struct device_node *cpu_np, *codec_np;
+ struct platform_device *cpu_pdev;
+ struct i2c_client *codec_dev;
+ struct imx_sgtl5000_data *data = NULL;
+ int ret;
+
+ cpu_np = of_parse_phandle(pdev->dev.of_node, "cpu-dai", 0);
codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
- if (!ssi_np || !codec_np) {
+ if (!cpu_np || !codec_np) {
dev_err(&pdev->dev, "phandle missing or invalid\n");
ret = -EINVAL;
goto fail;
}
- ssi_pdev = of_find_device_by_node(ssi_np);
- if (!ssi_pdev) {
+ if (strstr(cpu_np->name, "ssi")) {
+ ret = imx_sgtl5000_audmux_config(pdev);
+ if (ret)
+ goto fail;
+ }
+
+ cpu_pdev = of_find_device_by_node(cpu_np);
+ if (!cpu_pdev) {
dev_err(&pdev->dev, "failed to find SSI platform device\n");
ret = -EPROBE_DEFER;
goto fail;
@@ -139,8 +152,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
data->dai.stream_name = "HiFi";
data->dai.codec_dai_name = "sgtl5000";
data->dai.codec_of_node = codec_np;
- data->dai.cpu_of_node = ssi_np;
- data->dai.platform_of_node = ssi_np;
+ data->dai.cpu_of_node = cpu_np;
+ data->dai.platform_of_node = cpu_np;
data->dai.init = &imx_sgtl5000_dai_init;
data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM;
@@ -167,7 +180,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
goto fail;
}
- of_node_put(ssi_np);
+ of_node_put(cpu_np);
of_node_put(codec_np);
return 0;
@@ -175,8 +188,10 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
fail:
if (data && !IS_ERR(data->codec_clk))
clk_put(data->codec_clk);
- of_node_put(ssi_np);
- of_node_put(codec_np);
+ if (cpu_np)
+ of_node_put(cpu_np);
+ if (codec_np)
+ of_node_put(codec_np);
return ret;
}