diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/sgtl5000.c | 63 | ||||
-rw-r--r-- | sound/soc/fsl/Kconfig | 5 | ||||
-rw-r--r-- | sound/soc/fsl/Makefile | 3 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_spdif.c | 4 | ||||
-rw-r--r-- | sound/soc/fsl/imx-sgtl5000.c | 45 |
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; } |