diff options
Diffstat (limited to 'sound/soc')
118 files changed, 5532 insertions, 2832 deletions
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index e634eb78ed03..4789619a52d8 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -58,6 +58,6 @@ config SND_AT91_SOC_AFEB9260 depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC select SND_ATMEL_SOC_PDC select SND_ATMEL_SOC_SSC - select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC23_I2C help Say Y here to support sound on AFEB9260 board. diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 1ead3c977a51..de433cfd044c 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -341,6 +341,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, { int id = dai->id; struct atmel_ssc_info *ssc_p = &ssc_info[id]; + struct ssc_device *ssc = ssc_p->ssc; struct atmel_pcm_dma_params *dma_params; int dir, channels, bits; u32 tfmr, rfmr, tcmr, rcmr; @@ -466,7 +467,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RCMR_START, start_event) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); + | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_PIN : SSC_CKS_CLOCK); rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) @@ -481,7 +483,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(TCMR_START, start_event) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, SSC_CKS_PIN); + | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_CLOCK : SSC_CKS_PIN); tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSDEN, 0) @@ -550,7 +553,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RCMR_START, SSC_START_RISING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_PIN); + | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_PIN : SSC_CKS_CLOCK); rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) @@ -565,7 +569,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(TCMR_START, SSC_START_RISING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, SSC_CKS_PIN); + | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_CLOCK : SSC_CKS_PIN); tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSDEN, 0) diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index f15bff1548f8..174bd546c08b 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -155,25 +155,14 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) return ret; } - /* Add specific widgets */ - snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets, - ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); - /* Set up specific audio path interconnects */ - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - /* not connected */ snd_soc_dapm_nc_pin(dapm, "RLINEIN"); snd_soc_dapm_nc_pin(dapm, "LLINEIN"); -#ifdef ENABLE_MIC_INPUT - snd_soc_dapm_enable_pin(dapm, "Int Mic"); -#else - snd_soc_dapm_nc_pin(dapm, "Int Mic"); +#ifndef ENABLE_MIC_INPUT + snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic"); #endif - /* always connected */ - snd_soc_dapm_enable_pin(dapm, "Ext Spk"); - return 0; } @@ -194,6 +183,11 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = { .dai_link = &at91sam9g20ek_dai, .num_links = 1, .set_bias_level = at91sam9g20ek_set_bias_level, + + .dapm_widgets = at91sam9g20ek_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), }; static int at91sam9g20ek_audio_probe(struct platform_device *pdev) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 54f74f8cbb75..b2107918f0ad 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -11,7 +11,7 @@ config SND_BF5XX_I2S config SND_BF5XX_SOC_SSM2602 tristate "SoC SSM2602 Audio Codec Add-On Card support" - depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) + depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI select SND_BF5XX_SOC_I2S if !BF60x select SND_BF6XX_SOC_I2S if BF60x select SND_SOC_SSM2602 @@ -21,10 +21,9 @@ config SND_BF5XX_SOC_SSM2602 config SND_SOC_BFIN_EVAL_ADAU1701 tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" - depends on SND_BF5XX_I2S + depends on SND_BF5XX_I2S && I2C select SND_BF5XX_SOC_I2S select SND_SOC_ADAU1701 - select I2C help Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ board connected to one of the Blackfin evaluation boards like the @@ -45,9 +44,10 @@ config SND_SOC_BFIN_EVAL_ADAU1373 config SND_SOC_BFIN_EVAL_ADAV80X tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" - depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) + depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI select SND_BF5XX_SOC_I2S - select SND_SOC_ADAV80X + select SND_SOC_ADAV801 if SPI_MASTER + select SND_SOC_ADAV803 if I2C help Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or EVAL-ADAV803 board connected to one of the Blackfin evaluation boards @@ -58,7 +58,7 @@ config SND_SOC_BFIN_EVAL_ADAV80X config SND_BF5XX_SOC_AD1836 tristate "SoC AD1836 Audio support for BF5xx" - depends on SND_BF5XX_I2S + depends on SND_BF5XX_I2S && SPI_MASTER select SND_BF5XX_SOC_I2S select SND_SOC_AD1836 help @@ -66,9 +66,10 @@ config SND_BF5XX_SOC_AD1836 config SND_BF5XX_SOC_AD193X tristate "SoC AD193X Audio support for Blackfin" - depends on SND_BF5XX_I2S + depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI select SND_BF5XX_SOC_I2S - select SND_SOC_AD193X + select SND_SOC_AD193X_I2C if I2C + select SND_SOC_AD193X_SPI if SPI_MASTER help Say Y if you want to add support for AD193X codec on Blackfin. This driver supports AD1936, AD1937, AD1938 and AD1939. diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 06f938deda15..5477c5475923 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig @@ -1,6 +1,6 @@ config SND_EP93XX_SOC tristate "SoC Audio support for the Cirrus Logic EP93xx series" - depends on (ARCH_EP93XX || COMPILE_TEST) && SND_SOC + depends on ARCH_EP93XX || COMPILE_TEST select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to @@ -18,7 +18,7 @@ config SND_EP93XX_SOC_SNAPPERCL15 tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 select SND_EP93XX_SOC_I2S - select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC23_I2C help Say Y or M here if you want to add support for I2S audio on the Bluewater Systems Snapper CL15 module. diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 75d0ad5d2dcb..8703244ee9fb 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -448,38 +448,38 @@ static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"}; static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"}; -static const struct soc_enum pm860x_hs1_opamp_enum = - SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum, + PM860X_HS1_CTRL, 5, pm860x_opamp_texts); -static const struct soc_enum pm860x_hs2_opamp_enum = - SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum, + PM860X_HS2_CTRL, 5, pm860x_opamp_texts); -static const struct soc_enum pm860x_hs1_pa_enum = - SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum, + PM860X_HS1_CTRL, 3, pm860x_pa_texts); -static const struct soc_enum pm860x_hs2_pa_enum = - SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum, + PM860X_HS2_CTRL, 3, pm860x_pa_texts); -static const struct soc_enum pm860x_lo1_opamp_enum = - SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum, + PM860X_LO1_CTRL, 5, pm860x_opamp_texts); -static const struct soc_enum pm860x_lo2_opamp_enum = - SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum, + PM860X_LO2_CTRL, 5, pm860x_opamp_texts); -static const struct soc_enum pm860x_lo1_pa_enum = - SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum, + PM860X_LO1_CTRL, 3, pm860x_pa_texts); -static const struct soc_enum pm860x_lo2_pa_enum = - SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum, + PM860X_LO2_CTRL, 3, pm860x_pa_texts); -static const struct soc_enum pm860x_spk_pa_enum = - SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum, + PM860X_EAR_CTRL_1, 5, pm860x_pa_texts); -static const struct soc_enum pm860x_ear_pa_enum = - SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum, + PM860X_EAR_CTRL_2, 0, pm860x_pa_texts); -static const struct soc_enum pm860x_spk_ear_opamp_enum = - SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts); +static SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum, + PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts); static const struct snd_kcontrol_new pm860x_snd_controls[] = { SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2, @@ -561,8 +561,8 @@ static const char *aif1_text[] = { "PCM L", "PCM R", }; -static const struct soc_enum aif1_enum = - SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text); +static SOC_ENUM_SINGLE_DECL(aif1_enum, + PM860X_PCM_IFACE_3, 6, aif1_text); static const struct snd_kcontrol_new aif1_mux = SOC_DAPM_ENUM("PCM Mux", aif1_enum); @@ -572,8 +572,8 @@ static const char *i2s_din_text[] = { "DIN", "DIN1", }; -static const struct soc_enum i2s_din_enum = - SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text); +static SOC_ENUM_SINGLE_DECL(i2s_din_enum, + PM860X_I2S_IFACE_3, 1, i2s_din_text); static const struct snd_kcontrol_new i2s_din_mux = SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum); @@ -583,8 +583,8 @@ static const char *i2s_mic_text[] = { "Ex PA", "ADC", }; -static const struct soc_enum i2s_mic_enum = - SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text); +static SOC_ENUM_SINGLE_DECL(i2s_mic_enum, + PM860X_I2S_IFACE_3, 4, i2s_mic_text); static const struct snd_kcontrol_new i2s_mic_mux = SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum); @@ -594,8 +594,8 @@ static const char *adcl_text[] = { "ADCR", "ADCL", }; -static const struct soc_enum adcl_enum = - SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text); +static SOC_ENUM_SINGLE_DECL(adcl_enum, + PM860X_PCM_IFACE_3, 4, adcl_text); static const struct snd_kcontrol_new adcl_mux = SOC_DAPM_ENUM("ADC Left Mux", adcl_enum); @@ -605,8 +605,8 @@ static const char *adcr_text[] = { "ADCL", "ADCR", }; -static const struct soc_enum adcr_enum = - SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text); +static SOC_ENUM_SINGLE_DECL(adcr_enum, + PM860X_PCM_IFACE_3, 2, adcr_text); static const struct snd_kcontrol_new adcr_mux = SOC_DAPM_ENUM("ADC Right Mux", adcr_enum); @@ -616,8 +616,8 @@ static const char *adcr_ec_text[] = { "ADCR", "EC", }; -static const struct soc_enum adcr_ec_enum = - SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text); +static SOC_ENUM_SINGLE_DECL(adcr_ec_enum, + PM860X_ADC_EN_2, 3, adcr_ec_text); static const struct snd_kcontrol_new adcr_ec_mux = SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum); @@ -627,8 +627,8 @@ static const char *ec_text[] = { "Left", "Right", "Left + Right", }; -static const struct soc_enum ec_enum = - SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text); +static SOC_ENUM_SINGLE_DECL(ec_enum, + PM860X_EC_PATH, 1, ec_text); static const struct snd_kcontrol_new ec_mux = SOC_DAPM_ENUM("EC Mux", ec_enum); @@ -638,36 +638,36 @@ static const char *dac_text[] = { }; /* DAC Headset 1 Mux / Mux10 */ -static const struct soc_enum dac_hs1_enum = - SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_hs1_enum, + PM860X_ANA_INPUT_SEL_1, 0, dac_text); static const struct snd_kcontrol_new dac_hs1_mux = SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum); /* DAC Headset 2 Mux / Mux11 */ -static const struct soc_enum dac_hs2_enum = - SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_hs2_enum, + PM860X_ANA_INPUT_SEL_1, 2, dac_text); static const struct snd_kcontrol_new dac_hs2_mux = SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum); /* DAC Lineout 1 Mux / Mux12 */ -static const struct soc_enum dac_lo1_enum = - SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_lo1_enum, + PM860X_ANA_INPUT_SEL_1, 4, dac_text); static const struct snd_kcontrol_new dac_lo1_mux = SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum); /* DAC Lineout 2 Mux / Mux13 */ -static const struct soc_enum dac_lo2_enum = - SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_lo2_enum, + PM860X_ANA_INPUT_SEL_1, 6, dac_text); static const struct snd_kcontrol_new dac_lo2_mux = SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum); /* DAC Spearker Earphone Mux / Mux14 */ -static const struct soc_enum dac_spk_ear_enum = - SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text); +static SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum, + PM860X_ANA_INPUT_SEL_2, 0, dac_text); static const struct snd_kcontrol_new dac_spk_ear_mux = SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum); @@ -677,29 +677,29 @@ static const char *in_text[] = { "Digital", "Analog", }; -static const struct soc_enum hs1_enum = - SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text); +static SOC_ENUM_SINGLE_DECL(hs1_enum, + PM860X_ANA_TO_ANA, 0, in_text); static const struct snd_kcontrol_new hs1_mux = SOC_DAPM_ENUM("Headset1 Mux", hs1_enum); /* Headset 2 Mux / Mux16 */ -static const struct soc_enum hs2_enum = - SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text); +static SOC_ENUM_SINGLE_DECL(hs2_enum, + PM860X_ANA_TO_ANA, 1, in_text); static const struct snd_kcontrol_new hs2_mux = SOC_DAPM_ENUM("Headset2 Mux", hs2_enum); /* Lineout 1 Mux / Mux17 */ -static const struct soc_enum lo1_enum = - SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text); +static SOC_ENUM_SINGLE_DECL(lo1_enum, + PM860X_ANA_TO_ANA, 2, in_text); static const struct snd_kcontrol_new lo1_mux = SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum); /* Lineout 2 Mux / Mux18 */ -static const struct soc_enum lo2_enum = - SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text); +static SOC_ENUM_SINGLE_DECL(lo2_enum, + PM860X_ANA_TO_ANA, 3, in_text); static const struct snd_kcontrol_new lo2_mux = SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum); @@ -709,8 +709,8 @@ static const char *spk_text[] = { "Earpiece", "Speaker", }; -static const struct soc_enum spk_enum = - SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text); +static SOC_ENUM_SINGLE_DECL(spk_enum, + PM860X_ANA_TO_ANA, 6, spk_text); static const struct snd_kcontrol_new spk_demux = SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum); @@ -720,8 +720,8 @@ static const char *mic_text[] = { "Mic 1", "Mic 2", }; -static const struct soc_enum mic_enum = - SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text); +static SOC_ENUM_SINGLE_DECL(mic_enum, + PM860X_ADC_ANA_4, 4, mic_text); static const struct snd_kcontrol_new mic_mux = SOC_DAPM_ENUM("MIC Mux", mic_enum); @@ -1328,6 +1328,9 @@ static int pm860x_probe(struct snd_soc_codec *codec) pm860x->codec = codec; codec->control_data = pm860x->regmap; + ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); + if (ret) + return ret; for (i = 0; i < 4; i++) { ret = request_threaded_irq(pm860x->irq[i], NULL, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 983d087aa92a..cf7f169adb12 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -8,6 +8,8 @@ config SND_SOC_I2C_AND_SPI default y if I2C=y default y if SPI_MASTER=y +menu "CODEC drivers" + config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" depends on COMPILE_TEST @@ -16,15 +18,20 @@ config SND_SOC_ALL_CODECS select SND_SOC_AB8500_CODEC if ABX500_CORE select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS select SND_SOC_AD1836 if SPI_MASTER - select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI + select SND_SOC_AD193X_SPI if SPI_MASTER + select SND_SOC_AD193X_I2C if I2C select SND_SOC_AD1980 if SND_SOC_AC97_BUS select SND_SOC_AD73311 select SND_SOC_ADAU1373 if I2C - select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI + select SND_SOC_ADAV801 if SPI_MASTER + select SND_SOC_ADAV803 if I2C + select SND_SOC_ADAU1977_SPI if SPI_MASTER + select SND_SOC_ADAU1977_I2C if I2C select SND_SOC_ADAU1701 if I2C select SND_SOC_ADS117X select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C + select SND_SOC_AK4554 select SND_SOC_AK4641 if I2C select SND_SOC_AK4642 if I2C select SND_SOC_AK4671 if I2C @@ -59,6 +66,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1792A if SPI_MASTER select SND_SOC_PCM3008 + select SND_SOC_PCM512x_I2C if I2C + select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C select SND_SOC_SGTL5000 if I2C @@ -71,7 +80,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_STA529 if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS5086 if I2C - select SND_SOC_TLV320AIC23 if I2C + select SND_SOC_TLV320AIC23_I2C if I2C + select SND_SOC_TLV320AIC23_SPI if SPI_MASTER select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC32X4 if I2C select SND_SOC_TLV320AIC3X if I2C @@ -182,6 +192,14 @@ config SND_SOC_AD1836 config SND_SOC_AD193X tristate +config SND_SOC_AD193X_SPI + tristate + select SND_SOC_AD193X + +config SND_SOC_AD193X_I2C + tristate + select SND_SOC_AD193X + config SND_SOC_AD1980 tristate @@ -189,41 +207,66 @@ config SND_SOC_AD73311 tristate config SND_SOC_ADAU1701 + tristate "Analog Devices ADAU1701 CODEC" + depends on I2C select SND_SOC_SIGMADSP - tristate config SND_SOC_ADAU1373 tristate +config SND_SOC_ADAU1977 + tristate + +config SND_SOC_ADAU1977_SPI + tristate + select SND_SOC_ADAU1977 + select REGMAP_SPI + +config SND_SOC_ADAU1977_I2C + tristate + select SND_SOC_ADAU1977 + select REGMAP_I2C + config SND_SOC_ADAV80X tristate +config SND_SOC_ADAV801 + tristate + select SND_SOC_ADAV80X + +config SND_SOC_ADAV803 + tristate + select SND_SOC_ADAV80X + config SND_SOC_ADS117X tristate config SND_SOC_AK4104 - tristate + tristate "AKM AK4104 CODEC" + depends on SPI_MASTER config SND_SOC_AK4535 tristate config SND_SOC_AK4554 - tristate + tristate "AKM AK4554 CODEC" config SND_SOC_AK4641 tristate config SND_SOC_AK4642 - tristate + tristate "AKM AK4642 CODEC" + depends on I2C config SND_SOC_AK4671 tristate config SND_SOC_AK5386 - tristate + tristate "AKM AK5638 CODEC" config SND_SOC_ALC5623 tristate + config SND_SOC_ALC5632 tristate @@ -234,14 +277,17 @@ config SND_SOC_CS42L51 tristate config SND_SOC_CS42L52 - tristate + tristate "Cirrus Logic CS42L52 CODEC" + depends on I2C config SND_SOC_CS42L73 - tristate + tristate "Cirrus Logic CS42L73 CODEC" + depends on I2C # Cirrus Logic CS4270 Codec config SND_SOC_CS4270 - tristate + tristate "Cirrus Logic CS4270 CODEC" + depends on I2C # Cirrus Logic CS4270 Codec VD = 3.3V Errata # Select if you are affected by the errata where the part will not function @@ -252,7 +298,8 @@ config SND_SOC_CS4270_VD33_ERRATA depends on SND_SOC_CS4270 config SND_SOC_CS4271 - tristate + tristate "Cirrus Logic CS4271 CODEC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_CX20442 tristate @@ -283,6 +330,9 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate +config SND_SOC_HDMI_CODEC + tristate "HDMI stub CODEC" + config SND_SOC_ISABELLE tristate @@ -301,18 +351,32 @@ config SND_SOC_MAX98095 config SND_SOC_MAX9850 tristate -config SND_SOC_HDMI_CODEC - tristate - config SND_SOC_PCM1681 - tristate + tristate "Texas Instruments PCM1681 CODEC" + depends on I2C config SND_SOC_PCM1792A - tristate + tristate "Texas Instruments PCM1792A CODEC" + depends on SPI_MASTER config SND_SOC_PCM3008 tristate +config SND_SOC_PCM512x + tristate + +config SND_SOC_PCM512x_I2C + tristate "Texas Instruments PCM512x CODECs - I2C" + depends on I2C + select SND_SOC_PCM512x + select REGMAP_I2C + +config SND_SOC_PCM512x_SPI + tristate "Texas Instruments PCM512x CODECs - SPI" + depends on SPI_MASTER + select SND_SOC_PCM512x + select REGMAP_SPI + config SND_SOC_RT5631 tristate @@ -321,7 +385,8 @@ config SND_SOC_RT5640 #Freescale sgtl5000 codec config SND_SOC_SGTL5000 - tristate + tristate "Freescale SGTL5000 CODEC" + depends on I2C config SND_SOC_SI476X tristate @@ -334,7 +399,7 @@ config SND_SOC_SN95031 tristate config SND_SOC_SPDIF - tristate + tristate "S/PDIF CODEC" config SND_SOC_SSM2518 tristate @@ -352,11 +417,20 @@ config SND_SOC_STAC9766 tristate config SND_SOC_TAS5086 - tristate + tristate "Texas Instruments TAS5086 speaker amplifier" + depends on I2C config SND_SOC_TLV320AIC23 tristate +config SND_SOC_TLV320AIC23_I2C + tristate + select SND_SOC_TLV320AIC23 + +config SND_SOC_TLV320AIC23_SPI + tristate + select SND_SOC_TLV320AIC23 + config SND_SOC_TLV320AIC26 tristate depends on SPI @@ -365,7 +439,8 @@ config SND_SOC_TLV320AIC32X4 tristate config SND_SOC_TLV320AIC3X - tristate + tristate "Texas Instruments TLV320AIC3x CODECs" + depends on I2C config SND_SOC_TLV320DAC33 tristate @@ -414,55 +489,69 @@ config SND_SOC_WM8400 tristate config SND_SOC_WM8510 - tristate + tristate "Wolfson Microelectronics WM8510 CODEC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8523 - tristate + tristate "Wolfson Microelectronics WM8523 DAC" + depends on I2C config SND_SOC_WM8580 - tristate + tristate "Wolfson Microelectronics WM8523 CODEC" + depends on I2C config SND_SOC_WM8711 - tristate + tristate "Wolfson Microelectronics WM8711 CODEC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8727 tristate config SND_SOC_WM8728 - tristate + tristate "Wolfson Microelectronics WM8728 DAC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8731 - tristate + tristate "Wolfson Microelectronics WM8731 CODEC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8737 - tristate + tristate "Wolfson Microelectronics WM8737 ADC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8741 - tristate + tristate "Wolfson Microelectronics WM8737 DAC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8750 - tristate + tristate "Wolfson Microelectronics WM8750 CODEC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8753 - tristate + tristate "Wolfson Microelectronics WM8753 CODEC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8770 - tristate + tristate "Wolfson Microelectronics WM8770 CODEC" + depends on SPI_MASTER config SND_SOC_WM8776 - tristate + tristate "Wolfson Microelectronics WM8776 CODEC" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8782 tristate config SND_SOC_WM8804 - tristate + tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver" + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8900 tristate config SND_SOC_WM8903 - tristate + tristate "Wolfson Microelectronics WM8903 CODEC" + depends on I2C config SND_SOC_WM8904 tristate @@ -480,7 +569,8 @@ config SND_SOC_WM8961 tristate config SND_SOC_WM8962 - tristate + tristate "Wolfson Microelectronics WM8962 CODEC" + depends on I2C config SND_SOC_WM8971 tristate @@ -553,4 +643,7 @@ config SND_SOC_ML26124 tristate config SND_SOC_TPA6130A2 - tristate + tristate "Texas Instruments TPA6130A2 headphone amplifier" + depends on I2C + +endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bc126764a44d..08540dae0090 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -3,11 +3,18 @@ snd-soc-ab8500-codec-objs := ab8500-codec.o snd-soc-ac97-objs := ac97.o snd-soc-ad1836-objs := ad1836.o snd-soc-ad193x-objs := ad193x.o +snd-soc-ad193x-spi-objs := ad193x-spi.o +snd-soc-ad193x-i2c-objs := ad193x-i2c.o snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o snd-soc-adau1701-objs := adau1701.o snd-soc-adau1373-objs := adau1373.o +snd-soc-adau1977-objs := adau1977.o +snd-soc-adau1977-spi-objs := adau1977-spi.o +snd-soc-adau1977-i2c-objs := adau1977-i2c.o snd-soc-adav80x-objs := adav80x.o +snd-soc-adav801-objs := adav801.o +snd-soc-adav803-objs := adav803.o snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o @@ -46,6 +53,9 @@ snd-soc-hdmi-codec-objs := hdmi.o snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm1792a-codec-objs := pcm1792a.o snd-soc-pcm3008-objs := pcm3008.o +snd-soc-pcm512x-objs := pcm512x.o +snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o +snd-soc-pcm512x-spi-objs := pcm512x-spi.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-sgtl5000-objs := sgtl5000.o @@ -63,6 +73,8 @@ snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o snd-soc-tlv320aic23-objs := tlv320aic23.o +snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o +snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o @@ -134,11 +146,18 @@ obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o +obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o +obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o +obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o +obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o +obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o +obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o +obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o @@ -179,6 +198,9 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o +obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o +obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o @@ -193,6 +215,8 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o +obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o +obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 77f459868579..685998dd086e 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -40,8 +40,8 @@ struct ad1836_priv { */ static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; -static const struct soc_enum ad1836_deemp_enum = - SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp); +static SOC_ENUM_SINGLE_DECL(ad1836_deemp_enum, + AD1836_DAC_CTRL1, 8, ad1836_deemp); #define AD1836_DAC_VOLUME(x) \ SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \ diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c new file mode 100644 index 000000000000..df3a1a415825 --- /dev/null +++ b/sound/soc/codecs/ad193x-i2c.c @@ -0,0 +1,54 @@ +/* + * AD1936/AD1937 audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "ad193x.h" + +static const struct i2c_device_id ad193x_id[] = { + { "ad1936", 0 }, + { "ad1937", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ad193x_id); + +static int ad193x_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap_config config; + + config = ad193x_regmap_config; + config.val_bits = 8; + config.reg_bits = 8; + + return ad193x_probe(&client->dev, devm_regmap_init_i2c(client, &config)); +} + +static int ad193x_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static struct i2c_driver ad193x_i2c_driver = { + .driver = { + .name = "ad193x", + }, + .probe = ad193x_i2c_probe, + .remove = ad193x_i2c_remove, + .id_table = ad193x_id, +}; +module_i2c_driver(ad193x_i2c_driver); + +MODULE_DESCRIPTION("ASoC AD1936/AD1937 audio CODEC driver"); +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ad193x-spi.c b/sound/soc/codecs/ad193x-spi.c new file mode 100644 index 000000000000..390cef9b9dc2 --- /dev/null +++ b/sound/soc/codecs/ad193x-spi.c @@ -0,0 +1,48 @@ +/* + * AD1938/AD1939 audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "ad193x.h" + +static int ad193x_spi_probe(struct spi_device *spi) +{ + struct regmap_config config; + + config = ad193x_regmap_config; + config.val_bits = 8; + config.reg_bits = 16; + config.read_flag_mask = 0x09; + config.write_flag_mask = 0x08; + + return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); +} + +static int ad193x_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static struct spi_driver ad193x_spi_driver = { + .driver = { + .name = "ad193x", + .owner = THIS_MODULE, + }, + .probe = ad193x_spi_probe, + .remove = ad193x_spi_remove, +}; +module_spi_driver(ad193x_spi_driver); + +MODULE_DESCRIPTION("ASoC AD1938/AD1939 audio CODEC driver"); +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 5a42dca535b7..9381a767e75f 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -6,12 +6,10 @@ * Licensed under the GPL-2 or later. */ -#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> -#include <linux/i2c.h> -#include <linux/spi/spi.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -19,6 +17,7 @@ #include <sound/initval.h> #include <sound/soc.h> #include <sound/tlv.h> + #include "ad193x.h" /* codec private data */ @@ -32,8 +31,8 @@ struct ad193x_priv { */ static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; -static const struct soc_enum ad193x_deemp_enum = - SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp); +static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1, + ad193x_deemp); static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); @@ -320,7 +319,7 @@ static struct snd_soc_dai_driver ad193x_dai = { .ops = &ad193x_dai_ops, }; -static int ad193x_probe(struct snd_soc_codec *codec) +static int ad193x_codec_probe(struct snd_soc_codec *codec) { struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); int ret; @@ -352,7 +351,7 @@ static int ad193x_probe(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_ad193x = { - .probe = ad193x_probe, + .probe = ad193x_codec_probe, .controls = ad193x_snd_controls, .num_controls = ARRAY_SIZE(ad193x_snd_controls), .dapm_widgets = ad193x_dapm_widgets, @@ -366,140 +365,31 @@ static bool adau193x_reg_volatile(struct device *dev, unsigned int reg) return false; } -#if defined(CONFIG_SPI_MASTER) - -static const struct regmap_config ad193x_spi_regmap_config = { - .val_bits = 8, - .reg_bits = 16, - .read_flag_mask = 0x09, - .write_flag_mask = 0x08, - +const struct regmap_config ad193x_regmap_config = { .max_register = AD193X_NUM_REGS - 1, .volatile_reg = adau193x_reg_volatile, }; +EXPORT_SYMBOL_GPL(ad193x_regmap_config); -static int ad193x_spi_probe(struct spi_device *spi) +int ad193x_probe(struct device *dev, struct regmap *regmap) { struct ad193x_priv *ad193x; - ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv), - GFP_KERNEL); - if (ad193x == NULL) - return -ENOMEM; - - ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config); - if (IS_ERR(ad193x->regmap)) - return PTR_ERR(ad193x->regmap); - - spi_set_drvdata(spi, ad193x); - - return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x, - &ad193x_dai, 1); -} - -static int ad193x_spi_remove(struct spi_device *spi) -{ - snd_soc_unregister_codec(&spi->dev); - return 0; -} - -static struct spi_driver ad193x_spi_driver = { - .driver = { - .name = "ad193x", - .owner = THIS_MODULE, - }, - .probe = ad193x_spi_probe, - .remove = ad193x_spi_remove, -}; -#endif - -#if IS_ENABLED(CONFIG_I2C) - -static const struct regmap_config ad193x_i2c_regmap_config = { - .val_bits = 8, - .reg_bits = 8, - - .max_register = AD193X_NUM_REGS - 1, - .volatile_reg = adau193x_reg_volatile, -}; - -static const struct i2c_device_id ad193x_id[] = { - { "ad1936", 0 }, - { "ad1937", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ad193x_id); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); -static int ad193x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ad193x_priv *ad193x; - - ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv), - GFP_KERNEL); + ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL); if (ad193x == NULL) return -ENOMEM; - ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config); - if (IS_ERR(ad193x->regmap)) - return PTR_ERR(ad193x->regmap); - - i2c_set_clientdata(client, ad193x); - - return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x, - &ad193x_dai, 1); -} - -static int ad193x_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - return 0; -} + ad193x->regmap = regmap; -static struct i2c_driver ad193x_i2c_driver = { - .driver = { - .name = "ad193x", - }, - .probe = ad193x_i2c_probe, - .remove = ad193x_i2c_remove, - .id_table = ad193x_id, -}; -#endif - -static int __init ad193x_modinit(void) -{ - int ret; - -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&ad193x_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n", - ret); - } -#endif - -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&ad193x_spi_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(ad193x_modinit); - -static void __exit ad193x_modexit(void) -{ -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&ad193x_spi_driver); -#endif + dev_set_drvdata(dev, ad193x); -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&ad193x_i2c_driver); -#endif + return snd_soc_register_codec(dev, &soc_codec_dev_ad193x, + &ad193x_dai, 1); } -module_exit(ad193x_modexit); +EXPORT_SYMBOL_GPL(ad193x_probe); MODULE_DESCRIPTION("ASoC ad193x driver"); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h index 473388049992..ab9a998f15be 100644 --- a/sound/soc/codecs/ad193x.h +++ b/sound/soc/codecs/ad193x.h @@ -9,6 +9,13 @@ #ifndef __AD193X_H__ #define __AD193X_H__ +#include <linux/regmap.h> + +struct device; + +extern const struct regmap_config ad193x_regmap_config; +int ad193x_probe(struct device *dev, struct regmap *regmap); + #define AD193X_PLL_CLK_CTRL0 0x00 #define AD193X_PLL_POWERDOWN 0x01 #define AD193X_PLL_INPUT_MASK 0x6 diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 7257a8885f42..34d965a4a040 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -57,8 +57,8 @@ static const u16 ad1980_reg[] = { static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", "Stereo Mix", "Mono Mix", "Phone"}; -static const struct soc_enum ad1980_cap_src = - SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel); +static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src, + AC97_REC_SEL, 8, 0, ad1980_rec_sel); static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = { SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index eb836ed5271f..5223800775ad 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -345,15 +345,15 @@ static const char *adau1373_fdsp_sel_text[] = { "Channel 5", }; -static const SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum, ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum, ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum, ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum, ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum, ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text); static const char *adau1373_hpf_cutoff_text[] = { @@ -362,7 +362,7 @@ static const char *adau1373_hpf_cutoff_text[] = { "800Hz", }; -static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum, ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text); static const char *adau1373_bass_lpf_cutoff_text[] = { @@ -388,14 +388,14 @@ static const unsigned int adau1373_bass_tlv[] = { 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0), }; -static const SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum, ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text); -static const SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum, +static SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum, ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text, adau1373_bass_clip_level_values); -static const SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum, ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text); static const char *adau1373_3d_level_text[] = { @@ -409,9 +409,9 @@ static const char *adau1373_3d_cutoff_text[] = { "0.16875 fs", "0.27083 fs" }; -static const SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum, ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum, ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text); static const unsigned int adau1373_3d_tlv[] = { @@ -427,11 +427,11 @@ static const char *adau1373_lr_mux_text[] = { "Stereo", }; -static const SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum, ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum, ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text); -static const SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum, +static SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum, ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text); static const struct snd_kcontrol_new adau1373_controls[] = { @@ -576,8 +576,8 @@ static const char *adau1373_decimator_text[] = { "DMIC1", }; -static const struct soc_enum adau1373_decimator_enum = - SOC_ENUM_SINGLE(0, 0, 2, adau1373_decimator_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum, + adau1373_decimator_text); static const struct snd_kcontrol_new adau1373_decimator_mux = SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum); diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c new file mode 100644 index 000000000000..9700e8c838c9 --- /dev/null +++ b/sound/soc/codecs/adau1977-i2c.c @@ -0,0 +1,59 @@ +/* + * ADAU1977/ADAU1978/ADAU1979 driver + * + * Copyright 2014 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <sound/soc.h> + +#include "adau1977.h" + +static int adau1977_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap_config config; + + config = adau1977_regmap_config; + config.val_bits = 8; + config.reg_bits = 8; + + return adau1977_probe(&client->dev, + devm_regmap_init_i2c(client, &config), + id->driver_data, NULL); +} + +static int adau1977_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id adau1977_i2c_ids[] = { + { "adau1977", ADAU1977 }, + { "adau1978", ADAU1978 }, + { "adau1979", ADAU1978 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids); + +static struct i2c_driver adau1977_i2c_driver = { + .driver = { + .name = "adau1977", + .owner = THIS_MODULE, + }, + .probe = adau1977_i2c_probe, + .remove = adau1977_i2c_remove, + .id_table = adau1977_i2c_ids, +}; +module_i2c_driver(adau1977_i2c_driver); + +MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c new file mode 100644 index 000000000000..b05cf5da3a94 --- /dev/null +++ b/sound/soc/codecs/adau1977-spi.c @@ -0,0 +1,76 @@ +/* + * ADAU1977/ADAU1978/ADAU1979 driver + * + * Copyright 2014 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <sound/soc.h> + +#include "adau1977.h" + +static void adau1977_spi_switch_mode(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + + /* + * To get the device into SPI mode CLATCH has to be pulled low three + * times. Do this by issuing three dummy reads. + */ + spi_w8r8(spi, 0x00); + spi_w8r8(spi, 0x00); + spi_w8r8(spi, 0x00); +} + +static int adau1977_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct regmap_config config; + + if (!id) + return -EINVAL; + + config = adau1977_regmap_config; + config.val_bits = 8; + config.reg_bits = 16; + config.read_flag_mask = 0x1; + + return adau1977_probe(&spi->dev, + devm_regmap_init_spi(spi, &config), + id->driver_data, adau1977_spi_switch_mode); +} + +static int adau1977_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static const struct spi_device_id adau1977_spi_ids[] = { + { "adau1977", ADAU1977 }, + { "adau1978", ADAU1978 }, + { "adau1979", ADAU1978 }, + { } +}; +MODULE_DEVICE_TABLE(spi, adau1977_spi_ids); + +static struct spi_driver adau1977_spi_driver = { + .driver = { + .name = "adau1977", + .owner = THIS_MODULE, + }, + .probe = adau1977_spi_probe, + .remove = adau1977_spi_remove, + .id_table = adau1977_spi_ids, +}; +module_spi_driver(adau1977_spi_driver); + +MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c new file mode 100644 index 000000000000..fd55da7cb9d4 --- /dev/null +++ b/sound/soc/codecs/adau1977.c @@ -0,0 +1,1018 @@ +/* + * ADAU1977/ADAU1978/ADAU1979 driver + * + * Copyright 2014 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_data/adau1977.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "adau1977.h" + +#define ADAU1977_REG_POWER 0x00 +#define ADAU1977_REG_PLL 0x01 +#define ADAU1977_REG_BOOST 0x02 +#define ADAU1977_REG_MICBIAS 0x03 +#define ADAU1977_REG_BLOCK_POWER_SAI 0x04 +#define ADAU1977_REG_SAI_CTRL0 0x05 +#define ADAU1977_REG_SAI_CTRL1 0x06 +#define ADAU1977_REG_CMAP12 0x07 +#define ADAU1977_REG_CMAP34 0x08 +#define ADAU1977_REG_SAI_OVERTEMP 0x09 +#define ADAU1977_REG_POST_ADC_GAIN(x) (0x0a + (x)) +#define ADAU1977_REG_MISC_CONTROL 0x0e +#define ADAU1977_REG_DIAG_CONTROL 0x10 +#define ADAU1977_REG_STATUS(x) (0x11 + (x)) +#define ADAU1977_REG_DIAG_IRQ1 0x15 +#define ADAU1977_REG_DIAG_IRQ2 0x16 +#define ADAU1977_REG_ADJUST1 0x17 +#define ADAU1977_REG_ADJUST2 0x18 +#define ADAU1977_REG_ADC_CLIP 0x19 +#define ADAU1977_REG_DC_HPF_CAL 0x1a + +#define ADAU1977_POWER_RESET BIT(7) +#define ADAU1977_POWER_PWUP BIT(0) + +#define ADAU1977_PLL_CLK_S BIT(4) +#define ADAU1977_PLL_MCS_MASK 0x7 + +#define ADAU1977_MICBIAS_MB_VOLTS_MASK 0xf0 +#define ADAU1977_MICBIAS_MB_VOLTS_OFFSET 4 + +#define ADAU1977_BLOCK_POWER_SAI_LR_POL BIT(7) +#define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE BIT(6) +#define ADAU1977_BLOCK_POWER_SAI_LDO_EN BIT(5) + +#define ADAU1977_SAI_CTRL0_FMT_MASK (0x3 << 6) +#define ADAU1977_SAI_CTRL0_FMT_I2S (0x0 << 6) +#define ADAU1977_SAI_CTRL0_FMT_LJ (0x1 << 6) +#define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT (0x2 << 6) +#define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT (0x3 << 6) + +#define ADAU1977_SAI_CTRL0_SAI_MASK (0x7 << 3) +#define ADAU1977_SAI_CTRL0_SAI_I2S (0x0 << 3) +#define ADAU1977_SAI_CTRL0_SAI_TDM_2 (0x1 << 3) +#define ADAU1977_SAI_CTRL0_SAI_TDM_4 (0x2 << 3) +#define ADAU1977_SAI_CTRL0_SAI_TDM_8 (0x3 << 3) +#define ADAU1977_SAI_CTRL0_SAI_TDM_16 (0x4 << 3) + +#define ADAU1977_SAI_CTRL0_FS_MASK (0x7) +#define ADAU1977_SAI_CTRL0_FS_8000_12000 (0x0) +#define ADAU1977_SAI_CTRL0_FS_16000_24000 (0x1) +#define ADAU1977_SAI_CTRL0_FS_32000_48000 (0x2) +#define ADAU1977_SAI_CTRL0_FS_64000_96000 (0x3) +#define ADAU1977_SAI_CTRL0_FS_128000_192000 (0x4) + +#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK (0x3 << 5) +#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32 (0x0 << 5) +#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24 (0x1 << 5) +#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16 (0x2 << 5) +#define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK (0x1 << 4) +#define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT (0x1 << 4) +#define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT (0x0 << 4) +#define ADAU1977_SAI_CTRL1_LRCLK_PULSE BIT(3) +#define ADAU1977_SAI_CTRL1_MSB BIT(2) +#define ADAU1977_SAI_CTRL1_BCLKRATE_16 (0x1 << 1) +#define ADAU1977_SAI_CTRL1_BCLKRATE_32 (0x0 << 1) +#define ADAU1977_SAI_CTRL1_BCLKRATE_MASK (0x1 << 1) +#define ADAU1977_SAI_CTRL1_MASTER BIT(0) + +#define ADAU1977_SAI_OVERTEMP_DRV_C(x) BIT(4 + (x)) +#define ADAU1977_SAI_OVERTEMP_DRV_HIZ BIT(3) + +#define ADAU1977_MISC_CONTROL_SUM_MODE_MASK (0x3 << 6) +#define ADAU1977_MISC_CONTROL_SUM_MODE_1CH (0x2 << 6) +#define ADAU1977_MISC_CONTROL_SUM_MODE_2CH (0x1 << 6) +#define ADAU1977_MISC_CONTROL_SUM_MODE_4CH (0x0 << 6) +#define ADAU1977_MISC_CONTROL_MMUTE BIT(4) +#define ADAU1977_MISC_CONTROL_DC_CAL BIT(0) + +#define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET 4 +#define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET 0 + +struct adau1977 { + struct regmap *regmap; + bool right_j; + unsigned int sysclk; + enum adau1977_sysclk_src sysclk_src; + struct gpio_desc *reset_gpio; + enum adau1977_type type; + + struct regulator *avdd_reg; + struct regulator *dvdd_reg; + + struct snd_pcm_hw_constraint_list constraints; + + struct device *dev; + void (*switch_mode)(struct device *dev); + + unsigned int max_master_fs; + unsigned int slot_width; + bool enabled; + bool master; +}; + +static const struct reg_default adau1977_reg_defaults[] = { + { 0x00, 0x00 }, + { 0x01, 0x41 }, + { 0x02, 0x4a }, + { 0x03, 0x7d }, + { 0x04, 0x3d }, + { 0x05, 0x02 }, + { 0x06, 0x00 }, + { 0x07, 0x10 }, + { 0x08, 0x32 }, + { 0x09, 0xf0 }, + { 0x0a, 0xa0 }, + { 0x0b, 0xa0 }, + { 0x0c, 0xa0 }, + { 0x0d, 0xa0 }, + { 0x0e, 0x02 }, + { 0x10, 0x0f }, + { 0x15, 0x20 }, + { 0x16, 0x00 }, + { 0x17, 0x00 }, + { 0x18, 0x00 }, + { 0x1a, 0x00 }, +}; + +static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000); + +static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS, + 3, 0, NULL, 0) +}; + +static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI, + 4, 0, NULL, 0), + + SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0), + SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0), + SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0), + SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0), + + SND_SOC_DAPM_INPUT("AIN1"), + SND_SOC_DAPM_INPUT("AIN2"), + SND_SOC_DAPM_INPUT("AIN3"), + SND_SOC_DAPM_INPUT("AIN4"), + + SND_SOC_DAPM_OUTPUT("VREF"), +}; + +static const struct snd_soc_dapm_route adau1977_dapm_routes[] = { + { "ADC1", NULL, "AIN1" }, + { "ADC2", NULL, "AIN2" }, + { "ADC3", NULL, "AIN3" }, + { "ADC4", NULL, "AIN4" }, + + { "ADC1", NULL, "Vref" }, + { "ADC2", NULL, "Vref" }, + { "ADC3", NULL, "Vref" }, + { "ADC4", NULL, "Vref" }, + + { "VREF", NULL, "Vref" }, +}; + +#define ADAU1977_VOLUME(x) \ + SOC_SINGLE_TLV("ADC" #x " Capture Volume", \ + ADAU1977_REG_POST_ADC_GAIN((x) - 1), \ + 0, 255, 1, adau1977_adc_gain) + +#define ADAU1977_HPF_SWITCH(x) \ + SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \ + ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0) + +#define ADAU1977_DC_SUB_SWITCH(x) \ + SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \ + ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0) + +static const struct snd_kcontrol_new adau1977_snd_controls[] = { + ADAU1977_VOLUME(1), + ADAU1977_VOLUME(2), + ADAU1977_VOLUME(3), + ADAU1977_VOLUME(4), + + ADAU1977_HPF_SWITCH(1), + ADAU1977_HPF_SWITCH(2), + ADAU1977_HPF_SWITCH(3), + ADAU1977_HPF_SWITCH(4), + + ADAU1977_DC_SUB_SWITCH(1), + ADAU1977_DC_SUB_SWITCH(2), + ADAU1977_DC_SUB_SWITCH(3), + ADAU1977_DC_SUB_SWITCH(4), +}; + +static int adau1977_reset(struct adau1977 *adau1977) +{ + int ret; + + /* + * The reset bit is obviously volatile, but we need to be able to cache + * the other bits in the register, so we can't just mark the whole + * register as volatile. Since this is the only place where we'll ever + * touch the reset bit just bypass the cache for this operation. + */ + regcache_cache_bypass(adau1977->regmap, true); + ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER, + ADAU1977_POWER_RESET); + regcache_cache_bypass(adau1977->regmap, false); + if (ret) + return ret; + + return ret; +} + +/* + * Returns the appropriate setting for ths FS field in the CTRL0 register + * depending on the rate. + */ +static int adau1977_lookup_fs(unsigned int rate) +{ + if (rate >= 8000 && rate <= 12000) + return ADAU1977_SAI_CTRL0_FS_8000_12000; + else if (rate >= 16000 && rate <= 24000) + return ADAU1977_SAI_CTRL0_FS_16000_24000; + else if (rate >= 32000 && rate <= 48000) + return ADAU1977_SAI_CTRL0_FS_32000_48000; + else if (rate >= 64000 && rate <= 96000) + return ADAU1977_SAI_CTRL0_FS_64000_96000; + else if (rate >= 128000 && rate <= 192000) + return ADAU1977_SAI_CTRL0_FS_128000_192000; + else + return -EINVAL; +} + +static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate, + unsigned int fs) +{ + unsigned int mcs; + + /* + * rate = sysclk / (512 * mcs_lut[mcs]) * 2**fs + * => mcs_lut[mcs] = sysclk / (512 * rate) * 2**fs + * => mcs_lut[mcs] = sysclk / ((512 / 2**fs) * rate) + */ + + rate *= 512 >> fs; + + if (adau1977->sysclk % rate != 0) + return -EINVAL; + + mcs = adau1977->sysclk / rate; + + /* The factors configured by MCS are 1, 2, 3, 4, 6 */ + if (mcs < 1 || mcs > 6 || mcs == 5) + return -EINVAL; + + mcs = mcs - 1; + if (mcs == 5) + mcs = 4; + + return mcs; +} + +static int adau1977_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); + unsigned int rate = params_rate(params); + unsigned int slot_width; + unsigned int ctrl0, ctrl0_mask; + unsigned int ctrl1; + int mcs, fs; + int ret; + + fs = adau1977_lookup_fs(rate); + if (fs < 0) + return fs; + + if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) { + mcs = adau1977_lookup_mcs(adau1977, rate, fs); + if (mcs < 0) + return mcs; + } else { + mcs = 0; + } + + ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK; + ctrl0 = fs; + + if (adau1977->right_j) { + switch (params_width(params)) { + case 16: + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT; + break; + case 24: + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; + break; + default: + return -EINVAL; + } + ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK; + } + + if (adau1977->master) { + switch (params_width(params)) { + case 16: + ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT; + slot_width = 16; + break; + case 24: + case 32: + ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT; + slot_width = 32; + break; + default: + return -EINVAL; + } + + /* In TDM mode there is a fixed slot width */ + if (adau1977->slot_width) + slot_width = adau1977->slot_width; + + if (slot_width == 16) + ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16; + else + ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32; + + ret = regmap_update_bits(adau1977->regmap, + ADAU1977_REG_SAI_CTRL1, + ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK | + ADAU1977_SAI_CTRL1_BCLKRATE_MASK, + ctrl1); + if (ret < 0) + return ret; + } + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, + ctrl0_mask, ctrl0); + if (ret < 0) + return ret; + + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, + ADAU1977_PLL_MCS_MASK, mcs); +} + +static int adau1977_power_disable(struct adau1977 *adau1977) +{ + int ret = 0; + + if (!adau1977->enabled) + return 0; + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, + ADAU1977_POWER_PWUP, 0); + if (ret) + return ret; + + regcache_mark_dirty(adau1977->regmap); + + if (adau1977->reset_gpio) + gpiod_set_value_cansleep(adau1977->reset_gpio, 0); + + regcache_cache_only(adau1977->regmap, true); + + regulator_disable(adau1977->avdd_reg); + if (adau1977->dvdd_reg) + regulator_disable(adau1977->dvdd_reg); + + adau1977->enabled = false; + + return 0; +} + +static int adau1977_power_enable(struct adau1977 *adau1977) +{ + unsigned int val; + int ret = 0; + + if (adau1977->enabled) + return 0; + + ret = regulator_enable(adau1977->avdd_reg); + if (ret) + return ret; + + if (adau1977->dvdd_reg) { + ret = regulator_enable(adau1977->dvdd_reg); + if (ret) + goto err_disable_avdd; + } + + if (adau1977->reset_gpio) + gpiod_set_value_cansleep(adau1977->reset_gpio, 1); + + regcache_cache_only(adau1977->regmap, false); + + if (adau1977->switch_mode) + adau1977->switch_mode(adau1977->dev); + + ret = adau1977_reset(adau1977); + if (ret) + goto err_disable_dvdd; + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, + ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP); + if (ret) + goto err_disable_dvdd; + + ret = regcache_sync(adau1977->regmap); + if (ret) + goto err_disable_dvdd; + + /* + * The PLL register is not affected by the software reset. It is + * possible that the value of the register was changed to the + * default value while we were in cache only mode. In this case + * regcache_sync will skip over it and we have to manually sync + * it. + */ + ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val); + if (ret) + goto err_disable_dvdd; + + if (val == 0x41) { + regcache_cache_bypass(adau1977->regmap, true); + ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL, + 0x41); + if (ret) + goto err_disable_dvdd; + regcache_cache_bypass(adau1977->regmap, false); + } + + adau1977->enabled = true; + + return ret; + +err_disable_dvdd: + if (adau1977->dvdd_reg) + regulator_disable(adau1977->dvdd_reg); +err_disable_avdd: + regulator_disable(adau1977->avdd_reg); + return ret; +} + +static int adau1977_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + ret = adau1977_power_enable(adau1977); + break; + case SND_SOC_BIAS_OFF: + ret = adau1977_power_disable(adau1977); + break; + } + + if (ret) + return ret; + + codec->dapm.bias_level = level; + + return 0; +} + +static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int width) +{ + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); + unsigned int ctrl0, ctrl1, drv; + unsigned int slot[4]; + unsigned int i; + int ret; + + if (slots == 0) { + /* 0 = No fixed slot width */ + adau1977->slot_width = 0; + adau1977->max_master_fs = 192000; + return regmap_update_bits(adau1977->regmap, + ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK, + ADAU1977_SAI_CTRL0_SAI_I2S); + } + + if (rx_mask == 0 || tx_mask != 0) + return -EINVAL; + + drv = 0; + for (i = 0; i < 4; i++) { + slot[i] = __ffs(rx_mask); + drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i); + rx_mask &= ~(1 << slot[i]); + if (slot[i] >= slots) + return -EINVAL; + if (rx_mask == 0) + break; + } + + if (rx_mask != 0) + return -EINVAL; + + switch (width) { + case 16: + ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16; + break; + case 24: + /* We can only generate 16 bit or 32 bit wide slots */ + if (adau1977->master) + return -EINVAL; + ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24; + break; + case 32: + ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32; + break; + default: + return -EINVAL; + } + + switch (slots) { + case 2: + ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2; + break; + case 4: + ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4; + break; + case 8: + ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8; + break; + case 16: + ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16; + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, + ADAU1977_SAI_OVERTEMP_DRV_C(0) | + ADAU1977_SAI_OVERTEMP_DRV_C(1) | + ADAU1977_SAI_OVERTEMP_DRV_C(2) | + ADAU1977_SAI_OVERTEMP_DRV_C(3), drv); + if (ret) + return ret; + + ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12, + (slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | + (slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); + if (ret) + return ret; + + ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34, + (slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | + (slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); + if (ret) + return ret; + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, + ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0); + if (ret) + return ret; + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, + ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1); + if (ret) + return ret; + + adau1977->slot_width = width; + + /* In master mode the maximum bitclock is 24.576 MHz */ + adau1977->max_master_fs = min(192000, 24576000 / width / slots); + + return 0; +} + +static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); + unsigned int val; + + if (mute) + val = ADAU1977_MISC_CONTROL_MMUTE; + else + val = 0; + + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL, + ADAU1977_MISC_CONTROL_MMUTE, val); +} + +static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); + unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0; + bool invert_lrclk; + int ret; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + adau1977->master = false; + break; + case SND_SOC_DAIFMT_CBM_CFM: + ctrl1 |= ADAU1977_SAI_CTRL1_MASTER; + adau1977->master = true; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + invert_lrclk = false; + break; + case SND_SOC_DAIFMT_IB_NF: + block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; + invert_lrclk = false; + break; + case SND_SOC_DAIFMT_NB_IF: + invert_lrclk = true; + break; + case SND_SOC_DAIFMT_IB_IF: + block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; + invert_lrclk = true; + break; + default: + return -EINVAL; + } + + adau1977->right_j = false; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; + invert_lrclk = !invert_lrclk; + break; + case SND_SOC_DAIFMT_RIGHT_J: + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; + adau1977->right_j = true; + invert_lrclk = !invert_lrclk; + break; + case SND_SOC_DAIFMT_DSP_A: + ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; + invert_lrclk = false; + break; + case SND_SOC_DAIFMT_DSP_B: + ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; + invert_lrclk = false; + break; + default: + return -EINVAL; + } + + if (invert_lrclk) + block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL; + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, + ADAU1977_BLOCK_POWER_SAI_LR_POL | + ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power); + if (ret) + return ret; + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, + ADAU1977_SAI_CTRL0_FMT_MASK, + ctrl0); + if (ret) + return ret; + + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, + ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE, + ctrl1); +} + +static int adau1977_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); + u64 formats = 0; + + if (adau1977->slot_width == 16) + formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE; + else if (adau1977->right_j || adau1977->slot_width == 24) + formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE; + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints); + + if (adau1977->master) + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs); + + if (formats != 0) + snd_pcm_hw_constraint_mask64(substream->runtime, + SNDRV_PCM_HW_PARAM_FORMAT, formats); + + return 0; +} + +static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); + unsigned int val; + + if (tristate) + val = ADAU1977_SAI_OVERTEMP_DRV_HIZ; + else + val = 0; + + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, + ADAU1977_SAI_OVERTEMP_DRV_HIZ, val); +} + +static const struct snd_soc_dai_ops adau1977_dai_ops = { + .startup = adau1977_startup, + .hw_params = adau1977_hw_params, + .mute_stream = adau1977_mute, + .set_fmt = adau1977_set_dai_fmt, + .set_tdm_slot = adau1977_set_tdm_slot, + .set_tristate = adau1977_set_tristate, +}; + +static struct snd_soc_dai_driver adau1977_dai = { + .name = "adau1977-hifi", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 24, + }, + .ops = &adau1977_dai_ops, +}; + +static const unsigned int adau1977_rates[] = { + 8000, 16000, 32000, 64000, 128000, + 11025, 22050, 44100, 88200, 172400, + 12000, 24000, 48000, 96000, 192000, +}; + +#define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f +#define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0 +#define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00 +/* All rates >= 32000 */ +#define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c + +static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq) +{ + unsigned int mcs; + + if (mclk % (base_freq * 128) != 0) + return false; + + mcs = mclk / (128 * base_freq); + if (mcs < 1 || mcs > 6 || mcs == 5) + return false; + + return true; +} + +static int adau1977_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, unsigned int freq, int dir) +{ + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); + unsigned int mask = 0; + unsigned int clk_src; + unsigned int ret; + + if (dir != SND_SOC_CLOCK_IN) + return -EINVAL; + + if (clk_id != ADAU1977_SYSCLK) + return -EINVAL; + + switch (source) { + case ADAU1977_SYSCLK_SRC_MCLK: + clk_src = 0; + break; + case ADAU1977_SYSCLK_SRC_LRCLK: + clk_src = ADAU1977_PLL_CLK_S; + break; + default: + return -EINVAL; + } + + if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) { + if (freq < 4000000 || freq > 36864000) + return -EINVAL; + + if (adau1977_check_sysclk(freq, 32000)) + mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000; + if (adau1977_check_sysclk(freq, 44100)) + mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100; + if (adau1977_check_sysclk(freq, 48000)) + mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000; + + if (mask == 0) + return -EINVAL; + } else if (source == ADAU1977_SYSCLK_SRC_LRCLK) { + mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK; + } + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, + ADAU1977_PLL_CLK_S, clk_src); + if (ret) + return ret; + + adau1977->constraints.mask = mask; + adau1977->sysclk_src = source; + adau1977->sysclk = freq; + + return 0; +} + +static int adau1977_codec_probe(struct snd_soc_codec *codec) +{ + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (adau1977->type) { + case ADAU1977: + ret = snd_soc_dapm_new_controls(&codec->dapm, + adau1977_micbias_dapm_widgets, + ARRAY_SIZE(adau1977_micbias_dapm_widgets)); + if (ret < 0) + return ret; + break; + default: + break; + } + + return 0; +} + +static struct snd_soc_codec_driver adau1977_codec_driver = { + .probe = adau1977_codec_probe, + .set_bias_level = adau1977_set_bias_level, + .set_sysclk = adau1977_set_sysclk, + .idle_bias_off = true, + + .controls = adau1977_snd_controls, + .num_controls = ARRAY_SIZE(adau1977_snd_controls), + .dapm_widgets = adau1977_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets), + .dapm_routes = adau1977_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes), +}; + +static int adau1977_setup_micbias(struct adau1977 *adau1977) +{ + struct adau1977_platform_data *pdata = adau1977->dev->platform_data; + unsigned int micbias; + + if (pdata) { + micbias = pdata->micbias; + if (micbias > ADAU1977_MICBIAS_9V0) + return -EINVAL; + + } else { + micbias = ADAU1977_MICBIAS_8V5; + } + + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS, + ADAU1977_MICBIAS_MB_VOLTS_MASK, + micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET); +} + +int adau1977_probe(struct device *dev, struct regmap *regmap, + enum adau1977_type type, void (*switch_mode)(struct device *dev)) +{ + unsigned int power_off_mask; + struct adau1977 *adau1977; + int ret; + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL); + if (adau1977 == NULL) + return -ENOMEM; + + adau1977->dev = dev; + adau1977->type = type; + adau1977->regmap = regmap; + adau1977->switch_mode = switch_mode; + adau1977->max_master_fs = 192000; + + adau1977->constraints.list = adau1977_rates; + adau1977->constraints.count = ARRAY_SIZE(adau1977_rates); + + adau1977->avdd_reg = devm_regulator_get(dev, "AVDD"); + if (IS_ERR(adau1977->avdd_reg)) + return PTR_ERR(adau1977->avdd_reg); + + adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD"); + if (IS_ERR(adau1977->dvdd_reg)) { + if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV) + return PTR_ERR(adau1977->dvdd_reg); + adau1977->dvdd_reg = NULL; + } + + adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); + if (IS_ERR(adau1977->reset_gpio)) { + ret = PTR_ERR(adau1977->reset_gpio); + if (ret != -ENOENT && ret != -ENOSYS) + return PTR_ERR(adau1977->reset_gpio); + adau1977->reset_gpio = NULL; + } + + dev_set_drvdata(dev, adau1977); + + if (adau1977->reset_gpio) { + ret = gpiod_direction_output(adau1977->reset_gpio, 0); + if (ret) + return ret; + ndelay(100); + } + + ret = adau1977_power_enable(adau1977); + if (ret) + return ret; + + if (type == ADAU1977) { + ret = adau1977_setup_micbias(adau1977); + if (ret) + goto err_poweroff; + } + + if (adau1977->dvdd_reg) + power_off_mask = ~0; + else + power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN; + + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, + power_off_mask, 0x00); + if (ret) + goto err_poweroff; + + ret = adau1977_power_disable(adau1977); + if (ret) + return ret; + + return snd_soc_register_codec(dev, &adau1977_codec_driver, + &adau1977_dai, 1); + +err_poweroff: + adau1977_power_disable(adau1977); + return ret; + +} +EXPORT_SYMBOL_GPL(adau1977_probe); + +static bool adau1977_register_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADAU1977_REG_STATUS(0): + case ADAU1977_REG_STATUS(1): + case ADAU1977_REG_STATUS(2): + case ADAU1977_REG_STATUS(3): + case ADAU1977_REG_ADC_CLIP: + return true; + } + + return false; +} + +const struct regmap_config adau1977_regmap_config = { + .max_register = ADAU1977_REG_DC_HPF_CAL, + .volatile_reg = adau1977_register_volatile, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = adau1977_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults), +}; +EXPORT_SYMBOL_GPL(adau1977_regmap_config); + +MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1977.h b/sound/soc/codecs/adau1977.h new file mode 100644 index 000000000000..95e714345a86 --- /dev/null +++ b/sound/soc/codecs/adau1977.h @@ -0,0 +1,37 @@ +/* + * ADAU1977/ADAU1978/ADAU1979 driver + * + * Copyright 2014 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#ifndef __SOUND_SOC_CODECS_ADAU1977_H__ +#define __SOUND_SOC_CODECS_ADAU1977_H__ + +#include <linux/regmap.h> + +struct device; + +enum adau1977_type { + ADAU1977, + ADAU1978, + ADAU1979, +}; + +int adau1977_probe(struct device *dev, struct regmap *regmap, + enum adau1977_type type, void (*switch_mode)(struct device *dev)); + +extern const struct regmap_config adau1977_regmap_config; + +enum adau1977_clk_id { + ADAU1977_SYSCLK, +}; + +enum adau1977_sysclk_src { + ADAU1977_SYSCLK_SRC_MCLK, + ADAU1977_SYSCLK_SRC_LRCLK, +}; + +#endif diff --git a/sound/soc/codecs/adav801.c b/sound/soc/codecs/adav801.c new file mode 100644 index 000000000000..790fce33ab10 --- /dev/null +++ b/sound/soc/codecs/adav801.c @@ -0,0 +1,53 @@ +/* + * ADAV801 audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "adav80x.h" + +static const struct spi_device_id adav80x_spi_id[] = { + { "adav801", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, adav80x_spi_id); + +static int adav80x_spi_probe(struct spi_device *spi) +{ + struct regmap_config config; + + config = adav80x_regmap_config; + config.read_flag_mask = 0x01; + + return adav80x_bus_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); +} + +static int adav80x_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static struct spi_driver adav80x_spi_driver = { + .driver = { + .name = "adav801", + .owner = THIS_MODULE, + }, + .probe = adav80x_spi_probe, + .remove = adav80x_spi_remove, + .id_table = adav80x_spi_id, +}; +module_spi_driver(adav80x_spi_driver); + +MODULE_DESCRIPTION("ASoC ADAV801 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c new file mode 100644 index 000000000000..66d9fce34e62 --- /dev/null +++ b/sound/soc/codecs/adav803.c @@ -0,0 +1,50 @@ +/* + * ADAV803 audio driver + * + * Copyright 2014 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "adav80x.h" + +static const struct i2c_device_id adav803_id[] = { + { "adav803", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adav803_id); + +static int adav803_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return adav80x_bus_probe(&client->dev, + devm_regmap_init_i2c(client, &adav80x_regmap_config)); +} + +static int adav803_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static struct i2c_driver adav803_driver = { + .driver = { + .name = "adav803", + .owner = THIS_MODULE, + }, + .probe = adav803_probe, + .remove = adav803_remove, + .id_table = adav803_id, +}; +module_i2c_driver(adav803_driver); + +MODULE_DESCRIPTION("ASoC ADAV803 driver"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index f78b27a7c461..7470831ba756 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -8,17 +8,15 @@ * Licensed under the GPL-2 or later. */ -#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> -#include <linux/i2c.h> -#include <linux/spi/spi.h> +#include <linux/regmap.h> #include <linux/slab.h> -#include <sound/core.h> + #include <sound/pcm.h> #include <sound/pcm_params.h> -#include <sound/tlv.h> #include <sound/soc.h> +#include <sound/tlv.h> #include "adav80x.h" @@ -541,6 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, unsigned int freq, int dir) { struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; if (dir == SND_SOC_CLOCK_IN) { switch (clk_id) { @@ -573,7 +572,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, iclk_ctrl2); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_sync(dapm); } } else { unsigned int mask; @@ -600,17 +599,21 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, adav80x->sysclk_pd[clk_id] = false; } + snd_soc_dapm_mutex_lock(dapm); + if (adav80x->sysclk_pd[0]) - snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); + snd_soc_dapm_disable_pin_unlocked(dapm, "PLL1"); else - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL1"); if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) - snd_soc_dapm_disable_pin(&codec->dapm, "PLL2"); + snd_soc_dapm_disable_pin_unlocked(dapm, "PLL2"); else - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL2"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); } return 0; @@ -722,7 +725,7 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - if (!codec->active || !adav80x->rate) + if (!snd_soc_codec_is_active(codec) || !adav80x->rate) return 0; return snd_pcm_hw_constraint_minmax(substream->runtime, @@ -735,7 +738,7 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - if (!codec->active) + if (!snd_soc_codec_is_active(codec)) adav80x->rate = 0; } @@ -864,39 +867,26 @@ static struct snd_soc_codec_driver adav80x_codec_driver = { .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), }; -static int adav80x_bus_probe(struct device *dev, struct regmap *regmap) +int adav80x_bus_probe(struct device *dev, struct regmap *regmap) { struct adav80x *adav80x; - int ret; if (IS_ERR(regmap)) return PTR_ERR(regmap); - adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); + adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL); if (!adav80x) return -ENOMEM; - dev_set_drvdata(dev, adav80x); adav80x->regmap = regmap; - ret = snd_soc_register_codec(dev, &adav80x_codec_driver, + return snd_soc_register_codec(dev, &adav80x_codec_driver, adav80x_dais, ARRAY_SIZE(adav80x_dais)); - if (ret) - kfree(adav80x); - - return ret; } +EXPORT_SYMBOL_GPL(adav80x_bus_probe); -static int adav80x_bus_remove(struct device *dev) -{ - snd_soc_unregister_codec(dev); - kfree(dev_get_drvdata(dev)); - return 0; -} - -#if defined(CONFIG_SPI_MASTER) -static const struct regmap_config adav80x_spi_regmap_config = { +const struct regmap_config adav80x_regmap_config = { .val_bits = 8, .pad_bits = 1, .reg_bits = 7, @@ -908,105 +898,7 @@ static const struct regmap_config adav80x_spi_regmap_config = { .reg_defaults = adav80x_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), }; - -static const struct spi_device_id adav80x_spi_id[] = { - { "adav801", 0 }, - { } -}; -MODULE_DEVICE_TABLE(spi, adav80x_spi_id); - -static int adav80x_spi_probe(struct spi_device *spi) -{ - return adav80x_bus_probe(&spi->dev, - devm_regmap_init_spi(spi, &adav80x_spi_regmap_config)); -} - -static int adav80x_spi_remove(struct spi_device *spi) -{ - return adav80x_bus_remove(&spi->dev); -} - -static struct spi_driver adav80x_spi_driver = { - .driver = { - .name = "adav801", - .owner = THIS_MODULE, - }, - .probe = adav80x_spi_probe, - .remove = adav80x_spi_remove, - .id_table = adav80x_spi_id, -}; -#endif - -#if IS_ENABLED(CONFIG_I2C) -static const struct regmap_config adav80x_i2c_regmap_config = { - .val_bits = 8, - .pad_bits = 1, - .reg_bits = 7, - - .max_register = ADAV80X_PLL_OUTE, - - .cache_type = REGCACHE_RBTREE, - .reg_defaults = adav80x_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), -}; - -static const struct i2c_device_id adav80x_i2c_id[] = { - { "adav803", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id); - -static int adav80x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return adav80x_bus_probe(&client->dev, - devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config)); -} - -static int adav80x_i2c_remove(struct i2c_client *client) -{ - return adav80x_bus_remove(&client->dev); -} - -static struct i2c_driver adav80x_i2c_driver = { - .driver = { - .name = "adav803", - .owner = THIS_MODULE, - }, - .probe = adav80x_i2c_probe, - .remove = adav80x_i2c_remove, - .id_table = adav80x_i2c_id, -}; -#endif - -static int __init adav80x_init(void) -{ - int ret = 0; - -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&adav80x_i2c_driver); - if (ret) - return ret; -#endif - -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&adav80x_spi_driver); -#endif - - return ret; -} -module_init(adav80x_init); - -static void __exit adav80x_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&adav80x_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&adav80x_spi_driver); -#endif -} -module_exit(adav80x_exit); +EXPORT_SYMBOL_GPL(adav80x_regmap_config); MODULE_DESCRIPTION("ASoC ADAV80x driver"); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); diff --git a/sound/soc/codecs/adav80x.h b/sound/soc/codecs/adav80x.h index adb0fc76d4e3..8a1d7c09dca5 100644 --- a/sound/soc/codecs/adav80x.h +++ b/sound/soc/codecs/adav80x.h @@ -9,6 +9,13 @@ #ifndef _ADAV80X_H #define _ADAV80X_H +#include <linux/regmap.h> + +struct device; + +extern const struct regmap_config adav80x_regmap_config; +int adav80x_bus_probe(struct device *dev, struct regmap *regmap); + enum adav80x_pll_src { ADAV80X_PLL_SRC_XIN, ADAV80X_PLL_SRC_XTAL, diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index b4819dcd4f4d..10adf25d4c14 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -174,8 +174,6 @@ static int ak4104_probe(struct snd_soc_codec *codec) struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); int ret; - codec->control_data = ak4104->regmap; - /* set power-up and non-reset bits */ ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 94cbe508dd37..684b56f2856a 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -113,14 +113,14 @@ static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0); static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0); -static const struct soc_enum ak4641_mono_out_enum = - SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out); -static const struct soc_enum ak4641_hp_out_enum = - SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out); -static const struct soc_enum ak4641_mic_select_enum = - SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select); -static const struct soc_enum ak4641_mic_or_dac_enum = - SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac); +static SOC_ENUM_SINGLE_DECL(ak4641_mono_out_enum, + AK4641_SIG1, 6, ak4641_mono_out); +static SOC_ENUM_SINGLE_DECL(ak4641_hp_out_enum, + AK4641_MODE2, 2, ak4641_hp_out); +static SOC_ENUM_SINGLE_DECL(ak4641_mic_select_enum, + AK4641_MIC, 1, ak4641_mic_select); +static SOC_ENUM_SINGLE_DECL(ak4641_mic_or_dac_enum, + AK4641_BTIF, 4, ak4641_mic_or_dac); static const struct snd_kcontrol_new ak4641_snd_controls[] = { SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum), diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 25bdf6ad4a54..deb2b44669de 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/i2c.h> #include <linux/delay.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/soc.h> #include <sound/initval.h> @@ -23,104 +24,99 @@ #include "ak4671.h" -/* codec private data */ -struct ak4671_priv { - enum snd_soc_control_type control_type; -}; - /* ak4671 register cache & default register settings */ -static const u8 ak4671_reg[AK4671_CACHEREGNUM] = { - 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ - 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */ - 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */ - 0x02, /* AK4671_FORMAT_SELECT (0x03) */ - 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ - 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */ - 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ - 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ - 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ - 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ - 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ - 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ - 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ - 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ - 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ - 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ - 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ - 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ - 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ - 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ - 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ - 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ - 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */ - 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */ - 0x02, /* AK4671_MODE_CONTROL1 (0x18) */ - 0x01, /* AK4671_MODE_CONTROL2 (0x19) */ - 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ - 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ - 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ - 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ - 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ - 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ - 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ - 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ - 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */ - 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */ - 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */ - 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */ - 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */ - 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */ - 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ - 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ - 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ - 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ - 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ - 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ - 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ - 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ - 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ - 0x00, /* this register not used */ - 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */ - 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */ - 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */ - 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */ - 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */ - 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */ - 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */ - 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */ - 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */ - 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */ - 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */ - 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */ - 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */ - 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */ - 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */ - 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */ - 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */ - 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */ - 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */ - 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */ - 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */ - 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */ - 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */ - 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */ - 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */ - 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */ - 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */ - 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */ - 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */ - 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */ - 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ - 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ - 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ - 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */ - 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */ - 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */ - 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ - 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ - 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ - 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ - 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */ +static const struct reg_default ak4671_reg_defaults[] = { + { 0x00, 0x00 }, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ + { 0x01, 0xf6 }, /* AK4671_PLL_MODE_SELECT0 (0x01) */ + { 0x02, 0x00 }, /* AK4671_PLL_MODE_SELECT1 (0x02) */ + { 0x03, 0x02 }, /* AK4671_FORMAT_SELECT (0x03) */ + { 0x04, 0x00 }, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ + { 0x05, 0x55 }, /* AK4671_MIC_AMP_GAIN (0x05) */ + { 0x06, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ + { 0x07, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ + { 0x08, 0xb5 }, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ + { 0x09, 0x00 }, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ + { 0x0a, 0x00 }, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ + { 0x0b, 0x00 }, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ + { 0x0c, 0x00 }, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ + { 0x0d, 0x00 }, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ + { 0x0e, 0x00 }, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ + { 0x0f, 0x00 }, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ + { 0x10, 0x00 }, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ + { 0x11, 0x80 }, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ + { 0x12, 0x91 }, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ + { 0x13, 0x91 }, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ + { 0x14, 0xe1 }, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ + { 0x15, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ + { 0x16, 0x00 }, /* AK4671_ALC_TIMER_SELECT (0x16) */ + { 0x17, 0x00 }, /* AK4671_ALC_MODE_CONTROL (0x17) */ + { 0x18, 0x02 }, /* AK4671_MODE_CONTROL1 (0x18) */ + { 0x19, 0x01 }, /* AK4671_MODE_CONTROL2 (0x19) */ + { 0x1a, 0x18 }, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ + { 0x1b, 0x18 }, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ + { 0x1c, 0x00 }, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ + { 0x1d, 0x02 }, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ + { 0x1e, 0x00 }, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ + { 0x1f, 0x00 }, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ + { 0x20, 0x00 }, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ + { 0x21, 0x00 }, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ + { 0x22, 0x00 }, /* AK4671_EQ_COEFFICIENT0 (0x22) */ + { 0x23, 0x00 }, /* AK4671_EQ_COEFFICIENT1 (0x23) */ + { 0x24, 0x00 }, /* AK4671_EQ_COEFFICIENT2 (0x24) */ + { 0x25, 0x00 }, /* AK4671_EQ_COEFFICIENT3 (0x25) */ + { 0x26, 0x00 }, /* AK4671_EQ_COEFFICIENT4 (0x26) */ + { 0x27, 0x00 }, /* AK4671_EQ_COEFFICIENT5 (0x27) */ + { 0x28, 0xa9 }, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ + { 0x29, 0x1f }, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ + { 0x2a, 0xad }, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ + { 0x2b, 0x20 }, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ + { 0x2c, 0x00 }, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ + { 0x2d, 0x00 }, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ + { 0x2e, 0x00 }, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ + { 0x2f, 0x00 }, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ + { 0x30, 0x00 }, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ + + { 0x32, 0x00 }, /* AK4671_E1_COEFFICIENT0 (0x32) */ + { 0x33, 0x00 }, /* AK4671_E1_COEFFICIENT1 (0x33) */ + { 0x34, 0x00 }, /* AK4671_E1_COEFFICIENT2 (0x34) */ + { 0x35, 0x00 }, /* AK4671_E1_COEFFICIENT3 (0x35) */ + { 0x36, 0x00 }, /* AK4671_E1_COEFFICIENT4 (0x36) */ + { 0x37, 0x00 }, /* AK4671_E1_COEFFICIENT5 (0x37) */ + { 0x38, 0x00 }, /* AK4671_E2_COEFFICIENT0 (0x38) */ + { 0x39, 0x00 }, /* AK4671_E2_COEFFICIENT1 (0x39) */ + { 0x3a, 0x00 }, /* AK4671_E2_COEFFICIENT2 (0x3a) */ + { 0x3b, 0x00 }, /* AK4671_E2_COEFFICIENT3 (0x3b) */ + { 0x3c, 0x00 }, /* AK4671_E2_COEFFICIENT4 (0x3c) */ + { 0x3d, 0x00 }, /* AK4671_E2_COEFFICIENT5 (0x3d) */ + { 0x3e, 0x00 }, /* AK4671_E3_COEFFICIENT0 (0x3e) */ + { 0x3f, 0x00 }, /* AK4671_E3_COEFFICIENT1 (0x3f) */ + { 0x40, 0x00 }, /* AK4671_E3_COEFFICIENT2 (0x40) */ + { 0x41, 0x00 }, /* AK4671_E3_COEFFICIENT3 (0x41) */ + { 0x42, 0x00 }, /* AK4671_E3_COEFFICIENT4 (0x42) */ + { 0x43, 0x00 }, /* AK4671_E3_COEFFICIENT5 (0x43) */ + { 0x44, 0x00 }, /* AK4671_E4_COEFFICIENT0 (0x44) */ + { 0x45, 0x00 }, /* AK4671_E4_COEFFICIENT1 (0x45) */ + { 0x46, 0x00 }, /* AK4671_E4_COEFFICIENT2 (0x46) */ + { 0x47, 0x00 }, /* AK4671_E4_COEFFICIENT3 (0x47) */ + { 0x48, 0x00 }, /* AK4671_E4_COEFFICIENT4 (0x48) */ + { 0x49, 0x00 }, /* AK4671_E4_COEFFICIENT5 (0x49) */ + { 0x4a, 0x00 }, /* AK4671_E5_COEFFICIENT0 (0x4a) */ + { 0x4b, 0x00 }, /* AK4671_E5_COEFFICIENT1 (0x4b) */ + { 0x4c, 0x00 }, /* AK4671_E5_COEFFICIENT2 (0x4c) */ + { 0x4d, 0x00 }, /* AK4671_E5_COEFFICIENT3 (0x4d) */ + { 0x4e, 0x00 }, /* AK4671_E5_COEFFICIENT4 (0x4e) */ + { 0x4f, 0x00 }, /* AK4671_E5_COEFFICIENT5 (0x4f) */ + { 0x50, 0x88 }, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ + { 0x51, 0x88 }, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ + { 0x52, 0x08 }, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ + { 0x53, 0x00 }, /* AK4671_PCM_IF_CONTROL0 (0x53) */ + { 0x54, 0x00 }, /* AK4671_PCM_IF_CONTROL1 (0x54) */ + { 0x55, 0x00 }, /* AK4671_PCM_IF_CONTROL2 (0x55) */ + { 0x56, 0x18 }, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ + { 0x57, 0x18 }, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ + { 0x58, 0x00 }, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ + { 0x59, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ + { 0x5a, 0x00 }, /* AK4671_SAR_ADC_CONTROL (0x5a) */ }; /* @@ -241,19 +237,17 @@ static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = { /* Input MUXs */ static const char *ak4671_lin_mux_texts[] = {"LIN1", "LIN2", "LIN3", "LIN4"}; -static const struct soc_enum ak4671_lin_mux_enum = - SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0, - ARRAY_SIZE(ak4671_lin_mux_texts), - ak4671_lin_mux_texts); +static SOC_ENUM_SINGLE_DECL(ak4671_lin_mux_enum, + AK4671_MIC_SIGNAL_SELECT, 0, + ak4671_lin_mux_texts); static const struct snd_kcontrol_new ak4671_lin_mux_control = SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); static const char *ak4671_rin_mux_texts[] = {"RIN1", "RIN2", "RIN3", "RIN4"}; -static const struct soc_enum ak4671_rin_mux_enum = - SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2, - ARRAY_SIZE(ak4671_rin_mux_texts), - ak4671_rin_mux_texts); +static SOC_ENUM_SINGLE_DECL(ak4671_rin_mux_enum, + AK4671_MIC_SIGNAL_SELECT, 2, + ak4671_rin_mux_texts); static const struct snd_kcontrol_new ak4671_rin_mux_control = SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); @@ -619,18 +613,14 @@ static struct snd_soc_dai_driver ak4671_dai = { static int ak4671_probe(struct snd_soc_codec *codec) { - struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec); int ret; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } - snd_soc_add_codec_controls(codec, ak4671_snd_controls, - ARRAY_SIZE(ak4671_snd_controls)); - ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return ret; @@ -646,28 +636,36 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { .probe = ak4671_probe, .remove = ak4671_remove, .set_bias_level = ak4671_set_bias_level, - .reg_cache_size = AK4671_CACHEREGNUM, - .reg_word_size = sizeof(u8), - .reg_cache_default = ak4671_reg, + .controls = ak4671_snd_controls, + .num_controls = ARRAY_SIZE(ak4671_snd_controls), .dapm_widgets = ak4671_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets), .dapm_routes = ak4671_intercon, .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), }; +static const struct regmap_config ak4671_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = AK4671_SAR_ADC_CONTROL, + .reg_defaults = ak4671_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ak4671_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + static int ak4671_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct ak4671_priv *ak4671; + struct regmap *regmap; int ret; - ak4671 = devm_kzalloc(&client->dev, sizeof(struct ak4671_priv), - GFP_KERNEL); - if (ak4671 == NULL) - return -ENOMEM; - - i2c_set_clientdata(client, ak4671); - ak4671->control_type = SND_SOC_I2C; + regmap = devm_regmap_init_i2c(client, &ak4671_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&client->dev, "Failed to create regmap: %d\n", ret); + return ret; + } ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_ak4671, &ak4671_dai, 1); diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h index 61cb7ab7552c..394a34d3f50a 100644 --- a/sound/soc/codecs/ak4671.h +++ b/sound/soc/codecs/ak4671.h @@ -105,8 +105,6 @@ #define AK4671_DIGITAL_MIXING_CONTROL2 0x59 #define AK4671_SAR_ADC_CONTROL 0x5a -#define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1) - /* Bitfield Definitions */ /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index d3036283482a..ed506253a914 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -21,6 +21,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -38,26 +39,13 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)"); /* codec private data */ struct alc5623_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; u8 id; unsigned int sysclk; - u16 reg_cache[ALC5623_VENDOR_ID2+2]; unsigned int add_ctrl; unsigned int jack_det_ctrl; }; -static void alc5623_fill_cache(struct snd_soc_codec *codec) -{ - int i, step = codec->driver->reg_cache_step; - u16 *cache = codec->reg_cache; - - /* not really efficient ... */ - codec->cache_bypass = 1; - for (i = 0 ; i < codec->driver->reg_cache_size ; i += step) - cache[i] = snd_soc_read(codec, i); - codec->cache_bypass = 0; -} - static inline int alc5623_reset(struct snd_soc_codec *codec) { return snd_soc_write(codec, ALC5623_RESET, 0); @@ -228,32 +216,37 @@ static const char *alc5623_aux_out_input_sel[] = { "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; /* auxout output mux */ -static const struct soc_enum alc5623_aux_out_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 6, 4, alc5623_aux_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_aux_out_input_enum, + ALC5623_OUTPUT_MIXER_CTRL, 6, + alc5623_aux_out_input_sel); static const struct snd_kcontrol_new alc5623_auxout_mux_controls = SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum); /* speaker output mux */ -static const struct soc_enum alc5623_spkout_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 10, 4, alc5623_spkout_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_spkout_input_enum, + ALC5623_OUTPUT_MIXER_CTRL, 10, + alc5623_spkout_input_sel); static const struct snd_kcontrol_new alc5623_spkout_mux_controls = SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum); /* headphone left output mux */ -static const struct soc_enum alc5623_hpl_out_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 9, 2, alc5623_hpl_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_hpl_out_input_enum, + ALC5623_OUTPUT_MIXER_CTRL, 9, + alc5623_hpl_out_input_sel); static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls = SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum); /* headphone right output mux */ -static const struct soc_enum alc5623_hpr_out_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 8, 2, alc5623_hpr_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_hpr_out_input_enum, + ALC5623_OUTPUT_MIXER_CTRL, 8, + alc5623_hpr_out_input_sel); static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls = SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum); /* speaker output N select */ -static const struct soc_enum alc5623_spk_n_sour_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 14, 4, alc5623_spk_n_sour_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_spk_n_sour_enum, + ALC5623_OUTPUT_MIXER_CTRL, 14, + alc5623_spk_n_sour_sel); static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls = SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum); @@ -338,8 +331,9 @@ SND_SOC_DAPM_VMID("Vmid"), }; static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"}; -static const struct soc_enum alc5623_amp_enum = - SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 13, 2, alc5623_amp_names); +static SOC_ENUM_SINGLE_DECL(alc5623_amp_enum, + ALC5623_OUTPUT_MIXER_CTRL, 13, + alc5623_amp_names); static const struct snd_kcontrol_new alc5623_amp_mux_controls = SOC_DAPM_ENUM("Route", alc5623_amp_enum); @@ -869,18 +863,28 @@ static struct snd_soc_dai_driver alc5623_dai = { static int alc5623_suspend(struct snd_soc_codec *codec) { + struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); + alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); + regcache_cache_only(alc5623->regmap, true); + return 0; } static int alc5623_resume(struct snd_soc_codec *codec) { - int i, step = codec->driver->reg_cache_step; - u16 *cache = codec->reg_cache; + struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); + int ret; /* Sync reg_cache with the hardware */ - for (i = 2 ; i < codec->driver->reg_cache_size ; i += step) - snd_soc_write(codec, i, cache[i]); + regcache_cache_only(alc5623->regmap, false); + ret = regcache_sync(alc5623->regmap); + if (ret != 0) { + dev_err(codec->dev, "Failed to sync register cache: %d\n", + ret); + regcache_cache_only(alc5623->regmap, true); + return ret; + } alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -900,14 +904,14 @@ static int alc5623_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = &codec->dapm; int ret; - ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5623->control_type); + codec->control_data = alc5623->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } alc5623_reset(codec); - alc5623_fill_cache(codec); /* power on device */ alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -980,9 +984,15 @@ static struct snd_soc_codec_driver soc_codec_device_alc5623 = { .suspend = alc5623_suspend, .resume = alc5623_resume, .set_bias_level = alc5623_set_bias_level, - .reg_cache_size = ALC5623_VENDOR_ID2+2, - .reg_word_size = sizeof(u16), - .reg_cache_step = 2, +}; + +static const struct regmap_config alc5623_regmap = { + .reg_bits = 8, + .val_bits = 16, + .reg_stride = 2, + + .max_register = ALC5623_VENDOR_ID2, + .cache_type = REGCACHE_RBTREE, }; /* @@ -996,19 +1006,32 @@ static int alc5623_i2c_probe(struct i2c_client *client, { struct alc5623_platform_data *pdata; struct alc5623_priv *alc5623; - int ret, vid1, vid2; + unsigned int vid1, vid2; + int ret; - vid1 = i2c_smbus_read_word_data(client, ALC5623_VENDOR_ID1); - if (vid1 < 0) { - dev_err(&client->dev, "failed to read I2C\n"); - return -EIO; + alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), + GFP_KERNEL); + if (alc5623 == NULL) + return -ENOMEM; + + alc5623->regmap = devm_regmap_init_i2c(client, &alc5623_regmap); + if (IS_ERR(alc5623->regmap)) { + ret = PTR_ERR(alc5623->regmap); + dev_err(&client->dev, "Failed to initialise I/O: %d\n", ret); + return ret; + } + + ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID1, &vid1); + if (ret < 0) { + dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret); + return ret; } vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8); - vid2 = i2c_smbus_read_byte_data(client, ALC5623_VENDOR_ID2); - if (vid2 < 0) { - dev_err(&client->dev, "failed to read I2C\n"); - return -EIO; + ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2); + if (ret < 0) { + dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret); + return ret; } if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { @@ -1021,11 +1044,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2); - alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), - GFP_KERNEL); - if (alc5623 == NULL) - return -ENOMEM; - pdata = client->dev.platform_data; if (pdata) { alc5623->add_ctrl = pdata->add_ctrl; @@ -1048,7 +1066,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, } i2c_set_clientdata(client, alc5623); - alc5623->control_type = SND_SOC_I2C; ret = snd_soc_register_codec(&client->dev, &soc_codec_device_alc5623, &alc5623_dai, 1); diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index fb001c56cf8d..d885056ad8f2 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -293,51 +293,59 @@ static const char * const alc5632_i2s_out_sel[] = { "ADC LR", "Voice Stereo Digital"}; /* auxout output mux */ -static const struct soc_enum alc5632_aux_out_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 6, 4, alc5632_aux_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_aux_out_input_enum, + ALC5632_OUTPUT_MIXER_CTRL, 6, + alc5632_aux_out_input_sel); static const struct snd_kcontrol_new alc5632_auxout_mux_controls = SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum); /* speaker output mux */ -static const struct soc_enum alc5632_spkout_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 10, 4, alc5632_spkout_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_spkout_input_enum, + ALC5632_OUTPUT_MIXER_CTRL, 10, + alc5632_spkout_input_sel); static const struct snd_kcontrol_new alc5632_spkout_mux_controls = SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum); /* headphone left output mux */ -static const struct soc_enum alc5632_hpl_out_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 9, 2, alc5632_hpl_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_hpl_out_input_enum, + ALC5632_OUTPUT_MIXER_CTRL, 9, + alc5632_hpl_out_input_sel); static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls = SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum); /* headphone right output mux */ -static const struct soc_enum alc5632_hpr_out_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 8, 2, alc5632_hpr_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_hpr_out_input_enum, + ALC5632_OUTPUT_MIXER_CTRL, 8, + alc5632_hpr_out_input_sel); static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls = SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum); /* speaker output N select */ -static const struct soc_enum alc5632_spk_n_sour_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 14, 4, alc5632_spk_n_sour_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_spk_n_sour_enum, + ALC5632_OUTPUT_MIXER_CTRL, 14, + alc5632_spk_n_sour_sel); static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls = SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum); /* speaker amplifier */ static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"}; -static const struct soc_enum alc5632_amp_enum = - SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 13, 2, alc5632_amp_names); +static SOC_ENUM_SINGLE_DECL(alc5632_amp_enum, + ALC5632_OUTPUT_MIXER_CTRL, 13, + alc5632_amp_names); static const struct snd_kcontrol_new alc5632_amp_mux_controls = SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum); /* ADC output select */ -static const struct soc_enum alc5632_adcr_func_enum = - SOC_ENUM_SINGLE(ALC5632_DAC_FUNC_SELECT, 5, 2, alc5632_adcr_func_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_adcr_func_enum, + ALC5632_DAC_FUNC_SELECT, 5, + alc5632_adcr_func_sel); static const struct snd_kcontrol_new alc5632_adcr_func_controls = SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum); /* I2S out select */ -static const struct soc_enum alc5632_i2s_out_enum = - SOC_ENUM_SINGLE(ALC5632_I2S_OUT_CTL, 5, 2, alc5632_i2s_out_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_i2s_out_enum, + ALC5632_I2S_OUT_CTL, 5, + alc5632_i2s_out_sel); static const struct snd_kcontrol_new alc5632_i2s_out_controls = SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e4295fee8f13..29e198f57d4c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -53,6 +53,14 @@ #define ARIZONA_AIF_RX_ENABLES 0x1A #define ARIZONA_AIF_FORCE_WRITE 0x1B +#define ARIZONA_FLL_VCO_CORNER 141900000 +#define ARIZONA_FLL_MAX_FREF 13500000 +#define ARIZONA_FLL_MIN_FVCO 90000000 +#define ARIZONA_FLL_MAX_FRATIO 16 +#define ARIZONA_FLL_MAX_REFDIV 8 +#define ARIZONA_FLL_MIN_OUTDIV 2 +#define ARIZONA_FLL_MAX_OUTDIV 7 + #define arizona_fll_err(_fll, fmt, ...) \ dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) #define arizona_fll_warn(_fll, fmt, ...) \ @@ -542,67 +550,76 @@ static const char *arizona_vol_ramp_text[] = { "15ms/6dB", "30ms/6dB", }; -const struct soc_enum arizona_in_vd_ramp = - SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, - ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); +SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp, + ARIZONA_INPUT_VOLUME_RAMP, + ARIZONA_IN_VD_RAMP_SHIFT, + arizona_vol_ramp_text); EXPORT_SYMBOL_GPL(arizona_in_vd_ramp); -const struct soc_enum arizona_in_vi_ramp = - SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, - ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); +SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp, + ARIZONA_INPUT_VOLUME_RAMP, + ARIZONA_IN_VI_RAMP_SHIFT, + arizona_vol_ramp_text); EXPORT_SYMBOL_GPL(arizona_in_vi_ramp); -const struct soc_enum arizona_out_vd_ramp = - SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, - ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); +SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp, + ARIZONA_OUTPUT_VOLUME_RAMP, + ARIZONA_OUT_VD_RAMP_SHIFT, + arizona_vol_ramp_text); EXPORT_SYMBOL_GPL(arizona_out_vd_ramp); -const struct soc_enum arizona_out_vi_ramp = - SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, - ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); +SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp, + ARIZONA_OUTPUT_VOLUME_RAMP, + ARIZONA_OUT_VI_RAMP_SHIFT, + arizona_vol_ramp_text); EXPORT_SYMBOL_GPL(arizona_out_vi_ramp); static const char *arizona_lhpf_mode_text[] = { "Low-pass", "High-pass" }; -const struct soc_enum arizona_lhpf1_mode = - SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2, - arizona_lhpf_mode_text); +SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode, + ARIZONA_HPLPF1_1, + ARIZONA_LHPF1_MODE_SHIFT, + arizona_lhpf_mode_text); EXPORT_SYMBOL_GPL(arizona_lhpf1_mode); -const struct soc_enum arizona_lhpf2_mode = - SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2, - arizona_lhpf_mode_text); +SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode, + ARIZONA_HPLPF2_1, + ARIZONA_LHPF2_MODE_SHIFT, + arizona_lhpf_mode_text); EXPORT_SYMBOL_GPL(arizona_lhpf2_mode); -const struct soc_enum arizona_lhpf3_mode = - SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2, - arizona_lhpf_mode_text); +SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode, + ARIZONA_HPLPF3_1, + ARIZONA_LHPF3_MODE_SHIFT, + arizona_lhpf_mode_text); EXPORT_SYMBOL_GPL(arizona_lhpf3_mode); -const struct soc_enum arizona_lhpf4_mode = - SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2, - arizona_lhpf_mode_text); +SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode, + ARIZONA_HPLPF4_1, + ARIZONA_LHPF4_MODE_SHIFT, + arizona_lhpf_mode_text); EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); static const char *arizona_ng_hold_text[] = { "30ms", "120ms", "250ms", "500ms", }; -const struct soc_enum arizona_ng_hold = - SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT, - 4, arizona_ng_hold_text); +SOC_ENUM_SINGLE_DECL(arizona_ng_hold, + ARIZONA_NOISE_GATE_CONTROL, + ARIZONA_NGATE_HOLD_SHIFT, + arizona_ng_hold_text); EXPORT_SYMBOL_GPL(arizona_ng_hold); static const char * const arizona_in_hpf_cut_text[] = { "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz" }; -const struct soc_enum arizona_in_hpf_cut_enum = - SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT, - ARRAY_SIZE(arizona_in_hpf_cut_text), - arizona_in_hpf_cut_text); +SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum, + ARIZONA_HPF_CONTROL, + ARIZONA_IN_HPF_CUT_SHIFT, + arizona_in_hpf_cut_text); EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); static const char * const arizona_in_dmic_osr_text[] = { @@ -1377,74 +1394,147 @@ struct arizona_fll_cfg { int gain; }; -static int arizona_calc_fll(struct arizona_fll *fll, - struct arizona_fll_cfg *cfg, - unsigned int Fref, - unsigned int Fout) +static int arizona_validate_fll(struct arizona_fll *fll, + unsigned int Fref, + unsigned int Fout) { - unsigned int target, div, gcd_fll; - int i, ratio; + unsigned int Fvco_min; + + if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) { + arizona_fll_err(fll, + "Can't scale %dMHz in to <=13.5MHz\n", + Fref); + return -EINVAL; + } - arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout); + Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult; + if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) { + arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", + Fout); + return -EINVAL; + } + + return 0; +} + +static int arizona_find_fratio(unsigned int Fref, int *fratio) +{ + int i; + + /* Find an appropriate FLL_FRATIO */ + for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { + if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { + if (fratio) + *fratio = fll_fratios[i].fratio; + return fll_fratios[i].ratio; + } + } + + return -EINVAL; +} + +static int arizona_calc_fratio(struct arizona_fll *fll, + struct arizona_fll_cfg *cfg, + unsigned int target, + unsigned int Fref, bool sync) +{ + int init_ratio, ratio; + int refdiv, div; - /* Fref must be <=13.5MHz */ + /* Fref must be <=13.5MHz, find initial refdiv */ div = 1; cfg->refdiv = 0; - while ((Fref / div) > 13500000) { + while (Fref > ARIZONA_FLL_MAX_FREF) { div *= 2; + Fref /= 2; cfg->refdiv++; - if (div > 8) { - arizona_fll_err(fll, - "Can't scale %dMHz in to <=13.5MHz\n", - Fref); + if (div > ARIZONA_FLL_MAX_REFDIV) return -EINVAL; + } + + /* Find an appropriate FLL_FRATIO */ + init_ratio = arizona_find_fratio(Fref, &cfg->fratio); + if (init_ratio < 0) { + arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", + Fref); + return init_ratio; + } + + switch (fll->arizona->type) { + case WM5110: + if (fll->arizona->rev < 3 || sync) + return init_ratio; + break; + default: + return init_ratio; + } + + cfg->fratio = init_ratio - 1; + + /* Adjust FRATIO/refdiv to avoid integer mode if possible */ + refdiv = cfg->refdiv; + + while (div <= ARIZONA_FLL_MAX_REFDIV) { + for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; + ratio++) { + if (target % (ratio * Fref)) { + cfg->refdiv = refdiv; + cfg->fratio = ratio - 1; + return ratio; + } } + + for (ratio = init_ratio - 1; ratio >= 0; ratio--) { + if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < + Fref) + break; + + if (target % (ratio * Fref)) { + cfg->refdiv = refdiv; + cfg->fratio = ratio - 1; + return ratio; + } + } + + div *= 2; + Fref /= 2; + refdiv++; + init_ratio = arizona_find_fratio(Fref, NULL); } - /* Apply the division for our remaining calculations */ - Fref /= div; + arizona_fll_warn(fll, "Falling back to integer mode operation\n"); + return cfg->fratio + 1; +} + +static int arizona_calc_fll(struct arizona_fll *fll, + struct arizona_fll_cfg *cfg, + unsigned int Fref, bool sync) +{ + unsigned int target, div, gcd_fll; + int i, ratio; + + arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout); /* Fvco should be over the targt; don't check the upper bound */ - div = 1; - while (Fout * div < 90000000 * fll->vco_mult) { + div = ARIZONA_FLL_MIN_OUTDIV; + while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) { div++; - if (div > 7) { - arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", - Fout); + if (div > ARIZONA_FLL_MAX_OUTDIV) return -EINVAL; - } } - target = Fout * div / fll->vco_mult; + target = fll->fout * div / fll->vco_mult; cfg->outdiv = div; arizona_fll_dbg(fll, "Fvco=%dHz\n", target); - /* Find an appropraite FLL_FRATIO and factor it out of the target */ - for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { - if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { - cfg->fratio = fll_fratios[i].fratio; - ratio = fll_fratios[i].ratio; - break; - } - } - if (i == ARRAY_SIZE(fll_fratios)) { - arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", - Fref); - return -EINVAL; - } + /* Find an appropriate FLL_FRATIO and refdiv */ + ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync); + if (ratio < 0) + return ratio; - for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { - if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { - cfg->gain = fll_gains[i].gain; - break; - } - } - if (i == ARRAY_SIZE(fll_gains)) { - arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", - Fref); - return -EINVAL; - } + /* Apply the division for our remaining calculations */ + Fref = Fref / (1 << cfg->refdiv); cfg->n = target / (ratio * Fref); @@ -1469,6 +1559,18 @@ static int arizona_calc_fll(struct arizona_fll *fll, cfg->lambda >>= 1; } + for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { + if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { + cfg->gain = fll_gains[i].gain; + break; + } + } + if (i == ARRAY_SIZE(fll_gains)) { + arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", + Fref); + return -EINVAL; + } + arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", cfg->n, cfg->theta, cfg->lambda); arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", @@ -1496,14 +1598,18 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); - if (sync) - regmap_update_bits_async(arizona->regmap, base + 0x7, - ARIZONA_FLL1_GAIN_MASK, - cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); - else - regmap_update_bits_async(arizona->regmap, base + 0x9, - ARIZONA_FLL1_GAIN_MASK, - cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + if (sync) { + regmap_update_bits(arizona->regmap, base + 0x7, + ARIZONA_FLL1_GAIN_MASK, + cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + } else { + regmap_update_bits(arizona->regmap, base + 0x5, + ARIZONA_FLL1_OUTDIV_MASK, + cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + regmap_update_bits(arizona->regmap, base + 0x9, + ARIZONA_FLL1_GAIN_MASK, + cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + } regmap_update_bits_async(arizona->regmap, base + 2, ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, @@ -1526,13 +1632,12 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) return reg & ARIZONA_FLL1_ENA; } -static void arizona_enable_fll(struct arizona_fll *fll, - struct arizona_fll_cfg *ref, - struct arizona_fll_cfg *sync) +static void arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; int ret; bool use_sync = false; + struct arizona_fll_cfg cfg; /* * If we have both REFCLK and SYNCCLK then enable both, @@ -1540,23 +1645,21 @@ static void arizona_enable_fll(struct arizona_fll *fll, */ if (fll->ref_src >= 0 && fll->ref_freq && fll->ref_src != fll->sync_src) { - regmap_update_bits_async(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + arizona_calc_fll(fll, &cfg, fll->ref_freq, false); - arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, + arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src, false); if (fll->sync_src >= 0) { - arizona_apply_fll(arizona, fll->base + 0x10, sync, + arizona_calc_fll(fll, &cfg, fll->sync_freq, true); + + arizona_apply_fll(arizona, fll->base + 0x10, &cfg, fll->sync_src, true); use_sync = true; } } else if (fll->sync_src >= 0) { - regmap_update_bits_async(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + arizona_calc_fll(fll, &cfg, fll->sync_freq, false); - arizona_apply_fll(arizona, fll->base, sync, + arizona_apply_fll(arizona, fll->base, &cfg, fll->sync_src, false); regmap_update_bits_async(arizona->regmap, fll->base + 0x11, @@ -1618,32 +1721,22 @@ static void arizona_disable_fll(struct arizona_fll *fll) int arizona_set_fll_refclk(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { - struct arizona_fll_cfg ref, sync; int ret; if (fll->ref_src == source && fll->ref_freq == Fref) return 0; - if (fll->fout) { - if (Fref > 0) { - ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); - if (ret != 0) - return ret; - } - - if (fll->sync_src >= 0) { - ret = arizona_calc_fll(fll, &sync, fll->sync_freq, - fll->fout); - if (ret != 0) - return ret; - } + if (fll->fout && Fref > 0) { + ret = arizona_validate_fll(fll, Fref, fll->fout); + if (ret != 0) + return ret; } fll->ref_src = source; fll->ref_freq = Fref; if (fll->fout && Fref > 0) { - arizona_enable_fll(fll, &ref, &sync); + arizona_enable_fll(fll); } return 0; @@ -1653,7 +1746,6 @@ EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { - struct arizona_fll_cfg ref, sync; int ret; if (fll->sync_src == source && @@ -1662,13 +1754,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source, if (Fout) { if (fll->ref_src >= 0) { - ret = arizona_calc_fll(fll, &ref, fll->ref_freq, - Fout); + ret = arizona_validate_fll(fll, fll->ref_freq, Fout); if (ret != 0) return ret; } - ret = arizona_calc_fll(fll, &sync, Fref, Fout); + ret = arizona_validate_fll(fll, Fref, Fout); if (ret != 0) return ret; } @@ -1678,7 +1769,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->fout = Fout; if (Fout) { - arizona_enable_fll(fll, &ref, &sync); + arizona_enable_fll(fll); } else { arizona_disable_fll(fll); } diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index ce05fd93dc74..aef4965750c7 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -159,7 +159,6 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg) } struct cs4271_private { - /* SND_SOC_I2C or SND_SOC_SPI */ unsigned int mclk; bool master; bool deemph; @@ -540,14 +539,10 @@ static int cs4271_probe(struct snd_soc_codec *codec) struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; int ret; - int gpio_nreset = -EINVAL; bool amutec_eq_bmutec = false; #ifdef CONFIG_OF if (of_match_device(cs4271_dt_ids, codec->dev)) { - gpio_nreset = of_get_named_gpio(codec->dev->of_node, - "reset-gpio", 0); - if (of_get_property(codec->dev->of_node, "cirrus,amutec-eq-bmutec", NULL)) amutec_eq_bmutec = true; @@ -559,27 +554,19 @@ static int cs4271_probe(struct snd_soc_codec *codec) #endif if (cs4271plat) { - if (gpio_is_valid(cs4271plat->gpio_nreset)) - gpio_nreset = cs4271plat->gpio_nreset; - amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; cs4271->enable_soft_reset = cs4271plat->enable_soft_reset; } - if (gpio_nreset >= 0) - if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset")) - gpio_nreset = -EINVAL; - if (gpio_nreset >= 0) { + if (gpio_is_valid(cs4271->gpio_nreset)) { /* Reset codec */ - gpio_direction_output(gpio_nreset, 0); + gpio_direction_output(cs4271->gpio_nreset, 0); udelay(1); - gpio_set_value(gpio_nreset, 1); + gpio_set_value(cs4271->gpio_nreset, 1); /* Give the codec time to wake up */ udelay(1); } - cs4271->gpio_nreset = gpio_nreset; - ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, CS4271_MODE2_PDN | CS4271_MODE2_CPEN, CS4271_MODE2_PDN | CS4271_MODE2_CPEN); @@ -625,6 +612,36 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { .num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes), }; +static int cs4271_common_probe(struct device *dev, + struct cs4271_private **c) +{ + struct cs4271_platform_data *cs4271plat = dev->platform_data; + struct cs4271_private *cs4271; + + cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL); + if (!cs4271) + return -ENOMEM; + + if (of_match_device(cs4271_dt_ids, dev)) + cs4271->gpio_nreset = + of_get_named_gpio(dev->of_node, "reset-gpio", 0); + + if (cs4271plat) + cs4271->gpio_nreset = cs4271plat->gpio_nreset; + + if (gpio_is_valid(cs4271->gpio_nreset)) { + int ret; + + ret = devm_gpio_request(dev, cs4271->gpio_nreset, + "CS4271 Reset"); + if (ret < 0) + return ret; + } + + *c = cs4271; + return 0; +} + #if defined(CONFIG_SPI_MASTER) static const struct regmap_config cs4271_spi_regmap = { @@ -644,10 +661,11 @@ static const struct regmap_config cs4271_spi_regmap = { static int cs4271_spi_probe(struct spi_device *spi) { struct cs4271_private *cs4271; + int ret; - cs4271 = devm_kzalloc(&spi->dev, sizeof(*cs4271), GFP_KERNEL); - if (!cs4271) - return -ENOMEM; + ret = cs4271_common_probe(&spi->dev, &cs4271); + if (ret < 0) + return ret; spi_set_drvdata(spi, cs4271); cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); @@ -698,10 +716,11 @@ static int cs4271_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct cs4271_private *cs4271; + int ret; - cs4271 = devm_kzalloc(&client->dev, sizeof(*cs4271), GFP_KERNEL); - if (!cs4271) - return -ENOMEM; + ret = cs4271_common_probe(&client->dev, &cs4271); + if (ret < 0) + return ret; i2c_set_clientdata(client, cs4271); cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 6e9ea8379a91..3eab46020a30 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -30,6 +30,7 @@ #include <sound/pcm_params.h> #include <sound/pcm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include "cs42l51.h" @@ -40,7 +41,6 @@ enum master_slave_mode { }; struct cs42l51_private { - enum snd_soc_control_type control_type; unsigned int mclk; unsigned int audio_mode; /* The mode (I2S or left-justified) */ enum master_slave_mode func; @@ -52,24 +52,6 @@ struct cs42l51_private { SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) -static int cs42l51_fill_cache(struct snd_soc_codec *codec) -{ - u8 *cache = codec->reg_cache + 1; - struct i2c_client *i2c_client = to_i2c_client(codec->dev); - s32 length; - - length = i2c_smbus_read_i2c_block_data(i2c_client, - CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache); - if (length != CS42L51_NUMREGS) { - dev_err(&i2c_client->dev, - "I2C read failure, addr=0x%x (ret=%d vs %d)\n", - i2c_client->addr, length, CS42L51_NUMREGS); - return -EIO; - } - - return 0; -} - static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -505,16 +487,9 @@ static struct snd_soc_dai_driver cs42l51_dai = { static int cs42l51_probe(struct snd_soc_codec *codec) { - struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); int ret, reg; - ret = cs42l51_fill_cache(codec); - if (ret < 0) { - dev_err(codec->dev, "failed to fill register cache\n"); - return ret; - } - - ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -538,8 +513,6 @@ static int cs42l51_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { .probe = cs42l51_probe, - .reg_cache_size = CS42L51_NUMREGS + 1, - .reg_word_size = sizeof(u8), .controls = cs42l51_snd_controls, .num_controls = ARRAY_SIZE(cs42l51_snd_controls), @@ -549,38 +522,53 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), }; +static const struct regmap_config cs42l51_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS42L51_CHARGE_FREQ, + .cache_type = REGCACHE_RBTREE, +}; + static int cs42l51_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs42l51_private *cs42l51; + struct regmap *regmap; + unsigned int val; int ret; + regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c_client->dev, "Failed to create regmap: %d\n", + ret); + return ret; + } + /* Verify that we have a CS42L51 */ - ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID); + ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val); if (ret < 0) { dev_err(&i2c_client->dev, "failed to read I2C\n"); goto error; } - if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && - (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { - dev_err(&i2c_client->dev, "Invalid chip id\n"); + if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && + (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { + dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val); ret = -ENODEV; goto error; } dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", - ret & 7); + val & 7); cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private), GFP_KERNEL); - if (!cs42l51) { - dev_err(&i2c_client->dev, "could not allocate codec\n"); + if (!cs42l51) return -ENOMEM; - } i2c_set_clientdata(i2c_client, cs42l51); - cs42l51->control_type = SND_SOC_I2C; ret = snd_soc_register_codec(&i2c_client->dev, &soc_codec_device_cs42l51, &cs42l51_dai, 1); @@ -600,10 +588,17 @@ static const struct i2c_device_id cs42l51_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs42l51_id); +static const struct of_device_id cs42l51_of_match[] = { + { .compatible = "cirrus,cs42l51", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs42l51_of_match); + static struct i2c_driver cs42l51_i2c_driver = { .driver = { .name = "cs42l51-codec", .owner = THIS_MODULE, + .of_match_table = cs42l51_of_match, }, .id_table = cs42l51_id, .probe = cs42l51_i2c_probe, diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 0bac6d5a4ac8..be455ea5f2fe 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -210,13 +210,11 @@ static const char * const cs42l52_adca_text[] = { static const char * const cs42l52_adcb_text[] = { "Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"}; -static const struct soc_enum adca_enum = - SOC_ENUM_SINGLE(CS42L52_ADC_PGA_A, 5, - ARRAY_SIZE(cs42l52_adca_text), cs42l52_adca_text); +static SOC_ENUM_SINGLE_DECL(adca_enum, + CS42L52_ADC_PGA_A, 5, cs42l52_adca_text); -static const struct soc_enum adcb_enum = - SOC_ENUM_SINGLE(CS42L52_ADC_PGA_B, 5, - ARRAY_SIZE(cs42l52_adcb_text), cs42l52_adcb_text); +static SOC_ENUM_SINGLE_DECL(adcb_enum, + CS42L52_ADC_PGA_B, 5, cs42l52_adcb_text); static const struct snd_kcontrol_new adca_mux = SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum); @@ -229,26 +227,22 @@ static const char * const mic_bias_level_text[] = { "0.8 +VA", "0.83 +VA", "0.91 +VA" }; -static const struct soc_enum mic_bias_level_enum = - SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0, - ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text); +static SOC_ENUM_SINGLE_DECL(mic_bias_level_enum, + CS42L52_IFACE_CTL2, 0, mic_bias_level_text); static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" }; -static const struct soc_enum mica_enum = - SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5, - ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); +static SOC_ENUM_SINGLE_DECL(mica_enum, + CS42L52_MICA_CTL, 5, cs42l52_mic_text); -static const struct soc_enum micb_enum = - SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5, - ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); +static SOC_ENUM_SINGLE_DECL(micb_enum, + CS42L52_MICB_CTL, 5, cs42l52_mic_text); static const char * const digital_output_mux_text[] = {"ADC", "DSP"}; -static const struct soc_enum digital_output_mux_enum = - SOC_ENUM_SINGLE(CS42L52_ADC_MISC_CTL, 6, - ARRAY_SIZE(digital_output_mux_text), - digital_output_mux_text); +static SOC_ENUM_SINGLE_DECL(digital_output_mux_enum, + CS42L52_ADC_MISC_CTL, 6, + digital_output_mux_text); static const struct snd_kcontrol_new digital_output_mux = SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum); @@ -258,18 +252,18 @@ static const char * const hp_gain_num_text[] = { "0.7099", "0.8399", "1.000", "1.1430" }; -static const struct soc_enum hp_gain_enum = - SOC_ENUM_SINGLE(CS42L52_PB_CTL1, 5, - ARRAY_SIZE(hp_gain_num_text), hp_gain_num_text); +static SOC_ENUM_SINGLE_DECL(hp_gain_enum, + CS42L52_PB_CTL1, 5, + hp_gain_num_text); static const char * const beep_pitch_text[] = { "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7" }; -static const struct soc_enum beep_pitch_enum = - SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 4, - ARRAY_SIZE(beep_pitch_text), beep_pitch_text); +static SOC_ENUM_SINGLE_DECL(beep_pitch_enum, + CS42L52_BEEP_FREQ, 4, + beep_pitch_text); static const char * const beep_ontime_text[] = { "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s", @@ -277,66 +271,66 @@ static const char * const beep_ontime_text[] = { "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s" }; -static const struct soc_enum beep_ontime_enum = - SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 0, - ARRAY_SIZE(beep_ontime_text), beep_ontime_text); +static SOC_ENUM_SINGLE_DECL(beep_ontime_enum, + CS42L52_BEEP_FREQ, 0, + beep_ontime_text); static const char * const beep_offtime_text[] = { "1.23 s", "2.58 s", "3.90 s", "5.20 s", "6.60 s", "8.05 s", "9.35 s", "10.80 s" }; -static const struct soc_enum beep_offtime_enum = - SOC_ENUM_SINGLE(CS42L52_BEEP_VOL, 5, - ARRAY_SIZE(beep_offtime_text), beep_offtime_text); +static SOC_ENUM_SINGLE_DECL(beep_offtime_enum, + CS42L52_BEEP_VOL, 5, + beep_offtime_text); static const char * const beep_config_text[] = { "Off", "Single", "Multiple", "Continuous" }; -static const struct soc_enum beep_config_enum = - SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 6, - ARRAY_SIZE(beep_config_text), beep_config_text); +static SOC_ENUM_SINGLE_DECL(beep_config_enum, + CS42L52_BEEP_TONE_CTL, 6, + beep_config_text); static const char * const beep_bass_text[] = { "50 Hz", "100 Hz", "200 Hz", "250 Hz" }; -static const struct soc_enum beep_bass_enum = - SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 1, - ARRAY_SIZE(beep_bass_text), beep_bass_text); +static SOC_ENUM_SINGLE_DECL(beep_bass_enum, + CS42L52_BEEP_TONE_CTL, 1, + beep_bass_text); static const char * const beep_treble_text[] = { "5 kHz", "7 kHz", "10 kHz", " 15 kHz" }; -static const struct soc_enum beep_treble_enum = - SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 3, - ARRAY_SIZE(beep_treble_text), beep_treble_text); +static SOC_ENUM_SINGLE_DECL(beep_treble_enum, + CS42L52_BEEP_TONE_CTL, 3, + beep_treble_text); static const char * const ng_threshold_text[] = { "-34dB", "-37dB", "-40dB", "-43dB", "-46dB", "-52dB", "-58dB", "-64dB" }; -static const struct soc_enum ng_threshold_enum = - SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 2, - ARRAY_SIZE(ng_threshold_text), ng_threshold_text); +static SOC_ENUM_SINGLE_DECL(ng_threshold_enum, + CS42L52_NOISE_GATE_CTL, 2, + ng_threshold_text); static const char * const cs42l52_ng_delay_text[] = { "50ms", "100ms", "150ms", "200ms"}; -static const struct soc_enum ng_delay_enum = - SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 0, - ARRAY_SIZE(cs42l52_ng_delay_text), cs42l52_ng_delay_text); +static SOC_ENUM_SINGLE_DECL(ng_delay_enum, + CS42L52_NOISE_GATE_CTL, 0, + cs42l52_ng_delay_text); static const char * const cs42l52_ng_type_text[] = { "Apply Specific", "Apply All" }; -static const struct soc_enum ng_type_enum = - SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 6, - ARRAY_SIZE(cs42l52_ng_type_text), cs42l52_ng_type_text); +static SOC_ENUM_SINGLE_DECL(ng_type_enum, + CS42L52_NOISE_GATE_CTL, 6, + cs42l52_ng_type_text); static const char * const left_swap_text[] = { "Left", "LR 2", "Right"}; diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 549d5d6a3fef..06f429184821 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -278,13 +278,13 @@ static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1); static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" }; static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" }; -static const struct soc_enum pgaa_enum = - SOC_ENUM_SINGLE(CS42L73_ADCIPC, 3, - ARRAY_SIZE(cs42l73_pgaa_text), cs42l73_pgaa_text); +static SOC_ENUM_SINGLE_DECL(pgaa_enum, + CS42L73_ADCIPC, 3, + cs42l73_pgaa_text); -static const struct soc_enum pgab_enum = - SOC_ENUM_SINGLE(CS42L73_ADCIPC, 7, - ARRAY_SIZE(cs42l73_pgab_text), cs42l73_pgab_text); +static SOC_ENUM_SINGLE_DECL(pgab_enum, + CS42L73_ADCIPC, 7, + cs42l73_pgab_text); static const struct snd_kcontrol_new pgaa_mux = SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum); @@ -309,9 +309,9 @@ static const struct snd_kcontrol_new input_right_mixer[] = { static const char * const cs42l73_ng_delay_text[] = { "50ms", "100ms", "150ms", "200ms" }; -static const struct soc_enum ng_delay_enum = - SOC_ENUM_SINGLE(CS42L73_NGCAB, 0, - ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text); +static SOC_ENUM_SINGLE_DECL(ng_delay_enum, + CS42L73_NGCAB, 0, + cs42l73_ng_delay_text); static const char * const cs42l73_mono_mix_texts[] = { "Left", "Right", "Mono Mix"}; @@ -357,19 +357,19 @@ static const struct snd_kcontrol_new esl_xsp_mixer = static const char * const cs42l73_ip_swap_text[] = { "Stereo", "Mono A", "Mono B", "Swap A-B"}; -static const struct soc_enum ip_swap_enum = - SOC_ENUM_SINGLE(CS42L73_MIOPC, 6, - ARRAY_SIZE(cs42l73_ip_swap_text), cs42l73_ip_swap_text); +static SOC_ENUM_SINGLE_DECL(ip_swap_enum, + CS42L73_MIOPC, 6, + cs42l73_ip_swap_text); static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"}; -static const struct soc_enum vsp_output_mux_enum = - SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 5, - ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text); +static SOC_ENUM_SINGLE_DECL(vsp_output_mux_enum, + CS42L73_MIXERCTL, 5, + cs42l73_spo_mixer_text); -static const struct soc_enum xsp_output_mux_enum = - SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 4, - ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text); +static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum, + CS42L73_MIXERCTL, 4, + cs42l73_spo_mixer_text); static const struct snd_kcontrol_new vsp_output_mux = SOC_DAPM_ENUM("Route", vsp_output_mux_enum); @@ -1108,7 +1108,7 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return 0; } -static u32 cs42l73_asrc_rates[] = { +static const unsigned int cs42l73_asrc_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }; @@ -1241,7 +1241,7 @@ static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate) 0x7F, tristate << 7); } -static struct snd_pcm_hw_constraint_list constraints_12_24 = { +static const struct snd_pcm_hw_constraint_list constraints_12_24 = { .count = ARRAY_SIZE(cs42l73_asrc_rates), .list = cs42l73_asrc_rates, }; @@ -1255,9 +1255,6 @@ static int cs42l73_pcm_startup(struct snd_pcm_substream *substream, return 0; } -/* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */ -#define CS42L73_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT) - #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) @@ -1278,14 +1275,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { .stream_name = "XSP Playback", .channels_min = 1, .channels_max = 2, - .rates = CS42L73_RATES, + .rates = SNDRV_PCM_RATE_KNOT, .formats = CS42L73_FORMATS, }, .capture = { .stream_name = "XSP Capture", .channels_min = 1, .channels_max = 2, - .rates = CS42L73_RATES, + .rates = SNDRV_PCM_RATE_KNOT, .formats = CS42L73_FORMATS, }, .ops = &cs42l73_ops, @@ -1298,14 +1295,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { .stream_name = "ASP Playback", .channels_min = 2, .channels_max = 2, - .rates = CS42L73_RATES, + .rates = SNDRV_PCM_RATE_KNOT, .formats = CS42L73_FORMATS, }, .capture = { .stream_name = "ASP Capture", .channels_min = 2, .channels_max = 2, - .rates = CS42L73_RATES, + .rates = SNDRV_PCM_RATE_KNOT, .formats = CS42L73_FORMATS, }, .ops = &cs42l73_ops, @@ -1318,14 +1315,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { .stream_name = "VSP Playback", .channels_min = 1, .channels_max = 2, - .rates = CS42L73_RATES, + .rates = SNDRV_PCM_RATE_KNOT, .formats = CS42L73_FORMATS, }, .capture = { .stream_name = "VSP Capture", .channels_min = 1, .channels_max = 2, - .rates = CS42L73_RATES, + .rates = SNDRV_PCM_RATE_KNOT, .formats = CS42L73_FORMATS, }, .ops = &cs42l73_ops, diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index e62e294a8033..01e55fc72307 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -307,29 +307,29 @@ static const char * const da7210_hpf_cutoff_txt[] = { "Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi" }; -static const struct soc_enum da7210_dac_hpf_cutoff = - SOC_ENUM_SINGLE(DA7210_DAC_HPF, 0, 4, da7210_hpf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da7210_dac_hpf_cutoff, + DA7210_DAC_HPF, 0, da7210_hpf_cutoff_txt); -static const struct soc_enum da7210_adc_hpf_cutoff = - SOC_ENUM_SINGLE(DA7210_ADC_HPF, 0, 4, da7210_hpf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da7210_adc_hpf_cutoff, + DA7210_ADC_HPF, 0, da7210_hpf_cutoff_txt); /* ADC and DAC voice (8kHz) high pass cutoff value */ static const char * const da7210_vf_cutoff_txt[] = { "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" }; -static const struct soc_enum da7210_dac_vf_cutoff = - SOC_ENUM_SINGLE(DA7210_DAC_HPF, 4, 8, da7210_vf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da7210_dac_vf_cutoff, + DA7210_DAC_HPF, 4, da7210_vf_cutoff_txt); -static const struct soc_enum da7210_adc_vf_cutoff = - SOC_ENUM_SINGLE(DA7210_ADC_HPF, 4, 8, da7210_vf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da7210_adc_vf_cutoff, + DA7210_ADC_HPF, 4, da7210_vf_cutoff_txt); static const char *da7210_hp_mode_txt[] = { "Class H", "Class G" }; -static const struct soc_enum da7210_hp_mode_sel = - SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt); +static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel, + DA7210_HP_CFG, 0, da7210_hp_mode_txt); /* ALC can be enabled only if noise suppression is disabled */ static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 0c77e7ad7423..439d10387f10 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -63,30 +63,30 @@ static const char * const da7213_voice_hpf_corner_txt[] = { "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" }; -static const struct soc_enum da7213_dac_voice_hpf_corner = - SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, - DA7213_VOICE_HPF_CORNER_MAX, - da7213_voice_hpf_corner_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_voice_hpf_corner, + DA7213_DAC_FILTERS1, + DA7213_VOICE_HPF_CORNER_SHIFT, + da7213_voice_hpf_corner_txt); -static const struct soc_enum da7213_adc_voice_hpf_corner = - SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, - DA7213_VOICE_HPF_CORNER_MAX, - da7213_voice_hpf_corner_txt); +static SOC_ENUM_SINGLE_DECL(da7213_adc_voice_hpf_corner, + DA7213_ADC_FILTERS1, + DA7213_VOICE_HPF_CORNER_SHIFT, + da7213_voice_hpf_corner_txt); /* ADC and DAC high pass filter cutoff value */ static const char * const da7213_audio_hpf_corner_txt[] = { "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" }; -static const struct soc_enum da7213_dac_audio_hpf_corner = - SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, - DA7213_AUDIO_HPF_CORNER_MAX, - da7213_audio_hpf_corner_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_audio_hpf_corner, + DA7213_DAC_FILTERS1 + , DA7213_AUDIO_HPF_CORNER_SHIFT, + da7213_audio_hpf_corner_txt); -static const struct soc_enum da7213_adc_audio_hpf_corner = - SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, - DA7213_AUDIO_HPF_CORNER_MAX, - da7213_audio_hpf_corner_txt); +static SOC_ENUM_SINGLE_DECL(da7213_adc_audio_hpf_corner, + DA7213_ADC_FILTERS1, + DA7213_AUDIO_HPF_CORNER_SHIFT, + da7213_audio_hpf_corner_txt); /* Gain ramping rate value */ static const char * const da7213_gain_ramp_rate_txt[] = { @@ -94,52 +94,50 @@ static const char * const da7213_gain_ramp_rate_txt[] = { "nominal rate / 32" }; -static const struct soc_enum da7213_gain_ramp_rate = - SOC_ENUM_SINGLE(DA7213_GAIN_RAMP_CTRL, DA7213_GAIN_RAMP_RATE_SHIFT, - DA7213_GAIN_RAMP_RATE_MAX, da7213_gain_ramp_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_gain_ramp_rate, + DA7213_GAIN_RAMP_CTRL, + DA7213_GAIN_RAMP_RATE_SHIFT, + da7213_gain_ramp_rate_txt); /* DAC noise gate setup time value */ static const char * const da7213_dac_ng_setup_time_txt[] = { "256 samples", "512 samples", "1024 samples", "2048 samples" }; -static const struct soc_enum da7213_dac_ng_setup_time = - SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, - DA7213_DAC_NG_SETUP_TIME_SHIFT, - DA7213_DAC_NG_SETUP_TIME_MAX, - da7213_dac_ng_setup_time_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_setup_time, + DA7213_DAC_NG_SETUP_TIME, + DA7213_DAC_NG_SETUP_TIME_SHIFT, + da7213_dac_ng_setup_time_txt); /* DAC noise gate rampup rate value */ static const char * const da7213_dac_ng_rampup_txt[] = { "0.02 ms/dB", "0.16 ms/dB" }; -static const struct soc_enum da7213_dac_ng_rampup_rate = - SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, - DA7213_DAC_NG_RAMPUP_RATE_SHIFT, - DA7213_DAC_NG_RAMP_RATE_MAX, - da7213_dac_ng_rampup_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampup_rate, + DA7213_DAC_NG_SETUP_TIME, + DA7213_DAC_NG_RAMPUP_RATE_SHIFT, + da7213_dac_ng_rampup_txt); /* DAC noise gate rampdown rate value */ static const char * const da7213_dac_ng_rampdown_txt[] = { "0.64 ms/dB", "20.48 ms/dB" }; -static const struct soc_enum da7213_dac_ng_rampdown_rate = - SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, - DA7213_DAC_NG_RAMPDN_RATE_SHIFT, - DA7213_DAC_NG_RAMP_RATE_MAX, - da7213_dac_ng_rampdown_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampdown_rate, + DA7213_DAC_NG_SETUP_TIME, + DA7213_DAC_NG_RAMPDN_RATE_SHIFT, + da7213_dac_ng_rampdown_txt); /* DAC soft mute rate value */ static const char * const da7213_dac_soft_mute_rate_txt[] = { "1", "2", "4", "8", "16", "32", "64" }; -static const struct soc_enum da7213_dac_soft_mute_rate = - SOC_ENUM_SINGLE(DA7213_DAC_FILTERS5, DA7213_DAC_SOFTMUTE_RATE_SHIFT, - DA7213_DAC_SOFTMUTE_RATE_MAX, - da7213_dac_soft_mute_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_soft_mute_rate, + DA7213_DAC_FILTERS5, + DA7213_DAC_SOFTMUTE_RATE_SHIFT, + da7213_dac_soft_mute_rate_txt); /* ALC Attack Rate select */ static const char * const da7213_alc_attack_rate_txt[] = { @@ -147,9 +145,10 @@ static const char * const da7213_alc_attack_rate_txt[] = { "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" }; -static const struct soc_enum da7213_alc_attack_rate = - SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_ATTACK_SHIFT, - DA7213_ALC_ATTACK_MAX, da7213_alc_attack_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_attack_rate, + DA7213_ALC_CTRL2, + DA7213_ALC_ATTACK_SHIFT, + da7213_alc_attack_rate_txt); /* ALC Release Rate select */ static const char * const da7213_alc_release_rate_txt[] = { @@ -157,9 +156,10 @@ static const char * const da7213_alc_release_rate_txt[] = { "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" }; -static const struct soc_enum da7213_alc_release_rate = - SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_RELEASE_SHIFT, - DA7213_ALC_RELEASE_MAX, da7213_alc_release_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_release_rate, + DA7213_ALC_CTRL2, + DA7213_ALC_RELEASE_SHIFT, + da7213_alc_release_rate_txt); /* ALC Hold Time select */ static const char * const da7213_alc_hold_time_txt[] = { @@ -168,22 +168,25 @@ static const char * const da7213_alc_hold_time_txt[] = { "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" }; -static const struct soc_enum da7213_alc_hold_time = - SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_HOLD_SHIFT, - DA7213_ALC_HOLD_MAX, da7213_alc_hold_time_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_hold_time, + DA7213_ALC_CTRL3, + DA7213_ALC_HOLD_SHIFT, + da7213_alc_hold_time_txt); /* ALC Input Signal Tracking rate select */ static const char * const da7213_alc_integ_rate_txt[] = { "1/4", "1/16", "1/256", "1/65536" }; -static const struct soc_enum da7213_alc_integ_attack_rate = - SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_ATTACK_SHIFT, - DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_attack_rate, + DA7213_ALC_CTRL3, + DA7213_ALC_INTEG_ATTACK_SHIFT, + da7213_alc_integ_rate_txt); -static const struct soc_enum da7213_alc_integ_release_rate = - SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_RELEASE_SHIFT, - DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); +static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_release_rate, + DA7213_ALC_CTRL3, + DA7213_ALC_INTEG_RELEASE_SHIFT, + da7213_alc_integ_rate_txt); /* @@ -584,15 +587,17 @@ static const char * const da7213_mic_amp_in_sel_txt[] = { "Differential", "MIC_P", "MIC_N" }; -static const struct soc_enum da7213_mic_1_amp_in_sel = - SOC_ENUM_SINGLE(DA7213_MIC_1_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, - DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); +static SOC_ENUM_SINGLE_DECL(da7213_mic_1_amp_in_sel, + DA7213_MIC_1_CTRL, + DA7213_MIC_AMP_IN_SEL_SHIFT, + da7213_mic_amp_in_sel_txt); static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux = SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel); -static const struct soc_enum da7213_mic_2_amp_in_sel = - SOC_ENUM_SINGLE(DA7213_MIC_2_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, - DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); +static SOC_ENUM_SINGLE_DECL(da7213_mic_2_amp_in_sel, + DA7213_MIC_2_CTRL, + DA7213_MIC_AMP_IN_SEL_SHIFT, + da7213_mic_amp_in_sel_txt); static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux = SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel); @@ -601,15 +606,17 @@ static const char * const da7213_dai_src_txt[] = { "ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right" }; -static const struct soc_enum da7213_dai_l_src = - SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_L_SRC_SHIFT, - DA7213_DAI_SRC_MAX, da7213_dai_src_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dai_l_src, + DA7213_DIG_ROUTING_DAI, + DA7213_DAI_L_SRC_SHIFT, + da7213_dai_src_txt); static const struct snd_kcontrol_new da7213_dai_l_src_mux = SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src); -static const struct soc_enum da7213_dai_r_src = - SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_R_SRC_SHIFT, - DA7213_DAI_SRC_MAX, da7213_dai_src_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dai_r_src, + DA7213_DIG_ROUTING_DAI, + DA7213_DAI_R_SRC_SHIFT, + da7213_dai_src_txt); static const struct snd_kcontrol_new da7213_dai_r_src_mux = SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src); @@ -619,15 +626,17 @@ static const char * const da7213_dac_src_txt[] = { "DAI Input Right" }; -static const struct soc_enum da7213_dac_l_src = - SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_L_SRC_SHIFT, - DA7213_DAC_SRC_MAX, da7213_dac_src_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_l_src, + DA7213_DIG_ROUTING_DAC, + DA7213_DAC_L_SRC_SHIFT, + da7213_dac_src_txt); static const struct snd_kcontrol_new da7213_dac_l_src_mux = SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src); -static const struct soc_enum da7213_dac_r_src = - SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_R_SRC_SHIFT, - DA7213_DAC_SRC_MAX, da7213_dac_src_txt); +static SOC_ENUM_SINGLE_DECL(da7213_dac_r_src, + DA7213_DIG_ROUTING_DAC, + DA7213_DAC_R_SRC_SHIFT, + da7213_dac_src_txt); static const struct snd_kcontrol_new da7213_dac_r_src_mux = SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src); diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index f295b6569910..4d1c302f5a76 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -269,81 +269,65 @@ static const char *da732x_hpf_voice[] = { "150Hz", "200Hz", "300Hz", "400Hz" }; -static const struct soc_enum da732x_dac1_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac1_hpf_mode_enum, + DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, + da732x_hpf_mode); -static const struct soc_enum da732x_dac2_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac2_hpf_mode_enum, + DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, + da732x_hpf_mode); -static const struct soc_enum da732x_dac3_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac3_hpf_mode_enum, + DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, + da732x_hpf_mode); -static const struct soc_enum da732x_adc1_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc1_hpf_mode_enum, + DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, + da732x_hpf_mode); -static const struct soc_enum da732x_adc2_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc2_hpf_mode_enum, + DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, + da732x_hpf_mode); -static const struct soc_enum da732x_dac1_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac1_hp_filter_enum, + DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, + da732x_hpf_music); -static const struct soc_enum da732x_dac2_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac2_hp_filter_enum, + DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, + da732x_hpf_music); -static const struct soc_enum da732x_dac3_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac3_hp_filter_enum, + DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, + da732x_hpf_music); -static const struct soc_enum da732x_adc1_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc1_hp_filter_enum, + DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, + da732x_hpf_music); -static const struct soc_enum da732x_adc2_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc2_hp_filter_enum, + DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, + da732x_hpf_music); -static const struct soc_enum da732x_dac1_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac1_voice_filter_enum, + DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, + da732x_hpf_voice); -static const struct soc_enum da732x_dac2_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac2_voice_filter_enum, + DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, + da732x_hpf_voice); -static const struct soc_enum da732x_dac3_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; +static SOC_ENUM_SINGLE_DECL(da732x_dac3_voice_filter_enum, + DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, + da732x_hpf_voice); -static const struct soc_enum da732x_adc1_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; - -static const struct soc_enum da732x_adc2_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; +static SOC_ENUM_SINGLE_DECL(da732x_adc1_voice_filter_enum, + DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, + da732x_hpf_voice); +static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum, + DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, + da732x_hpf_voice); static int da732x_hpf_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -714,65 +698,65 @@ static const char *enable_text[] = { }; /* ADC1LMUX */ -static const struct soc_enum adc1l_enum = - SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, - DA732X_ADCL_MUX_MAX, adcl_text); +static SOC_ENUM_SINGLE_DECL(adc1l_enum, + DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, + adcl_text); static const struct snd_kcontrol_new adc1l_mux = SOC_DAPM_ENUM("ADC Route", adc1l_enum); /* ADC1RMUX */ -static const struct soc_enum adc1r_enum = - SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, - DA732X_ADCR_MUX_MAX, adcr_text); +static SOC_ENUM_SINGLE_DECL(adc1r_enum, + DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, + adcr_text); static const struct snd_kcontrol_new adc1r_mux = SOC_DAPM_ENUM("ADC Route", adc1r_enum); /* ADC2LMUX */ -static const struct soc_enum adc2l_enum = - SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, - DA732X_ADCL_MUX_MAX, adcl_text); +static SOC_ENUM_SINGLE_DECL(adc2l_enum, + DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, + adcl_text); static const struct snd_kcontrol_new adc2l_mux = SOC_DAPM_ENUM("ADC Route", adc2l_enum); /* ADC2RMUX */ -static const struct soc_enum adc2r_enum = - SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, - DA732X_ADCR_MUX_MAX, adcr_text); +static SOC_ENUM_SINGLE_DECL(adc2r_enum, + DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, + adcr_text); static const struct snd_kcontrol_new adc2r_mux = SOC_DAPM_ENUM("ADC Route", adc2r_enum); -static const struct soc_enum da732x_hp_left_output = - SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_hp_left_output, + DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, + enable_text); static const struct snd_kcontrol_new hpl_mux = SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output); -static const struct soc_enum da732x_hp_right_output = - SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_hp_right_output, + DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, + enable_text); static const struct snd_kcontrol_new hpr_mux = SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output); -static const struct soc_enum da732x_speaker_output = - SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_speaker_output, + DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, + enable_text); static const struct snd_kcontrol_new spk_mux = SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output); -static const struct soc_enum da732x_lout4_output = - SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_lout4_output, + DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, + enable_text); static const struct snd_kcontrol_new lout4_mux = SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output); -static const struct soc_enum da732x_lout2_output = - SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); +static SOC_ENUM_SINGLE_DECL(da732x_lout2_output, + DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, + enable_text); static const struct snd_kcontrol_new lout2_mux = SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output); @@ -1268,11 +1252,23 @@ static struct snd_soc_dai_driver da732x_dai[] = { }, }; +static bool da732x_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA732X_REG_HPL_DAC_OFF_CNTL: + case DA732X_REG_HPR_DAC_OFF_CNTL: + return true; + default: + return false; + } +} + static const struct regmap_config da732x_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = DA732X_MAX_REG, + .volatile_reg = da732x_volatile, .reg_defaults = da732x_reg_cache, .num_reg_defaults = ARRAY_SIZE(da732x_reg_cache), .cache_type = REGCACHE_RBTREE, @@ -1487,8 +1483,8 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, da732x_hp_dc_offset_cancellation(codec); - regcache_cache_only(codec->control_data, false); - regcache_sync(codec->control_data); + regcache_cache_only(da732x->regmap, false); + regcache_sync(da732x->regmap); } else { snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_BOOST_MASK, @@ -1499,7 +1495,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, } break; case SND_SOC_BIAS_OFF: - regcache_cache_only(codec->control_data, true); + regcache_cache_only(da732x->regmap, true); da732x_set_charge_pump(codec, DA732X_DISABLE_CP); snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN, DA732X_BIAS_DIS); @@ -1554,7 +1550,6 @@ static struct snd_soc_codec_driver soc_codec_dev_da732x = { .dapm_routes = da732x_dapm_routes, .num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes), .set_pll = da732x_set_dai_pll, - .reg_cache_size = ARRAY_SIZE(da732x_reg_cache), }; static int da732x_i2c_probe(struct i2c_client *i2c, diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h index c8ce5475de22..1dceafeec415 100644 --- a/sound/soc/codecs/da732x.h +++ b/sound/soc/codecs/da732x.h @@ -113,9 +113,6 @@ #define DA732X_EQ_OVERALL_VOL_DB_MIN -1800 #define DA732X_EQ_OVERALL_VOL_DB_INC 600 -#define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \ - {.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext} - enum da732x_sysctl { DA732X_SR_8KHZ = 0x1, DA732X_SR_11_025KHZ = 0x2, diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 52b79a487ac7..f118daa91234 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -18,6 +18,8 @@ #include <linux/regmap.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -321,22 +323,22 @@ static const char * const da9055_hpf_cutoff_txt[] = { "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" }; -static const struct soc_enum da9055_dac_hpf_cutoff = - SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_hpf_cutoff, + DA9055_DAC_FILTERS1, 4, da9055_hpf_cutoff_txt); -static const struct soc_enum da9055_adc_hpf_cutoff = - SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da9055_adc_hpf_cutoff, + DA9055_ADC_FILTERS1, 4, da9055_hpf_cutoff_txt); /* ADC and DAC voice mode (8kHz) high pass cutoff value */ static const char * const da9055_vf_cutoff_txt[] = { "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" }; -static const struct soc_enum da9055_dac_vf_cutoff = - SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_vf_cutoff, + DA9055_DAC_FILTERS1, 0, da9055_vf_cutoff_txt); -static const struct soc_enum da9055_adc_vf_cutoff = - SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); +static SOC_ENUM_SINGLE_DECL(da9055_adc_vf_cutoff, + DA9055_ADC_FILTERS1, 0, da9055_vf_cutoff_txt); /* Gain ramping rate value */ static const char * const da9055_gain_ramping_txt[] = { @@ -344,44 +346,44 @@ static const char * const da9055_gain_ramping_txt[] = { "nominal rate / 8" }; -static const struct soc_enum da9055_gain_ramping_rate = - SOC_ENUM_SINGLE(DA9055_GAIN_RAMP_CTRL, 0, 4, da9055_gain_ramping_txt); +static SOC_ENUM_SINGLE_DECL(da9055_gain_ramping_rate, + DA9055_GAIN_RAMP_CTRL, 0, da9055_gain_ramping_txt); /* DAC noise gate setup time value */ static const char * const da9055_dac_ng_setup_time_txt[] = { "256 samples", "512 samples", "1024 samples", "2048 samples" }; -static const struct soc_enum da9055_dac_ng_setup_time = - SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 0, 4, - da9055_dac_ng_setup_time_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_setup_time, + DA9055_DAC_NG_SETUP_TIME, 0, + da9055_dac_ng_setup_time_txt); /* DAC noise gate rampup rate value */ static const char * const da9055_dac_ng_rampup_txt[] = { "0.02 ms/dB", "0.16 ms/dB" }; -static const struct soc_enum da9055_dac_ng_rampup_rate = - SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 2, 2, - da9055_dac_ng_rampup_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampup_rate, + DA9055_DAC_NG_SETUP_TIME, 2, + da9055_dac_ng_rampup_txt); /* DAC noise gate rampdown rate value */ static const char * const da9055_dac_ng_rampdown_txt[] = { "0.64 ms/dB", "20.48 ms/dB" }; -static const struct soc_enum da9055_dac_ng_rampdown_rate = - SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 3, 2, - da9055_dac_ng_rampdown_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampdown_rate, + DA9055_DAC_NG_SETUP_TIME, 3, + da9055_dac_ng_rampdown_txt); /* DAC soft mute rate value */ static const char * const da9055_dac_soft_mute_rate_txt[] = { "1", "2", "4", "8", "16", "32", "64" }; -static const struct soc_enum da9055_dac_soft_mute_rate = - SOC_ENUM_SINGLE(DA9055_DAC_FILTERS5, 4, 7, - da9055_dac_soft_mute_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_soft_mute_rate, + DA9055_DAC_FILTERS5, 4, + da9055_dac_soft_mute_rate_txt); /* DAC routing select */ static const char * const da9055_dac_src_txt[] = { @@ -389,40 +391,40 @@ static const char * const da9055_dac_src_txt[] = { "AIF input right" }; -static const struct soc_enum da9055_dac_l_src = - SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 0, 4, da9055_dac_src_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_l_src, + DA9055_DIG_ROUTING_DAC, 0, da9055_dac_src_txt); -static const struct soc_enum da9055_dac_r_src = - SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 4, 4, da9055_dac_src_txt); +static SOC_ENUM_SINGLE_DECL(da9055_dac_r_src, + DA9055_DIG_ROUTING_DAC, 4, da9055_dac_src_txt); /* MIC PGA Left source select */ static const char * const da9055_mic_l_src_txt[] = { "MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L" }; -static const struct soc_enum da9055_mic_l_src = - SOC_ENUM_SINGLE(DA9055_MIXIN_L_SELECT, 4, 4, da9055_mic_l_src_txt); +static SOC_ENUM_SINGLE_DECL(da9055_mic_l_src, + DA9055_MIXIN_L_SELECT, 4, da9055_mic_l_src_txt); /* MIC PGA Right source select */ static const char * const da9055_mic_r_src_txt[] = { "MIC2_R_L", "MIC2_R", "MIC2_L" }; -static const struct soc_enum da9055_mic_r_src = - SOC_ENUM_SINGLE(DA9055_MIXIN_R_SELECT, 4, 3, da9055_mic_r_src_txt); +static SOC_ENUM_SINGLE_DECL(da9055_mic_r_src, + DA9055_MIXIN_R_SELECT, 4, da9055_mic_r_src_txt); /* ALC Input Signal Tracking rate select */ static const char * const da9055_signal_tracking_rate_txt[] = { "1/4", "1/16", "1/256", "1/65536" }; -static const struct soc_enum da9055_integ_attack_rate = - SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 4, 4, - da9055_signal_tracking_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_integ_attack_rate, + DA9055_ALC_CTRL3, 4, + da9055_signal_tracking_rate_txt); -static const struct soc_enum da9055_integ_release_rate = - SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 6, 4, - da9055_signal_tracking_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_integ_release_rate, + DA9055_ALC_CTRL3, 6, + da9055_signal_tracking_rate_txt); /* ALC Attack Rate select */ static const char * const da9055_attack_rate_txt[] = { @@ -430,8 +432,8 @@ static const char * const da9055_attack_rate_txt[] = { "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" }; -static const struct soc_enum da9055_attack_rate = - SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 0, 13, da9055_attack_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_attack_rate, + DA9055_ALC_CTRL2, 0, da9055_attack_rate_txt); /* ALC Release Rate select */ static const char * const da9055_release_rate_txt[] = { @@ -439,8 +441,8 @@ static const char * const da9055_release_rate_txt[] = { "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" }; -static const struct soc_enum da9055_release_rate = - SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 4, 11, da9055_release_rate_txt); +static SOC_ENUM_SINGLE_DECL(da9055_release_rate, + DA9055_ALC_CTRL2, 4, da9055_release_rate_txt); /* ALC Hold Time select */ static const char * const da9055_hold_time_txt[] = { @@ -449,8 +451,8 @@ static const char * const da9055_hold_time_txt[] = { "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" }; -static const struct soc_enum da9055_hold_time = - SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 0, 16, da9055_hold_time_txt); +static SOC_ENUM_SINGLE_DECL(da9055_hold_time, + DA9055_ALC_CTRL3, 0, da9055_hold_time_txt); static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) { @@ -1523,17 +1525,30 @@ static int da9055_remove(struct i2c_client *client) return 0; } +/* + * DO NOT change the device Ids. The naming is intentionally specific as both + * the CODEC and PMIC parts of this chip are instantiated separately as I2C + * devices (both have configurable I2C addresses, and are to all intents and + * purposes separate). As a result there are specific DA9055 Ids for CODEC + * and PMIC, which must be different to operate together. + */ static const struct i2c_device_id da9055_i2c_id[] = { - { "da9055", 0 }, + { "da9055-codec", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); +static const struct of_device_id da9055_of_match[] = { + { .compatible = "dlg,da9055-codec", }, + { } +}; + /* I2C codec control layer */ static struct i2c_driver da9055_i2c_driver = { .driver = { - .name = "da9055", + .name = "da9055-codec", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(da9055_of_match), }, .probe = da9055_i2c_probe, .remove = da9055_remove, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 5839048ec467..cb736ddc446d 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -140,13 +140,17 @@ static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"}; static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"}; static const struct soc_enum isabelle_rx1_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts), - SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts), + SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, + ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts), + SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, + ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts), }; static const struct soc_enum isabelle_rx2_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts), - SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts), + SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, + ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts), + SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, + ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts), }; /* Headset DAC playback switches */ @@ -161,13 +165,17 @@ static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"}; static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"}; static const struct soc_enum isabelle_atx_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts), - SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts), + SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, + ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts), + SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, + ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts), }; static const struct soc_enum isabelle_vtx_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts), - SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts), + SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, + ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts), + SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, + ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts), }; static const struct snd_kcontrol_new atx_mux_controls = @@ -183,17 +191,13 @@ static const char *isabelle_amic1_texts[] = { /* Left analog microphone selection */ static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"}; -static const struct soc_enum isabelle_amic1_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5, - ARRAY_SIZE(isabelle_amic1_texts), - isabelle_amic1_texts), -}; +static SOC_ENUM_SINGLE_DECL(isabelle_amic1_enum, + ISABELLE_AMIC_CFG_REG, 5, + isabelle_amic1_texts); -static const struct soc_enum isabelle_amic2_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4, - ARRAY_SIZE(isabelle_amic2_texts), - isabelle_amic2_texts), -}; +static SOC_ENUM_SINGLE_DECL(isabelle_amic2_enum, + ISABELLE_AMIC_CFG_REG, 4, + isabelle_amic2_texts); static const struct snd_kcontrol_new amic1_control = SOC_DAPM_ENUM("Route", isabelle_amic1_enum); @@ -206,16 +210,20 @@ static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"}; static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"}; static const struct soc_enum isabelle_st_audio_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1, + SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, + ARRAY_SIZE(isabelle_st_audio_texts), isabelle_st_audio_texts), - SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1, + SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, + ARRAY_SIZE(isabelle_st_audio_texts), isabelle_st_audio_texts), }; static const struct soc_enum isabelle_st_voice_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1, + SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, + ARRAY_SIZE(isabelle_st_voice_texts), isabelle_st_voice_texts), - SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1, + SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, + ARRAY_SIZE(isabelle_st_voice_texts), isabelle_st_voice_texts), }; diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index e19490cfb3a8..6b7fe5e54881 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -195,18 +195,18 @@ struct lm49453_priv { static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"}; -static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5, - lm49453_mic2mode_text); +static SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5, + lm49453_mic2mode_text); static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"}; -static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum, - LM49453_P0_DIGITAL_MIC1_CONFIG_REG, - 7, lm49453_dmic_cfg_text); +static SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum, + LM49453_P0_DIGITAL_MIC1_CONFIG_REG, 7, + lm49453_dmic_cfg_text); -static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum, - LM49453_P0_DIGITAL_MIC2_CONFIG_REG, - 7, lm49453_dmic_cfg_text); +static SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum, + LM49453_P0_DIGITAL_MIC2_CONFIG_REG, 7, + lm49453_dmic_cfg_text); /* MUX Controls */ static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" }; diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index ee660e2d3df3..bb1ecfc4459b 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1849,7 +1849,7 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec) /* Now point the soc_enum to .texts array items */ max98088->eq_enum.texts = max98088->eq_texts; - max98088->eq_enum.max = max98088->eq_textcnt; + max98088->eq_enum.items = max98088->eq_textcnt; ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); if (ret != 0) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 51f9b3d16b41..f363de19be07 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -336,6 +336,7 @@ static bool max98090_readable_register(struct device *dev, unsigned int reg) case M98090_REG_RECORD_TDM_SLOT: case M98090_REG_SAMPLE_RATE: case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E: + case M98090_REG_REVISION_ID: return true; default: return false; @@ -512,65 +513,75 @@ static const char *max98090_perf_pwr_text[] = static const char *max98090_pwr_perf_text[] = { "Low Power", "High Performance" }; -static const struct soc_enum max98090_vcmbandgap_enum = - SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT, - ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); +static SOC_ENUM_SINGLE_DECL(max98090_vcmbandgap_enum, + M98090_REG_BIAS_CONTROL, + M98090_VCM_MODE_SHIFT, + max98090_pwr_perf_text); static const char *max98090_osr128_text[] = { "64*fs", "128*fs" }; -static const struct soc_enum max98090_osr128_enum = - SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT, - ARRAY_SIZE(max98090_osr128_text), max98090_osr128_text); +static SOC_ENUM_SINGLE_DECL(max98090_osr128_enum, + M98090_REG_ADC_CONTROL, + M98090_OSR128_SHIFT, + max98090_osr128_text); static const char *max98090_mode_text[] = { "Voice", "Music" }; -static const struct soc_enum max98090_mode_enum = - SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, M98090_MODE_SHIFT, - ARRAY_SIZE(max98090_mode_text), max98090_mode_text); +static SOC_ENUM_SINGLE_DECL(max98090_mode_enum, + M98090_REG_FILTER_CONFIG, + M98090_MODE_SHIFT, + max98090_mode_text); -static const struct soc_enum max98090_filter_dmic34mode_enum = - SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, - M98090_FLT_DMIC34MODE_SHIFT, - ARRAY_SIZE(max98090_mode_text), max98090_mode_text); +static SOC_ENUM_SINGLE_DECL(max98090_filter_dmic34mode_enum, + M98090_REG_FILTER_CONFIG, + M98090_FLT_DMIC34MODE_SHIFT, + max98090_mode_text); static const char *max98090_drcatk_text[] = { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" }; -static const struct soc_enum max98090_drcatk_enum = - SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT, - ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text); +static SOC_ENUM_SINGLE_DECL(max98090_drcatk_enum, + M98090_REG_DRC_TIMING, + M98090_DRCATK_SHIFT, + max98090_drcatk_text); static const char *max98090_drcrls_text[] = { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" }; -static const struct soc_enum max98090_drcrls_enum = - SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT, - ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text); +static SOC_ENUM_SINGLE_DECL(max98090_drcrls_enum, + M98090_REG_DRC_TIMING, + M98090_DRCRLS_SHIFT, + max98090_drcrls_text); static const char *max98090_alccmp_text[] = { "1:1", "1:1.5", "1:2", "1:4", "1:INF" }; -static const struct soc_enum max98090_alccmp_enum = - SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT, - ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text); +static SOC_ENUM_SINGLE_DECL(max98090_alccmp_enum, + M98090_REG_DRC_COMPRESSOR, + M98090_DRCCMP_SHIFT, + max98090_alccmp_text); static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" }; -static const struct soc_enum max98090_drcexp_enum = - SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT, - ARRAY_SIZE(max98090_drcexp_text), max98090_drcexp_text); +static SOC_ENUM_SINGLE_DECL(max98090_drcexp_enum, + M98090_REG_DRC_EXPANDER, + M98090_DRCEXP_SHIFT, + max98090_drcexp_text); -static const struct soc_enum max98090_dac_perfmode_enum = - SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_PERFMODE_SHIFT, - ARRAY_SIZE(max98090_perf_pwr_text), max98090_perf_pwr_text); +static SOC_ENUM_SINGLE_DECL(max98090_dac_perfmode_enum, + M98090_REG_DAC_CONTROL, + M98090_PERFMODE_SHIFT, + max98090_perf_pwr_text); -static const struct soc_enum max98090_dachp_enum = - SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_DACHP_SHIFT, - ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); +static SOC_ENUM_SINGLE_DECL(max98090_dachp_enum, + M98090_REG_DAC_CONTROL, + M98090_DACHP_SHIFT, + max98090_pwr_perf_text); -static const struct soc_enum max98090_adchp_enum = - SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_ADCHP_SHIFT, - ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); +static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum, + M98090_REG_ADC_CONTROL, + M98090_ADCHP_SHIFT, + max98090_pwr_perf_text); static const struct snd_kcontrol_new max98090_snd_controls[] = { SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum), @@ -841,39 +852,42 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w, static const char *mic1_mux_text[] = { "IN12", "IN56" }; -static const struct soc_enum mic1_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC1_SHIFT, - ARRAY_SIZE(mic1_mux_text), mic1_mux_text); +static SOC_ENUM_SINGLE_DECL(mic1_mux_enum, + M98090_REG_INPUT_MODE, + M98090_EXTMIC1_SHIFT, + mic1_mux_text); static const struct snd_kcontrol_new max98090_mic1_mux = SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum); static const char *mic2_mux_text[] = { "IN34", "IN56" }; -static const struct soc_enum mic2_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC2_SHIFT, - ARRAY_SIZE(mic2_mux_text), mic2_mux_text); +static SOC_ENUM_SINGLE_DECL(mic2_mux_enum, + M98090_REG_INPUT_MODE, + M98090_EXTMIC2_SHIFT, + mic2_mux_text); static const struct snd_kcontrol_new max98090_mic2_mux = SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum); static const char *dmic_mux_text[] = { "ADC", "DMIC" }; -static const struct soc_enum dmic_mux_enum = - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dmic_mux_text), dmic_mux_text); +static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text); static const struct snd_kcontrol_new max98090_dmic_mux = SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum); static const char *max98090_micpre_text[] = { "Off", "On" }; -static const struct soc_enum max98090_pa1en_enum = - SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, - ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); +static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum, + M98090_REG_MIC1_INPUT_LEVEL, + M98090_MIC_PA1EN_SHIFT, + max98090_micpre_text); -static const struct soc_enum max98090_pa2en_enum = - SOC_ENUM_SINGLE(M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT, - ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); +static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum, + M98090_REG_MIC2_INPUT_LEVEL, + M98090_MIC_PA2EN_SHIFT, + max98090_micpre_text); /* LINEA mixer switch */ static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { @@ -937,13 +951,15 @@ static const struct snd_kcontrol_new max98090_right_adc_mixer_controls[] = { static const char *lten_mux_text[] = { "Normal", "Loopthrough" }; -static const struct soc_enum ltenl_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, - ARRAY_SIZE(lten_mux_text), lten_mux_text); +static SOC_ENUM_SINGLE_DECL(ltenl_mux_enum, + M98090_REG_IO_CONFIGURATION, + M98090_LTEN_SHIFT, + lten_mux_text); -static const struct soc_enum ltenr_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, - ARRAY_SIZE(lten_mux_text), lten_mux_text); +static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum, + M98090_REG_IO_CONFIGURATION, + M98090_LTEN_SHIFT, + lten_mux_text); static const struct snd_kcontrol_new max98090_ltenl_mux = SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum); @@ -953,13 +969,15 @@ static const struct snd_kcontrol_new max98090_ltenr_mux = static const char *lben_mux_text[] = { "Normal", "Loopback" }; -static const struct soc_enum lbenl_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, - ARRAY_SIZE(lben_mux_text), lben_mux_text); +static SOC_ENUM_SINGLE_DECL(lbenl_mux_enum, + M98090_REG_IO_CONFIGURATION, + M98090_LBEN_SHIFT, + lben_mux_text); -static const struct soc_enum lbenr_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, - ARRAY_SIZE(lben_mux_text), lben_mux_text); +static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum, + M98090_REG_IO_CONFIGURATION, + M98090_LBEN_SHIFT, + lben_mux_text); static const struct snd_kcontrol_new max98090_lbenl_mux = SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum); @@ -971,13 +989,15 @@ static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" }; static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" }; -static const struct soc_enum stenl_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSL_SHIFT, - ARRAY_SIZE(stenl_mux_text), stenl_mux_text); +static SOC_ENUM_SINGLE_DECL(stenl_mux_enum, + M98090_REG_ADC_SIDETONE, + M98090_DSTSL_SHIFT, + stenl_mux_text); -static const struct soc_enum stenr_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSR_SHIFT, - ARRAY_SIZE(stenr_mux_text), stenr_mux_text); +static SOC_ENUM_SINGLE_DECL(stenr_mux_enum, + M98090_REG_ADC_SIDETONE, + M98090_DSTSR_SHIFT, + stenr_mux_text); static const struct snd_kcontrol_new max98090_stenl_mux = SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum); @@ -1085,9 +1105,10 @@ static const struct snd_kcontrol_new max98090_right_rcv_mixer_controls[] = { static const char *linmod_mux_text[] = { "Left Only", "Left and Right" }; -static const struct soc_enum linmod_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_LOUTR_MIXER, M98090_LINMOD_SHIFT, - ARRAY_SIZE(linmod_mux_text), linmod_mux_text); +static SOC_ENUM_SINGLE_DECL(linmod_mux_enum, + M98090_REG_LOUTR_MIXER, + M98090_LINMOD_SHIFT, + linmod_mux_text); static const struct snd_kcontrol_new max98090_linmod_mux = SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum); @@ -1097,16 +1118,18 @@ static const char *mixhpsel_mux_text[] = { "DAC Only", "HP Mixer" }; /* * This is a mux as it selects the HP output, but to DAPM it is a Mixer enable */ -static const struct soc_enum mixhplsel_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPLSEL_SHIFT, - ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); +static SOC_ENUM_SINGLE_DECL(mixhplsel_mux_enum, + M98090_REG_HP_CONTROL, + M98090_MIXHPLSEL_SHIFT, + mixhpsel_mux_text); static const struct snd_kcontrol_new max98090_mixhplsel_mux = SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum); -static const struct soc_enum mixhprsel_mux_enum = - SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPRSEL_SHIFT, - ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); +static SOC_ENUM_SINGLE_DECL(mixhprsel_mux_enum, + M98090_REG_HP_CONTROL, + M98090_MIXHPRSEL_SHIFT, + mixhpsel_mux_text); static const struct snd_kcontrol_new max98090_mixhprsel_mux = SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); @@ -1769,16 +1792,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = regcache_sync(max98090->regmap); - - if (ret != 0) { - dev_err(codec->dev, - "Failed to sync cache: %d\n", ret); - return ret; - } - } - if (max98090->jack_state == M98090_JACK_STATE_HEADSET) { /* * Set to normal bias level. @@ -1792,6 +1805,16 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + ret = regcache_sync(max98090->regmap); + if (ret != 0) { + dev_err(codec->dev, + "Failed to sync cache: %d\n", ret); + return ret; + } + } + break; + case SND_SOC_BIAS_OFF: /* Set internal pull-up to lowest power mode */ snd_soc_update_bits(codec, M98090_REG_JACK_DETECT, diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 3ba1170ebb53..5bce9cde4a6d 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -1861,7 +1861,7 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec) /* Now point the soc_enum to .texts array items */ max98095->eq_enum.texts = max98095->eq_texts; - max98095->eq_enum.max = max98095->eq_textcnt; + max98095->eq_enum.items = max98095->eq_textcnt; ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); if (ret != 0) @@ -2016,7 +2016,7 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec) /* Now point the soc_enum to .texts array items */ max98095->bq_enum.texts = max98095->bq_texts; - max98095->bq_enum.max = max98095->bq_textcnt; + max98095->bq_enum.items = max98095->bq_textcnt; ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); if (ret != 0) diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 582c2bbd42cb..ec89b8f90a64 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -408,8 +408,7 @@ static const char * const adcl_enum_text[] = { "MC1L", "RXINL", }; -static const struct soc_enum adcl_enum = - SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text); static const struct snd_kcontrol_new left_input_mux = SOC_DAPM_ENUM_VIRT("Route", adcl_enum); @@ -418,8 +417,7 @@ static const char * const adcr_enum_text[] = { "MC1R", "MC2", "RXINR", "TXIN", }; -static const struct soc_enum adcr_enum = - SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text); static const struct snd_kcontrol_new right_input_mux = SOC_DAPM_ENUM_VIRT("Route", adcr_enum); @@ -430,8 +428,8 @@ static const struct snd_kcontrol_new samp_ctl = static const char * const speaker_amp_source_text[] = { "CODEC", "Right" }; -static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, - speaker_amp_source_text); +static SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, + speaker_amp_source_text); static const struct snd_kcontrol_new speaker_amp_source_mux = SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source); @@ -439,8 +437,8 @@ static const char * const headset_amp_source_text[] = { "CODEC", "Mixer" }; -static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, - headset_amp_source_text); +static SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, + headset_amp_source_text); static const struct snd_kcontrol_new headset_amp_source_mux = SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source); @@ -580,9 +578,9 @@ static struct snd_soc_dapm_route mc13783_routes[] = { static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix", "Mono", "Mono Mix"}; -static const struct soc_enum mc13783_enum_3d_mixer = - SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer), - mc13783_3d_mixer); +static SOC_ENUM_SINGLE_DECL(mc13783_enum_3d_mixer, + MC13783_AUDIO_RX1, 16, + mc13783_3d_mixer); static struct snd_kcontrol_new mc13783_control_list[] = { SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0), diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 73f9c3630e2c..e427544183d7 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -172,16 +172,21 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); int val = 0, ret; - int pcm_format = params_format(params); priv->rate = params_rate(params); switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: - if (pcm_format == SNDRV_PCM_FORMAT_S24_LE) - val = 0x00; - else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) - val = 0x03; + switch (params_width(params)) { + case 24: + val = 0; + break; + case 16: + val = 3; + break; + default: + return -EINVAL; + } break; case SND_SOC_DAIFMT_I2S: val = 0x04; diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 7146653a8e16..3a80ba4452df 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c @@ -107,24 +107,35 @@ static int pcm1792a_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); int val = 0, ret; - int pcm_format = params_format(params); priv->rate = params_rate(params); switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: - if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || - pcm_format == SNDRV_PCM_FORMAT_S32_LE) - val = 0x02; - else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) - val = 0x00; + switch (params_width(params)) { + case 24: + case 32: + val = 2; + break; + case 16: + val = 0; + break; + default: + return -EINVAL; + } break; case SND_SOC_DAIFMT_I2S: - if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || - pcm_format == SNDRV_PCM_FORMAT_S32_LE) - val = 0x05; - else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) - val = 0x04; + switch (params_width(params)) { + case 24: + case 32: + val = 5; + break; + case 16: + val = 4; + break; + default: + return -EINVAL; + } break; default: dev_err(codec->dev, "Invalid DAI format\n"); diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c new file mode 100644 index 000000000000..4d62230bd378 --- /dev/null +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -0,0 +1,71 @@ +/* + * Driver for the PCM512x CODECs + * + * Author: Mark Brown <broonie@linaro.org> + * Copyright 2014 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/i2c.h> + +#include "pcm512x.h" + +static int pcm512x_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return pcm512x_probe(&i2c->dev, regmap); +} + +static int pcm512x_i2c_remove(struct i2c_client *i2c) +{ + pcm512x_remove(&i2c->dev); + return 0; +} + +static const struct i2c_device_id pcm512x_i2c_id[] = { + { "pcm5121", }, + { "pcm5122", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); + +static const struct of_device_id pcm512x_of_match[] = { + { .compatible = "ti,pcm5121", }, + { .compatible = "ti,pcm5122", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm512x_of_match); + +static struct i2c_driver pcm512x_i2c_driver = { + .probe = pcm512x_i2c_probe, + .remove = pcm512x_i2c_remove, + .id_table = pcm512x_i2c_id, + .driver = { + .name = "pcm512x", + .owner = THIS_MODULE, + .of_match_table = pcm512x_of_match, + .pm = &pcm512x_pm_ops, + }, +}; + +module_i2c_driver(pcm512x_i2c_driver); + +MODULE_DESCRIPTION("ASoC PCM512x codec driver - I2C"); +MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c new file mode 100644 index 000000000000..f297058c0038 --- /dev/null +++ b/sound/soc/codecs/pcm512x-spi.c @@ -0,0 +1,69 @@ +/* + * Driver for the PCM512x CODECs + * + * Author: Mark Brown <broonie@linaro.org> + * Copyright 2014 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include "pcm512x.h" + +static int pcm512x_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_spi(spi, &pcm512x_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + return ret; + } + + return pcm512x_probe(&spi->dev, regmap); +} + +static int pcm512x_spi_remove(struct spi_device *spi) +{ + pcm512x_remove(&spi->dev); + return 0; +} + +static const struct spi_device_id pcm512x_spi_id[] = { + { "pcm5121", }, + { "pcm5122", }, + { }, +}; +MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); + +static const struct of_device_id pcm512x_of_match[] = { + { .compatible = "ti,pcm5121", }, + { .compatible = "ti,pcm5122", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm512x_of_match); + +static struct spi_driver pcm512x_spi_driver = { + .probe = pcm512x_spi_probe, + .remove = pcm512x_spi_remove, + .id_table = pcm512x_spi_id, + .driver = { + .name = "pcm512x", + .owner = THIS_MODULE, + .of_match_table = pcm512x_of_match, + .pm = &pcm512x_pm_ops, + }, +}; + +module_spi_driver(pcm512x_spi_driver); diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c new file mode 100644 index 000000000000..4b4c0c7bb918 --- /dev/null +++ b/sound/soc/codecs/pcm512x.c @@ -0,0 +1,589 @@ +/* + * Driver for the PCM512x CODECs + * + * Author: Mark Brown <broonie@linaro.org> + * Copyright 2014 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +#include "pcm512x.h" + +#define PCM512x_NUM_SUPPLIES 3 +static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { + "AVDD", + "DVDD", + "CPVDD", +}; + +struct pcm512x_priv { + struct regmap *regmap; + struct clk *sclk; + struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; + struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; +}; + +/* + * We can't use the same notifier block for more than one supply and + * there's no way I can see to get from a callback to the caller + * except container_of(). + */ +#define PCM512x_REGULATOR_EVENT(n) \ +static int pcm512x_regulator_event_##n(struct notifier_block *nb, \ + unsigned long event, void *data) \ +{ \ + struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \ + supply_nb[n]); \ + if (event & REGULATOR_EVENT_DISABLE) { \ + regcache_mark_dirty(pcm512x->regmap); \ + regcache_cache_only(pcm512x->regmap, true); \ + } \ + return 0; \ +} + +PCM512x_REGULATOR_EVENT(0) +PCM512x_REGULATOR_EVENT(1) +PCM512x_REGULATOR_EVENT(2) + +static const struct reg_default pcm512x_reg_defaults[] = { + { PCM512x_RESET, 0x00 }, + { PCM512x_POWER, 0x00 }, + { PCM512x_MUTE, 0x00 }, + { PCM512x_DSP, 0x00 }, + { PCM512x_PLL_REF, 0x00 }, + { PCM512x_DAC_ROUTING, 0x11 }, + { PCM512x_DSP_PROGRAM, 0x01 }, + { PCM512x_CLKDET, 0x00 }, + { PCM512x_AUTO_MUTE, 0x00 }, + { PCM512x_ERROR_DETECT, 0x00 }, + { PCM512x_DIGITAL_VOLUME_1, 0x00 }, + { PCM512x_DIGITAL_VOLUME_2, 0x30 }, + { PCM512x_DIGITAL_VOLUME_3, 0x30 }, + { PCM512x_DIGITAL_MUTE_1, 0x22 }, + { PCM512x_DIGITAL_MUTE_2, 0x00 }, + { PCM512x_DIGITAL_MUTE_3, 0x07 }, + { PCM512x_OUTPUT_AMPLITUDE, 0x00 }, + { PCM512x_ANALOG_GAIN_CTRL, 0x00 }, + { PCM512x_UNDERVOLTAGE_PROT, 0x00 }, + { PCM512x_ANALOG_MUTE_CTRL, 0x00 }, + { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, + { PCM512x_VCOM_CTRL_1, 0x00 }, + { PCM512x_VCOM_CTRL_2, 0x01 }, +}; + +static bool pcm512x_readable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case PCM512x_RESET: + case PCM512x_POWER: + case PCM512x_MUTE: + case PCM512x_PLL_EN: + case PCM512x_SPI_MISO_FUNCTION: + case PCM512x_DSP: + case PCM512x_GPIO_EN: + case PCM512x_BCLK_LRCLK_CFG: + case PCM512x_DSP_GPIO_INPUT: + case PCM512x_MASTER_MODE: + case PCM512x_PLL_REF: + case PCM512x_PLL_COEFF_0: + case PCM512x_PLL_COEFF_1: + case PCM512x_PLL_COEFF_2: + case PCM512x_PLL_COEFF_3: + case PCM512x_PLL_COEFF_4: + case PCM512x_DSP_CLKDIV: + case PCM512x_DAC_CLKDIV: + case PCM512x_NCP_CLKDIV: + case PCM512x_OSR_CLKDIV: + case PCM512x_MASTER_CLKDIV_1: + case PCM512x_MASTER_CLKDIV_2: + case PCM512x_FS_SPEED_MODE: + case PCM512x_IDAC_1: + case PCM512x_IDAC_2: + case PCM512x_ERROR_DETECT: + case PCM512x_I2S_1: + case PCM512x_I2S_2: + case PCM512x_DAC_ROUTING: + case PCM512x_DSP_PROGRAM: + case PCM512x_CLKDET: + case PCM512x_AUTO_MUTE: + case PCM512x_DIGITAL_VOLUME_1: + case PCM512x_DIGITAL_VOLUME_2: + case PCM512x_DIGITAL_VOLUME_3: + case PCM512x_DIGITAL_MUTE_1: + case PCM512x_DIGITAL_MUTE_2: + case PCM512x_DIGITAL_MUTE_3: + case PCM512x_GPIO_OUTPUT_1: + case PCM512x_GPIO_OUTPUT_2: + case PCM512x_GPIO_OUTPUT_3: + case PCM512x_GPIO_OUTPUT_4: + case PCM512x_GPIO_OUTPUT_5: + case PCM512x_GPIO_OUTPUT_6: + case PCM512x_GPIO_CONTROL_1: + case PCM512x_GPIO_CONTROL_2: + case PCM512x_OVERFLOW: + case PCM512x_RATE_DET_1: + case PCM512x_RATE_DET_2: + case PCM512x_RATE_DET_3: + case PCM512x_RATE_DET_4: + case PCM512x_ANALOG_MUTE_DET: + case PCM512x_GPIN: + case PCM512x_DIGITAL_MUTE_DET: + case PCM512x_OUTPUT_AMPLITUDE: + case PCM512x_ANALOG_GAIN_CTRL: + case PCM512x_UNDERVOLTAGE_PROT: + case PCM512x_ANALOG_MUTE_CTRL: + case PCM512x_ANALOG_GAIN_BOOST: + case PCM512x_VCOM_CTRL_1: + case PCM512x_VCOM_CTRL_2: + case PCM512x_CRAM_CTRL: + return true; + default: + /* There are 256 raw register addresses */ + return reg < 0xff; + } +} + +static bool pcm512x_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case PCM512x_PLL_EN: + case PCM512x_OVERFLOW: + case PCM512x_RATE_DET_1: + case PCM512x_RATE_DET_2: + case PCM512x_RATE_DET_3: + case PCM512x_RATE_DET_4: + case PCM512x_ANALOG_MUTE_DET: + case PCM512x_GPIN: + case PCM512x_DIGITAL_MUTE_DET: + case PCM512x_CRAM_CTRL: + return true; + default: + /* There are 256 raw register addresses */ + return reg < 0xff; + } +} + +static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); +static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); + +static const char * const pcm512x_dsp_program_texts[] = { + "FIR interpolation with de-emphasis", + "Low latency IIR with de-emphasis", + "Fixed process flow", + "High attenuation with de-emphasis", + "Ringing-less low latency FIR", +}; + +static const unsigned int pcm512x_dsp_program_values[] = { + 1, + 2, + 3, + 5, + 7, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, + PCM512x_DSP_PROGRAM, 0, 0x1f, + pcm512x_dsp_program_texts, + pcm512x_dsp_program_values); + +static const char * const pcm512x_clk_missing_text[] = { + "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" +}; + +static const struct soc_enum pcm512x_clk_missing = + SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 8, pcm512x_clk_missing_text); + +static const char * const pcm512x_autom_text[] = { + "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s" +}; + +static const struct soc_enum pcm512x_autom_l = + SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8, + pcm512x_autom_text); + +static const struct soc_enum pcm512x_autom_r = + SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8, + pcm512x_autom_text); + +static const char * const pcm512x_ramp_rate_text[] = { + "1 sample/update", "2 samples/update", "4 samples/update", + "Immediate" +}; + +static const struct soc_enum pcm512x_vndf = + SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4, + pcm512x_ramp_rate_text); + +static const struct soc_enum pcm512x_vnuf = + SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4, + pcm512x_ramp_rate_text); + +static const struct soc_enum pcm512x_vedf = + SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4, + pcm512x_ramp_rate_text); + +static const char * const pcm512x_ramp_step_text[] = { + "4dB/step", "2dB/step", "1dB/step", "0.5dB/step" +}; + +static const struct soc_enum pcm512x_vnds = + SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4, + pcm512x_ramp_step_text); + +static const struct soc_enum pcm512x_vnus = + SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4, + pcm512x_ramp_step_text); + +static const struct soc_enum pcm512x_veds = + SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, + pcm512x_ramp_step_text); + +static const struct snd_kcontrol_new pcm512x_controls[] = { +SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, + PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), +SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, + PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), +SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, + PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), +SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, + PCM512x_RQMR_SHIFT, 1, 1), + +SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), +SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program), + +SOC_ENUM("Clock Missing Period", pcm512x_clk_missing), +SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), +SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r), +SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3, + PCM512x_ACTL_SHIFT, 1, 0), +SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT, + PCM512x_AMLR_SHIFT, 1, 0), + +SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf), +SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds), +SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), +SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), +SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), +SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), +}; + +static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), + +SND_SOC_DAPM_OUTPUT("OUTL"), +SND_SOC_DAPM_OUTPUT("OUTR"), +}; + +static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { + { "DACL", NULL, "Playback" }, + { "DACR", NULL, "Playback" }, + + { "OUTL", NULL, "DACL" }, + { "OUTR", NULL, "DACR" }, +}; + +static int pcm512x_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + + case SND_SOC_BIAS_STANDBY: + ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, + PCM512x_RQST, 0); + if (ret != 0) { + dev_err(codec->dev, "Failed to remove standby: %d\n", + ret); + return ret; + } + break; + + case SND_SOC_BIAS_OFF: + ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, + PCM512x_RQST, PCM512x_RQST); + if (ret != 0) { + dev_err(codec->dev, "Failed to request standby: %d\n", + ret); + return ret; + } + break; + } + + codec->dapm.bias_level = level; + + return 0; +} + +static struct snd_soc_dai_driver pcm512x_dai = { + .name = "pcm512x-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE + }, +}; + +static struct snd_soc_codec_driver pcm512x_codec_driver = { + .set_bias_level = pcm512x_set_bias_level, + .idle_bias_off = true, + + .controls = pcm512x_controls, + .num_controls = ARRAY_SIZE(pcm512x_controls), + .dapm_widgets = pcm512x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), + .dapm_routes = pcm512x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), +}; + +static const struct regmap_range_cfg pcm512x_range = { + .name = "Pages", .range_min = PCM512x_VIRT_BASE, + .range_max = PCM512x_MAX_REGISTER, + .selector_reg = PCM512x_PAGE, + .selector_mask = 0xff, + .window_start = 0, .window_len = 0x100, +}; + +const struct regmap_config pcm512x_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .readable_reg = pcm512x_readable, + .volatile_reg = pcm512x_volatile, + + .ranges = &pcm512x_range, + .num_ranges = 1, + + .max_register = PCM512x_MAX_REGISTER, + .reg_defaults = pcm512x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(pcm512x_regmap); + +int pcm512x_probe(struct device *dev, struct regmap *regmap) +{ + struct pcm512x_priv *pcm512x; + int i, ret; + + pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL); + if (!pcm512x) + return -ENOMEM; + + dev_set_drvdata(dev, pcm512x); + pcm512x->regmap = regmap; + + for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) + pcm512x->supplies[i].supply = pcm512x_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies), + pcm512x->supplies); + if (ret != 0) { + dev_err(dev, "Failed to get supplies: %d\n", ret); + return ret; + } + + pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0; + pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1; + pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; + + for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { + ret = regulator_register_notifier(pcm512x->supplies[i].consumer, + &pcm512x->supply_nb[i]); + if (ret != 0) { + dev_err(dev, + "Failed to register regulator notifier: %d\n", + ret); + } + } + + ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), + pcm512x->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + /* Reset the device, verifying I/O in the process for I2C */ + ret = regmap_write(regmap, PCM512x_RESET, + PCM512x_RSTM | PCM512x_RSTR); + if (ret != 0) { + dev_err(dev, "Failed to reset device: %d\n", ret); + goto err; + } + + ret = regmap_write(regmap, PCM512x_RESET, 0); + if (ret != 0) { + dev_err(dev, "Failed to reset device: %d\n", ret); + goto err; + } + + pcm512x->sclk = devm_clk_get(dev, NULL); + if (IS_ERR(pcm512x->sclk)) { + if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_info(dev, "No SCLK, using BCLK: %ld\n", + PTR_ERR(pcm512x->sclk)); + + /* Disable reporting of missing SCLK as an error */ + regmap_update_bits(regmap, PCM512x_ERROR_DETECT, + PCM512x_IDCH, PCM512x_IDCH); + + /* Switch PLL input to BCLK */ + regmap_update_bits(regmap, PCM512x_PLL_REF, + PCM512x_SREF, PCM512x_SREF); + } else { + ret = clk_prepare_enable(pcm512x->sclk); + if (ret != 0) { + dev_err(dev, "Failed to enable SCLK: %d\n", ret); + return ret; + } + } + + /* Default to standby mode */ + ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, + PCM512x_RQST, PCM512x_RQST); + if (ret != 0) { + dev_err(dev, "Failed to request standby: %d\n", + ret); + goto err_clk; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + ret = snd_soc_register_codec(dev, &pcm512x_codec_driver, + &pcm512x_dai, 1); + if (ret != 0) { + dev_err(dev, "Failed to register CODEC: %d\n", ret); + goto err_pm; + } + + return 0; + +err_pm: + pm_runtime_disable(dev); +err_clk: + if (!IS_ERR(pcm512x->sclk)) + clk_disable_unprepare(pcm512x->sclk); +err: + regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), + pcm512x->supplies); + return ret; +} +EXPORT_SYMBOL_GPL(pcm512x_probe); + +void pcm512x_remove(struct device *dev) +{ + struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); + + snd_soc_unregister_codec(dev); + pm_runtime_disable(dev); + if (!IS_ERR(pcm512x->sclk)) + clk_disable_unprepare(pcm512x->sclk); + regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), + pcm512x->supplies); +} +EXPORT_SYMBOL_GPL(pcm512x_remove); + +static int pcm512x_suspend(struct device *dev) +{ + struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); + int ret; + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, + PCM512x_RQPD, PCM512x_RQPD); + if (ret != 0) { + dev_err(dev, "Failed to request power down: %d\n", ret); + return ret; + } + + ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), + pcm512x->supplies); + if (ret != 0) { + dev_err(dev, "Failed to disable supplies: %d\n", ret); + return ret; + } + + if (!IS_ERR(pcm512x->sclk)) + clk_disable_unprepare(pcm512x->sclk); + + return 0; +} + +static int pcm512x_resume(struct device *dev) +{ + struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); + int ret; + + if (!IS_ERR(pcm512x->sclk)) { + ret = clk_prepare_enable(pcm512x->sclk); + if (ret != 0) { + dev_err(dev, "Failed to enable SCLK: %d\n", ret); + return ret; + } + } + + ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), + pcm512x->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + regcache_cache_only(pcm512x->regmap, false); + ret = regcache_sync(pcm512x->regmap); + if (ret != 0) { + dev_err(dev, "Failed to sync cache: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, + PCM512x_RQPD, 0); + if (ret != 0) { + dev_err(dev, "Failed to remove power down: %d\n", ret); + return ret; + } + + return 0; +} + +const struct dev_pm_ops pcm512x_pm_ops = { + SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) +}; +EXPORT_SYMBOL_GPL(pcm512x_pm_ops); + +MODULE_DESCRIPTION("ASoC PCM512x codec driver"); +MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h new file mode 100644 index 000000000000..6ee76aaca09a --- /dev/null +++ b/sound/soc/codecs/pcm512x.h @@ -0,0 +1,171 @@ +/* + * Driver for the PCM512x CODECs + * + * Author: Mark Brown <broonie@linaro.org> + * Copyright 2014 Linaro Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _SND_SOC_PCM512X +#define _SND_SOC_PCM512X + +#include <linux/pm.h> +#include <linux/regmap.h> + +#define PCM512x_VIRT_BASE 0x100 +#define PCM512x_PAGE_LEN 0x100 +#define PCM512x_PAGE_BASE(n) (PCM512x_VIRT_BASE + (PCM512x_PAGE_LEN * n)) + +#define PCM512x_PAGE 0 + +#define PCM512x_RESET (PCM512x_PAGE_BASE(0) + 1) +#define PCM512x_POWER (PCM512x_PAGE_BASE(0) + 2) +#define PCM512x_MUTE (PCM512x_PAGE_BASE(0) + 3) +#define PCM512x_PLL_EN (PCM512x_PAGE_BASE(0) + 4) +#define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_BASE(0) + 6) +#define PCM512x_DSP (PCM512x_PAGE_BASE(0) + 7) +#define PCM512x_GPIO_EN (PCM512x_PAGE_BASE(0) + 8) +#define PCM512x_BCLK_LRCLK_CFG (PCM512x_PAGE_BASE(0) + 9) +#define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_BASE(0) + 10) +#define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12) +#define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13) +#define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20) +#define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_BASE(0) + 21) +#define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_BASE(0) + 22) +#define PCM512x_PLL_COEFF_3 (PCM512x_PAGE_BASE(0) + 23) +#define PCM512x_PLL_COEFF_4 (PCM512x_PAGE_BASE(0) + 24) +#define PCM512x_DSP_CLKDIV (PCM512x_PAGE_BASE(0) + 27) +#define PCM512x_DAC_CLKDIV (PCM512x_PAGE_BASE(0) + 28) +#define PCM512x_NCP_CLKDIV (PCM512x_PAGE_BASE(0) + 29) +#define PCM512x_OSR_CLKDIV (PCM512x_PAGE_BASE(0) + 30) +#define PCM512x_MASTER_CLKDIV_1 (PCM512x_PAGE_BASE(0) + 32) +#define PCM512x_MASTER_CLKDIV_2 (PCM512x_PAGE_BASE(0) + 33) +#define PCM512x_FS_SPEED_MODE (PCM512x_PAGE_BASE(0) + 34) +#define PCM512x_IDAC_1 (PCM512x_PAGE_BASE(0) + 35) +#define PCM512x_IDAC_2 (PCM512x_PAGE_BASE(0) + 36) +#define PCM512x_ERROR_DETECT (PCM512x_PAGE_BASE(0) + 37) +#define PCM512x_I2S_1 (PCM512x_PAGE_BASE(0) + 40) +#define PCM512x_I2S_2 (PCM512x_PAGE_BASE(0) + 41) +#define PCM512x_DAC_ROUTING (PCM512x_PAGE_BASE(0) + 42) +#define PCM512x_DSP_PROGRAM (PCM512x_PAGE_BASE(0) + 43) +#define PCM512x_CLKDET (PCM512x_PAGE_BASE(0) + 44) +#define PCM512x_AUTO_MUTE (PCM512x_PAGE_BASE(0) + 59) +#define PCM512x_DIGITAL_VOLUME_1 (PCM512x_PAGE_BASE(0) + 60) +#define PCM512x_DIGITAL_VOLUME_2 (PCM512x_PAGE_BASE(0) + 61) +#define PCM512x_DIGITAL_VOLUME_3 (PCM512x_PAGE_BASE(0) + 62) +#define PCM512x_DIGITAL_MUTE_1 (PCM512x_PAGE_BASE(0) + 63) +#define PCM512x_DIGITAL_MUTE_2 (PCM512x_PAGE_BASE(0) + 64) +#define PCM512x_DIGITAL_MUTE_3 (PCM512x_PAGE_BASE(0) + 65) +#define PCM512x_GPIO_OUTPUT_1 (PCM512x_PAGE_BASE(0) + 80) +#define PCM512x_GPIO_OUTPUT_2 (PCM512x_PAGE_BASE(0) + 81) +#define PCM512x_GPIO_OUTPUT_3 (PCM512x_PAGE_BASE(0) + 82) +#define PCM512x_GPIO_OUTPUT_4 (PCM512x_PAGE_BASE(0) + 83) +#define PCM512x_GPIO_OUTPUT_5 (PCM512x_PAGE_BASE(0) + 84) +#define PCM512x_GPIO_OUTPUT_6 (PCM512x_PAGE_BASE(0) + 85) +#define PCM512x_GPIO_CONTROL_1 (PCM512x_PAGE_BASE(0) + 86) +#define PCM512x_GPIO_CONTROL_2 (PCM512x_PAGE_BASE(0) + 87) +#define PCM512x_OVERFLOW (PCM512x_PAGE_BASE(0) + 90) +#define PCM512x_RATE_DET_1 (PCM512x_PAGE_BASE(0) + 91) +#define PCM512x_RATE_DET_2 (PCM512x_PAGE_BASE(0) + 92) +#define PCM512x_RATE_DET_3 (PCM512x_PAGE_BASE(0) + 93) +#define PCM512x_RATE_DET_4 (PCM512x_PAGE_BASE(0) + 94) +#define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_BASE(0) + 108) +#define PCM512x_GPIN (PCM512x_PAGE_BASE(0) + 119) +#define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_BASE(0) + 120) + +#define PCM512x_OUTPUT_AMPLITUDE (PCM512x_PAGE_BASE(1) + 1) +#define PCM512x_ANALOG_GAIN_CTRL (PCM512x_PAGE_BASE(1) + 2) +#define PCM512x_UNDERVOLTAGE_PROT (PCM512x_PAGE_BASE(1) + 5) +#define PCM512x_ANALOG_MUTE_CTRL (PCM512x_PAGE_BASE(1) + 6) +#define PCM512x_ANALOG_GAIN_BOOST (PCM512x_PAGE_BASE(1) + 7) +#define PCM512x_VCOM_CTRL_1 (PCM512x_PAGE_BASE(1) + 8) +#define PCM512x_VCOM_CTRL_2 (PCM512x_PAGE_BASE(1) + 9) + +#define PCM512x_CRAM_CTRL (PCM512x_PAGE_BASE(44) + 1) + +#define PCM512x_MAX_REGISTER (PCM512x_PAGE_BASE(44) + 1) + +/* Page 0, Register 1 - reset */ +#define PCM512x_RSTR (1 << 0) +#define PCM512x_RSTM (1 << 4) + +/* Page 0, Register 2 - power */ +#define PCM512x_RQPD (1 << 0) +#define PCM512x_RQPD_SHIFT 0 +#define PCM512x_RQST (1 << 4) +#define PCM512x_RQST_SHIFT 4 + +/* Page 0, Register 3 - mute */ +#define PCM512x_RQMR_SHIFT 0 +#define PCM512x_RQML_SHIFT 4 + +/* Page 0, Register 4 - PLL */ +#define PCM512x_PLCE (1 << 0) +#define PCM512x_RLCE_SHIFT 0 +#define PCM512x_PLCK (1 << 4) +#define PCM512x_PLCK_SHIFT 4 + +/* Page 0, Register 7 - DSP */ +#define PCM512x_SDSL (1 << 0) +#define PCM512x_SDSL_SHIFT 0 +#define PCM512x_DEMP (1 << 4) +#define PCM512x_DEMP_SHIFT 4 + +/* Page 0, Register 13 - PLL reference */ +#define PCM512x_SREF (1 << 4) + +/* Page 0, Register 37 - Error detection */ +#define PCM512x_IPLK (1 << 0) +#define PCM512x_DCAS (1 << 1) +#define PCM512x_IDCM (1 << 2) +#define PCM512x_IDCH (1 << 3) +#define PCM512x_IDSK (1 << 4) +#define PCM512x_IDBK (1 << 5) +#define PCM512x_IDFS (1 << 6) + +/* Page 0, Register 42 - DAC routing */ +#define PCM512x_AUPR_SHIFT 0 +#define PCM512x_AUPL_SHIFT 4 + +/* Page 0, Register 59 - auto mute */ +#define PCM512x_ATMR_SHIFT 0 +#define PCM512x_ATML_SHIFT 4 + +/* Page 0, Register 63 - ramp rates */ +#define PCM512x_VNDF_SHIFT 6 +#define PCM512x_VNDS_SHIFT 4 +#define PCM512x_VNUF_SHIFT 2 +#define PCM512x_VNUS_SHIFT 0 + +/* Page 0, Register 64 - emergency ramp rates */ +#define PCM512x_VEDF_SHIFT 6 +#define PCM512x_VEDS_SHIFT 4 + +/* Page 0, Register 65 - Digital mute enables */ +#define PCM512x_ACTL_SHIFT 2 +#define PCM512x_AMLE_SHIFT 1 +#define PCM512x_AMLR_SHIFT 0 + +/* Page 1, Register 2 - analog volume control */ +#define PCM512x_RAGN_SHIFT 0 +#define PCM512x_LAGN_SHIFT 4 + +/* Page 1, Register 7 - analog boost control */ +#define PCM512x_AGBR_SHIFT 0 +#define PCM512x_AGBL_SHIFT 4 + +extern const struct dev_pm_ops pcm512x_pm_ops; +extern const struct regmap_config pcm512x_regmap; + +int pcm512x_probe(struct device *dev, struct regmap *regmap); +void pcm512x_remove(struct device *dev); + +#endif diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 912c9cbc2724..ce199d375209 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -210,26 +210,22 @@ static int rt5631_dmic_put(struct snd_kcontrol *kcontrol, static const char *rt5631_input_mode[] = { "Single ended", "Differential"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1, - RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode); +static SOC_ENUM_SINGLE_DECL(rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1, + RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode); -static const SOC_ENUM_SINGLE_DECL( - rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1, - RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode); +static SOC_ENUM_SINGLE_DECL(rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1, + RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode); /* MONO Input Type */ -static const SOC_ENUM_SINGLE_DECL( - rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL, - RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode); +static SOC_ENUM_SINGLE_DECL(rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL, + RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode); /* SPK Ratio Gain Control */ static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x", "1.56x", "1.68x", "1.99x", "2.34x"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG, - RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio); +static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG, + RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio); static const struct snd_kcontrol_new rt5631_snd_controls[] = { /* MIC */ @@ -759,9 +755,8 @@ static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = { /* Left SPK Volume Input */ static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL, - RT5631_L_EN_SHIFT, rt5631_spkvoll_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL, + RT5631_L_EN_SHIFT, rt5631_spkvoll_sel); static const struct snd_kcontrol_new rt5631_spkvoll_mux_control = SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum); @@ -769,9 +764,8 @@ static const struct snd_kcontrol_new rt5631_spkvoll_mux_control = /* Left HP Volume Input */ static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_hpvoll_enum, RT5631_HP_OUT_VOL, - RT5631_L_EN_SHIFT, rt5631_hpvoll_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_hpvoll_enum, RT5631_HP_OUT_VOL, + RT5631_L_EN_SHIFT, rt5631_hpvoll_sel); static const struct snd_kcontrol_new rt5631_hpvoll_mux_control = SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum); @@ -779,9 +773,8 @@ static const struct snd_kcontrol_new rt5631_hpvoll_mux_control = /* Left Out Volume Input */ static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL, - RT5631_L_EN_SHIFT, rt5631_outvoll_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL, + RT5631_L_EN_SHIFT, rt5631_outvoll_sel); static const struct snd_kcontrol_new rt5631_outvoll_mux_control = SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum); @@ -789,9 +782,8 @@ static const struct snd_kcontrol_new rt5631_outvoll_mux_control = /* Right Out Volume Input */ static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL, - RT5631_R_EN_SHIFT, rt5631_outvolr_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL, + RT5631_R_EN_SHIFT, rt5631_outvolr_sel); static const struct snd_kcontrol_new rt5631_outvolr_mux_control = SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum); @@ -799,9 +791,8 @@ static const struct snd_kcontrol_new rt5631_outvolr_mux_control = /* Right HP Volume Input */ static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_hpvolr_enum, RT5631_HP_OUT_VOL, - RT5631_R_EN_SHIFT, rt5631_hpvolr_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_hpvolr_enum, RT5631_HP_OUT_VOL, + RT5631_R_EN_SHIFT, rt5631_hpvolr_sel); static const struct snd_kcontrol_new rt5631_hpvolr_mux_control = SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum); @@ -809,9 +800,8 @@ static const struct snd_kcontrol_new rt5631_hpvolr_mux_control = /* Right SPK Volume Input */ static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL, - RT5631_R_EN_SHIFT, rt5631_spkvolr_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL, + RT5631_R_EN_SHIFT, rt5631_spkvolr_sel); static const struct snd_kcontrol_new rt5631_spkvolr_mux_control = SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum); @@ -820,9 +810,8 @@ static const struct snd_kcontrol_new rt5631_spkvolr_mux_control = static const char *rt5631_spol_src_sel[] = { "SPOLMIX", "MONOIN_RX", "VDAC", "DACL"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, - RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel); static const struct snd_kcontrol_new rt5631_spol_mux_control = SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum); @@ -831,9 +820,8 @@ static const struct snd_kcontrol_new rt5631_spol_mux_control = static const char *rt5631_spor_src_sel[] = { "SPORMIX", "MONOIN_RX", "VDAC", "DACR"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, - RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel); static const struct snd_kcontrol_new rt5631_spor_mux_control = SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum); @@ -841,9 +829,8 @@ static const struct snd_kcontrol_new rt5631_spor_mux_control = /* MONO Input */ static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, - RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel); static const struct snd_kcontrol_new rt5631_mono_mux_control = SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum); @@ -851,9 +838,8 @@ static const struct snd_kcontrol_new rt5631_mono_mux_control = /* Left HPO Input */ static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, - RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel); static const struct snd_kcontrol_new rt5631_hpl_mux_control = SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum); @@ -861,9 +847,8 @@ static const struct snd_kcontrol_new rt5631_hpl_mux_control = /* Right HPO Input */ static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"}; -static const SOC_ENUM_SINGLE_DECL( - rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, - RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel); +static SOC_ENUM_SINGLE_DECL(rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel); static const struct snd_kcontrol_new rt5631_hpr_mux_control = SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum); diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index a3fb41179636..1a1e1150237d 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -361,25 +361,24 @@ static unsigned int bst_tlv[] = { static const char * const rt5640_data_select[] = { "Normal", "left copy to right", "right copy to left", "Swap"}; -static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, - RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, + RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, - RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, + RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, - RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, + RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, - RT5640_IF2_ADC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, + RT5640_IF2_ADC_SEL_SFT, rt5640_data_select); /* Class D speaker gain ratio */ static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x", "2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"}; -static const SOC_ENUM_SINGLE_DECL( - rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, - RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio); +static SOC_ENUM_SINGLE_DECL(rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, + RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio); static const struct snd_kcontrol_new rt5640_snd_controls[] = { /* Speaker Output Volume */ @@ -753,9 +752,8 @@ static const char * const rt5640_stereo_adc1_src[] = { "DIG MIX", "ADC" }; -static const SOC_ENUM_SINGLE_DECL( - rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, - RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src); +static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, + RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src); static const struct snd_kcontrol_new rt5640_sto_adc_1_mux = SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum); @@ -764,9 +762,8 @@ static const char * const rt5640_stereo_adc2_src[] = { "DMIC1", "DMIC2", "DIG MIX" }; -static const SOC_ENUM_SINGLE_DECL( - rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, - RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src); +static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, + RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src); static const struct snd_kcontrol_new rt5640_sto_adc_2_mux = SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum); @@ -776,9 +773,8 @@ static const char * const rt5640_mono_adc_l1_src[] = { "Mono DAC MIXL", "ADCL" }; -static const SOC_ENUM_SINGLE_DECL( - rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, - RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, + RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src); static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux = SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum); @@ -787,9 +783,8 @@ static const char * const rt5640_mono_adc_l2_src[] = { "DMIC L1", "DMIC L2", "Mono DAC MIXL" }; -static const SOC_ENUM_SINGLE_DECL( - rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, - RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, + RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src); static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux = SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum); @@ -798,9 +793,8 @@ static const char * const rt5640_mono_adc_r1_src[] = { "Mono DAC MIXR", "ADCR" }; -static const SOC_ENUM_SINGLE_DECL( - rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, - RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, + RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src); static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux = SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum); @@ -809,9 +803,8 @@ static const char * const rt5640_mono_adc_r2_src[] = { "DMIC R1", "DMIC R2", "Mono DAC MIXR" }; -static const SOC_ENUM_SINGLE_DECL( - rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, - RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, + RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src); static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux = SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum); @@ -826,9 +819,9 @@ static int rt5640_dac_l2_values[] = { 3, }; -static const SOC_VALUE_ENUM_SINGLE_DECL( - rt5640_dac_l2_enum, RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, - 0x3, rt5640_dac_l2_src, rt5640_dac_l2_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum, + RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, + 0x3, rt5640_dac_l2_src, rt5640_dac_l2_values); static const struct snd_kcontrol_new rt5640_dac_l2_mux = SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); @@ -841,9 +834,9 @@ static int rt5640_dac_r2_values[] = { 0, }; -static const SOC_VALUE_ENUM_SINGLE_DECL( - rt5640_dac_r2_enum, RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, - 0x3, rt5640_dac_r2_src, rt5640_dac_r2_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_r2_enum, + RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, + 0x3, rt5640_dac_r2_src, rt5640_dac_r2_values); static const struct snd_kcontrol_new rt5640_dac_r2_mux = SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum); @@ -860,9 +853,10 @@ static int rt5640_dai_iis_map_values[] = { 7, }; -static const SOC_VALUE_ENUM_SINGLE_DECL( - rt5640_dai_iis_map_enum, RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, - 0x7, rt5640_dai_iis_map, rt5640_dai_iis_map_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum, + RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, + 0x7, rt5640_dai_iis_map, + rt5640_dai_iis_map_values); static const struct snd_kcontrol_new rt5640_dai_mux = SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum); @@ -872,9 +866,8 @@ static const char * const rt5640_sdi_sel[] = { "IF1", "IF2" }; -static const SOC_ENUM_SINGLE_DECL( - rt5640_sdi_sel_enum, RT5640_I2S2_SDP, - RT5640_I2S2_SDI_SFT, rt5640_sdi_sel); +static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP, + RT5640_I2S2_SDI_SFT, rt5640_sdi_sel); static const struct snd_kcontrol_new rt5640_sdi_mux = SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); @@ -2093,6 +2086,7 @@ MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id); #ifdef CONFIG_ACPI static struct acpi_device_id rt5640_acpi_match[] = { { "INT33CA", 0 }, + { "10EC5640", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 52e7cb08434b..fa2b8e07f420 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -210,7 +210,7 @@ out: static int si476x_codec_probe(struct snd_soc_codec *codec) { codec->control_data = dev_get_regmap(codec->dev->parent, NULL); - return 0; + return snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); } static struct snd_soc_dai_ops si476x_dai_ops = { diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index cc8debce752f..806f3d826ffb 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -169,19 +169,19 @@ static const char * const ssm2518_drc_hold_time_text[] = { "682.24 ms", "1364 ms", }; -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum, SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum, SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum, SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum, SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum, SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum, SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum, SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text); static const struct snd_kcontrol_new ssm2518_snd_controls[] = { diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 06edb396e733..2735361a4c3c 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -187,42 +187,42 @@ static const unsigned int sta32x_limiter_drc_release_tlv[] = { 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), }; -static const struct soc_enum sta32x_drc_ac_enum = - SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, - 2, sta32x_drc_ac); -static const struct soc_enum sta32x_auto_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, - 3, sta32x_auto_eq_mode); -static const struct soc_enum sta32x_auto_gc_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, - 4, sta32x_auto_gc_mode); -static const struct soc_enum sta32x_auto_xo_enum = - SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, - 16, sta32x_auto_xo_mode); -static const struct soc_enum sta32x_preset_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, - 32, sta32x_preset_eq_mode); -static const struct soc_enum sta32x_limiter_ch1_enum = - SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch2_enum = - SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch3_enum = - SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter1_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter2_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter1_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); -static const struct soc_enum sta32x_limiter2_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum, + STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, + sta32x_drc_ac); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum, + STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, + sta32x_auto_eq_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum, + STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, + sta32x_auto_gc_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum, + STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, + sta32x_auto_xo_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum, + STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, + sta32x_preset_eq_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum, + STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, + sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum, + STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, + sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum, + STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, + sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum, + STA32X_L1AR, STA32X_LxA_SHIFT, + sta32x_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum, + STA32X_L2AR, STA32X_LxA_SHIFT, + sta32x_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum, + STA32X_L1AR, STA32X_LxR_SHIFT, + sta32x_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum, + STA32X_L2AR, STA32X_LxR_SHIFT, + sta32x_limiter_release_rate); /* byte array controls for setting biquad, mixer, scaling coefficients; * for biquads all five coefficients need to be set in one go, @@ -331,7 +331,7 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec) static int sta32x_cache_sync(struct snd_soc_codec *codec) { - struct sta32x_priv *sta32x = codec->control_data; + struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); unsigned int mute; int rc; @@ -434,7 +434,7 @@ SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), -SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), +SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum), /* depending on mode, the attack/release thresholds have * two different enum definitions; provide both diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 40c07be9b581..f15b0e37274c 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -141,7 +141,7 @@ static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary", static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0); static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0); -static const SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text); +static SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text); static const struct snd_kcontrol_new sta529_snd_controls[] = { SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0, diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c new file mode 100644 index 000000000000..20fc46092c2c --- /dev/null +++ b/sound/soc/codecs/tlv320aic23-i2c.c @@ -0,0 +1,59 @@ +/* + * ALSA SoC TLV320AIC23 codec driver I2C interface + * + * Author: Arun KS, <arunks@mistralsolutions.com> + * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., + * + * Based on sound/soc/codecs/wm8731.c by Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <sound/soc.h> + +#include "tlv320aic23.h" + +static int tlv320aic23_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *i2c_id) +{ + struct regmap *regmap; + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EINVAL; + + regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); + return tlv320aic23_probe(&i2c->dev, regmap); +} + +static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + return 0; +} + +static const struct i2c_device_id tlv320aic23_id[] = { + {"tlv320aic23", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); + +static struct i2c_driver tlv320aic23_i2c_driver = { + .driver = { + .name = "tlv320aic23-codec", + }, + .probe = tlv320aic23_i2c_probe, + .remove = __exit_p(tlv320aic23_i2c_remove), + .id_table = tlv320aic23_id, +}; + +module_i2c_driver(tlv320aic23_i2c_driver); + +MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver I2C"); +MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic23-spi.c b/sound/soc/codecs/tlv320aic23-spi.c new file mode 100644 index 000000000000..585aea436c6a --- /dev/null +++ b/sound/soc/codecs/tlv320aic23-spi.c @@ -0,0 +1,57 @@ +/* + * ALSA SoC TLV320AIC23 codec driver SPI interface + * + * Author: Arun KS, <arunks@mistralsolutions.com> + * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., + * + * Based on sound/soc/codecs/wm8731.c by Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <sound/soc.h> + +#include "tlv320aic23.h" + +static int aic23_spi_probe(struct spi_device *spi) +{ + int ret; + struct regmap *regmap; + + dev_dbg(&spi->dev, "probing tlv320aic23 spi device\n"); + + spi->bits_per_word = 16; + spi->mode = SPI_MODE_0; + ret = spi_setup(spi); + if (ret < 0) + return ret; + + regmap = devm_regmap_init_spi(spi, &tlv320aic23_regmap); + return tlv320aic23_probe(&spi->dev, regmap); +} + +static int aic23_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static struct spi_driver aic23_spi = { + .driver = { + .name = "tlv320aic23", + .owner = THIS_MODULE, + }, + .probe = aic23_spi_probe, + .remove = aic23_spi_remove, +}; + +module_spi_driver(aic23_spi); + +MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver SPI"); +MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 5d430cc56f51..27261e4b27c7 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -23,7 +23,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/i2c.h> #include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> @@ -51,7 +50,7 @@ static const struct reg_default tlv320aic23_reg[] = { { 9, 0x0000 }, }; -static const struct regmap_config tlv320aic23_regmap = { +const struct regmap_config tlv320aic23_regmap = { .reg_bits = 7, .val_bits = 9, @@ -64,16 +63,16 @@ static const struct regmap_config tlv320aic23_regmap = { static const char *rec_src_text[] = { "Line", "Mic" }; static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"}; -static const struct soc_enum rec_src_enum = - SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); +static SOC_ENUM_SINGLE_DECL(rec_src_enum, + TLV320AIC23_ANLG, 2, rec_src_text); static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls = SOC_DAPM_ENUM("Input Select", rec_src_enum); -static const struct soc_enum tlv320aic23_rec_src = - SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); -static const struct soc_enum tlv320aic23_deemph = - SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text); +static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src, + TLV320AIC23_ANLG, 2, rec_src_text); +static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph, + TLV320AIC23_DIGT, 1, deemph_text); static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0); static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0); @@ -400,7 +399,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); /* deactivate */ - if (!codec->active) { + if (!snd_soc_codec_is_active(codec)) { udelay(50); snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0); } @@ -557,7 +556,7 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec) return 0; } -static int tlv320aic23_probe(struct snd_soc_codec *codec) +static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) { int ret; @@ -604,7 +603,7 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { - .probe = tlv320aic23_probe, + .probe = tlv320aic23_codec_probe, .remove = tlv320aic23_remove, .suspend = tlv320aic23_suspend, .resume = tlv320aic23_resume, @@ -617,57 +616,25 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), }; -/* - * If the i2c layer weren't so broken, we could pass this kind of data - * around - */ -static int tlv320aic23_codec_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +int tlv320aic23_probe(struct device *dev, struct regmap *regmap) { struct aic23 *aic23; - int ret; - if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EINVAL; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - aic23 = devm_kzalloc(&i2c->dev, sizeof(struct aic23), GFP_KERNEL); + aic23 = devm_kzalloc(dev, sizeof(struct aic23), GFP_KERNEL); if (aic23 == NULL) return -ENOMEM; - aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); - if (IS_ERR(aic23->regmap)) - return PTR_ERR(aic23->regmap); + aic23->regmap = regmap; - i2c_set_clientdata(i2c, aic23); + dev_set_drvdata(dev, aic23); - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); - return ret; -} -static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) -{ - snd_soc_unregister_codec(&i2c->dev); - return 0; + return snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23, + &tlv320aic23_dai, 1); } -static const struct i2c_device_id tlv320aic23_id[] = { - {"tlv320aic23", 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); - -static struct i2c_driver tlv320aic23_i2c_driver = { - .driver = { - .name = "tlv320aic23-codec", - }, - .probe = tlv320aic23_codec_probe, - .remove = __exit_p(tlv320aic23_i2c_remove), - .id_table = tlv320aic23_id, -}; - -module_i2c_driver(tlv320aic23_i2c_driver); - MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h index e804120bd3da..3a7235a04a89 100644 --- a/sound/soc/codecs/tlv320aic23.h +++ b/sound/soc/codecs/tlv320aic23.h @@ -12,6 +12,12 @@ #ifndef _TLV320AIC23_H #define _TLV320AIC23_H +struct device; +struct regmap_config; + +extern const struct regmap_config tlv320aic23_regmap; +int tlv320aic23_probe(struct device *dev, struct regmap *regmap); + /* Codec TLV320AIC23 */ #define TLV320AIC23_LINVOL 0x00 #define TLV320AIC23_RINVOL 0x01 diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 4f358393d6d6..35b2d244e42e 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -461,7 +461,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol, if (dac33->fifo_mode == ucontrol->value.integer.value[0]) return 0; /* Do not allow changes while stream is running*/ - if (codec->active) + if (snd_soc_codec_is_active(codec)) return -EPERM; if (ucontrol->value.integer.value[0] < 0 || diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 00665ada23e2..682e4ac88939 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -965,9 +965,6 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short val; - unsigned short mask; if (twl4030->configured) { dev_err(codec->dev, @@ -975,19 +972,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, return -EBUSY; } - if (ucontrol->value.enumerated.item[0] > e->max - 1) - return -EINVAL; - - val = ucontrol->value.enumerated.item[0] << e->shift_l; - mask = e->mask << e->shift_l; - if (e->shift_l != e->shift_r) { - if (ucontrol->value.enumerated.item[1] > e->max - 1) - return -EINVAL; - val |= ucontrol->value.enumerated.item[1] << e->shift_r; - mask |= e->mask << e->shift_r; - } - - return snd_soc_update_bits(codec, e->reg, mask, val); + return snd_soc_put_enum_double(kcontrol, ucontrol); } /* diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 726df6d43c2b..8e3940dcff20 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -108,7 +108,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, /* the interpolator & decimator regs must only be written when the * codec DAI is active. */ - if (!codec->active && (reg >= UDA1380_MVOL)) + if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL)) return 0; pr_debug("uda1380: hw write %x val %x\n", reg, value); if (codec->hw_write(codec->control_data, data, 3) == 3) { diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index b7ab2ef567c8..47e96ff30064 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -197,7 +197,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, return 0; /* Do not allow changes while stream is running */ - if (codec->active) + if (snd_soc_codec_is_active(codec)) return -EPERM; if (ucontrol->value.integer.value[0] < 0 || diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4e3e31aaf509..492fe846ae68 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2100,6 +2100,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100) int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) { struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; if (jack) { wm5100->jack = jack; @@ -2117,9 +2118,14 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) WM5100_ACCDET_RATE_MASK); /* We need the charge pump to power MICBIAS */ - snd_soc_dapm_force_enable_pin(&codec->dapm, "CP2"); - snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_mutex_lock(dapm); + + snd_soc_dapm_force_enable_pin_unlocked(dapm, "CP2"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); + + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); /* We start off just enabling microphone detection - even a * plain headphone will trigger detection. diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index ce9c8e14d4bd..34109050ceed 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -582,7 +582,7 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = w->codec; struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - struct regmap *regmap = codec->control_data; + struct regmap *regmap = arizona->regmap; const struct reg_default *patch = NULL; int i, patch_size; @@ -622,13 +622,16 @@ static const unsigned int wm5102_osr_val[] = { static const struct soc_enum wm5102_hpout_osr[] = { SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, - ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, + ARIZONA_OUT1_OSR_SHIFT, 0x7, + ARRAY_SIZE(wm5102_osr_text), wm5102_osr_text, wm5102_osr_val), SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, - ARIZONA_OUT2_OSR_SHIFT, 0x7, 3, + ARIZONA_OUT2_OSR_SHIFT, 0x7, + ARRAY_SIZE(wm5102_osr_text), wm5102_osr_text, wm5102_osr_val), SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, - ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, + ARIZONA_OUT3_OSR_SHIFT, 0x7, + ARRAY_SIZE(wm5102_osr_text), wm5102_osr_text, wm5102_osr_val), }; @@ -685,15 +688,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21, - ARIZONA_EQ1_ENA_MASK), -SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, - ARIZONA_EQ2_ENA_MASK), -SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, - ARIZONA_EQ3_ENA_MASK), -SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21, - ARIZONA_EQ4_ENA_MASK), - +SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), +SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -705,6 +701,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, 24, 0, eq_tlv), +SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), +SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -716,6 +714,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, 24, 0, eq_tlv), +SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), +SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -727,6 +727,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, 24, 0, eq_tlv), +SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), +SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 2c3c962d9a85..d7bf8848174a 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -136,7 +136,7 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = w->codec; struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - struct regmap *regmap = codec->control_data; + struct regmap *regmap = arizona->regmap; const struct reg_default *patch = NULL; int i, patch_size; @@ -247,15 +247,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21, - ARIZONA_EQ1_ENA_MASK), -SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, - ARIZONA_EQ2_ENA_MASK), -SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, - ARIZONA_EQ3_ENA_MASK), -SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21, - ARIZONA_EQ4_ENA_MASK), - +SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), +SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -267,6 +260,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, 24, 0, eq_tlv), +SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), +SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -278,6 +273,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, 24, 0, eq_tlv), +SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), +SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -289,6 +286,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, 24, 0, eq_tlv), +SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), +SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 48dc7d2fee36..6d684d934f4d 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -117,19 +117,23 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, static const char *wm8400_digital_sidetone[] = {"None", "Left ADC", "Right ADC", "Reserved"}; -static const struct soc_enum wm8400_left_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, - WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8400_left_digital_sidetone_enum, + WM8400_DIGITAL_SIDE_TONE, + WM8400_ADC_TO_DACL_SHIFT, + wm8400_digital_sidetone); -static const struct soc_enum wm8400_right_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, - WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8400_right_digital_sidetone_enum, + WM8400_DIGITAL_SIDE_TONE, + WM8400_ADC_TO_DACR_SHIFT, + wm8400_digital_sidetone); static const char *wm8400_adcmode[] = {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; -static const struct soc_enum wm8400_right_adcmode_enum = -SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode); +static SOC_ENUM_SINGLE_DECL(wm8400_right_adcmode_enum, + WM8400_ADC_CTRL, + WM8400_ADC_HPF_CUT_SHIFT, + wm8400_adcmode); static const struct snd_kcontrol_new wm8400_snd_controls[] = { /* INMIXL */ @@ -422,9 +426,10 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT, static const char *wm8400_ainlmux[] = {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; -static const struct soc_enum wm8400_ainlmux_enum = -SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT, - ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux); +static SOC_ENUM_SINGLE_DECL(wm8400_ainlmux_enum, + WM8400_INPUT_MIXER1, + WM8400_AINLMODE_SHIFT, + wm8400_ainlmux); static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls = SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); @@ -435,9 +440,10 @@ SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); static const char *wm8400_ainrmux[] = {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; -static const struct soc_enum wm8400_ainrmux_enum = -SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT, - ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux); +static SOC_ENUM_SINGLE_DECL(wm8400_ainrmux_enum, + WM8400_INPUT_MIXER1, + WM8400_AINRMODE_SHIFT, + wm8400_ainrmux); static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls = SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum); diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index d99f948c513c..6efcc40a7cb3 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -201,7 +201,7 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; /* deactivate */ - if (!codec->active) { + if (!snd_soc_codec_is_active(codec)) { udelay(50); snd_soc_write(codec, WM8711_ACTIVE, 0x0); } diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index be85da93a268..5cf4bebc5d89 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -251,7 +251,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, if (wm8753->dai_func == ucontrol->value.integer.value[0]) return 0; - if (codec->active) + if (snd_soc_codec_is_active(codec)) return -EBUSY; ioctl = snd_soc_read(codec, WM8753_IOCTL); @@ -1314,7 +1314,7 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute) /* the digital mute covers the HiFi and Voice DAC's on the WM8753. * make sure we check if they are not both active when we mute */ if (mute && wm8753->dai_func == 1) { - if (!codec->active) + if (!snd_soc_codec_is_active(codec)) snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8); } else { if (mute) diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 89a18d82f303..5bce21013485 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -196,8 +196,8 @@ static const char *ain_text[] = { "AIN5", "AIN6", "AIN7", "AIN8" }; -static const struct soc_enum ain_enum = - SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text); +static SOC_ENUM_DOUBLE_DECL(ain_enum, + WM8770_ADCMUX, 0, 4, ain_text); static const struct snd_kcontrol_new ain_mux = SOC_DAPM_ENUM("Capture Mux", ain_enum); diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 9bc8206a6807..72d12bbe1a56 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -92,7 +92,7 @@ WM8804_REGULATOR_EVENT(0) WM8804_REGULATOR_EVENT(1) static const char *txsrc_text[] = { "S/PDIF RX", "AIF" }; -static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text); +static SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text); static const struct snd_kcontrol_new wm8804_snd_controls[] = { SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put), diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index e98bc7038a08..43c2201cb901 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -304,53 +304,53 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; -static const struct soc_enum mic_bias_level = -SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt); +static SOC_ENUM_SINGLE_DECL(mic_bias_level, + WM8900_REG_INCTL, 8, mic_bias_level_txt); static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; -static const struct soc_enum dac_mute_rate = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt); +static SOC_ENUM_SINGLE_DECL(dac_mute_rate, + WM8900_REG_DACCTRL, 7, dac_mute_rate_txt); static const char *dac_deemphasis_txt[] = { "Disabled", "32kHz", "44.1kHz", "48kHz" }; -static const struct soc_enum dac_deemphasis = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt); +static SOC_ENUM_SINGLE_DECL(dac_deemphasis, + WM8900_REG_DACCTRL, 4, dac_deemphasis_txt); static const char *adc_hpf_cut_txt[] = { "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3" }; -static const struct soc_enum adc_hpf_cut = -SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt); +static SOC_ENUM_SINGLE_DECL(adc_hpf_cut, + WM8900_REG_ADCCTRL, 5, adc_hpf_cut_txt); static const char *lr_txt[] = { "Left", "Right" }; -static const struct soc_enum aifl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(aifl_src, + WM8900_REG_AUDIO1, 15, lr_txt); -static const struct soc_enum aifr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(aifr_src, + WM8900_REG_AUDIO1, 14, lr_txt); -static const struct soc_enum dacl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(dacl_src, + WM8900_REG_AUDIO2, 15, lr_txt); -static const struct soc_enum dacr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(dacr_src, + WM8900_REG_AUDIO2, 14, lr_txt); static const char *sidetone_txt[] = { "Disabled", "Left ADC", "Right ADC" }; -static const struct soc_enum dacl_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt); +static SOC_ENUM_SINGLE_DECL(dacl_sidetone, + WM8900_REG_SIDETONE, 2, sidetone_txt); -static const struct soc_enum dacr_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt); +static SOC_ENUM_SINGLE_DECL(dacr_sidetone, + WM8900_REG_SIDETONE, 0, sidetone_txt); static const struct snd_kcontrol_new wm8900_snd_controls[] = { SOC_ENUM("Mic Bias Level", mic_bias_level), @@ -496,8 +496,8 @@ SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0), static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" }; -static const struct soc_enum wm8900_lineout2_lp_mux = -SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm8900_lp_mux); +static SOC_ENUM_SINGLE_DECL(wm8900_lineout2_lp_mux, + WM8900_REG_LOUTMIXCTL1, 1, wm8900_lp_mux); static const struct snd_kcontrol_new wm8900_lineout2_lp = SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 53bbfac6a83a..b2664ec901b9 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1981,7 +1981,7 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec) dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", wm8904->num_retune_mobile_texts); - wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts; + wm8904->retune_mobile_enum.items = wm8904->num_retune_mobile_texts; wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts; ret = snd_soc_add_codec_controls(codec, &control, 1); @@ -2022,7 +2022,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec) for (i = 0; i < pdata->num_drc_cfgs; i++) wm8904->drc_texts[i] = pdata->drc_cfgs[i].name; - wm8904->drc_enum.max = pdata->num_drc_cfgs; + wm8904->drc_enum.items = pdata->num_drc_cfgs; wm8904->drc_enum.texts = wm8904->drc_texts; ret = snd_soc_add_codec_controls(codec, &control, 1); diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index b7488f190d2b..7ac2e511403c 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -153,7 +153,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name, data32 &= 0xffffff; - wm8994_bulk_write(codec->control_data, + wm8994_bulk_write(wm8994->wm8994, data32 & 0xffffff, block_len / 2, (void *)(data + 8)); @@ -944,7 +944,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) for (i = 0; i < pdata->num_mbc_cfgs; i++) wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name; - wm8994->mbc_enum.max = pdata->num_mbc_cfgs; + wm8994->mbc_enum.items = pdata->num_mbc_cfgs; wm8994->mbc_enum.texts = wm8994->mbc_texts; ret = snd_soc_add_codec_controls(wm8994->hubs.codec, @@ -973,7 +973,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) for (i = 0; i < pdata->num_vss_cfgs; i++) wm8994->vss_texts[i] = pdata->vss_cfgs[i].name; - wm8994->vss_enum.max = pdata->num_vss_cfgs; + wm8994->vss_enum.items = pdata->num_vss_cfgs; wm8994->vss_enum.texts = wm8994->vss_texts; ret = snd_soc_add_codec_controls(wm8994->hubs.codec, @@ -1003,7 +1003,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) for (i = 0; i < pdata->num_vss_hpf_cfgs; i++) wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name; - wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs; + wm8994->vss_hpf_enum.items = pdata->num_vss_hpf_cfgs; wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; ret = snd_soc_add_codec_controls(wm8994->hubs.codec, @@ -1034,7 +1034,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) for (i = 0; i < pdata->num_enh_eq_cfgs; i++) wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name; - wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs; + wm8994->enh_eq_enum.items = pdata->num_enh_eq_cfgs; wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; ret = snd_soc_add_codec_controls(wm8994->hubs.codec, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 97db3b45b411..9e6233633c44 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3089,6 +3089,7 @@ static irqreturn_t wm8962_irq(int irq, void *data) int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) { struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; int irq_mask, enable; wm8962->jack = jack; @@ -3109,14 +3110,18 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) snd_soc_jack_report(wm8962->jack, 0, SND_JACK_MICROPHONE | SND_JACK_BTN_0); + snd_soc_dapm_mutex_lock(dapm); + if (jack) { - snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); - snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS"); } else { - snd_soc_dapm_disable_pin(&codec->dapm, "SYSCLK"); - snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS"); + snd_soc_dapm_disable_pin_unlocked(dapm, "SYSCLK"); + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS"); } + snd_soc_dapm_mutex_unlock(dapm); + return 0; } EXPORT_SYMBOL_GPL(wm8962_mic_detect); diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index d8fc531c0e59..a9e2f465c331 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -117,21 +117,21 @@ static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"}; static const char *wm8978_alc3[] = {"ALC", "Limiter"}; static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"}; -static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, - wm8978_companding); -static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, - wm8978_companding); -static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); -static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); -static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); -static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); -static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); -static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); -static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); -static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); -static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); -static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); -static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); +static SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, + wm8978_companding); +static SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, + wm8978_companding); +static SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); +static SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); +static SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); +static SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); +static SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); +static SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); +static SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); +static SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); +static SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); +static SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); +static SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index aa41ba0dfff4..770e5a705851 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -205,49 +205,44 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; -static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, - alc_sel_text); +static SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, alc_sel_text); static const char *alc_mode_text[] = { "ALC", "Limiter" }; -static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, - alc_mode_text); +static SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, alc_mode_text); static const char *filter_mode_text[] = { "Audio", "Application" }; -static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, - filter_mode_text); +static SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, + filter_mode_text); static const char *eq_bw_text[] = { "Narrow", "Wide" }; static const char *eqmode_text[] = { "Capture", "Playback" }; -static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); +static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); static const char *eq1_cutoff_text[] = { "80Hz", "105Hz", "135Hz", "175Hz" }; -static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, - eq1_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, + eq1_cutoff_text); static const char *eq2_cutoff_text[] = { "230Hz", "300Hz", "385Hz", "500Hz" }; -static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, - eq2_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, eq2_cutoff_text); static const char *eq3_cutoff_text[] = { "650Hz", "850Hz", "1.1kHz", "1.4kHz" }; -static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, - eq3_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, eq3_cutoff_text); static const char *eq4_cutoff_text[] = { "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" }; -static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, - eq4_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, eq4_cutoff_text); static const char *eq5_cutoff_text[] = { "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" }; -static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, - eq5_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, + eq5_cutoff_text); static const char *depth_3d_text[] = { "Off", @@ -267,8 +262,8 @@ static const char *depth_3d_text[] = { "93.3%", "100%" }; -static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, - depth_3d_text); +static SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, + depth_3d_text); static const struct snd_kcontrol_new wm8983_snd_controls[] = { SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL, diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 271b517911a4..d786f2b39764 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -226,52 +226,48 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; -static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, - alc_sel_text); +static SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, alc_sel_text); static const char *alc_mode_text[] = { "ALC", "Limiter" }; -static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, - alc_mode_text); +static SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, alc_mode_text); static const char *filter_mode_text[] = { "Audio", "Application" }; -static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7, - filter_mode_text); +static SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7, + filter_mode_text); static const char *eq_bw_text[] = { "Narrow", "Wide" }; static const char *eqmode_text[] = { "Capture", "Playback" }; -static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); +static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); static const char *eq1_cutoff_text[] = { "80Hz", "105Hz", "135Hz", "175Hz" }; -static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5, - eq1_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5, + eq1_cutoff_text); static const char *eq2_cutoff_text[] = { "230Hz", "300Hz", "385Hz", "500Hz" }; -static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, - eq2_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, eq2_cutoff_text); static const char *eq3_cutoff_text[] = { "650Hz", "850Hz", "1.1kHz", "1.4kHz" }; -static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5, - eq3_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5, + eq3_cutoff_text); static const char *eq4_cutoff_text[] = { "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" }; -static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text); -static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, - eq4_cutoff_text); +static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text); +static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, eq4_cutoff_text); static const char *eq5_cutoff_text[] = { "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" }; -static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5, +static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5, eq5_cutoff_text); static const char *speaker_mode_text[] = { "Class A/B", "Class D" }; -static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); +static SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); static const char *depth_3d_text[] = { "Off", @@ -291,8 +287,7 @@ static const char *depth_3d_text[] = { "93.3%", "100%" }; -static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, - depth_3d_text); +static SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, depth_3d_text); static const struct snd_kcontrol_new wm8985_snd_controls[] = { SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL, diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 433d59a0f3ef..2ee23a39622c 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1562,7 +1562,6 @@ static int wm8993_remove(struct snd_soc_codec *codec) struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); return 0; } diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index b9be9cbc4603..79854cb7feb6 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -265,21 +265,21 @@ static const char *sidetone_hpf_text[] = { "2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz" }; -static const struct soc_enum sidetone_hpf = - SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text); +static SOC_ENUM_SINGLE_DECL(sidetone_hpf, + WM8994_SIDETONE, 7, sidetone_hpf_text); static const char *adc_hpf_text[] = { "HiFi", "Voice 1", "Voice 2", "Voice 3" }; -static const struct soc_enum aif1adc1_hpf = - SOC_ENUM_SINGLE(WM8994_AIF1_ADC1_FILTERS, 13, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf, + WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text); -static const struct soc_enum aif1adc2_hpf = - SOC_ENUM_SINGLE(WM8994_AIF1_ADC2_FILTERS, 13, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf, + WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text); -static const struct soc_enum aif2adc_hpf = - SOC_ENUM_SINGLE(WM8994_AIF2_ADC_FILTERS, 13, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(aif2adc_hpf, + WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text); static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0); static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); @@ -501,39 +501,39 @@ static const char *aif_chan_src_text[] = { "Left", "Right" }; -static const struct soc_enum aif1adcl_src = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1adcl_src, + WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text); -static const struct soc_enum aif1adcr_src = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1adcr_src, + WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text); -static const struct soc_enum aif2adcl_src = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2adcl_src, + WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text); -static const struct soc_enum aif2adcr_src = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2adcr_src, + WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text); -static const struct soc_enum aif1dacl_src = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1dacl_src, + WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text); -static const struct soc_enum aif1dacr_src = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1dacr_src, + WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text); -static const struct soc_enum aif2dacl_src = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacl_src, + WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text); -static const struct soc_enum aif2dacr_src = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacr_src, + WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text); static const char *osr_text[] = { "Low Power", "High Performance", }; -static const struct soc_enum dac_osr = - SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 0, 2, osr_text); +static SOC_ENUM_SINGLE_DECL(dac_osr, + WM8994_OVERSAMPLING, 0, osr_text); -static const struct soc_enum adc_osr = - SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text); +static SOC_ENUM_SINGLE_DECL(adc_osr, + WM8994_OVERSAMPLING, 1, osr_text); static const struct snd_kcontrol_new wm8994_snd_controls[] = { SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, @@ -690,17 +690,20 @@ static const char *wm8958_ng_text[] = { "30ms", "125ms", "250ms", "500ms", }; -static const struct soc_enum wm8958_aif1dac1_ng_hold = - SOC_ENUM_SINGLE(WM8958_AIF1_DAC1_NOISE_GATE, - WM8958_AIF1DAC1_NG_THR_SHIFT, 4, wm8958_ng_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold, + WM8958_AIF1_DAC1_NOISE_GATE, + WM8958_AIF1DAC1_NG_THR_SHIFT, + wm8958_ng_text); -static const struct soc_enum wm8958_aif1dac2_ng_hold = - SOC_ENUM_SINGLE(WM8958_AIF1_DAC2_NOISE_GATE, - WM8958_AIF1DAC2_NG_THR_SHIFT, 4, wm8958_ng_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold, + WM8958_AIF1_DAC2_NOISE_GATE, + WM8958_AIF1DAC2_NG_THR_SHIFT, + wm8958_ng_text); -static const struct soc_enum wm8958_aif2dac_ng_hold = - SOC_ENUM_SINGLE(WM8958_AIF2_DAC_NOISE_GATE, - WM8958_AIF2DAC_NG_THR_SHIFT, 4, wm8958_ng_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold, + WM8958_AIF2_DAC_NOISE_GATE, + WM8958_AIF2DAC_NG_THR_SHIFT, + wm8958_ng_text); static const struct snd_kcontrol_new wm8958_snd_controls[] = { SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), @@ -1341,8 +1344,7 @@ static const char *adc_mux_text[] = { "DMIC", }; -static const struct soc_enum adc_enum = - SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text); static const struct snd_kcontrol_new adcl_mux = SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); @@ -1478,14 +1480,14 @@ static const char *sidetone_text[] = { "ADC/DMIC1", "DMIC2", }; -static const struct soc_enum sidetone1_enum = - SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone1_enum, + WM8994_SIDETONE, 0, sidetone_text); static const struct snd_kcontrol_new sidetone1_mux = SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); -static const struct soc_enum sidetone2_enum = - SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone2_enum, + WM8994_SIDETONE, 1, sidetone_text); static const struct snd_kcontrol_new sidetone2_mux = SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); @@ -1498,22 +1500,24 @@ static const char *loopback_text[] = { "None", "ADCDAT", }; -static const struct soc_enum aif1_loopback_enum = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2, - loopback_text); +static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum, + WM8994_AIF1_CONTROL_2, + WM8994_AIF1_LOOPBACK_SHIFT, + loopback_text); static const struct snd_kcontrol_new aif1_loopback = SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum); -static const struct soc_enum aif2_loopback_enum = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2, - loopback_text); +static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum, + WM8994_AIF2_CONTROL_2, + WM8994_AIF2_LOOPBACK_SHIFT, + loopback_text); static const struct snd_kcontrol_new aif2_loopback = SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum); -static const struct soc_enum aif1dac_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text); +static SOC_ENUM_SINGLE_DECL(aif1dac_enum, + WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text); static const struct snd_kcontrol_new aif1dac_mux = SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum); @@ -1522,8 +1526,8 @@ static const char *aif2dac_text[] = { "AIF2DACDAT", "AIF3DACDAT", }; -static const struct soc_enum aif2dac_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text); +static SOC_ENUM_SINGLE_DECL(aif2dac_enum, + WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text); static const struct snd_kcontrol_new aif2dac_mux = SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum); @@ -1532,8 +1536,8 @@ static const char *aif2adc_text[] = { "AIF2ADCDAT", "AIF3DACDAT", }; -static const struct soc_enum aif2adc_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text); +static SOC_ENUM_SINGLE_DECL(aif2adc_enum, + WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text); static const struct snd_kcontrol_new aif2adc_mux = SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum); @@ -1542,14 +1546,14 @@ static const char *aif3adc_text[] = { "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM", }; -static const struct soc_enum wm8994_aif3adc_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text); +static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum, + WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text); static const struct snd_kcontrol_new wm8994_aif3adc_mux = SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum); -static const struct soc_enum wm8958_aif3adc_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 4, aif3adc_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum, + WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text); static const struct snd_kcontrol_new wm8958_aif3adc_mux = SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum); @@ -1558,8 +1562,8 @@ static const char *mono_pcm_out_text[] = { "None", "AIF2ADCL", "AIF2ADCR", }; -static const struct soc_enum mono_pcm_out_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 9, 3, mono_pcm_out_text); +static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum, + WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text); static const struct snd_kcontrol_new mono_pcm_out_mux = SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum); @@ -1569,14 +1573,14 @@ static const char *aif2dac_src_text[] = { }; /* Note that these two control shouldn't be simultaneously switched to AIF3 */ -static const struct soc_enum aif2dacl_src_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 7, 2, aif2dac_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum, + WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text); static const struct snd_kcontrol_new aif2dacl_src_mux = SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum); -static const struct soc_enum aif2dacr_src_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 8, 2, aif2dac_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum, + WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text); static const struct snd_kcontrol_new aif2dacr_src_mux = SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum); @@ -2549,43 +2553,52 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; switch (mode) { case WM8994_VMID_NORMAL: + snd_soc_dapm_mutex_lock(dapm); + if (wm8994->hubs.lineout1_se) { - snd_soc_dapm_disable_pin(&codec->dapm, - "LINEOUT1N Driver"); - snd_soc_dapm_disable_pin(&codec->dapm, - "LINEOUT1P Driver"); + snd_soc_dapm_disable_pin_unlocked(dapm, + "LINEOUT1N Driver"); + snd_soc_dapm_disable_pin_unlocked(dapm, + "LINEOUT1P Driver"); } if (wm8994->hubs.lineout2_se) { - snd_soc_dapm_disable_pin(&codec->dapm, - "LINEOUT2N Driver"); - snd_soc_dapm_disable_pin(&codec->dapm, - "LINEOUT2P Driver"); + snd_soc_dapm_disable_pin_unlocked(dapm, + "LINEOUT2N Driver"); + snd_soc_dapm_disable_pin_unlocked(dapm, + "LINEOUT2P Driver"); } /* Do the sync with the old mode to allow it to clean up */ - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_sync_unlocked(dapm); wm8994->vmid_mode = mode; + + snd_soc_dapm_mutex_unlock(dapm); break; case WM8994_VMID_FORCE: + snd_soc_dapm_mutex_lock(dapm); + if (wm8994->hubs.lineout1_se) { - snd_soc_dapm_force_enable_pin(&codec->dapm, - "LINEOUT1N Driver"); - snd_soc_dapm_force_enable_pin(&codec->dapm, - "LINEOUT1P Driver"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, + "LINEOUT1N Driver"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, + "LINEOUT1P Driver"); } if (wm8994->hubs.lineout2_se) { - snd_soc_dapm_force_enable_pin(&codec->dapm, - "LINEOUT2N Driver"); - snd_soc_dapm_force_enable_pin(&codec->dapm, - "LINEOUT2P Driver"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, + "LINEOUT2N Driver"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, + "LINEOUT2P Driver"); } wm8994->vmid_mode = mode; - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); break; default: @@ -3237,7 +3250,7 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", wm8994->num_retune_mobile_texts); - wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; + wm8994->retune_mobile_enum.items = wm8994->num_retune_mobile_texts; wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, @@ -3293,7 +3306,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) for (i = 0; i < pdata->num_drc_cfgs; i++) wm8994->drc_texts[i] = pdata->drc_cfgs[i].name; - wm8994->drc_enum.max = pdata->num_drc_cfgs; + wm8994->drc_enum.items = pdata->num_drc_cfgs; wm8994->drc_enum.texts = wm8994->drc_texts; ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 4300caff1783..ddb197dc1d53 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -423,24 +423,24 @@ static const char *in1l_text[] = { "Differential", "Single-ended IN1LN", "Single-ended IN1LP" }; -static const SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL, - 2, in1l_text); +static SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL, + 2, in1l_text); static const char *in1r_text[] = { "Differential", "Single-ended IN1RN", "Single-ended IN1RP" }; -static const SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL, - 0, in1r_text); +static SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL, + 0, in1r_text); static const char *dmic_src_text[] = { "DMICDAT1", "DMICDAT2", "DMICDAT3" }; -static const SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5, - 8, dmic_src_text); -static const SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5, - 6, dmic_src_text); +static SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5, + 8, dmic_src_text); +static SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5, + 6, dmic_src_text); static const struct snd_kcontrol_new wm8995_snd_controls[] = { SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME, @@ -561,10 +561,8 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec; - struct wm8995_priv *wm8995; codec = w->codec; - wm8995 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -783,14 +781,12 @@ static const char *sidetone_text[] = { "ADC/DMIC1", "DMIC2", }; -static const struct soc_enum sidetone1_enum = - SOC_ENUM_SINGLE(WM8995_SIDETONE, 0, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone1_enum, WM8995_SIDETONE, 0, sidetone_text); static const struct snd_kcontrol_new sidetone1_mux = SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); -static const struct soc_enum sidetone2_enum = - SOC_ENUM_SINGLE(WM8995_SIDETONE, 1, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone2_enum, WM8995_SIDETONE, 1, sidetone_text); static const struct snd_kcontrol_new sidetone2_mux = SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); @@ -886,8 +882,7 @@ static const char *adc_mux_text[] = { "DMIC", }; -static const struct soc_enum adc_enum = - SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text); static const struct snd_kcontrol_new adcl_mux = SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); @@ -899,14 +894,14 @@ static const char *spk_src_text[] = { "DAC1L", "DAC1R", "DAC2L", "DAC2R" }; -static const SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1, - 0, spk_src_text); -static const SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1, - 0, spk_src_text); -static const SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2, - 0, spk_src_text); -static const SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2, - 0, spk_src_text); +static SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1, + 0, spk_src_text); +static SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1, + 0, spk_src_text); +static SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2, + 0, spk_src_text); +static SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2, + 0, spk_src_text); static const struct snd_kcontrol_new spk1l_mux = SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum); diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 1a7655b0aa22..0330165079a4 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2251,6 +2251,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, wm8996_polarity_fn polarity_cb) { struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; wm8996->jack = jack; wm8996->detecting = true; @@ -2267,8 +2268,12 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, WM8996_MICB2_DISCH, 0); /* LDO2 powers the microphones, SYSCLK clocks detection */ - snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); - snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); + snd_soc_dapm_mutex_lock(dapm); + + snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); + + snd_soc_dapm_mutex_unlock(dapm); /* We start off just enabling microphone detection - even a * plain headphone will trigger detection. @@ -2595,7 +2600,7 @@ static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec) dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", wm8996->num_retune_mobile_texts); - wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts; + wm8996->retune_mobile_enum.items = wm8996->num_retune_mobile_texts; wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts; ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 555115ee2159..e10f44d7fdb7 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -86,7 +86,7 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = w->codec; struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - struct regmap *regmap = codec->control_data; + struct regmap *regmap = arizona->regmap; const struct reg_default *patch = NULL; int i, patch_size; @@ -123,10 +123,12 @@ static const unsigned int wm8997_osr_val[] = { static const struct soc_enum wm8997_hpout_osr[] = { SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, - ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, + ARIZONA_OUT1_OSR_SHIFT, 0x7, + ARRAY_SIZE(wm8997_osr_text), wm8997_osr_text, wm8997_osr_val), SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, - ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, + ARIZONA_OUT3_OSR_SHIFT, 0x7, + ARRAY_SIZE(wm8997_osr_text), wm8997_osr_text, wm8997_osr_val), }; @@ -170,15 +172,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21, - ARIZONA_EQ1_ENA_MASK), -SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, - ARIZONA_EQ2_ENA_MASK), -SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, - ARIZONA_EQ3_ENA_MASK), -SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21, - ARIZONA_EQ4_ENA_MASK), - +SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), +SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -190,6 +185,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, 24, 0, eq_tlv), +SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), +SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -201,6 +198,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, 24, 0, eq_tlv), +SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), +SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -212,6 +211,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, 24, 0, eq_tlv), +SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), +SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 444626fcab40..bb5f7b4e3ebb 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -684,24 +684,38 @@ static int wm_adsp_load(struct wm_adsp *dsp) } if (reg) { - buf = wm_adsp_buf_alloc(region->data, - le32_to_cpu(region->len), - &buf_list); - if (!buf) { - adsp_err(dsp, "Out of memory\n"); - ret = -ENOMEM; - goto out_fw; - } + size_t to_write = PAGE_SIZE; + size_t remain = le32_to_cpu(region->len); + const u8 *data = region->data; + + while (remain > 0) { + if (remain < PAGE_SIZE) + to_write = remain; + + buf = wm_adsp_buf_alloc(data, + to_write, + &buf_list); + if (!buf) { + adsp_err(dsp, "Out of memory\n"); + ret = -ENOMEM; + goto out_fw; + } - ret = regmap_raw_write_async(regmap, reg, buf->buf, - le32_to_cpu(region->len)); - if (ret != 0) { - adsp_err(dsp, - "%s.%d: Failed to write %d bytes at %d in %s: %d\n", - file, regions, - le32_to_cpu(region->len), offset, - region_name, ret); - goto out_fw; + ret = regmap_raw_write_async(regmap, reg, + buf->buf, + to_write); + if (ret != 0) { + adsp_err(dsp, + "%s.%d: Failed to write %zd bytes at %d in %s: %d\n", + file, regions, + to_write, offset, + region_name, ret); + goto out_fw; + } + + data += to_write; + reg += to_write / 2; + remain -= to_write; } } @@ -1679,6 +1693,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, list_del(&alg_region->list); kfree(alg_region); } + + adsp_dbg(dsp, "Shutdown complete\n"); break; default: diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 70ff3772079f..621e9a997d4c 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -17,6 +17,7 @@ #include <linux/platform_data/edma.h> #include <linux/i2c.h> #include <linux/of_platform.h> +#include <linux/clk.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> @@ -30,9 +31,34 @@ #include "davinci-i2s.h" struct snd_soc_card_drvdata_davinci { + struct clk *mclk; unsigned sysclk; }; +static int evm_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *soc_card = rtd->codec->card; + struct snd_soc_card_drvdata_davinci *drvdata = + snd_soc_card_get_drvdata(soc_card); + + if (drvdata->mclk) + return clk_prepare_enable(drvdata->mclk); + + return 0; +} + +static void evm_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *soc_card = rtd->codec->card; + struct snd_soc_card_drvdata_davinci *drvdata = + snd_soc_card_get_drvdata(soc_card); + + if (drvdata->mclk) + clk_disable_unprepare(drvdata->mclk); +} + static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -59,6 +85,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream, } static struct snd_soc_ops evm_ops = { + .startup = evm_startup, + .shutdown = evm_shutdown, .hw_params = evm_hw_params, }; @@ -348,6 +376,7 @@ static int davinci_evm_probe(struct platform_device *pdev) of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data; struct snd_soc_card_drvdata_davinci *drvdata = NULL; + struct clk *mclk; int ret = 0; evm_soc_card.dai_link = dai; @@ -367,13 +396,38 @@ static int davinci_evm_probe(struct platform_device *pdev) if (ret) return ret; + mclk = devm_clk_get(&pdev->dev, "mclk"); + if (PTR_ERR(mclk) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (IS_ERR(mclk)) { + dev_dbg(&pdev->dev, "mclk not found.\n"); + mclk = NULL; + } + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) return -ENOMEM; + drvdata->mclk = mclk; + ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); - if (ret < 0) - return -EINVAL; + + if (ret < 0) { + if (!drvdata->mclk) { + dev_err(&pdev->dev, + "No clock or clock rate defined.\n"); + return -EINVAL; + } + drvdata->sysclk = clk_get_rate(drvdata->mclk); + } else if (drvdata->mclk) { + unsigned int requestd_rate = drvdata->sysclk; + clk_set_rate(drvdata->mclk, drvdata->sysclk); + drvdata->sysclk = clk_get_rate(drvdata->mclk); + if (drvdata->sysclk != requestd_rate) + dev_warn(&pdev->dev, + "Could not get requested rate %u using %u.\n", + requestd_rate, drvdata->sysclk); + } snd_soc_card_set_drvdata(&evm_soc_card, drvdata); ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); @@ -399,6 +453,7 @@ static struct platform_driver davinci_evm_driver = { .driver = { .name = "davinci_evm", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, .of_match_table = of_match_ptr(davinci_evm_dt_ids), }, }; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index b7858bfa0295..b0ae0677f023 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -37,6 +37,16 @@ #include "davinci-pcm.h" #include "davinci-mcasp.h" +struct davinci_mcasp_context { + u32 txfmtctl; + u32 rxfmtctl; + u32 txfmt; + u32 rxfmt; + u32 aclkxctl; + u32 aclkrctl; + u32 pdir; +}; + struct davinci_mcasp { struct davinci_pcm_dma_params dma_params[2]; struct snd_dmaengine_dai_dma_data dma_data[2]; @@ -53,6 +63,9 @@ struct davinci_mcasp { u16 bclk_lrclk_ratio; int streams; + int sysclk_freq; + bool bclk_master; + /* McASP FIFO related */ u8 txnumevt; u8 rxnumevt; @@ -60,15 +73,7 @@ struct davinci_mcasp { bool dat_port; #ifdef CONFIG_PM_SLEEP - struct { - u32 txfmtctl; - u32 rxfmtctl; - u32 txfmt; - u32 rxfmt; - u32 aclkxctl; - u32 aclkrctl; - u32 pdir; - } context; + struct davinci_mcasp_context context; #endif }; @@ -263,7 +268,9 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); + int ret = 0; + pm_runtime_get_sync(mcasp->dev); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_AC97: @@ -292,6 +299,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); + mcasp->bclk_master = 1; break; case SND_SOC_DAIFMT_CBM_CFS: /* codec is clock master and frame slave */ @@ -303,6 +311,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); + mcasp->bclk_master = 0; break; case SND_SOC_DAIFMT_CBM_CFM: /* codec is clock and frame master */ @@ -314,10 +323,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); + mcasp->bclk_master = 0; break; default: - return -EINVAL; + ret = -EINVAL; + goto out; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -354,10 +365,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, break; default: - return -EINVAL; + ret = -EINVAL; + break; } - - return 0; +out: + pm_runtime_put_sync(mcasp->dev); + return ret; } static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) @@ -405,6 +418,8 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX); } + mcasp->sysclk_freq = freq; + return 0; } @@ -448,7 +463,7 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, return 0; } -static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, +static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, int channels) { int i; @@ -524,12 +539,18 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, return 0; } -static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream) +static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) { int i, active_slots; u32 mask = 0; u32 busel = 0; + if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) { + dev_err(mcasp->dev, "tdm slot %d not supported\n", + mcasp->tdm_slots); + return -EINVAL; + } + active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots; for (i = 0; i < active_slots; i++) mask |= (1 << i); @@ -539,35 +560,21 @@ static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream) if (!mcasp->dat_port) busel = TXSEL; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* bit stream is MSB first with no delay */ - /* DSP_B mode */ - mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); - - if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32)) - mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, - FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); - else - printk(KERN_ERR "playback tdm slot %d not supported\n", - mcasp->tdm_slots); - } else { - /* bit stream is MSB first with no delay */ - /* DSP_B mode */ - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); - mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); - - if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32)) - mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, - FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); - else - printk(KERN_ERR "capture tdm slot %d not supported\n", - mcasp->tdm_slots); - } + mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); + mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); + mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, + FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); + + mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); + mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); + mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, + FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); + + return 0; } /* S/PDIF */ -static void davinci_hw_dit_param(struct davinci_mcasp *mcasp) +static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp) { /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 and LSB first */ @@ -589,6 +596,8 @@ static void davinci_hw_dit_param(struct davinci_mcasp *mcasp) /* Enable the DIT */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); + + return 0; } static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, @@ -604,24 +613,31 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, u8 fifo_level; u8 slots = mcasp->tdm_slots; u8 active_serializers; - int channels; - struct snd_interval *pcm_channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - channels = pcm_channels->min; + int channels = params_channels(params); + int ret; - active_serializers = (channels + slots - 1) / slots; + /* If mcasp is BCLK master we need to set BCLK divider */ + if (mcasp->bclk_master) { + unsigned int bclk_freq = snd_soc_params_to_bclk(params); + if (mcasp->sysclk_freq % bclk_freq != 0) { + dev_err(mcasp->dev, "Can't produce requred BCLK\n"); + return -EINVAL; + } + davinci_mcasp_set_clkdiv( + cpu_dai, 1, mcasp->sysclk_freq / bclk_freq); + } - if (davinci_hw_common_param(mcasp, substream->stream, channels) == -EINVAL) - return -EINVAL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fifo_level = mcasp->txnumevt * active_serializers; - else - fifo_level = mcasp->rxnumevt * active_serializers; + ret = mcasp_common_hw_param(mcasp, substream->stream, channels); + if (ret) + return ret; if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) - davinci_hw_dit_param(mcasp); + ret = mcasp_dit_hw_param(mcasp); else - davinci_hw_param(mcasp, substream->stream); + ret = mcasp_i2s_hw_param(mcasp, substream->stream); + + if (ret) + return ret; switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: @@ -655,6 +671,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* Calculate FIFO level */ + active_serializers = (channels + slots - 1) / slots; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + fifo_level = mcasp->txnumevt * active_serializers; + else + fifo_level = mcasp->rxnumevt * active_serializers; + if (mcasp->version == MCASP_VERSION_2 && !fifo_level) dma_params->acnt = 4; else @@ -678,19 +701,9 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = pm_runtime_get_sync(mcasp->dev); - if (IS_ERR_VALUE(ret)) - dev_err(mcasp->dev, "pm_runtime_get_sync() failed\n"); davinci_mcasp_start(mcasp, substream->stream); break; - case SNDRV_PCM_TRIGGER_SUSPEND: - davinci_mcasp_stop(mcasp, substream->stream); - ret = pm_runtime_put_sync(mcasp->dev); - if (IS_ERR_VALUE(ret)) - dev_err(mcasp->dev, "pm_runtime_put_sync() failed\n"); - break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: davinci_mcasp_stop(mcasp, substream->stream); @@ -726,6 +739,43 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { .set_sysclk = davinci_mcasp_set_sysclk, }; +#ifdef CONFIG_PM_SLEEP +static int davinci_mcasp_suspend(struct snd_soc_dai *dai) +{ + struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + struct davinci_mcasp_context *context = &mcasp->context; + + context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); + context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); + context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); + context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); + context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); + context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); + context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); + + return 0; +} + +static int davinci_mcasp_resume(struct snd_soc_dai *dai) +{ + struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + struct davinci_mcasp_context *context = &mcasp->context; + + mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl); + mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl); + mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt); + mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt); + mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl); + mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl); + mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir); + + return 0; +} +#else +#define davinci_mcasp_suspend NULL +#define davinci_mcasp_resume NULL +#endif + #define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ @@ -742,6 +792,8 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { static struct snd_soc_dai_driver davinci_mcasp_dai[] = { { .name = "davinci-mcasp.0", + .suspend = davinci_mcasp_suspend, + .resume = davinci_mcasp_resume, .playback = { .channels_min = 2, .channels_max = 32 * 16, @@ -775,28 +827,28 @@ static const struct snd_soc_component_driver davinci_mcasp_component = { }; /* Some HW specific values and defaults. The rest is filled in from DT. */ -static struct snd_platform_data dm646x_mcasp_pdata = { +static struct davinci_mcasp_pdata dm646x_mcasp_pdata = { .tx_dma_offset = 0x400, .rx_dma_offset = 0x400, .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_1, }; -static struct snd_platform_data da830_mcasp_pdata = { +static struct davinci_mcasp_pdata da830_mcasp_pdata = { .tx_dma_offset = 0x2000, .rx_dma_offset = 0x2000, .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_2, }; -static struct snd_platform_data am33xx_mcasp_pdata = { +static struct davinci_mcasp_pdata am33xx_mcasp_pdata = { .tx_dma_offset = 0, .rx_dma_offset = 0, .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_3, }; -static struct snd_platform_data dra7_mcasp_pdata = { +static struct davinci_mcasp_pdata dra7_mcasp_pdata = { .tx_dma_offset = 0x200, .rx_dma_offset = 0x284, .asp_chan_q = EVENTQ_0, @@ -864,11 +916,11 @@ err1: return ret; } -static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( +static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct snd_platform_data *pdata = NULL; + struct davinci_mcasp_pdata *pdata = NULL; const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev); struct of_phandle_args dma_spec; @@ -881,7 +933,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( pdata = pdev->dev.platform_data; return pdata; } else if (match) { - pdata = (struct snd_platform_data *) match->data; + pdata = (struct davinci_mcasp_pdata*) match->data; } else { /* control shouldn't reach here. something is wrong */ ret = -EINVAL; @@ -973,9 +1025,9 @@ nodata: static int davinci_mcasp_probe(struct platform_device *pdev) { - struct davinci_pcm_dma_params *dma_data; + struct davinci_pcm_dma_params *dma_params; struct resource *mem, *ioarea, *res, *dat; - struct snd_platform_data *pdata; + struct davinci_mcasp_pdata *pdata; struct davinci_mcasp *mcasp; int ret; @@ -1042,41 +1094,41 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (dat) mcasp->dat_port = true; - dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; - dma_data->asp_chan_q = pdata->asp_chan_q; - dma_data->ram_chan_q = pdata->ram_chan_q; - dma_data->sram_pool = pdata->sram_pool; - dma_data->sram_size = pdata->sram_size_playback; + dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; + dma_params->asp_chan_q = pdata->asp_chan_q; + dma_params->ram_chan_q = pdata->ram_chan_q; + dma_params->sram_pool = pdata->sram_pool; + dma_params->sram_size = pdata->sram_size_playback; if (dat) - dma_data->dma_addr = dat->start; + dma_params->dma_addr = dat->start; else - dma_data->dma_addr = mem->start + pdata->tx_dma_offset; + dma_params->dma_addr = mem->start + pdata->tx_dma_offset; /* Unconditional dmaengine stuff */ - mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr; + mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_params->dma_addr; res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (res) - dma_data->channel = res->start; + dma_params->channel = res->start; else - dma_data->channel = pdata->tx_dma_channel; + dma_params->channel = pdata->tx_dma_channel; - dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE]; - dma_data->asp_chan_q = pdata->asp_chan_q; - dma_data->ram_chan_q = pdata->ram_chan_q; - dma_data->sram_pool = pdata->sram_pool; - dma_data->sram_size = pdata->sram_size_capture; + dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE]; + dma_params->asp_chan_q = pdata->asp_chan_q; + dma_params->ram_chan_q = pdata->ram_chan_q; + dma_params->sram_pool = pdata->sram_pool; + dma_params->sram_size = pdata->sram_size_capture; if (dat) - dma_data->dma_addr = dat->start; + dma_params->dma_addr = dat->start; else - dma_data->dma_addr = mem->start + pdata->rx_dma_offset; + dma_params->dma_addr = mem->start + pdata->rx_dma_offset; /* Unconditional dmaengine stuff */ - mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr; + mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_params->dma_addr; if (mcasp->version < MCASP_VERSION_3) { mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; - /* dma_data->dma_addr is pointing to the data port address */ + /* dma_params->dma_addr is pointing to the data port address */ mcasp->dat_port = true; } else { mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; @@ -1084,9 +1136,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (res) - dma_data->channel = res->start; + dma_params->channel = res->start; else - dma_data->channel = pdata->rx_dma_channel; + dma_params->channel = pdata->rx_dma_channel; /* Unconditional dmaengine stuff */ mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx"; @@ -1134,49 +1186,12 @@ static int davinci_mcasp_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int davinci_mcasp_suspend(struct device *dev) -{ - struct davinci_mcasp *mcasp = dev_get_drvdata(dev); - - mcasp->context.txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); - mcasp->context.rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); - mcasp->context.txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); - mcasp->context.rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); - mcasp->context.aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); - mcasp->context.aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); - mcasp->context.pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); - - return 0; -} - -static int davinci_mcasp_resume(struct device *dev) -{ - struct davinci_mcasp *mcasp = dev_get_drvdata(dev); - - mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, mcasp->context.txfmtctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, mcasp->context.rxfmtctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, mcasp->context.txfmt); - mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, mcasp->context.rxfmt); - mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, mcasp->context.aclkxctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, mcasp->context.aclkrctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, mcasp->context.pdir); - - return 0; -} -#endif - -SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops, - davinci_mcasp_suspend, - davinci_mcasp_resume); - static struct platform_driver davinci_mcasp_driver = { .probe = davinci_mcasp_probe, .remove = davinci_mcasp_remove, .driver = { .name = "davinci-mcasp", .owner = THIS_MODULE, - .pm = &davinci_mcasp_pm_ops, .of_match_table = mcasp_dt_ids, }, }; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 07f8f141727d..597962ec28fa 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -1,5 +1,6 @@ config SND_SOC_FSL_SAI tristate + select REGMAP_MMIO select SND_SOC_GENERIC_DMAENGINE_PCM config SND_SOC_FSL_SSI @@ -7,9 +8,11 @@ config SND_SOC_FSL_SSI config SND_SOC_FSL_SPDIF tristate + select REGMAP_MMIO config SND_SOC_FSL_ESAI tristate + select REGMAP_MMIO config SND_SOC_FSL_UTILS tristate @@ -168,12 +171,14 @@ config SND_SOC_EUKREA_TLV320 depends on MACH_EUKREA_MBIMX27_BASEBOARD \ || MACH_EUKREA_MBIMXSD25_BASEBOARD \ || MACH_EUKREA_MBIMXSD35_BASEBOARD \ - || MACH_EUKREA_MBIMXSD51_BASEBOARD + || MACH_EUKREA_MBIMXSD51_BASEBOARD \ + || (OF && ARM) depends on I2C - select SND_SOC_TLV320AIC23 - select SND_SOC_IMX_PCM_FIQ + select SND_SOC_TLV320AIC23_I2C select SND_SOC_IMX_AUDMUX select SND_SOC_IMX_SSI + select SND_SOC_FSL_SSI + select SND_SOC_IMX_PCM_DMA help Enable I2S based access to the TLV320AIC23B codec attached to the SSI interface @@ -204,7 +209,6 @@ config SND_SOC_IMX_SPDIF tristate "SoC Audio support for i.MX boards with S/PDIF" select SND_SOC_IMX_PCM_DMA select SND_SOC_FSL_SPDIF - select REGMAP_MMIO help SoC Audio support for i.MX boards with S/PDIF Say Y if you want to add support for SoC audio on an i.MX board with diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 5983740be123..eb093d5b85c4 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -15,8 +15,11 @@ * */ +#include <linux/errno.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/of.h> +#include <linux/of_platform.h> #include <linux/device.h> #include <linux/i2c.h> #include <sound/core.h> @@ -26,6 +29,7 @@ #include "../codecs/tlv320aic23.h" #include "imx-ssi.h" +#include "fsl_ssi.h" #include "imx-audmux.h" #define CODEC_CLOCK 12000000 @@ -41,7 +45,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) { + /* fsl_ssi lacks the set_fmt ops. */ + if (ret && ret != -ENOTSUPP) { dev_err(cpu_dai->dev, "Failed to set the cpu dai format.\n"); return ret; @@ -63,11 +68,13 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, "Failed to set the codec sysclk.\n"); return ret; } + snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN); - if (ret) { + /* fsl_ssi lacks the set_sysclk ops */ + if (ret && ret != -EINVAL) { dev_err(cpu_dai->dev, "Can't set the IMX_SSP_SYS_CLK CPU system clock.\n"); return ret; @@ -84,14 +91,10 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = { .name = "tlv320aic23", .stream_name = "TLV320AIC23", .codec_dai_name = "tlv320aic23-hifi", - .platform_name = "imx-ssi.0", - .codec_name = "tlv320aic23-codec.0-001a", - .cpu_dai_name = "imx-ssi.0", .ops = &eukrea_tlv320_snd_ops, }; static struct snd_soc_card eukrea_tlv320 = { - .name = "cpuimx-audio", .owner = THIS_MODULE, .dai_link = &eukrea_tlv320_dai, .num_links = 1, @@ -101,8 +104,65 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) { int ret; int int_port = 0, ext_port; + struct device_node *np = pdev->dev.of_node; + struct device_node *ssi_np, *codec_np; - if (machine_is_eukrea_cpuimx27()) { + eukrea_tlv320.dev = &pdev->dev; + if (np) { + ret = snd_soc_of_parse_card_name(&eukrea_tlv320, + "eukrea,model"); + if (ret) { + dev_err(&pdev->dev, + "eukrea,model node missing or invalid.\n"); + goto err; + } + + ssi_np = of_parse_phandle(pdev->dev.of_node, + "ssi-controller", 0); + if (!ssi_np) { + dev_err(&pdev->dev, + "ssi-controller missing or invalid.\n"); + ret = -ENODEV; + goto err; + } + + codec_np = of_parse_phandle(ssi_np, "codec-handle", 0); + if (codec_np) + eukrea_tlv320_dai.codec_of_node = codec_np; + else + dev_err(&pdev->dev, "codec-handle node missing or invalid.\n"); + + ret = of_property_read_u32(np, "fsl,mux-int-port", &int_port); + if (ret) { + dev_err(&pdev->dev, + "fsl,mux-int-port node missing or invalid.\n"); + return ret; + } + ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port); + if (ret) { + dev_err(&pdev->dev, + "fsl,mux-ext-port node missing or invalid.\n"); + return ret; + } + + /* + * The port numbering in the hardware manual starts at 1, while + * the audmux API expects it starts at 0. + */ + int_port--; + ext_port--; + + eukrea_tlv320_dai.cpu_of_node = ssi_np; + eukrea_tlv320_dai.platform_of_node = ssi_np; + } else { + eukrea_tlv320_dai.cpu_dai_name = "imx-ssi.0"; + eukrea_tlv320_dai.platform_name = "imx-ssi.0"; + eukrea_tlv320_dai.codec_name = "tlv320aic23-codec.0-001a"; + eukrea_tlv320.name = "cpuimx-audio"; + } + + if (machine_is_eukrea_cpuimx27() || + of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux")) { imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, IMX_AUDMUX_V1_PCR_SYN | IMX_AUDMUX_V1_PCR_TFSDIR | @@ -119,8 +179,12 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) ); } else if (machine_is_eukrea_cpuimx25sd() || machine_is_eukrea_cpuimx35sd() || - machine_is_eukrea_cpuimx51sd()) { - ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3; + machine_is_eukrea_cpuimx51sd() || + of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux")) { + if (!np) + ext_port = machine_is_eukrea_cpuimx25sd() ? + 4 : 3; + imx_audmux_v2_configure_port(int_port, IMX_AUDMUX_V2_PTCR_SYN | IMX_AUDMUX_V2_PTCR_TFSDIR | @@ -134,14 +198,27 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) IMX_AUDMUX_V2_PDCR_RXDSEL(int_port) ); } else { - /* return happy. We might run on a totally different machine */ - return 0; + if (np) { + /* The eukrea,asoc-tlv320 driver was explicitely + * requested (through the device tree). + */ + dev_err(&pdev->dev, + "Missing or invalid audmux DT node.\n"); + return -ENODEV; + } else { + /* Return happy. + * We might run on a totally different machine. + */ + return 0; + } } - eukrea_tlv320.dev = &pdev->dev; ret = snd_soc_register_card(&eukrea_tlv320); +err: if (ret) dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + if (np) + of_node_put(ssi_np); return ret; } @@ -153,10 +230,17 @@ static int eukrea_tlv320_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id imx_tlv320_dt_ids[] = { + { .compatible = "eukrea,asoc-tlv320"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_tlv320_dt_ids); + static struct platform_driver eukrea_tlv320_driver = { .driver = { .name = "eukrea_tlv320", .owner = THIS_MODULE, + .of_match_table = imx_tlv320_dt_ids, }, .probe = eukrea_tlv320_probe, .remove = eukrea_tlv320_remove, diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index d0c72ed261e7..0ba37005ab04 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -326,7 +326,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA, ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask)); regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB, - ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask)); + ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask)); regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); @@ -334,7 +334,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA, ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask)); regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB, - ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask)); + ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); esai_priv->slot_width = slot_width; @@ -431,17 +431,26 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) static int fsl_esai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + int ret; struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); /* * Some platforms might use the same bit to gate all three or two of * clocks, so keep all clocks open/close at the same time for safety */ - clk_prepare_enable(esai_priv->coreclk); - if (!IS_ERR(esai_priv->extalclk)) - clk_prepare_enable(esai_priv->extalclk); - if (!IS_ERR(esai_priv->fsysclk)) - clk_prepare_enable(esai_priv->fsysclk); + ret = clk_prepare_enable(esai_priv->coreclk); + if (ret) + return ret; + if (!IS_ERR(esai_priv->extalclk)) { + ret = clk_prepare_enable(esai_priv->extalclk); + if (ret) + goto err_extalck; + } + if (!IS_ERR(esai_priv->fsysclk)) { + ret = clk_prepare_enable(esai_priv->fsysclk); + if (ret) + goto err_fsysclk; + } if (!dai->active) { /* Reset Port C */ @@ -463,6 +472,14 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, } return 0; + +err_fsysclk: + if (!IS_ERR(esai_priv->extalclk)) + clk_disable_unprepare(esai_priv->extalclk); +err_extalck: + clk_disable_unprepare(esai_priv->coreclk); + + return ret; } static int fsl_esai_hw_params(struct snd_pcm_substream *substream, @@ -661,7 +678,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg) } } -static const struct regmap_config fsl_esai_regmap_config = { +static struct regmap_config fsl_esai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -687,6 +704,9 @@ static int fsl_esai_probe(struct platform_device *pdev) esai_priv->pdev = pdev; strcpy(esai_priv->name, np->name); + if (of_property_read_bool(np, "big-endian")) + fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; + /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h index 9c9f957fcae1..75e14033e8d8 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h @@ -322,7 +322,7 @@ #define ESAI_xSMB_xS_SHIFT 0 #define ESAI_xSMB_xS_WIDTH 16 #define ESAI_xSMB_xS_MASK (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT) -#define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK) +#define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMB_xS_MASK) /* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */ #define ESAI_PRRC_PDC_SHIFT 0 diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index cdd3fa830704..c4a423111673 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -15,6 +15,7 @@ #include <linux/dmaengine.h> #include <linux/module.h> #include <linux/of_address.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/dmaengine_pcm.h> @@ -22,34 +23,6 @@ #include "fsl_sai.h" -static inline u32 sai_readl(struct fsl_sai *sai, - const void __iomem *addr) -{ - u32 val; - - val = __raw_readl(addr); - - if (likely(sai->big_endian_regs)) - val = be32_to_cpu(val); - else - val = le32_to_cpu(val); - rmb(); - - return val; -} - -static inline void sai_writel(struct fsl_sai *sai, - u32 val, void __iomem *addr) -{ - wmb(); - if (likely(sai->big_endian_regs)) - val = cpu_to_be32(val); - else - val = cpu_to_le32(val); - - __raw_writel(val, addr); -} - static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int fsl_dir) { @@ -61,7 +34,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, else reg_cr2 = FSL_SAI_RCR2; - val_cr2 = sai_readl(sai, sai->base + reg_cr2); + regmap_read(sai->regmap, reg_cr2, &val_cr2); + val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK; switch (clk_id) { @@ -81,7 +55,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, return -EINVAL; } - sai_writel(sai, val_cr2, sai->base + reg_cr2); + regmap_write(sai->regmap, reg_cr2, val_cr2); return 0; } @@ -89,32 +63,22 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { - struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); int ret; if (dir == SND_SOC_CLOCK_IN) return 0; - ret = clk_prepare_enable(sai->clk); - if (ret) - return ret; - ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, FSL_FMT_TRANSMITTER); if (ret) { dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret); - goto err_clk; + return ret; } ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, FSL_FMT_RECEIVER); - if (ret) { + if (ret) dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret); - goto err_clk; - } - -err_clk: - clk_disable_unprepare(sai->clk); return ret; } @@ -133,43 +97,84 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, reg_cr4 = FSL_SAI_RCR4; } - val_cr2 = sai_readl(sai, sai->base + reg_cr2); - val_cr4 = sai_readl(sai, sai->base + reg_cr4); + regmap_read(sai->regmap, reg_cr2, &val_cr2); + regmap_read(sai->regmap, reg_cr4, &val_cr4); if (sai->big_endian_data) val_cr4 &= ~FSL_SAI_CR4_MF; else val_cr4 |= FSL_SAI_CR4_MF; + /* DAI mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: + /* + * Frame low, 1clk before data, one word length for frame sync, + * frame sync starts one serial clock cycle earlier, + * that is, together with the last bit of the previous + * data word. + */ + val_cr2 &= ~FSL_SAI_CR2_BCP; + val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP; + break; + case SND_SOC_DAIFMT_LEFT_J: + /* + * Frame high, one word length for frame sync, + * frame sync asserts with the first bit of the frame. + */ + val_cr2 &= ~FSL_SAI_CR2_BCP; + val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); + break; + case SND_SOC_DAIFMT_DSP_A: + /* + * Frame high, 1clk before data, one bit for frame sync, + * frame sync starts one serial clock cycle earlier, + * that is, together with the last bit of the previous + * data word. + */ + val_cr2 &= ~FSL_SAI_CR2_BCP; + val_cr4 &= ~FSL_SAI_CR4_FSP; val_cr4 |= FSL_SAI_CR4_FSE; + sai->is_dsp_mode = true; + break; + case SND_SOC_DAIFMT_DSP_B: + /* + * Frame high, one bit for frame sync, + * frame sync asserts with the first bit of the frame. + */ + val_cr2 &= ~FSL_SAI_CR2_BCP; + val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); + sai->is_dsp_mode = true; break; + case SND_SOC_DAIFMT_RIGHT_J: + /* To be done */ default: return -EINVAL; } + /* DAI clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_IF: - val_cr4 |= FSL_SAI_CR4_FSP; - val_cr2 &= ~FSL_SAI_CR2_BCP; + /* Invert both clocks */ + val_cr2 ^= FSL_SAI_CR2_BCP; + val_cr4 ^= FSL_SAI_CR4_FSP; break; case SND_SOC_DAIFMT_IB_NF: - val_cr4 &= ~FSL_SAI_CR4_FSP; - val_cr2 &= ~FSL_SAI_CR2_BCP; + /* Invert bit clock */ + val_cr2 ^= FSL_SAI_CR2_BCP; break; case SND_SOC_DAIFMT_NB_IF: - val_cr4 |= FSL_SAI_CR4_FSP; - val_cr2 |= FSL_SAI_CR2_BCP; + /* Invert frame clock */ + val_cr4 ^= FSL_SAI_CR4_FSP; break; case SND_SOC_DAIFMT_NB_NF: - val_cr4 &= ~FSL_SAI_CR4_FSP; - val_cr2 |= FSL_SAI_CR2_BCP; + /* Nothing to do for both normal cases */ break; default: return -EINVAL; } + /* DAI clock master masks */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; @@ -179,39 +184,37 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; break; + case SND_SOC_DAIFMT_CBS_CFM: + val_cr2 |= FSL_SAI_CR2_BCD_MSTR; + val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; + val_cr4 |= FSL_SAI_CR4_FSD_MSTR; + break; default: return -EINVAL; } - sai_writel(sai, val_cr2, sai->base + reg_cr2); - sai_writel(sai, val_cr4, sai->base + reg_cr4); + regmap_write(sai->regmap, reg_cr2, val_cr2); + regmap_write(sai->regmap, reg_cr4, val_cr4); return 0; } static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { - struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); int ret; - ret = clk_prepare_enable(sai->clk); - if (ret) - return ret; - ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER); if (ret) { dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret); - goto err_clk; + return ret; } ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER); - if (ret) { + if (ret) dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret); - goto err_clk; - } - -err_clk: - clk_disable_unprepare(sai->clk); return ret; } @@ -235,16 +238,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, reg_mr = FSL_SAI_RMR; } - val_cr4 = sai_readl(sai, sai->base + reg_cr4); + regmap_read(sai->regmap, reg_cr4, &val_cr4); + regmap_read(sai->regmap, reg_cr4, &val_cr5); + val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK; val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK; - val_cr5 = sai_readl(sai, sai->base + reg_cr5); val_cr5 &= ~FSL_SAI_CR5_WNW_MASK; val_cr5 &= ~FSL_SAI_CR5_W0W_MASK; val_cr5 &= ~FSL_SAI_CR5_FBT_MASK; - val_cr4 |= FSL_SAI_CR4_SYWD(word_width); + if (!sai->is_dsp_mode) + val_cr4 |= FSL_SAI_CR4_SYWD(word_width); + val_cr5 |= FSL_SAI_CR5_WNW(word_width); val_cr5 |= FSL_SAI_CR5_W0W(word_width); @@ -257,9 +263,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, val_cr4 |= FSL_SAI_CR4_FRSZ(channels); val_mr = ~0UL - ((1 << channels) - 1); - sai_writel(sai, val_cr4, sai->base + reg_cr4); - sai_writel(sai, val_cr5, sai->base + reg_cr5); - sai_writel(sai, val_mr, sai->base + reg_mr); + regmap_write(sai->regmap, reg_cr4, val_cr4); + regmap_write(sai->regmap, reg_cr5, val_cr5); + regmap_write(sai->regmap, reg_mr, val_mr); return 0; } @@ -268,44 +274,42 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); - u32 tcsr, rcsr, val_cr2, val_cr3, reg_cr3; - - val_cr2 = sai_readl(sai, sai->base + FSL_SAI_TCR2); - val_cr2 &= ~FSL_SAI_CR2_SYNC; - sai_writel(sai, val_cr2, sai->base + FSL_SAI_TCR2); + u32 tcsr, rcsr; - val_cr2 = sai_readl(sai, sai->base + FSL_SAI_RCR2); - val_cr2 |= FSL_SAI_CR2_SYNC; - sai_writel(sai, val_cr2, sai->base + FSL_SAI_RCR2); + /* + * The transmitter bit clock and frame sync are to be + * used by both the transmitter and receiver. + */ + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, + ~FSL_SAI_CR2_SYNC); + regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, + FSL_SAI_CR2_SYNC); - tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR); - rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR); + regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr); + regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { tcsr |= FSL_SAI_CSR_FRDE; rcsr &= ~FSL_SAI_CSR_FRDE; - reg_cr3 = FSL_SAI_TCR3; } else { rcsr |= FSL_SAI_CSR_FRDE; tcsr &= ~FSL_SAI_CSR_FRDE; - reg_cr3 = FSL_SAI_RCR3; } - val_cr3 = sai_readl(sai, sai->base + reg_cr3); - + /* + * It is recommended that the transmitter is the last enabled + * and the first disabled. + */ switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: tcsr |= FSL_SAI_CSR_TERE; rcsr |= FSL_SAI_CSR_TERE; - val_cr3 |= FSL_SAI_CR3_TRCE; - sai_writel(sai, val_cr3, sai->base + reg_cr3); - sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR); - sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR); + regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); + regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -314,11 +318,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, rcsr &= ~FSL_SAI_CSR_TERE; } - val_cr3 &= ~FSL_SAI_CR3_TRCE; - - sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR); - sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR); - sai_writel(sai, val_cr3, sai->base + reg_cr3); + regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); + regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); break; default: return -EINVAL; @@ -331,16 +332,32 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + reg = FSL_SAI_TCR3; + else + reg = FSL_SAI_RCR3; + + regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, + FSL_SAI_CR3_TRCE); - return clk_prepare_enable(sai->clk); + return 0; } static void fsl_sai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + reg = FSL_SAI_TCR3; + else + reg = FSL_SAI_RCR3; - clk_disable_unprepare(sai->clk); + regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, + ~FSL_SAI_CR3_TRCE); } static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { @@ -355,18 +372,13 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); - int ret; - ret = clk_prepare_enable(sai->clk); - if (ret) - return ret; - - sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR); - sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR); - sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1); - sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1); - - clk_disable_unprepare(sai->clk); + regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0); + regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, + FSL_SAI_MAXBURST_TX * 2); + regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, + FSL_SAI_MAXBURST_RX - 1); snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, &sai->dma_params_rx); @@ -397,26 +409,109 @@ static const struct snd_soc_component_driver fsl_component = { .name = "fsl-sai", }; +static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case FSL_SAI_TCSR: + case FSL_SAI_TCR1: + case FSL_SAI_TCR2: + case FSL_SAI_TCR3: + case FSL_SAI_TCR4: + case FSL_SAI_TCR5: + case FSL_SAI_TFR: + case FSL_SAI_TMR: + case FSL_SAI_RCSR: + case FSL_SAI_RCR1: + case FSL_SAI_RCR2: + case FSL_SAI_RCR3: + case FSL_SAI_RCR4: + case FSL_SAI_RCR5: + case FSL_SAI_RDR: + case FSL_SAI_RFR: + case FSL_SAI_RMR: + return true; + default: + return false; + } +} + +static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case FSL_SAI_TFR: + case FSL_SAI_RFR: + case FSL_SAI_TDR: + case FSL_SAI_RDR: + return true; + default: + return false; + } + +} + +static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case FSL_SAI_TCSR: + case FSL_SAI_TCR1: + case FSL_SAI_TCR2: + case FSL_SAI_TCR3: + case FSL_SAI_TCR4: + case FSL_SAI_TCR5: + case FSL_SAI_TDR: + case FSL_SAI_TMR: + case FSL_SAI_RCSR: + case FSL_SAI_RCR1: + case FSL_SAI_RCR2: + case FSL_SAI_RCR3: + case FSL_SAI_RCR4: + case FSL_SAI_RCR5: + case FSL_SAI_RMR: + return true; + default: + return false; + } +} + +static struct regmap_config fsl_sai_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .max_register = FSL_SAI_RMR, + .readable_reg = fsl_sai_readable_reg, + .volatile_reg = fsl_sai_volatile_reg, + .writeable_reg = fsl_sai_writeable_reg, +}; + static int fsl_sai_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct fsl_sai *sai; struct resource *res; + void __iomem *base; int ret; sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); if (!sai) return -ENOMEM; + sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); + if (sai->big_endian_regs) + fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; + + sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - sai->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(sai->base)) - return PTR_ERR(sai->base); - - sai->clk = devm_clk_get(&pdev->dev, "sai"); - if (IS_ERR(sai->clk)) { - dev_err(&pdev->dev, "Cannot get SAI's clock\n"); - return PTR_ERR(sai->clk); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, + "sai", base, &fsl_sai_regmap_config); + if (IS_ERR(sai->regmap)) { + dev_err(&pdev->dev, "regmap init failed\n"); + return PTR_ERR(sai->regmap); } sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; @@ -424,9 +519,6 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; - sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); - sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); - platform_set_drvdata(pdev, sai); ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 41bb62e69361..e432260be598 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -15,31 +15,36 @@ SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) +/* SAI Register Map Register */ +#define FSL_SAI_TCSR 0x00 /* SAI Transmit Control */ +#define FSL_SAI_TCR1 0x04 /* SAI Transmit Configuration 1 */ +#define FSL_SAI_TCR2 0x08 /* SAI Transmit Configuration 2 */ +#define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */ +#define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */ +#define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */ +#define FSL_SAI_TDR 0x20 /* SAI Transmit Data */ +#define FSL_SAI_TFR 0x40 /* SAI Transmit FIFO */ +#define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */ +#define FSL_SAI_RCSR 0x80 /* SAI Receive Control */ +#define FSL_SAI_RCR1 0x84 /* SAI Receive Configuration 1 */ +#define FSL_SAI_RCR2 0x88 /* SAI Receive Configuration 2 */ +#define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */ +#define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */ +#define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */ +#define FSL_SAI_RDR 0xa0 /* SAI Receive Data */ +#define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */ +#define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ + /* SAI Transmit/Recieve Control Register */ -#define FSL_SAI_TCSR 0x00 -#define FSL_SAI_RCSR 0x80 #define FSL_SAI_CSR_TERE BIT(31) #define FSL_SAI_CSR_FWF BIT(17) #define FSL_SAI_CSR_FRIE BIT(8) #define FSL_SAI_CSR_FRDE BIT(0) -/* SAI Transmit Data/FIFO/MASK Register */ -#define FSL_SAI_TDR 0x20 -#define FSL_SAI_TFR 0x40 -#define FSL_SAI_TMR 0x60 - -/* SAI Recieve Data/FIFO/MASK Register */ -#define FSL_SAI_RDR 0xa0 -#define FSL_SAI_RFR 0xc0 -#define FSL_SAI_RMR 0xe0 - /* SAI Transmit and Recieve Configuration 1 Register */ -#define FSL_SAI_TCR1 0x04 -#define FSL_SAI_RCR1 0x84 +#define FSL_SAI_CR1_RFW_MASK 0x1f /* SAI Transmit and Recieve Configuration 2 Register */ -#define FSL_SAI_TCR2 0x08 -#define FSL_SAI_RCR2 0x88 #define FSL_SAI_CR2_SYNC BIT(30) #define FSL_SAI_CR2_MSEL_MASK (0xff << 26) #define FSL_SAI_CR2_MSEL_BUS 0 @@ -50,15 +55,11 @@ #define FSL_SAI_CR2_BCD_MSTR BIT(24) /* SAI Transmit and Recieve Configuration 3 Register */ -#define FSL_SAI_TCR3 0x0c -#define FSL_SAI_RCR3 0x8c #define FSL_SAI_CR3_TRCE BIT(16) #define FSL_SAI_CR3_WDFL(x) (x) #define FSL_SAI_CR3_WDFL_MASK 0x1f /* SAI Transmit and Recieve Configuration 4 Register */ -#define FSL_SAI_TCR4 0x10 -#define FSL_SAI_RCR4 0x90 #define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16) #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16) #define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8) @@ -69,8 +70,6 @@ #define FSL_SAI_CR4_FSD_MSTR BIT(0) /* SAI Transmit and Recieve Configuration 5 Register */ -#define FSL_SAI_TCR5 0x14 -#define FSL_SAI_RCR5 0x94 #define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24) #define FSL_SAI_CR5_WNW_MASK (0x1f << 24) #define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16) @@ -100,12 +99,11 @@ #define FSL_SAI_MAXBURST_RX 6 struct fsl_sai { - struct clk *clk; - - void __iomem *base; + struct regmap *regmap; bool big_endian_regs; bool big_endian_data; + bool is_dsp_mode; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 73ceb2f9b90d..6452ca83d889 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -911,8 +911,8 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) { struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); - dai->playback_dma_data = &spdif_private->dma_params_tx; - dai->capture_dma_data = &spdif_private->dma_params_rx; + snd_soc_dai_init_dma_data(dai, &spdif_private->dma_params_tx, + &spdif_private->dma_params_rx); snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index 79cee782dbbf..a2fd7321b5a9 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c @@ -160,7 +160,6 @@ static struct platform_driver imx_mc13783_audio_driver = { .driver = { .name = "imx_mc13783", .owner = THIS_MODULE, - .pm = &snd_soc_pm_ops, }, .probe = imx_mc13783_probe, .remove = imx_mc13783_remove diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 6553202dd48c..7abf6a079574 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -270,18 +270,17 @@ static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) ret = imx_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); if (ret) - goto out; + return ret; } if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { ret = imx_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); if (ret) - goto out; + return ret; } -out: - return ret; + return 0; } static int ssi_irq = 0; diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index f2beae78969f..1cb22dd034eb 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -33,8 +33,7 @@ struct imx_sgtl5000_data { static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct imx_sgtl5000_data *data = container_of(rtd->card, - struct imx_sgtl5000_data, card); + struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(rtd->card); struct device *dev = rtd->card->dev; int ret; @@ -159,13 +158,15 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) data->card.dapm_widgets = imx_sgtl5000_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets); + platform_set_drvdata(pdev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto fail; } - platform_set_drvdata(pdev, data); of_node_put(ssi_np); of_node_put(codec_np); @@ -184,7 +185,8 @@ fail: static int imx_sgtl5000_remove(struct platform_device *pdev) { - struct imx_sgtl5000_data *data = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(card); clk_put(data->codec_clk); diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 3fd76bc391de..3a3d17ce6ba4 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -71,7 +71,7 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card, { struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; struct imx_priv *priv = &card_priv; - struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev); + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; unsigned int pll_out; int ret; @@ -137,7 +137,7 @@ static int imx_wm8962_late_probe(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; struct imx_priv *priv = &card_priv; - struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev); + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; int ret; @@ -264,13 +264,15 @@ static int imx_wm8962_probe(struct platform_device *pdev) data->card.late_probe = imx_wm8962_late_probe; data->card.set_bias_level = imx_wm8962_set_bias_level; + platform_set_drvdata(pdev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto clk_fail; } - platform_set_drvdata(pdev, data); of_node_put(ssi_np); of_node_put(codec_np); @@ -289,7 +291,8 @@ fail: static int imx_wm8962_remove(struct platform_device *pdev) { - struct imx_wm8962_data *data = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); if (!IS_ERR(data->codec_clk)) clk_disable_unprepare(data->codec_clk); diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c index fce63252bdbb..804749a6c61e 100644 --- a/sound/soc/fsl/wm1133-ev1.c +++ b/sound/soc/fsl/wm1133-ev1.c @@ -214,12 +214,6 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - snd_soc_dapm_new_controls(dapm, wm1133_ev1_widgets, - ARRAY_SIZE(wm1133_ev1_widgets)); - - snd_soc_dapm_add_routes(dapm, wm1133_ev1_map, - ARRAY_SIZE(wm1133_ev1_map)); - /* Headphone jack detection */ snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack); snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), @@ -257,6 +251,11 @@ static struct snd_soc_card wm1133_ev1 = { .owner = THIS_MODULE, .dai_link = &wm1133_ev1_dai, .num_links = 1, + + .dapm_widgets = wm1133_ev1_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm1133_ev1_widgets), + .dapm_routes = wm1133_ev1_map, + .num_dapm_routes = ARRAY_SIZE(wm1133_ev1_map), }; static struct platform_device *wm1133_ev1_snd_device; diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c index d3d4c32434f7..0cef32e9d402 100644 --- a/sound/soc/intel/mfld_machine.c +++ b/sound/soc/intel/mfld_machine.c @@ -101,20 +101,27 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = &codec->dapm; if (ucontrol->value.integer.value[0] == hs_switch) return 0; + snd_soc_dapm_mutex_lock(dapm); + if (ucontrol->value.integer.value[0]) { pr_debug("hs_set HS path\n"); - snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); - snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones"); + snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); } else { pr_debug("hs_set EP path\n"); - snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); - snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); + snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT"); } - snd_soc_dapm_sync(&codec->dapm); + + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); + hs_switch = ucontrol->value.integer.value[0]; return 0; @@ -122,18 +129,20 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol, static void lo_enable_out_pins(struct snd_soc_codec *codec) { - snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL"); - snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR"); - snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL"); - snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR"); - snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT"); - snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT"); + struct snd_soc_dapm_context *dapm = &codec->dapm; + + snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL"); + snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR"); + snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL"); + snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR"); + snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT"); + snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT"); if (hs_switch) { - snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); - snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones"); + snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); } else { - snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); - snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); + snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT"); } } @@ -148,44 +157,52 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = &codec->dapm; if (ucontrol->value.integer.value[0] == lo_dac) return 0; + snd_soc_dapm_mutex_lock(dapm); + /* we dont want to work with last state of lineout so just enable all * pins and then disable pins not required */ lo_enable_out_pins(codec); + switch (ucontrol->value.integer.value[0]) { case 0: pr_debug("set vibra path\n"); - snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT"); - snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT"); + snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT"); + snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT"); snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0); break; case 1: pr_debug("set hs path\n"); - snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); - snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); + snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22); break; case 2: pr_debug("set spkr path\n"); - snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL"); - snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR"); + snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL"); + snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR"); snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44); break; case 3: pr_debug("set null path\n"); - snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL"); - snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR"); + snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL"); + snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR"); snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66); break; } - snd_soc_dapm_sync(&codec->dapm); + + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); + lo_dac = ucontrol->value.integer.value[0]; return 0; } diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 22ad9c5654b5..e00659351a4e 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -58,7 +58,7 @@ config SND_OMAP_SOC_OSK5912 tristate "SoC Audio support for omap osk5912" depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C select SND_OMAP_SOC_MCBSP - select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC23_I2C help Say Y if you want to add support for SoC audio on osk5912. @@ -66,7 +66,7 @@ config SND_OMAP_SOC_AM3517EVM tristate "SoC Audio support for OMAP3517 / AM3517 EVM" depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C select SND_OMAP_SOC_MCBSP - select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC23_I2C help Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517 EVM. diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 629446482a91..8a5363674075 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -103,60 +103,62 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol, if (!codec->hw_write) return -EUNATCH; - if (ucontrol->value.enumerated.item[0] >= control->max) + if (ucontrol->value.enumerated.item[0] >= control->items) return -EINVAL; - mutex_lock(&codec->mutex); + snd_soc_dapm_mutex_lock(dapm); /* Translate selection to bitmap */ pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]]; /* Setup pins after corresponding bits if changed */ pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE)); + if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) { changed = 1; if (pin) - snd_soc_dapm_enable_pin(dapm, "Mouthpiece"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece"); else - snd_soc_dapm_disable_pin(dapm, "Mouthpiece"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece"); } pin = !!(pins & (1 << AMS_DELTA_EARPIECE)); if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) { changed = 1; if (pin) - snd_soc_dapm_enable_pin(dapm, "Earpiece"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece"); else - snd_soc_dapm_disable_pin(dapm, "Earpiece"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Earpiece"); } pin = !!(pins & (1 << AMS_DELTA_MICROPHONE)); if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) { changed = 1; if (pin) - snd_soc_dapm_enable_pin(dapm, "Microphone"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone"); else - snd_soc_dapm_disable_pin(dapm, "Microphone"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Microphone"); } pin = !!(pins & (1 << AMS_DELTA_SPEAKER)); if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) { changed = 1; if (pin) - snd_soc_dapm_enable_pin(dapm, "Speaker"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); else - snd_soc_dapm_disable_pin(dapm, "Speaker"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); } pin = !!(pins & (1 << AMS_DELTA_AGC)); if (pin != ams_delta_audio_agc) { ams_delta_audio_agc = pin; changed = 1; if (pin) - snd_soc_dapm_enable_pin(dapm, "AGCIN"); + snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN"); else - snd_soc_dapm_disable_pin(dapm, "AGCIN"); + snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN"); } + if (changed) - snd_soc_dapm_sync(dapm); + snd_soc_dapm_sync_unlocked(dapm); - mutex_unlock(&codec->mutex); + snd_soc_dapm_mutex_unlock(dapm); return changed; } @@ -315,12 +317,17 @@ static void cx81801_close(struct tty_struct *tty) v253_ops.close(tty); /* Revert back to default audio input/output constellation */ - snd_soc_dapm_disable_pin(dapm, "Mouthpiece"); - snd_soc_dapm_enable_pin(dapm, "Earpiece"); - snd_soc_dapm_enable_pin(dapm, "Microphone"); - snd_soc_dapm_disable_pin(dapm, "Speaker"); - snd_soc_dapm_disable_pin(dapm, "AGCIN"); - snd_soc_dapm_sync(dapm); + snd_soc_dapm_mutex_lock(dapm); + + snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); + snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN"); + + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(codec); } /* Line discipline .hangup() */ diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 3fde9e402710..fd4d9c809e50 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -68,26 +68,30 @@ static void n810_ext_control(struct snd_soc_dapm_context *dapm) break; } + snd_soc_dapm_mutex_lock(dapm); + if (n810_spk_func) - snd_soc_dapm_enable_pin(dapm, "Ext Spk"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); else - snd_soc_dapm_disable_pin(dapm, "Ext Spk"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); if (hp) - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); else - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); if (line1l) - snd_soc_dapm_enable_pin(dapm, "LINE1L"); + snd_soc_dapm_enable_pin_unlocked(dapm, "LINE1L"); else - snd_soc_dapm_disable_pin(dapm, "LINE1L"); + snd_soc_dapm_disable_pin_unlocked(dapm, "LINE1L"); if (n810_dmic_func) - snd_soc_dapm_enable_pin(dapm, "DMic"); + snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); else - snd_soc_dapm_disable_pin(dapm, "DMic"); + snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); + + snd_soc_dapm_sync_unlocked(dapm); - snd_soc_dapm_sync(dapm); + snd_soc_dapm_mutex_unlock(dapm); } static int n810_startup(struct snd_pcm_substream *substream) @@ -305,7 +309,9 @@ static int __init n810_soc_init(void) int err; struct device *dev; - if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax())) + if (!of_have_populated_dt() || + (!of_machine_is_compatible("nokia,n810") && + !of_machine_is_compatible("nokia,n810-wimax"))) return -ENODEV; n810_snd_device = platform_device_alloc("soc-audio", -1); diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 611179c3bca4..7fb3d4b10370 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -74,26 +74,30 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm) break; } + snd_soc_dapm_mutex_lock(dapm); + if (rx51_spk_func) - snd_soc_dapm_enable_pin(dapm, "Ext Spk"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); else - snd_soc_dapm_disable_pin(dapm, "Ext Spk"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); if (rx51_dmic_func) - snd_soc_dapm_enable_pin(dapm, "DMic"); + snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); else - snd_soc_dapm_disable_pin(dapm, "DMic"); + snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); if (hp) - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); else - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); if (hs) - snd_soc_dapm_enable_pin(dapm, "HS Mic"); + snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic"); else - snd_soc_dapm_disable_pin(dapm, "HS Mic"); + snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic"); gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout); - snd_soc_dapm_sync(dapm); + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); } static int rx51_startup(struct snd_pcm_substream *substream) diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 1853d41034bf..9d9c8ad57f0e 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -47,51 +47,55 @@ static int corgi_spk_func; static void corgi_ext_control(struct snd_soc_dapm_context *dapm) { + snd_soc_dapm_mutex_lock(dapm); + /* set up jack connection */ switch (corgi_jack_func) { case CORGI_HP: /* set = unmute headphone */ gpio_set_value(CORGI_GPIO_MUTE_L, 1); gpio_set_value(CORGI_GPIO_MUTE_R, 1); - snd_soc_dapm_disable_pin(dapm, "Mic Jack"); - snd_soc_dapm_disable_pin(dapm, "Line Jack"); - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(dapm, "Headset Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); break; case CORGI_MIC: /* reset = mute headphone */ gpio_set_value(CORGI_GPIO_MUTE_L, 0); gpio_set_value(CORGI_GPIO_MUTE_R, 0); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - snd_soc_dapm_disable_pin(dapm, "Line Jack"); - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(dapm, "Headset Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); break; case CORGI_LINE: gpio_set_value(CORGI_GPIO_MUTE_L, 0); gpio_set_value(CORGI_GPIO_MUTE_R, 0); - snd_soc_dapm_disable_pin(dapm, "Mic Jack"); - snd_soc_dapm_enable_pin(dapm, "Line Jack"); - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(dapm, "Headset Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); break; case CORGI_HEADSET: gpio_set_value(CORGI_GPIO_MUTE_L, 0); gpio_set_value(CORGI_GPIO_MUTE_R, 1); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - snd_soc_dapm_disable_pin(dapm, "Line Jack"); - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Headset Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); break; } if (corgi_spk_func == CORGI_SPK_ON) - snd_soc_dapm_enable_pin(dapm, "Ext Spk"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); else - snd_soc_dapm_disable_pin(dapm, "Ext Spk"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); /* signal a DAPM event */ - snd_soc_dapm_sync(dapm); + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); } static int corgi_startup(struct snd_pcm_substream *substream) diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index aace19e0fe2c..31242be08823 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -45,27 +45,31 @@ static void magician_ext_control(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = &codec->dapm; + snd_soc_dapm_mutex_lock(dapm); + if (magician_spk_switch) - snd_soc_dapm_enable_pin(dapm, "Speaker"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); else - snd_soc_dapm_disable_pin(dapm, "Speaker"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); if (magician_hp_switch) - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); else - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); switch (magician_in_sel) { case MAGICIAN_MIC: - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_enable_pin(dapm, "Call Mic"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Mic"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Call Mic"); break; case MAGICIAN_MIC_EXT: - snd_soc_dapm_disable_pin(dapm, "Call Mic"); - snd_soc_dapm_enable_pin(dapm, "Headset Mic"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Call Mic"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Mic"); break; } - snd_soc_dapm_sync(dapm); + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); } static int magician_startup(struct snd_pcm_substream *substream) diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index fc052d8247ff..04dbb5a38fa4 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -46,61 +46,66 @@ static int spitz_mic_gpio; static void spitz_ext_control(struct snd_soc_dapm_context *dapm) { + snd_soc_dapm_mutex_lock(dapm); + if (spitz_spk_func == SPITZ_SPK_ON) - snd_soc_dapm_enable_pin(dapm, "Ext Spk"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); else - snd_soc_dapm_disable_pin(dapm, "Ext Spk"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); /* set up jack connection */ switch (spitz_jack_func) { case SPITZ_HP: /* enable and unmute hp jack, disable mic bias */ - snd_soc_dapm_disable_pin(dapm, "Headset Jack"); - snd_soc_dapm_disable_pin(dapm, "Mic Jack"); - snd_soc_dapm_disable_pin(dapm, "Line Jack"); - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); gpio_set_value(SPITZ_GPIO_MUTE_L, 1); gpio_set_value(SPITZ_GPIO_MUTE_R, 1); break; case SPITZ_MIC: /* enable mic jack and bias, mute hp */ - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(dapm, "Headset Jack"); - snd_soc_dapm_disable_pin(dapm, "Line Jack"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); gpio_set_value(SPITZ_GPIO_MUTE_L, 0); gpio_set_value(SPITZ_GPIO_MUTE_R, 0); break; case SPITZ_LINE: /* enable line jack, disable mic bias and mute hp */ - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(dapm, "Headset Jack"); - snd_soc_dapm_disable_pin(dapm, "Mic Jack"); - snd_soc_dapm_enable_pin(dapm, "Line Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack"); gpio_set_value(SPITZ_GPIO_MUTE_L, 0); gpio_set_value(SPITZ_GPIO_MUTE_R, 0); break; case SPITZ_HEADSET: /* enable and unmute headset jack enable mic bias, mute L hp */ - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - snd_soc_dapm_disable_pin(dapm, "Line Jack"); - snd_soc_dapm_enable_pin(dapm, "Headset Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); gpio_set_value(SPITZ_GPIO_MUTE_L, 0); gpio_set_value(SPITZ_GPIO_MUTE_R, 1); break; case SPITZ_HP_OFF: /* jack removed, everything off */ - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(dapm, "Headset Jack"); - snd_soc_dapm_disable_pin(dapm, "Mic Jack"); - snd_soc_dapm_disable_pin(dapm, "Line Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); gpio_set_value(SPITZ_GPIO_MUTE_L, 0); gpio_set_value(SPITZ_GPIO_MUTE_R, 0); break; } - snd_soc_dapm_sync(dapm); + + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); } static int spitz_startup(struct snd_pcm_substream *substream) diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 1d9c2ed223bc..2a4b438ce97c 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -48,31 +48,35 @@ static void tosa_ext_control(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = &codec->dapm; + snd_soc_dapm_mutex_lock(dapm); + /* set up jack connection */ switch (tosa_jack_func) { case TOSA_HP: - snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(dapm, "Headset Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); break; case TOSA_MIC_INT: - snd_soc_dapm_enable_pin(dapm, "Mic (Internal)"); - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_disable_pin(dapm, "Headset Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Mic (Internal)"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); break; case TOSA_HEADSET: - snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); - snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Headset Jack"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); break; } if (tosa_spk_func == TOSA_SPK_ON) - snd_soc_dapm_enable_pin(dapm, "Speaker"); + snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); else - snd_soc_dapm_disable_pin(dapm, "Speaker"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); + + snd_soc_dapm_sync_unlocked(dapm); - snd_soc_dapm_sync(dapm); + snd_soc_dapm_mutex_unlock(dapm); } static int tosa_startup(struct snd_pcm_substream *substream) diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 454f41cfc828..f2e289180e46 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -59,7 +59,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 select SND_SOC_WM8750 select SND_S3C2412_SOC_I2S help - Sat Y if you want to add support for SoC audio on the Jive. + Say Y if you want to add support for SoC audio on the Jive. config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" @@ -117,7 +117,7 @@ config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23 tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" depends on SND_SOC_SAMSUNG && ARCH_S3C24XX select SND_S3C24XX_I2S - select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC23_I2C select SND_SOC_SAMSUNG_SIMTEC config SND_SOC_SAMSUNG_SIMTEC_HERMES @@ -145,11 +145,11 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 config SND_SOC_SAMSUNG_SMDK_WM9713 tristate "SoC AC97 Audio support for SMDK with WM9713" - depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 || MACH_SMDKV310 || MACH_SMDKC210) + depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) select SND_SOC_WM9713 select SND_SAMSUNG_AC97 help - Sat Y if you want to add support for SoC audio on the SMDK. + Say Y if you want to add support for SoC audio on the SMDK. config SND_SOC_SMARTQ tristate "SoC I2S Audio support for SmartQ board" diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 375dc6dfba4e..bfed3e4c45ff 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -96,8 +96,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) { dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", codec->name); - if (!codec->reg_cache) - return 0; + kfree(codec->reg_cache); codec->reg_cache = NULL; return 0; @@ -117,8 +116,9 @@ int snd_soc_cache_read(struct snd_soc_codec *codec, return -EINVAL; mutex_lock(&codec->cache_rw_mutex); - *value = snd_soc_get_cache_val(codec->reg_cache, reg, - codec->driver->reg_word_size); + if (!ZERO_OR_NULL_PTR(codec->reg_cache)) + *value = snd_soc_get_cache_val(codec->reg_cache, reg, + codec->driver->reg_word_size); mutex_unlock(&codec->cache_rw_mutex); return 0; @@ -136,8 +136,9 @@ int snd_soc_cache_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { mutex_lock(&codec->cache_rw_mutex); - snd_soc_set_cache_val(codec->reg_cache, reg, value, - codec->driver->reg_word_size); + if (!ZERO_OR_NULL_PTR(codec->reg_cache)) + snd_soc_set_cache_val(codec->reg_cache, reg, value, + codec->driver->reg_word_size); mutex_unlock(&codec->cache_rw_mutex); return 0; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 5e9690c85d8f..91083e6a6b38 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -30,8 +30,6 @@ static int soc_compr_open(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -52,17 +50,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) } } - if (cstream->direction == SND_COMPRESS_PLAYBACK) { - cpu_dai->playback_active++; - codec_dai->playback_active++; - } else { - cpu_dai->capture_active++; - codec_dai->capture_active++; - } - - cpu_dai->active++; - codec_dai->active++; - rtd->codec->active++; + snd_soc_runtime_activate(rtd, cstream->direction); mutex_unlock(&rtd->pcm_mutex); @@ -81,8 +69,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; struct snd_soc_platform *platform = fe->platform; - struct snd_soc_dai *cpu_dai = fe->cpu_dai; - struct snd_soc_dai *codec_dai = fe->codec_dai; struct snd_soc_dpcm *dpcm; struct snd_soc_dapm_widget_list *list; int stream; @@ -140,17 +126,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; - if (cstream->direction == SND_COMPRESS_PLAYBACK) { - cpu_dai->playback_active++; - codec_dai->playback_active++; - } else { - cpu_dai->capture_active++; - codec_dai->capture_active++; - } - - cpu_dai->active++; - codec_dai->active++; - fe->codec->active++; + snd_soc_runtime_activate(fe, stream); mutex_unlock(&fe->card->mutex); @@ -202,23 +178,18 @@ static int soc_compr_free(struct snd_compr_stream *cstream) struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = rtd->codec; + int stream; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (cstream->direction == SND_COMPRESS_PLAYBACK) { - cpu_dai->playback_active--; - codec_dai->playback_active--; - } else { - cpu_dai->capture_active--; - codec_dai->capture_active--; - } + if (cstream->direction == SND_COMPRESS_PLAYBACK) + stream = SNDRV_PCM_STREAM_PLAYBACK; + else + stream = SNDRV_PCM_STREAM_CAPTURE; - snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); + snd_soc_runtime_deactivate(rtd, stream); - cpu_dai->active--; - codec_dai->active--; - codec->active--; + snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); if (!cpu_dai->active) cpu_dai->rate = 0; @@ -235,8 +206,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) cpu_dai->runtime = NULL; if (cstream->direction == SND_COMPRESS_PLAYBACK) { - if (!rtd->pmdown_time || codec->ignore_pmdown_time || - rtd->dai_link->ignore_pmdown_time) { + if (snd_soc_runtime_ignore_pmdown_time(rtd)) { snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_STOP); @@ -261,26 +231,17 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_soc_platform *platform = fe->platform; - struct snd_soc_dai *cpu_dai = fe->cpu_dai; - struct snd_soc_dai *codec_dai = fe->codec_dai; struct snd_soc_dpcm *dpcm; int stream, ret; mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); - if (cstream->direction == SND_COMPRESS_PLAYBACK) { + if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; - cpu_dai->playback_active--; - codec_dai->playback_active--; - } else { + else stream = SNDRV_PCM_STREAM_CAPTURE; - cpu_dai->capture_active--; - codec_dai->capture_active--; - } - cpu_dai->active--; - codec_dai->active--; - fe->codec->active--; + snd_soc_runtime_deactivate(fe, stream); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fe1df50805a3..4ba0959a0d7b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -56,7 +56,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); #endif static DEFINE_MUTEX(client_mutex); -static LIST_HEAD(dai_list); static LIST_HEAD(platform_list); static LIST_HEAD(codec_list); static LIST_HEAD(component_list); @@ -370,18 +369,22 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf, { char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); ssize_t len, ret = 0; + struct snd_soc_component *component; struct snd_soc_dai *dai; if (!buf) return -ENOMEM; - list_for_each_entry(dai, &dai_list, list) { - len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name); - if (len >= 0) - ret += len; - if (ret > PAGE_SIZE) { - ret = PAGE_SIZE; - break; + list_for_each_entry(component, &component_list, list) { + list_for_each_entry(dai, &component->dai_list, list) { + len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", + dai->name); + if (len >= 0) + ret += len; + if (ret > PAGE_SIZE) { + ret = PAGE_SIZE; + break; + } } } @@ -855,6 +858,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; + struct snd_soc_component *component; struct snd_soc_codec *codec; struct snd_soc_platform *platform; struct snd_soc_dai *codec_dai, *cpu_dai; @@ -863,18 +867,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); /* Find CPU DAI from registered DAIs*/ - list_for_each_entry(cpu_dai, &dai_list, list) { + list_for_each_entry(component, &component_list, list) { if (dai_link->cpu_of_node && - (cpu_dai->dev->of_node != dai_link->cpu_of_node)) + component->dev->of_node != dai_link->cpu_of_node) continue; if (dai_link->cpu_name && - strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name)) - continue; - if (dai_link->cpu_dai_name && - strcmp(cpu_dai->name, dai_link->cpu_dai_name)) + strcmp(dev_name(component->dev), dai_link->cpu_name)) continue; + list_for_each_entry(cpu_dai, &component->dai_list, list) { + if (dai_link->cpu_dai_name && + strcmp(cpu_dai->name, dai_link->cpu_dai_name)) + continue; - rtd->cpu_dai = cpu_dai; + rtd->cpu_dai = cpu_dai; + } } if (!rtd->cpu_dai) { @@ -899,12 +905,10 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) * CODEC found, so find CODEC DAI from registered DAIs from * this CODEC */ - list_for_each_entry(codec_dai, &dai_list, list) { - if (codec->dev == codec_dai->dev && - !strcmp(codec_dai->name, - dai_link->codec_dai_name)) { - + list_for_each_entry(codec_dai, &codec->component.dai_list, list) { + if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) { rtd->codec_dai = codec_dai; + break; } } @@ -1128,12 +1132,8 @@ static int soc_probe_codec(struct snd_soc_card *card, driver->num_dapm_widgets); /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(dai, &dai_list, list) { - if (dai->dev != codec->dev) - continue; - + list_for_each_entry(dai, &codec->component.dai_list, list) snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); - } codec->dapm.idle_bias_off = driver->idle_bias_off; @@ -1180,6 +1180,7 @@ static int soc_probe_platform(struct snd_soc_card *card, { int ret = 0; const struct snd_soc_platform_driver *driver = platform->driver; + struct snd_soc_component *component; struct snd_soc_dai *dai; platform->card = card; @@ -1195,11 +1196,11 @@ static int soc_probe_platform(struct snd_soc_card *card, driver->dapm_widgets, driver->num_dapm_widgets); /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(dai, &dai_list, list) { - if (dai->dev != platform->dev) + list_for_each_entry(component, &component_list, list) { + if (component->dev != platform->dev) continue; - - snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); + list_for_each_entry(dai, &component->dai_list, list) + snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); } platform->dapm.idle_bias_off = 1; @@ -2571,10 +2572,10 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = e->shift_l == e->shift_r ? 1 : 2; - uinfo->value.enumerated.items = e->max; + uinfo->value.enumerated.items = e->items; - if (uinfo->value.enumerated.item > e->max - 1) - uinfo->value.enumerated.item = e->max - 1; + if (uinfo->value.enumerated.item >= e->items) + uinfo->value.enumerated.item = e->items - 1; strlcpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item], sizeof(uinfo->value.enumerated.name)); @@ -2596,14 +2597,18 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int val; + unsigned int val, item; + unsigned int reg_val; - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] - = (val >> e->shift_l) & e->mask; - if (e->shift_l != e->shift_r) - ucontrol->value.enumerated.item[1] = - (val >> e->shift_r) & e->mask; + reg_val = snd_soc_read(codec, e->reg); + val = (reg_val >> e->shift_l) & e->mask; + item = snd_soc_enum_val_to_item(e, val); + ucontrol->value.enumerated.item[0] = item; + if (e->shift_l != e->shift_r) { + val = (reg_val >> e->shift_l) & e->mask; + item = snd_soc_enum_val_to_item(e, val); + ucontrol->value.enumerated.item[1] = item; + } return 0; } @@ -2623,17 +2628,18 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; unsigned int val; unsigned int mask; - if (ucontrol->value.enumerated.item[0] > e->max - 1) + if (item[0] >= e->items) return -EINVAL; - val = ucontrol->value.enumerated.item[0] << e->shift_l; + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; mask = e->mask << e->shift_l; if (e->shift_l != e->shift_r) { - if (ucontrol->value.enumerated.item[1] > e->max - 1) + if (item[1] >= e->items) return -EINVAL; - val |= ucontrol->value.enumerated.item[1] << e->shift_r; + val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; mask |= e->mask << e->shift_r; } @@ -2642,78 +2648,46 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); /** - * snd_soc_get_value_enum_double - semi enumerated double mixer get callback - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to get the value of a double semi enumerated mixer. + * snd_soc_read_signed - Read a codec register and interprete as signed value + * @codec: codec + * @reg: Register to read + * @mask: Mask to use after shifting the register value + * @shift: Right shift of register value + * @sign_bit: Bit that describes if a number is negative or not. * - * Semi enumerated mixer: the enumerated items are referred as values. Can be - * used for handling bitfield coded enumeration for example. + * This functions reads a codec register. The register value is shifted right + * by 'shift' bits and masked with the given 'mask'. Afterwards it translates + * the given registervalue into a signed integer if sign_bit is non-zero. * - * Returns 0 for success. + * Returns the register value as signed int. */ -int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg, + unsigned int mask, unsigned int shift, unsigned int sign_bit) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int reg_val, val, mux; + int ret; + unsigned int val; - reg_val = snd_soc_read(codec, e->reg); - val = (reg_val >> e->shift_l) & e->mask; - for (mux = 0; mux < e->max; mux++) { - if (val == e->values[mux]) - break; - } - ucontrol->value.enumerated.item[0] = mux; - if (e->shift_l != e->shift_r) { - val = (reg_val >> e->shift_r) & e->mask; - for (mux = 0; mux < e->max; mux++) { - if (val == e->values[mux]) - break; - } - ucontrol->value.enumerated.item[1] = mux; - } + val = (snd_soc_read(codec, reg) >> shift) & mask; - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double); + if (!sign_bit) + return val; -/** - * snd_soc_put_value_enum_double - semi enumerated double mixer put callback - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to set the value of a double semi enumerated mixer. - * - * Semi enumerated mixer: the enumerated items are referred as values. Can be - * used for handling bitfield coded enumeration for example. - * - * Returns 0 for success. - */ -int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int val; - unsigned int mask; + /* non-negative number */ + if (!(val & BIT(sign_bit))) + return val; - if (ucontrol->value.enumerated.item[0] > e->max - 1) - return -EINVAL; - val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; - mask = e->mask << e->shift_l; - if (e->shift_l != e->shift_r) { - if (ucontrol->value.enumerated.item[1] > e->max - 1) - return -EINVAL; - val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; - mask |= e->mask << e->shift_r; - } + ret = val; - return snd_soc_update_bits_locked(codec, e->reg, mask, val); + /* + * The register most probably does not contain a full-sized int. + * Instead we have an arbitrary number of bits in a signed + * representation which has to be translated into a full-sized int. + * This is done by filling up all bits above the sign-bit. + */ + ret |= ~((int)(BIT(sign_bit) - 1)); + + return ret; } -EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); /** * snd_soc_info_volsw - single mixer info callback @@ -2743,7 +2717,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = platform_max; + uinfo->value.integer.max = platform_max - mc->min; return 0; } EXPORT_SYMBOL_GPL(snd_soc_info_volsw); @@ -2769,11 +2743,16 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, unsigned int shift = mc->shift; unsigned int rshift = mc->rshift; int max = mc->max; + int min = mc->min; + int sign_bit = mc->sign_bit; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; - ucontrol->value.integer.value[0] = - (snd_soc_read(codec, reg) >> shift) & mask; + if (sign_bit) + mask = BIT(sign_bit + 1) - 1; + + ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask, + shift, sign_bit) - min; if (invert) ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0]; @@ -2781,10 +2760,12 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, if (snd_soc_volsw_is_stereo(mc)) { if (reg == reg2) ucontrol->value.integer.value[1] = - (snd_soc_read(codec, reg) >> rshift) & mask; + snd_soc_read_signed(codec, reg, mask, rshift, + sign_bit) - min; else ucontrol->value.integer.value[1] = - (snd_soc_read(codec, reg2) >> shift) & mask; + snd_soc_read_signed(codec, reg2, mask, shift, + sign_bit) - min; if (invert) ucontrol->value.integer.value[1] = max - ucontrol->value.integer.value[1]; @@ -2815,20 +2796,25 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, unsigned int shift = mc->shift; unsigned int rshift = mc->rshift; int max = mc->max; + int min = mc->min; + unsigned int sign_bit = mc->sign_bit; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; int err; - bool type_2r = 0; + bool type_2r = false; unsigned int val2 = 0; unsigned int val, val_mask; - val = (ucontrol->value.integer.value[0] & mask); + if (sign_bit) + mask = BIT(sign_bit + 1) - 1; + + val = ((ucontrol->value.integer.value[0] + min) & mask); if (invert) val = max - val; val_mask = mask << shift; val = val << shift; if (snd_soc_volsw_is_stereo(mc)) { - val2 = (ucontrol->value.integer.value[1] & mask); + val2 = ((ucontrol->value.integer.value[1] + min) & mask); if (invert) val2 = max - val2; if (reg == reg2) { @@ -2836,7 +2822,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, val |= val2 << rshift; } else { val2 = val2 << shift; - type_2r = 1; + type_2r = true; } } err = snd_soc_update_bits_locked(codec, reg, val_mask, val); @@ -3234,7 +3220,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, struct soc_bytes *params = (void *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int ret, len; - unsigned int val; + unsigned int val, mask; void *data; if (!codec->using_regmap) @@ -3264,12 +3250,36 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, ((u8 *)data)[0] |= val; break; case 2: - ((u16 *)data)[0] &= cpu_to_be16(~params->mask); - ((u16 *)data)[0] |= cpu_to_be16(val); + mask = ~params->mask; + ret = regmap_parse_val(codec->control_data, + &mask, &mask); + if (ret != 0) + goto out; + + ((u16 *)data)[0] &= mask; + + ret = regmap_parse_val(codec->control_data, + &val, &val); + if (ret != 0) + goto out; + + ((u16 *)data)[0] |= val; break; case 4: - ((u32 *)data)[0] &= cpu_to_be32(~params->mask); - ((u32 *)data)[0] |= cpu_to_be32(val); + mask = ~params->mask; + ret = regmap_parse_val(codec->control_data, + &mask, &mask); + if (ret != 0) + goto out; + + ((u32 *)data)[0] &= mask; + + ret = regmap_parse_val(codec->control_data, + &val, &val); + if (ret != 0) + goto out; + + ((u32 *)data)[0] |= val; break; default: ret = -EINVAL; @@ -3626,7 +3636,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, slots, slot_width); else - return -EINVAL; + return -ENOTSUPP; } EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); @@ -3882,95 +3892,42 @@ static inline char *fmt_multiple_name(struct device *dev, } /** - * snd_soc_register_dai - Register a DAI with the ASoC core + * snd_soc_unregister_dai - Unregister DAIs from the ASoC core * - * @dai: DAI to register + * @component: The component for which the DAIs should be unregistered */ -static int snd_soc_register_dai(struct device *dev, - struct snd_soc_dai_driver *dai_drv) +static void snd_soc_unregister_dais(struct snd_soc_component *component) { - struct snd_soc_codec *codec; - struct snd_soc_dai *dai; - - dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev)); - - dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); - if (dai == NULL) - return -ENOMEM; + struct snd_soc_dai *dai, *_dai; - /* create DAI component name */ - dai->name = fmt_single_name(dev, &dai->id); - if (dai->name == NULL) { + list_for_each_entry_safe(dai, _dai, &component->dai_list, list) { + dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", + dai->name); + list_del(&dai->list); + kfree(dai->name); kfree(dai); - return -ENOMEM; - } - - dai->dev = dev; - dai->driver = dai_drv; - dai->dapm.dev = dev; - if (!dai->driver->ops) - dai->driver->ops = &null_dai_ops; - - mutex_lock(&client_mutex); - - list_for_each_entry(codec, &codec_list, list) { - if (codec->dev == dev) { - dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n", - dai->name, codec->name); - dai->codec = codec; - break; - } - } - - if (!dai->codec) - dai->dapm.idle_bias_off = 1; - - list_add(&dai->list, &dai_list); - - mutex_unlock(&client_mutex); - - dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); - - return 0; -} - -/** - * snd_soc_unregister_dai - Unregister a DAI from the ASoC core - * - * @dai: DAI to unregister - */ -static void snd_soc_unregister_dai(struct device *dev) -{ - struct snd_soc_dai *dai; - - list_for_each_entry(dai, &dai_list, list) { - if (dev == dai->dev) - goto found; } - return; - -found: - mutex_lock(&client_mutex); - list_del(&dai->list); - mutex_unlock(&client_mutex); - - dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name); - kfree(dai->name); - kfree(dai); } /** - * snd_soc_register_dais - Register multiple DAIs with the ASoC core + * snd_soc_register_dais - Register a DAI with the ASoC core * - * @dai: Array of DAIs to register + * @component: The component the DAIs are registered for + * @codec: The CODEC that the DAIs are registered for, NULL if the component is + * not a CODEC. + * @dai_drv: DAI driver to use for the DAIs * @count: Number of DAIs + * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the + * parent's name. */ -static int snd_soc_register_dais(struct device *dev, - struct snd_soc_dai_driver *dai_drv, size_t count) +static int snd_soc_register_dais(struct snd_soc_component *component, + struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv, + size_t count, bool legacy_dai_naming) { - struct snd_soc_codec *codec; + struct device *dev = component->dev; struct snd_soc_dai *dai; - int i, ret = 0; + unsigned int i; + int ret; dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); @@ -3982,70 +3939,54 @@ static int snd_soc_register_dais(struct device *dev, goto err; } - /* create DAI component name */ - dai->name = fmt_multiple_name(dev, &dai_drv[i]); + /* + * Back in the old days when we still had component-less DAIs, + * instead of having a static name, component-less DAIs would + * inherit the name of the parent device so it is possible to + * register multiple instances of the DAI. We still need to keep + * the same naming style even though those DAIs are not + * component-less anymore. + */ + if (count == 1 && legacy_dai_naming) { + dai->name = fmt_single_name(dev, &dai->id); + } else { + dai->name = fmt_multiple_name(dev, &dai_drv[i]); + if (dai_drv[i].id) + dai->id = dai_drv[i].id; + else + dai->id = i; + } if (dai->name == NULL) { kfree(dai); - ret = -EINVAL; + ret = -ENOMEM; goto err; } + dai->component = component; + dai->codec = codec; dai->dev = dev; dai->driver = &dai_drv[i]; - if (dai->driver->id) - dai->id = dai->driver->id; - else - dai->id = i; dai->dapm.dev = dev; if (!dai->driver->ops) dai->driver->ops = &null_dai_ops; - mutex_lock(&client_mutex); - - list_for_each_entry(codec, &codec_list, list) { - if (codec->dev == dev) { - dev_dbg(dev, - "ASoC: Mapped DAI %s to CODEC %s\n", - dai->name, codec->name); - dai->codec = codec; - break; - } - } - if (!dai->codec) dai->dapm.idle_bias_off = 1; - list_add(&dai->list, &dai_list); + list_add(&dai->list, &component->dai_list); - mutex_unlock(&client_mutex); - - dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name); + dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); } return 0; err: - for (i--; i >= 0; i--) - snd_soc_unregister_dai(dev); + snd_soc_unregister_dais(component); return ret; } /** - * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core - * - * @dai: Array of DAIs to unregister - * @count: Number of DAIs - */ -static void snd_soc_unregister_dais(struct device *dev, size_t count) -{ - int i; - - for (i = 0; i < count; i++) - snd_soc_unregister_dai(dev); -} - -/** * snd_soc_register_component - Register a component with the ASoC core * */ @@ -4053,6 +3994,7 @@ static int __snd_soc_register_component(struct device *dev, struct snd_soc_component *cmpnt, const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv, int num_dai, bool allow_single_dai) { @@ -4075,20 +4017,10 @@ __snd_soc_register_component(struct device *dev, cmpnt->driver = cmpnt_drv; cmpnt->dai_drv = dai_drv; cmpnt->num_dai = num_dai; + INIT_LIST_HEAD(&cmpnt->dai_list); - /* - * snd_soc_register_dai() uses fmt_single_name(), and - * snd_soc_register_dais() uses fmt_multiple_name() - * for dai->name which is used for name based matching - * - * this function is used from cpu/codec. - * allow_single_dai flag can ignore "codec" driver reworking - * since it had been used snd_soc_register_dais(), - */ - if ((1 == num_dai) && allow_single_dai) - ret = snd_soc_register_dai(dev, dai_drv); - else - ret = snd_soc_register_dais(dev, dai_drv, num_dai); + ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai, + allow_single_dai); if (ret < 0) { dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); goto error_component_name; @@ -4121,7 +4053,9 @@ int snd_soc_register_component(struct device *dev, return -ENOMEM; } - return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, + cmpnt->ignore_pmdown_time = true; + + return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL, dai_drv, num_dai, true); } EXPORT_SYMBOL_GPL(snd_soc_register_component); @@ -4141,7 +4075,7 @@ void snd_soc_unregister_component(struct device *dev) return; found: - snd_soc_unregister_dais(dev, cmpnt->num_dai); + snd_soc_unregister_dais(cmpnt); mutex_lock(&client_mutex); list_del(&cmpnt->list); @@ -4319,7 +4253,7 @@ int snd_soc_register_codec(struct device *dev, codec->volatile_register = codec_drv->volatile_register; codec->readable_register = codec_drv->readable_register; codec->writable_register = codec_drv->writable_register; - codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time; + codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; codec->dapm.bias_level = SND_SOC_BIAS_OFF; codec->dapm.dev = dev; codec->dapm.codec = codec; @@ -4342,7 +4276,7 @@ int snd_soc_register_codec(struct device *dev, /* register component */ ret = __snd_soc_register_component(dev, &codec->component, &codec_drv->component_driver, - dai_drv, num_dai, false); + codec, dai_drv, num_dai, false); if (ret < 0) { dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); goto fail_codec_name; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dc8ff13187f7..c8a780d0d057 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -70,8 +70,6 @@ static int dapm_up_seq[] = { [snd_soc_dapm_aif_out] = 4, [snd_soc_dapm_mic] = 5, [snd_soc_dapm_mux] = 6, - [snd_soc_dapm_virt_mux] = 6, - [snd_soc_dapm_value_mux] = 6, [snd_soc_dapm_dac] = 7, [snd_soc_dapm_switch] = 8, [snd_soc_dapm_mixer] = 8, @@ -102,8 +100,6 @@ static int dapm_down_seq[] = { [snd_soc_dapm_mic] = 7, [snd_soc_dapm_micbias] = 8, [snd_soc_dapm_mux] = 9, - [snd_soc_dapm_virt_mux] = 9, - [snd_soc_dapm_value_mux] = 9, [snd_soc_dapm_aif_in] = 10, [snd_soc_dapm_aif_out] = 10, [snd_soc_dapm_dai_in] = 10, @@ -115,6 +111,12 @@ static int dapm_down_seq[] = { [snd_soc_dapm_post] = 14, }; +static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) +{ + if (dapm->card && dapm->card->instantiated) + lockdep_assert_held(&dapm->card->dapm_mutex); +} + static void pop_wait(u32 pop_time) { if (pop_time) @@ -146,15 +148,16 @@ static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w) return !list_empty(&w->dirty); } -void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) +static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) { + dapm_assert_locked(w->dapm); + if (!dapm_dirty_widget(w)) { dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n", w->name, reason); list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty); } } -EXPORT_SYMBOL_GPL(dapm_mark_dirty); void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) { @@ -361,6 +364,8 @@ static void dapm_reset(struct snd_soc_card *card) { struct snd_soc_dapm_widget *w; + lockdep_assert_held(&card->dapm_mutex); + memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); list_for_each_entry(w, &card->widgets, list) { @@ -386,7 +391,8 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, return -1; } -static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) +static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, + unsigned int val) { if (w->codec) return snd_soc_write(w->codec, reg, val); @@ -498,131 +504,40 @@ out: return ret; } -/* set up initial codec paths */ -static void dapm_set_path_status(struct snd_soc_dapm_widget *w, - struct snd_soc_dapm_path *p, int i) +/* connect mux widget to its interconnecting audio paths */ +static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, + struct snd_soc_dapm_path *path, const char *control_name, + const struct snd_kcontrol_new *kcontrol) { - switch (w->id) { - case snd_soc_dapm_switch: - case snd_soc_dapm_mixer: - case snd_soc_dapm_mixer_named_ctl: { - int val; - struct soc_mixer_control *mc = (struct soc_mixer_control *) - w->kcontrol_news[i].private_value; - int reg = mc->reg; - unsigned int shift = mc->shift; - int max = mc->max; - unsigned int mask = (1 << fls(max)) - 1; - unsigned int invert = mc->invert; - - if (reg != SND_SOC_NOPM) { - soc_widget_read(w, reg, &val); - val = (val >> shift) & mask; - if (invert) - val = max - val; - p->connect = !!val; - } else { - p->connect = 0; - } - - } - break; - case snd_soc_dapm_mux: { - struct soc_enum *e = (struct soc_enum *) - w->kcontrol_news[i].private_value; - int val, item; - - soc_widget_read(w, e->reg, &val); - item = (val >> e->shift_l) & e->mask; - - if (item < e->max && !strcmp(p->name, e->texts[item])) - p->connect = 1; - else - p->connect = 0; - } - break; - case snd_soc_dapm_virt_mux: { - struct soc_enum *e = (struct soc_enum *) - w->kcontrol_news[i].private_value; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val, item; + int i; - p->connect = 0; + if (e->reg != SND_SOC_NOPM) { + soc_widget_read(dest, e->reg, &val); + val = (val >> e->shift_l) & e->mask; + item = snd_soc_enum_val_to_item(e, val); + } else { /* since a virtual mux has no backing registers to * decide which path to connect, it will try to match * with the first enumeration. This is to ensure * that the default mux choice (the first) will be * correctly powered up during initialization. */ - if (!strcmp(p->name, e->texts[0])) - p->connect = 1; - } - break; - case snd_soc_dapm_value_mux: { - struct soc_enum *e = (struct soc_enum *) - w->kcontrol_news[i].private_value; - int val, item; - - soc_widget_read(w, e->reg, &val); - val = (val >> e->shift_l) & e->mask; - for (item = 0; item < e->max; item++) { - if (val == e->values[item]) - break; - } - - if (item < e->max && !strcmp(p->name, e->texts[item])) - p->connect = 1; - else - p->connect = 0; - } - break; - /* does not affect routing - always connected */ - case snd_soc_dapm_pga: - case snd_soc_dapm_out_drv: - case snd_soc_dapm_output: - case snd_soc_dapm_adc: - case snd_soc_dapm_input: - case snd_soc_dapm_siggen: - case snd_soc_dapm_dac: - case snd_soc_dapm_micbias: - case snd_soc_dapm_vmid: - case snd_soc_dapm_supply: - case snd_soc_dapm_regulator_supply: - case snd_soc_dapm_clock_supply: - case snd_soc_dapm_aif_in: - case snd_soc_dapm_aif_out: - case snd_soc_dapm_dai_in: - case snd_soc_dapm_dai_out: - case snd_soc_dapm_hp: - case snd_soc_dapm_mic: - case snd_soc_dapm_spk: - case snd_soc_dapm_line: - case snd_soc_dapm_dai_link: - case snd_soc_dapm_kcontrol: - p->connect = 1; - break; - /* does affect routing - dynamically connected */ - case snd_soc_dapm_pre: - case snd_soc_dapm_post: - p->connect = 0; - break; + item = 0; } -} - -/* connect mux widget to its interconnecting audio paths */ -static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, - struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, - struct snd_soc_dapm_path *path, const char *control_name, - const struct snd_kcontrol_new *kcontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int i; - for (i = 0; i < e->max; i++) { + for (i = 0; i < e->items; i++) { if (!(strcmp(control_name, e->texts[i]))) { list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &dest->sources); list_add(&path->list_source, &src->sinks); path->name = (char*)e->texts[i]; - dapm_set_path_status(dest, path, 0); + if (i == item) + path->connect = 1; + else + path->connect = 0; return 0; } } @@ -630,6 +545,30 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, return -ENODEV; } +/* set up initial codec paths */ +static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_path *p, int i) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *) + w->kcontrol_news[i].private_value; + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int max = mc->max; + unsigned int mask = (1 << fls(max)) - 1; + unsigned int invert = mc->invert; + unsigned int val; + + if (reg != SND_SOC_NOPM) { + soc_widget_read(w, reg, &val); + val = (val >> shift) & mask; + if (invert) + val = max - val; + p->connect = !!val; + } else { + p->connect = 0; + } +} + /* connect mixer widget to its interconnecting audio paths */ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, @@ -644,7 +583,7 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, list_add(&path->list_sink, &dest->sources); list_add(&path->list_source, &src->sinks); path->name = dest->kcontrol_news[i].name; - dapm_set_path_status(dest, path, i); + dapm_set_mixer_path_status(dest, path, i); return 0; } } @@ -723,8 +662,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, kcname_in_long_name = true; break; case snd_soc_dapm_mux: - case snd_soc_dapm_virt_mux: - case snd_soc_dapm_value_mux: wname_in_long_name = true; kcname_in_long_name = false; break; @@ -1218,7 +1155,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ret = regulator_allow_bypass(w->regulator, false); if (ret != 0) dev_warn(w->dapm->dev, - "ASoC: Failed to bypass %s: %d\n", + "ASoC: Failed to unbypass %s: %d\n", w->name, ret); } @@ -1228,7 +1165,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) dev_warn(w->dapm->dev, - "ASoC: Failed to unbypass %s: %d\n", + "ASoC: Failed to bypass %s: %d\n", w->name, ret); } @@ -1823,6 +1760,8 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) ASYNC_DOMAIN_EXCLUSIVE(async_domain); enum snd_soc_bias_level bias; + lockdep_assert_held(&card->dapm_mutex); + trace_snd_soc_dapm_start(card); list_for_each_entry(d, &card->dapm_list, list) { @@ -1897,10 +1836,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) trace_snd_soc_dapm_walk_done(card); - /* Run all the bias changes in parallel */ - list_for_each_entry(d, &card->dapm_list, list) - async_schedule_domain(dapm_pre_sequence_async, d, - &async_domain); + /* Run card bias changes at first */ + dapm_pre_sequence_async(&card->dapm, 0); + /* Run other bias changes in parallel */ + list_for_each_entry(d, &card->dapm_list, list) { + if (d != &card->dapm) + async_schedule_domain(dapm_pre_sequence_async, d, + &async_domain); + } async_synchronize_full_domain(&async_domain); list_for_each_entry(w, &down_list, power_list) { @@ -1920,10 +1863,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) dapm_seq_run(card, &up_list, event, true); /* Run all the bias changes in parallel */ - list_for_each_entry(d, &card->dapm_list, list) - async_schedule_domain(dapm_post_sequence_async, d, - &async_domain); + list_for_each_entry(d, &card->dapm_list, list) { + if (d != &card->dapm) + async_schedule_domain(dapm_post_sequence_async, d, + &async_domain); + } async_synchronize_full_domain(&async_domain); + /* Run card bias changes at last */ + dapm_post_sequence_async(&card->dapm, 0); /* do we need to notify any clients that DAPM event is complete */ list_for_each_entry(d, &card->dapm_list, list) { @@ -2110,6 +2057,8 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card, struct snd_soc_dapm_path *path; int found = 0; + lockdep_assert_held(&card->dapm_mutex); + /* find dapm widget path assoc with kcontrol */ dapm_kcontrol_for_each_path(path, kcontrol) { if (!path->name || !e->texts[mux]) @@ -2160,6 +2109,8 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, struct snd_soc_dapm_path *path; int found = 0; + lockdep_assert_held(&card->dapm_mutex); + /* find dapm widget path assoc with kcontrol */ dapm_kcontrol_for_each_path(path, kcontrol) { found = 1; @@ -2325,6 +2276,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, { struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); + dapm_assert_locked(dapm); + if (!w) { dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); return -EINVAL; @@ -2341,18 +2294,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, } /** - * snd_soc_dapm_sync - scan and power dapm paths + * snd_soc_dapm_sync_unlocked - scan and power dapm paths * @dapm: DAPM context * * Walks all dapm audio paths and powers widgets according to their * stream or path usage. * + * Requires external locking. + * * Returns 0 for success. */ -int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) +int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm) { - int ret; - /* * Suppress early reports (eg, jacks syncing their state) to avoid * silly DAPM runs during card startup. @@ -2360,8 +2313,25 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) if (!dapm->card || !dapm->card->instantiated) return 0; + return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked); + +/** + * snd_soc_dapm_sync - scan and power dapm paths + * @dapm: DAPM context + * + * Walks all dapm audio paths and powers widgets according to their + * stream or path usage. + * + * Returns 0 for success. + */ +int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) +{ + int ret; + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); + ret = snd_soc_dapm_sync_unlocked(dapm); mutex_unlock(&dapm->card->dapm_mutex); return ret; } @@ -2444,8 +2414,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, path->connect = 1; return 0; case snd_soc_dapm_mux: - case snd_soc_dapm_virt_mux: - case snd_soc_dapm_value_mux: ret = dapm_connect_mux(dapm, wsource, wsink, path, control, &wsink->kcontrol_news[0]); if (ret != 0) @@ -2772,8 +2740,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) dapm_new_mixer(w); break; case snd_soc_dapm_mux: - case snd_soc_dapm_virt_mux: - case snd_soc_dapm_value_mux: dapm_new_mux(w); break; case snd_soc_dapm_pga: @@ -2935,213 +2901,75 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int val; - - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; - if (e->shift_l != e->shift_r) - ucontrol->value.enumerated.item[1] = - (val >> e->shift_r) & e->mask; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); - -/** - * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to set the value of a dapm enumerated double mixer control. - * - * Returns 0 for success. - */ -int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); - struct snd_soc_card *card = codec->card; - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int val, mux, change; - unsigned int mask; - struct snd_soc_dapm_update update; - int ret = 0; - - if (ucontrol->value.enumerated.item[0] > e->max - 1) - return -EINVAL; - mux = ucontrol->value.enumerated.item[0]; - val = mux << e->shift_l; - mask = e->mask << e->shift_l; - if (e->shift_l != e->shift_r) { - if (ucontrol->value.enumerated.item[1] > e->max - 1) - return -EINVAL; - val |= ucontrol->value.enumerated.item[1] << e->shift_r; - mask |= e->mask << e->shift_r; - } - - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - - change = snd_soc_test_bits(codec, e->reg, mask, val); - if (change) { - update.kcontrol = kcontrol; - update.reg = e->reg; - update.mask = mask; - update.val = val; - card->update = &update; - - ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); - - card->update = NULL; - } - - mutex_unlock(&card->dapm_mutex); + unsigned int reg_val, val; - if (ret > 0) - soc_dpcm_runtime_update(card); - - return change; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); - -/** - * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Returns 0 for success. - */ -int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol); - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); - -/** - * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Returns 0 for success. - */ -int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); - struct snd_soc_card *card = codec->card; - unsigned int value; - struct soc_enum *e = - (struct soc_enum *)kcontrol->private_value; - int change; - int ret = 0; - - if (ucontrol->value.enumerated.item[0] >= e->max) - return -EINVAL; - - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - - value = ucontrol->value.enumerated.item[0]; - change = dapm_kcontrol_set_value(kcontrol, value); - if (change) - ret = soc_dapm_mux_update_power(card, kcontrol, value, e); - - mutex_unlock(&card->dapm_mutex); - - if (ret > 0) - soc_dpcm_runtime_update(card); - - return change; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); - -/** - * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get - * callback - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to get the value of a dapm semi enumerated double mixer control. - * - * Semi enumerated mixer: the enumerated items are referred as values. Can be - * used for handling bitfield coded enumeration for example. - * - * Returns 0 for success. - */ -int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int reg_val, val, mux; + if (e->reg != SND_SOC_NOPM) + reg_val = snd_soc_read(codec, e->reg); + else + reg_val = dapm_kcontrol_get_value(kcontrol); - reg_val = snd_soc_read(codec, e->reg); val = (reg_val >> e->shift_l) & e->mask; - for (mux = 0; mux < e->max; mux++) { - if (val == e->values[mux]) - break; - } - ucontrol->value.enumerated.item[0] = mux; + ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); if (e->shift_l != e->shift_r) { val = (reg_val >> e->shift_r) & e->mask; - for (mux = 0; mux < e->max; mux++) { - if (val == e->values[mux]) - break; - } - ucontrol->value.enumerated.item[1] = mux; + val = snd_soc_enum_val_to_item(e, val); + ucontrol->value.enumerated.item[1] = val; } return 0; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); +EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); /** - * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set - * callback + * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback * @kcontrol: mixer control * @ucontrol: control element information * - * Callback to set the value of a dapm semi enumerated double mixer control. - * - * Semi enumerated mixer: the enumerated items are referred as values. Can be - * used for handling bitfield coded enumeration for example. + * Callback to set the value of a dapm enumerated double mixer control. * * Returns 0 for success. */ -int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, +int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); struct snd_soc_card *card = codec->card; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int val, mux, change; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, change; unsigned int mask; struct snd_soc_dapm_update update; int ret = 0; - if (ucontrol->value.enumerated.item[0] > e->max - 1) + if (item[0] >= e->items) return -EINVAL; - mux = ucontrol->value.enumerated.item[0]; - val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; + + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; mask = e->mask << e->shift_l; if (e->shift_l != e->shift_r) { - if (ucontrol->value.enumerated.item[1] > e->max - 1) + if (item[1] > e->items) return -EINVAL; - val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; + val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l; mask |= e->mask << e->shift_r; } mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - change = snd_soc_test_bits(codec, e->reg, mask, val); + if (e->reg != SND_SOC_NOPM) + change = snd_soc_test_bits(codec, e->reg, mask, val); + else + change = dapm_kcontrol_set_value(kcontrol, val); + if (change) { - update.kcontrol = kcontrol; - update.reg = e->reg; - update.mask = mask; - update.val = val; - card->update = &update; + if (e->reg != SND_SOC_NOPM) { + update.kcontrol = kcontrol; + update.reg = e->reg; + update.mask = mask; + update.val = val; + card->update = &update; + } - ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); + ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e); card->update = NULL; } @@ -3153,7 +2981,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, return change; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); +EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); /** * snd_soc_dapm_info_pin_switch - Info for a pin switch @@ -3210,15 +3038,11 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); const char *pin = (const char *)kcontrol->private_value; - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - if (ucontrol->value.integer.value[0]) snd_soc_dapm_enable_pin(&card->dapm, pin); else snd_soc_dapm_disable_pin(&card->dapm, pin); - mutex_unlock(&card->dapm_mutex); - snd_soc_dapm_sync(&card->dapm); return 0; } @@ -3248,7 +3072,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) dev_warn(w->dapm->dev, - "ASoC: Failed to unbypass %s: %d\n", + "ASoC: Failed to bypass %s: %d\n", w->name, ret); } break; @@ -3287,8 +3111,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_mux: - case snd_soc_dapm_virt_mux: - case snd_soc_dapm_value_mux: w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_dai_out: @@ -3767,23 +3589,52 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, } /** + * snd_soc_dapm_enable_pin_unlocked - enable pin. + * @dapm: DAPM context + * @pin: pin name + * + * Enables input/output pin and its parents or children widgets iff there is + * a valid audio route and active audio stream. + * + * Requires external locking. + * + * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to + * do any widget power switching. + */ +int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin) +{ + return snd_soc_dapm_set_pin(dapm, pin, 1); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked); + +/** * snd_soc_dapm_enable_pin - enable pin. * @dapm: DAPM context * @pin: pin name * * Enables input/output pin and its parents or children widgets iff there is * a valid audio route and active audio stream. + * * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. */ int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin) { - return snd_soc_dapm_set_pin(dapm, pin, 1); + int ret; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_set_pin(dapm, pin, 1); + + mutex_unlock(&dapm->card->dapm_mutex); + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); /** - * snd_soc_dapm_force_enable_pin - force a pin to be enabled + * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled * @dapm: DAPM context * @pin: pin name * @@ -3791,11 +3642,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); * intended for use with microphone bias supplies used in microphone * jack detection. * + * Requires external locking. + * * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. */ -int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, - const char *pin) +int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin) { struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); @@ -3811,25 +3664,103 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, return 0; } +EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked); + +/** + * snd_soc_dapm_force_enable_pin - force a pin to be enabled + * @dapm: DAPM context + * @pin: pin name + * + * Enables input/output pin regardless of any other state. This is + * intended for use with microphone bias supplies used in microphone + * jack detection. + * + * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to + * do any widget power switching. + */ +int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, + const char *pin) +{ + int ret; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); + + mutex_unlock(&dapm->card->dapm_mutex); + + return ret; +} EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin); /** + * snd_soc_dapm_disable_pin_unlocked - disable pin. + * @dapm: DAPM context + * @pin: pin name + * + * Disables input/output pin and its parents or children widgets. + * + * Requires external locking. + * + * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to + * do any widget power switching. + */ +int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin) +{ + return snd_soc_dapm_set_pin(dapm, pin, 0); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked); + +/** * snd_soc_dapm_disable_pin - disable pin. * @dapm: DAPM context * @pin: pin name * * Disables input/output pin and its parents or children widgets. + * * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. */ int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin) { - return snd_soc_dapm_set_pin(dapm, pin, 0); + int ret; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_set_pin(dapm, pin, 0); + + mutex_unlock(&dapm->card->dapm_mutex); + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); /** + * snd_soc_dapm_nc_pin_unlocked - permanently disable pin. + * @dapm: DAPM context + * @pin: pin name + * + * Marks the specified pin as being not connected, disabling it along + * any parent or child widgets. At present this is identical to + * snd_soc_dapm_disable_pin() but in future it will be extended to do + * additional things such as disabling controls which only affect + * paths through the pin. + * + * Requires external locking. + * + * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to + * do any widget power switching. + */ +int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin) +{ + return snd_soc_dapm_set_pin(dapm, pin, 0); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked); + +/** * snd_soc_dapm_nc_pin - permanently disable pin. * @dapm: DAPM context * @pin: pin name @@ -3845,7 +3776,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); */ int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin) { - return snd_soc_dapm_set_pin(dapm, pin, 0); + int ret; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_set_pin(dapm, pin, 0); + + mutex_unlock(&dapm->card->dapm_mutex); + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); @@ -3985,7 +3924,7 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) } EXPORT_SYMBOL_GPL(snd_soc_dapm_free); -static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) +static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) { struct snd_soc_card *card = dapm->card; struct snd_soc_dapm_widget *w; @@ -4025,14 +3964,21 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) */ void snd_soc_dapm_shutdown(struct snd_soc_card *card) { - struct snd_soc_codec *codec; + struct snd_soc_dapm_context *dapm; - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - soc_dapm_shutdown_codec(&codec->dapm); - if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) - snd_soc_dapm_set_bias_level(&codec->dapm, - SND_SOC_BIAS_OFF); + list_for_each_entry(dapm, &card->dapm_list, list) { + if (dapm != &card->dapm) { + soc_dapm_shutdown_dapm(dapm); + if (dapm->bias_level == SND_SOC_BIAS_STANDBY) + snd_soc_dapm_set_bias_level(dapm, + SND_SOC_BIAS_OFF); + } } + + soc_dapm_shutdown_dapm(&card->dapm); + if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) + snd_soc_dapm_set_bias_level(&card->dapm, + SND_SOC_BIAS_OFF); } /* Module information */ diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 47e1ce771e65..330eaf007d89 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -35,6 +35,86 @@ #define DPCM_MAX_BE_USERS 8 /** + * snd_soc_runtime_activate() - Increment active count for PCM runtime components + * @rtd: ASoC PCM runtime that is activated + * @stream: Direction of the PCM stream + * + * Increments the active count for all the DAIs and components attached to a PCM + * runtime. Should typically be called when a stream is opened. + * + * Must be called with the rtd->pcm_mutex being held + */ +void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) +{ + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + lockdep_assert_held(&rtd->pcm_mutex); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + cpu_dai->playback_active++; + codec_dai->playback_active++; + } else { + cpu_dai->capture_active++; + codec_dai->capture_active++; + } + + cpu_dai->active++; + codec_dai->active++; + cpu_dai->component->active++; + codec_dai->component->active++; +} + +/** + * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components + * @rtd: ASoC PCM runtime that is deactivated + * @stream: Direction of the PCM stream + * + * Decrements the active count for all the DAIs and components attached to a PCM + * runtime. Should typically be called when a stream is closed. + * + * Must be called with the rtd->pcm_mutex being held + */ +void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) +{ + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + lockdep_assert_held(&rtd->pcm_mutex); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + cpu_dai->playback_active--; + codec_dai->playback_active--; + } else { + cpu_dai->capture_active--; + codec_dai->capture_active--; + } + + cpu_dai->active--; + codec_dai->active--; + cpu_dai->component->active--; + codec_dai->component->active--; +} + +/** + * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay + * @rtd: The ASoC PCM runtime that should be checked. + * + * This function checks whether the power down delay should be ignored for a + * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has + * been configured to ignore the delay, or if none of the components benefits + * from having the delay. + */ +bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) +{ + if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) + return true; + + return rtd->cpu_dai->component->ignore_pmdown_time && + rtd->codec_dai->component->ignore_pmdown_time; +} + +/** * snd_soc_set_runtime_hwparams - set the runtime hardware parameters * @substream: the pcm substream * @hw: the hardware parameters @@ -378,16 +458,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) runtime->hw.rate_max); dynamic: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - cpu_dai->playback_active++; - codec_dai->playback_active++; - } else { - cpu_dai->capture_active++; - codec_dai->capture_active++; - } - cpu_dai->active++; - codec_dai->active++; - rtd->codec->active++; + + snd_soc_runtime_activate(rtd, substream->stream); + mutex_unlock(&rtd->pcm_mutex); return 0; @@ -459,21 +532,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = rtd->codec; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - cpu_dai->playback_active--; - codec_dai->playback_active--; - } else { - cpu_dai->capture_active--; - codec_dai->capture_active--; - } - - cpu_dai->active--; - codec_dai->active--; - codec->active--; + snd_soc_runtime_deactivate(rtd, substream->stream); /* clear the corresponding DAIs rate when inactive */ if (!cpu_dai->active) @@ -496,8 +558,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) cpu_dai->runtime = NULL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (!rtd->pmdown_time || codec->ignore_pmdown_time || - rtd->dai_link->ignore_pmdown_time) { + if (snd_soc_runtime_ignore_pmdown_time(rtd)) { /* powered down playback stream now */ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, @@ -1989,6 +2050,7 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); if (paths < 0) { + dpcm_path_put(&list); dev_warn(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name, "playback"); mutex_unlock(&card->mutex); @@ -2018,6 +2080,7 @@ capture: paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); if (paths < 0) { + dpcm_path_put(&list); dev_warn(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name, "capture"); mutex_unlock(&card->mutex); @@ -2082,6 +2145,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) fe->dpcm[stream].runtime = fe_substream->runtime; if (dpcm_path_get(fe, stream, &list) <= 0) { + dpcm_path_put(&list); dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", fe->dai_link->name, stream ? "capture" : "playback"); } diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c index fe99f461aff0..19cca043e6e4 100644 --- a/sound/soc/spear/spdif_out.c +++ b/sound/soc/spear/spdif_out.c @@ -213,10 +213,7 @@ static int spdif_digital_mute(struct snd_soc_dai *dai, int mute) static int spdif_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct snd_soc_card *card = codec->card; - struct snd_soc_pcm_runtime *rtd = card->rtd; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai); ucontrol->value.integer.value[0] = host->saved_params.mute; @@ -226,10 +223,7 @@ static int spdif_mute_get(struct snd_kcontrol *kcontrol, static int spdif_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct snd_soc_card *card = codec->card; - struct snd_soc_pcm_runtime *rtd = card->rtd; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai); if (host->saved_params.mute == ucontrol->value.integer.value[0]) diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 9f9c1856f822..31198cf7f88d 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -105,7 +105,7 @@ config SND_SOC_TEGRA_TRIMSLICE tristate "SoC Audio support for TrimSlice board" depends on SND_SOC_TEGRA && I2C select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC - select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC23_I2C help Say Y or M here if you want to add support for SoC audio on the TrimSlice platform. diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index e0305a148568..9edd68db9f48 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c @@ -183,14 +183,16 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); drvdata->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(drvdata->base)) return PTR_ERR(drvdata->base); - drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; platform_set_drvdata(pdev, drvdata); drvdata->physbase = r->start; if (sizeof(drvdata->physbase) > sizeof(r->start) && |