diff options
Diffstat (limited to 'sound')
141 files changed, 3326 insertions, 1501 deletions
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 1c16830af3d8..6faaac60161a 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -520,7 +520,7 @@ static int snd_es18xx_playback1_trigger(struct snd_es18xx *chip, snd_es18xx_mixer_write(chip, 0x78, 0x93); #ifdef AVOID_POPS /* Avoid pops */ - udelay(100000); + mdelay(100); if (chip->caps & ES18XX_PCM2) /* Restore Audio 2 volume */ snd_es18xx_mixer_write(chip, 0x7C, chip->audio2_vol); @@ -537,7 +537,7 @@ static int snd_es18xx_playback1_trigger(struct snd_es18xx *chip, /* Stop DMA */ snd_es18xx_mixer_write(chip, 0x78, 0x00); #ifdef AVOID_POPS - udelay(25000); + mdelay(25); if (chip->caps & ES18XX_PCM2) /* Set Audio 2 volume to 0 */ snd_es18xx_mixer_write(chip, 0x7C, 0); @@ -596,7 +596,7 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream) snd_es18xx_write(chip, 0xA5, count >> 8); #ifdef AVOID_POPS - udelay(100000); + mdelay(100); #endif /* Set format */ @@ -691,7 +691,7 @@ static int snd_es18xx_playback2_trigger(struct snd_es18xx *chip, snd_es18xx_write(chip, 0xB8, 0x05); #ifdef AVOID_POPS /* Avoid pops */ - udelay(100000); + mdelay(100); /* Enable Audio 1 */ snd_es18xx_dsp_command(chip, 0xD1); #endif @@ -705,7 +705,7 @@ static int snd_es18xx_playback2_trigger(struct snd_es18xx *chip, snd_es18xx_write(chip, 0xB8, 0x00); #ifdef AVOID_POPS /* Avoid pops */ - udelay(25000); + mdelay(25); /* Disable Audio 1 */ snd_es18xx_dsp_command(chip, 0xD3); #endif diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 248b90abb882..480bbddbd801 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1059,24 +1059,26 @@ static void azx_init_cmd_io(struct azx *chip) /* reset the corb hw read pointer */ azx_writew(chip, CORBRP, ICH6_CORBRP_RST); - for (timeout = 1000; timeout > 0; timeout--) { - if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST) - break; - udelay(1); - } - if (timeout <= 0) - dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n", - azx_readw(chip, CORBRP)); + if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) { + for (timeout = 1000; timeout > 0; timeout--) { + if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST) + break; + udelay(1); + } + if (timeout <= 0) + dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n", + azx_readw(chip, CORBRP)); - azx_writew(chip, CORBRP, 0); - for (timeout = 1000; timeout > 0; timeout--) { - if (azx_readw(chip, CORBRP) == 0) - break; - udelay(1); + azx_writew(chip, CORBRP, 0); + for (timeout = 1000; timeout > 0; timeout--) { + if (azx_readw(chip, CORBRP) == 0) + break; + udelay(1); + } + if (timeout <= 0) + dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n", + azx_readw(chip, CORBRP)); } - if (timeout <= 0) - dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n", - azx_readw(chip, CORBRP)); /* enable corb dma */ azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d6bca62ef387..b540ad71eb0d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -249,7 +249,8 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\ - AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT) + AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT |\ + AZX_DCAPS_CORBRP_SELF_CLEAR) #define AZX_DCAPS_PRESET_CTHDA \ (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY) diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index ba38b819f984..4a7cb01fa912 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -189,6 +189,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ +#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ /* position fix mode */ enum { diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 0cb5b89cd0c8..1edbb9c47c2d 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1127,8 +1127,10 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, AMP_OUT_UNMUTE); eld = &per_pin->sink_eld; - if (!eld->monitor_present) + if (!eld->monitor_present) { + hdmi_set_channel_count(codec, per_pin->cvt_nid, channels); return; + } if (!non_pcm && per_pin->chmap_set) ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 14ae979a92ea..5f7c765391f1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4621,6 +4621,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0667, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0674, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x067e, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x067f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -4912,6 +4915,7 @@ static int patch_alc269(struct hda_codec *codec) spec->codec_variant = ALC269_TYPE_ALC285; break; case 0x10ec0286: + case 0x10ec0288: spec->codec_variant = ALC269_TYPE_ALC286; break; case 0x10ec0255: @@ -5539,6 +5543,8 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE), SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_AUTO_MUTE), + SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A), SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), @@ -5781,6 +5787,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 }, { .id = 0x10ec0285, .name = "ALC285", .patch = patch_alc269 }, { .id = 0x10ec0286, .name = "ALC286", .patch = patch_alc269 }, + { .id = 0x10ec0288, .name = "ALC288", .patch = patch_alc269 }, { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, { .id = 0x10ec0293, .name = "ALC293", .patch = patch_alc269 }, diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 4789619a52d8..27e3fc4a536b 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -35,7 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731 config SND_ATMEL_SOC_WM8904 tristate "Atmel ASoC driver for boards using WM8904 codec" - depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC + depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && I2C select SND_ATMEL_SOC_SSC select SND_ATMEL_SOC_DMA select SND_SOC_WM8904 diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c index 33ec592ecd75..a366b3503c28 100644 --- a/sound/soc/atmel/atmel-pcm-pdc.c +++ b/sound/soc/atmel/atmel-pcm-pdc.c @@ -76,12 +76,6 @@ struct atmel_runtime_data { size_t period_size; dma_addr_t period_ptr; /* physical address of next period */ - - /* PDC register save */ - u32 pdc_xpr_save; - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; }; /*--------------------------------------------------------------------------*\ @@ -320,67 +314,10 @@ static struct snd_pcm_ops atmel_pcm_ops = { .mmap = atmel_pcm_mmap, }; - -/*--------------------------------------------------------------------------*\ - * ASoC platform driver -\*--------------------------------------------------------------------------*/ -#ifdef CONFIG_PM -static int atmel_pcm_suspend(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* disable the PDC and save the PDC registers */ - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); - - prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); - prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); - prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); - prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); - - return 0; -} - -static int atmel_pcm_resume(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* restore the PDC registers and enable the PDC */ - ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); - ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); - ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); - ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); - return 0; -} -#else -#define atmel_pcm_suspend NULL -#define atmel_pcm_resume NULL -#endif - static struct snd_soc_platform_driver atmel_soc_platform = { .ops = &atmel_pcm_ops, .pcm_new = atmel_pcm_new, .pcm_free = atmel_pcm_free, - .suspend = atmel_pcm_suspend, - .resume = atmel_pcm_resume, }; int atmel_pcm_pdc_platform_register(struct device *dev) diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c index f65f08beac31..9579799ace54 100644 --- a/sound/soc/atmel/snd-soc-afeb9260.c +++ b/sound/soc/atmel/snd-soc-afeb9260.c @@ -80,17 +80,6 @@ static const struct snd_soc_dapm_route afeb9260_audio_map[] = { {"MICIN", NULL, "Mic Jack"}, }; -static int afeb9260_tlv320aic23_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_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Line In"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - - return 0; -} /* Digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link afeb9260_dai = { @@ -100,7 +89,6 @@ static struct snd_soc_dai_link afeb9260_dai = { .codec_dai_name = "tlv320aic23-hifi", .platform_name = "atmel_pcm-audio", .codec_name = "tlv320aic23-codec.0-001a", - .init = afeb9260_tlv320aic23_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBM_CFM, .ops = &afeb9260_ops, diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index b07e17160f94..3c4b10ff48c1 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -276,7 +276,7 @@ static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; int val[2], val2[2], i; @@ -300,7 +300,7 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; int err; @@ -333,7 +333,7 @@ static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -353,7 +353,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -1327,10 +1327,6 @@ static int pm860x_probe(struct snd_soc_codec *codec) pm860x->codec = codec; - ret = snd_soc_codec_set_cache_io(codec, pm860x->regmap); - if (ret) - return ret; - for (i = 0; i < 4; i++) { ret = request_threaded_irq(pm860x->irq[i], NULL, pm860x_codec_handler, IRQF_ONESHOT, @@ -1362,10 +1358,18 @@ static int pm860x_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *pm860x_get_regmap(struct device *dev) +{ + struct pm860x_priv *pm860x = dev_get_drvdata(dev); + + return pm860x->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_pm860x = { .probe = pm860x_probe, .remove = pm860x_remove, .set_bias_level = pm860x_set_bias_level, + .get_regmap = pm860x_get_regmap, .controls = pm860x_snd_controls, .num_controls = ARRAY_SIZE(pm860x_snd_controls), diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 755372509cc8..685168df04e6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -81,6 +81,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_SSM2602_SPI if SPI_MASTER select SND_SOC_SSM2602_I2C if I2C select SND_SOC_STA32X if I2C + select SND_SOC_STA350 if I2C select SND_SOC_STA529 if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS5086 if I2C @@ -270,7 +271,7 @@ config SND_SOC_AK5386 tristate "AKM AK5638 CODEC" config SND_SOC_ALC5623 - tristate + tristate "Realtek ALC5623 CODEC" config SND_SOC_ALC5632 tristate @@ -444,6 +445,10 @@ config SND_SOC_SSM2602_I2C config SND_SOC_STA32X tristate +config SND_SOC_STA350 + tristate "STA350 speaker amplifier" + depends on I2C + config SND_SOC_STA529 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index c225dae517c3..2b542306c73d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -76,6 +76,7 @@ snd-soc-ssm2602-objs := ssm2602.o snd-soc-ssm2602-spi-objs := ssm2602-spi.o snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o snd-soc-sta32x-objs := sta32x.o +snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o @@ -225,6 +226,7 @@ obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o +obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o 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 diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 1ad92cbf0b24..1fb4402bf72d 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -1139,7 +1139,7 @@ static void anc_configure(struct snd_soc_codec *codec, static int sid_status_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); mutex_lock(&codec->mutex); @@ -1153,7 +1153,7 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol, static int sid_status_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); unsigned int param, sidconf, val; int status = 1; @@ -1208,7 +1208,7 @@ out: static int anc_status_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); mutex_lock(&codec->mutex); @@ -1221,7 +1221,7 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol, static int anc_status_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); struct device *dev = codec->dev; bool apply_fir, apply_iir; @@ -1306,7 +1306,7 @@ static int filter_control_info(struct snd_kcontrol *kcontrol, static int filter_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct filter_control *fc = (struct filter_control *)kcontrol->private_value; unsigned int i; @@ -1322,7 +1322,7 @@ static int filter_control_get(struct snd_kcontrol *kcontrol, static int filter_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct filter_control *fc = (struct filter_control *)kcontrol->private_value; unsigned int i; diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 34d965a4a040..304d3003339a 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -189,28 +189,27 @@ static struct snd_soc_dai_driver ad1980_dai = { static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) { - u16 retry_cnt = 0; + unsigned int retry_cnt = 0; -retry: - if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(codec->ac97); - if (ac97_read(codec, AC97_RESET) == 0x0090) - return 1; - } - - soc_ac97_ops->reset(codec->ac97); - /* Set bit 16slot in register 74h, then every slot will has only 16 - * bits. This command is sent out in 20bit mode, in which case the - * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ - ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); - - if (ac97_read(codec, AC97_RESET) != 0x0090) - goto err; - return 0; + do { + if (try_warm && soc_ac97_ops->warm_reset) { + soc_ac97_ops->warm_reset(codec->ac97); + if (ac97_read(codec, AC97_RESET) == 0x0090) + return 1; + } -err: - while (retry_cnt++ < 10) - goto retry; + soc_ac97_ops->reset(codec->ac97); + /* + * Set bit 16slot in register 74h, then every slot will has only + * 16 bits. This command is sent out in 20bit mode, in which + * case the first nibble of data is eaten by the addr. (Tag is + * always 16 bit) + */ + ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); + + if (ac97_read(codec, AC97_RESET) == 0x0090) + return 0; + } while (retry_cnt++ < 10); printk(KERN_ERR "AD1980 AC97 reset failed\n"); return -EIO; diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 877f5737bb6b..1ff7d4d027e9 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -519,8 +519,7 @@ static const struct snd_kcontrol_new adau1373_controls[] = { SOC_ENUM("HPF Channel", adau1373_hpf_channel_enum), SOC_ENUM("Bass HPF Cutoff", adau1373_bass_hpf_cutoff_enum), - SOC_VALUE_ENUM("Bass Clip Level Threshold", - adau1373_bass_clip_level_enum), + SOC_ENUM("Bass Clip Level Threshold", adau1373_bass_clip_level_enum), SOC_ENUM("Bass LPF Cutoff", adau1373_bass_lpf_cutoff_enum), SOC_DOUBLE("Bass Playback Switch", ADAU1373_BASS2, 0, 1, 1, 0), SOC_SINGLE_TLV("Bass Playback Volume", ADAU1373_BASS2, 2, 7, 0, @@ -580,7 +579,7 @@ 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); + SOC_DAPM_ENUM("Decimator Mux", adau1373_decimator_enum); static const struct snd_kcontrol_new adau1373_left_adc_mixer_controls[] = { SOC_DAPM_SINGLE("DAC1 Switch", ADAU1373_LADC_MIXER, 4, 1, 0), @@ -694,7 +693,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = { SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1373_DIGMICCTRL, 0, 0), SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1373_DIGMICCTRL, 2, 0), - SND_SOC_DAPM_VIRT_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0, &adau1373_decimator_mux), SND_SOC_DAPM_SUPPLY("MICBIAS2", ADAU1373_PWDN_CTRL1, 5, 0, NULL, 0), diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 5062e34ee8dc..c43b93fdf0df 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -172,14 +172,14 @@ static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3); static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3); static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum); + SOC_DAPM_ENUM("Route", adav80x_aux_capture_enum); static const struct snd_kcontrol_new adav80x_capture_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum); + SOC_DAPM_ENUM("Route", adav80x_capture_enum); static const struct snd_kcontrol_new adav80x_dac_mux_ctrl = - SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum); + SOC_DAPM_ENUM("Route", adav80x_dac_enum); #define ADAV80X_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1), @@ -315,7 +315,7 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec) static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); unsigned int deemph = ucontrol->value.enumerated.item[0]; @@ -330,7 +330,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, static int adav80x_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = adav80x->deemph; diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 10adf25d4c14..1fd7f72b2a62 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -11,13 +11,14 @@ #include <linux/module.h> #include <linux/slab.h> -#include <sound/core.h> -#include <sound/soc.h> -#include <sound/initval.h> #include <linux/spi/spi.h> #include <linux/of_device.h> #include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> #include <sound/asoundef.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/initval.h> /* AK4104 registers addresses */ #define AK4104_REG_CONTROL1 0x00 @@ -47,6 +48,7 @@ struct ak4104_private { struct regmap *regmap; + struct regulator *regulator; }; static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { @@ -174,20 +176,30 @@ static int ak4104_probe(struct snd_soc_codec *codec) struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); int ret; + ret = regulator_enable(ak4104->regulator); + if (ret < 0) { + dev_err(codec->dev, "Unable to enable regulator: %d\n", ret); + return ret; + } + /* set power-up and non-reset bits */ ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); if (ret < 0) - return ret; + goto exit_disable_regulator; /* enable transmitter */ ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, AK4104_TX_TXE, AK4104_TX_TXE); if (ret < 0) - return ret; + goto exit_disable_regulator; return 0; + +exit_disable_regulator: + regulator_disable(ak4104->regulator); + return ret; } static int ak4104_remove(struct snd_soc_codec *codec) @@ -196,13 +208,42 @@ static int ak4104_remove(struct snd_soc_codec *codec) regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); + regulator_disable(ak4104->regulator); return 0; } +#ifdef CONFIG_PM +static int ak4104_soc_suspend(struct snd_soc_codec *codec) +{ + struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); + + regulator_disable(priv->regulator); + + return 0; +} + +static int ak4104_soc_resume(struct snd_soc_codec *codec) +{ + struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = regulator_enable(priv->regulator); + if (ret < 0) + return ret; + + return 0; +} +#else +#define ak4104_soc_suspend NULL +#define ak4104_soc_resume NULL +#endif /* CONFIG_PM */ + static struct snd_soc_codec_driver soc_codec_device_ak4104 = { - .probe = ak4104_probe, - .remove = ak4104_remove, + .probe = ak4104_probe, + .remove = ak4104_remove, + .suspend = ak4104_soc_suspend, + .resume = ak4104_soc_resume, .dapm_widgets = ak4104_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets), @@ -239,6 +280,13 @@ static int ak4104_spi_probe(struct spi_device *spi) if (ak4104 == NULL) return -ENOMEM; + ak4104->regulator = devm_regulator_get(&spi->dev, "vdd"); + if (IS_ERR(ak4104->regulator)) { + ret = PTR_ERR(ak4104->regulator); + dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret); + return ret; + } + ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap); if (IS_ERR(ak4104->regmap)) { ret = PTR_ERR(ak4104->regmap); diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 868c0e2da1ec..7afe8f482088 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -74,7 +74,7 @@ static int ak4641_set_deemph(struct snd_soc_codec *codec) static int ak4641_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; @@ -89,7 +89,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol, static int ak4641_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = ak4641->deemph; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 92655cc189ae..3ba4c0f11418 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -98,7 +98,7 @@ #define MGAIN0 (1 << 0) /* MIC amp gain*/ /* TIMER */ -#define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */ +#define ZTM(param) ((param & 0x3) << 4) /* ALC Zero Crossing TimeOut */ #define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2)) /* ALC_CTL1 */ @@ -134,6 +134,15 @@ /* MD_CTL4 */ #define DACH (1 << 0) +struct ak4642_drvdata { + const struct regmap_config *regmap_config; + int extended_frequencies; +}; + +struct ak4642_priv { + const struct ak4642_drvdata *drvdata; +}; + /* * Playback Volume (table 39) * @@ -148,6 +157,8 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = { SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC, 0, 0xFF, 1, out_tlv), + SOC_SINGLE("ALC Capture Switch", ALC_CTL1, 5, 1, 0), + SOC_SINGLE("ALC Capture ZC Switch", ALC_CTL1, 4, 1, 1), }; static const struct snd_kcontrol_new ak4642_headphone_control = @@ -287,7 +298,9 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; + struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); u8 pll; + int extended_freq = 0; switch (freq) { case 11289600: @@ -308,9 +321,25 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai, case 27000000: pll = PLL3 | PLL2 | PLL0; break; + case 19200000: + pll = PLL3; + extended_freq = 1; + break; + case 13000000: + pll = PLL3 | PLL2 | PLL1; + extended_freq = 1; + break; + case 26000000: + pll = PLL3 | PLL2 | PLL1 | PLL0; + extended_freq = 1; + break; default: return -EINVAL; } + + if (extended_freq && !priv->drvdata->extended_frequencies) + return -EINVAL; + snd_soc_update_bits(codec, MD_CTL1, PLL_MASK, pll); return 0; @@ -505,30 +534,52 @@ static const struct regmap_config ak4648_regmap = { .num_reg_defaults = ARRAY_SIZE(ak4648_reg), }; +static const struct ak4642_drvdata ak4642_drvdata = { + .regmap_config = &ak4642_regmap, +}; + +static const struct ak4642_drvdata ak4643_drvdata = { + .regmap_config = &ak4642_regmap, +}; + +static const struct ak4642_drvdata ak4648_drvdata = { + .regmap_config = &ak4648_regmap, + .extended_frequencies = 1, +}; + static struct of_device_id ak4642_of_match[]; static int ak4642_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct device_node *np = i2c->dev.of_node; - const struct regmap_config *regmap_config = NULL; + const struct ak4642_drvdata *drvdata = NULL; struct regmap *regmap; + struct ak4642_priv *priv; if (np) { const struct of_device_id *of_id; of_id = of_match_device(ak4642_of_match, &i2c->dev); if (of_id) - regmap_config = of_id->data; + drvdata = of_id->data; } else { - regmap_config = (const struct regmap_config *)id->driver_data; + drvdata = (const struct ak4642_drvdata *)id->driver_data; } - if (!regmap_config) { + if (!drvdata) { dev_err(&i2c->dev, "Unknown device type\n"); return -EINVAL; } - regmap = devm_regmap_init_i2c(i2c, regmap_config); + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->drvdata = drvdata; + + i2c_set_clientdata(i2c, priv); + + regmap = devm_regmap_init_i2c(i2c, drvdata->regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -543,17 +594,17 @@ static int ak4642_i2c_remove(struct i2c_client *client) } static struct of_device_id ak4642_of_match[] = { - { .compatible = "asahi-kasei,ak4642", .data = &ak4642_regmap}, - { .compatible = "asahi-kasei,ak4643", .data = &ak4642_regmap}, - { .compatible = "asahi-kasei,ak4648", .data = &ak4648_regmap}, + { .compatible = "asahi-kasei,ak4642", .data = &ak4642_drvdata}, + { .compatible = "asahi-kasei,ak4643", .data = &ak4643_drvdata}, + { .compatible = "asahi-kasei,ak4648", .data = &ak4648_drvdata}, {}, }; MODULE_DEVICE_TABLE(of, ak4642_of_match); static const struct i2c_device_id ak4642_i2c_id[] = { - { "ak4642", (kernel_ulong_t)&ak4642_regmap }, - { "ak4643", (kernel_ulong_t)&ak4642_regmap }, - { "ak4648", (kernel_ulong_t)&ak4648_regmap }, + { "ak4642", (kernel_ulong_t)&ak4642_drvdata }, + { "ak4643", (kernel_ulong_t)&ak4643_drvdata }, + { "ak4648", (kernel_ulong_t)&ak4648_drvdata }, { } }; MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id); diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index f500905e9373..9d0755aa1d16 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -23,6 +23,7 @@ #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/slab.h> +#include <linux/of.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -998,8 +999,10 @@ static int alc5623_i2c_probe(struct i2c_client *client, { struct alc5623_platform_data *pdata; struct alc5623_priv *alc5623; + struct device_node *np; unsigned int vid1, vid2; int ret; + u32 val32; alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), GFP_KERNEL); @@ -1018,13 +1021,13 @@ static int alc5623_i2c_probe(struct i2c_client *client, dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret); return ret; } - vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8); 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; } + vid2 >>= 8; if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { dev_err(&client->dev, "unknown or wrong codec\n"); @@ -1040,6 +1043,16 @@ static int alc5623_i2c_probe(struct i2c_client *client, if (pdata) { alc5623->add_ctrl = pdata->add_ctrl; alc5623->jack_det_ctrl = pdata->jack_det_ctrl; + } else { + if (client->dev.of_node) { + np = client->dev.of_node; + ret = of_property_read_u32(np, "add-ctrl", &val32); + if (!ret) + alc5623->add_ctrl = val32; + ret = of_property_read_u32(np, "jack-det-ctrl", &val32); + if (!ret) + alc5623->jack_det_ctrl = val32; + } } alc5623->id = vid2; @@ -1081,11 +1094,18 @@ static const struct i2c_device_id alc5623_i2c_table[] = { }; MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table); +static const struct of_device_id alc5623_of_match[] = { + { .compatible = "realtek,alc5623", }, + { } +}; +MODULE_DEVICE_TABLE(of, alc5623_of_match); + /* i2c codec control layer */ static struct i2c_driver alc5623_i2c_driver = { .driver = { .name = "alc562x-codec", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(alc5623_of_match), }, .probe = alc5623_i2c_probe, .remove = alc5623_i2c_remove, diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 16df0f913353..05ae17f5bca3 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -107,7 +107,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_MUX_CTL_DECL(name) \ const struct snd_kcontrol_new name##_mux = \ - SOC_DAPM_VALUE_ENUM("Route", name##_enum) + SOC_DAPM_ENUM("Route", name##_enum) #define ARIZONA_MUX_ENUMS(name, base_reg) \ static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg); \ @@ -128,7 +128,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40) #define ARIZONA_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) #define ARIZONA_MUX_WIDGETS(name, name_str) \ ARIZONA_MUX(name_str " Input", &name##_mux) diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 1e25c7af853b..537327c7f7f1 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -139,8 +139,6 @@ static int cq93vc_probe(struct snd_soc_codec *codec) davinci_vc->cq93vc.codec = codec; - snd_soc_codec_set_cache_io(codec, davinci_vc->regmap); - /* Off, with power on */ cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -154,11 +152,19 @@ static int cq93vc_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *cq93vc_get_regmap(struct device *dev) +{ + struct davinci_vc *davinci_vc = dev->platform_data; + + return davinci_vc->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { .set_bias_level = cq93vc_set_bias_level, .probe = cq93vc_probe, .remove = cq93vc_remove, .resume = cq93vc_resume, + .get_regmap = cq93vc_get_regmap, .controls = cq93vc_snd_controls, .num_controls = ARRAY_SIZE(cq93vc_snd_controls), }; diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 3920e6264948..9947a9583679 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -438,7 +438,7 @@ static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute) static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); int left = !ucontrol->value.integer.value[0]; int right = !ucontrol->value.integer.value[1]; diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index aef4965750c7..93cec52f4733 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -284,7 +284,7 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec) static int cs4271_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = cs4271->deemph; @@ -294,7 +294,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol, static int cs4271_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); cs4271->deemph = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 6aa69e5aaa3f..09488d97de60 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -54,7 +54,7 @@ struct cs42l51_private { static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3; switch (value) { @@ -82,7 +82,7 @@ static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned char val; switch (ucontrol->value.integer.value[0]) { diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index b7635400f31b..071fc77f2f06 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1217,8 +1217,10 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, } if (cs42l52->pdata.reset_gpio) { - ret = gpio_request_one(cs42l52->pdata.reset_gpio, - GPIOF_OUT_INIT_HIGH, "CS42L52 /RST"); + ret = devm_gpio_request_one(&i2c_client->dev, + cs42l52->pdata.reset_gpio, + GPIOF_OUT_INIT_HIGH, + "CS42L52 /RST"); if (ret < 0) { dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n", cs42l52->pdata.reset_gpio, ret); diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 0ee60a19a263..ae3717992d56 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1443,8 +1443,10 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, i2c_set_clientdata(i2c_client, cs42l73); if (cs42l73->pdata.reset_gpio) { - ret = gpio_request_one(cs42l73->pdata.reset_gpio, - GPIOF_OUT_INIT_HIGH, "CS42L73 /RST"); + ret = devm_gpio_request_one(&i2c_client->dev, + cs42l73->pdata.reset_gpio, + GPIOF_OUT_INIT_HIGH, + "CS42L73 /RST"); if (ret < 0) { dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n", cs42l73->pdata.reset_gpio, ret); diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 85020322eee7..a25bc6061a30 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -248,8 +248,7 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_codec *codec = dai->codec; struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 ratio = cs42xx8->sysclk / params_rate(params); diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 137e8ebc092c..21810e5f3321 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -335,7 +335,7 @@ static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel, static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); if (ucontrol->value.integer.value[0]) { /* Check if noise suppression is enabled */ @@ -358,7 +358,7 @@ static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); u8 val; if (ucontrol->value.integer.value[0]) { diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 738fa18a50d2..9ec577f0edb4 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -345,7 +345,7 @@ static void da7213_alc_calib(struct snd_soc_codec *codec) static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); int ret; @@ -361,7 +361,7 @@ static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol, static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); /* Force ALC offset calibration if enabling ALC */ diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 48f3fef68484..2fae31cb0067 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -332,7 +332,7 @@ static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum, static int da732x_hpf_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value; unsigned int reg = enum_ctrl->reg; unsigned int sel = ucontrol->value.integer.value[0]; @@ -360,7 +360,7 @@ static int da732x_hpf_set(struct snd_kcontrol *kcontrol, static int da732x_hpf_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value; unsigned int reg = enum_ctrl->reg; int val; diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 4ff06b50fbba..ad19cc56702b 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -484,7 +484,7 @@ static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); u8 reg_val, adc_left, adc_right, mic_left, mic_right; int avg_left_data, avg_right_data, offset_l, offset_r; diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 4f048db9f55f..a924bb9d7886 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -49,7 +49,7 @@ static const struct reg_default lm4857_default_regs[] = { static int lm4857_get_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = lm4857->mode; @@ -60,7 +60,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol, static int lm4857_set_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); uint8_t value = ucontrol->value.integer.value[0]; diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index ec481fc428c7..e1c196a41930 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -43,7 +43,7 @@ static struct reg_default max9768_default_regs[] = { static int max9768_get_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); int val = gpio_get_value_cansleep(max9768->mute_gpio); @@ -55,7 +55,7 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol, static int max9768_set_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index ef7cf89f5623..9134982807b5 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -635,7 +635,7 @@ static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum, static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); unsigned int sel = ucontrol->value.integer.value[0]; @@ -649,7 +649,7 @@ static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol, static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = max98088->mic1pre; @@ -659,7 +659,7 @@ static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol, static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); unsigned int sel = ucontrol->value.integer.value[0]; @@ -673,7 +673,7 @@ static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol, static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = max98088->mic2pre; @@ -1750,7 +1750,7 @@ static void max98088_setup_eq2(struct snd_soc_codec *codec) static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); struct max98088_pdata *pdata = max98088->pdata; int channel = max98088_get_channel(codec, kcontrol->id.name); @@ -1782,7 +1782,7 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol, static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); int channel = max98088_get_channel(codec, kcontrol->id.name); struct max98088_cdata *cdata; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index f7b0b37aa858..906534d18d3f 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -255,6 +255,7 @@ static struct reg_default max98090_reg[] = { static bool max98090_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { + case M98090_REG_SOFTWARE_RESET: case M98090_REG_DEVICE_STATUS: case M98090_REG_JACK_STATUS: case M98090_REG_REVISION_ID: @@ -389,6 +390,7 @@ static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0); +static const DECLARE_TLV_DB_SCALE(max98090_sdg_tlv, 50, 200, 0); static const unsigned int max98090_mixout_tlv[] = { TLV_DB_RANGE_HEAD(2), @@ -426,7 +428,7 @@ static const unsigned int max98090_rcv_lout_tlv[] = { static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -466,7 +468,7 @@ static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol, static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -665,7 +667,7 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = { SOC_SINGLE_EXT_TLV("Digital Sidetone Volume", M98090_REG_ADC_SIDETONE, M98090_DVST_SHIFT, M98090_DVST_NUM - 1, 1, max98090_get_enab_tlv, - max98090_put_enab_tlv, max98090_micboost_tlv), + max98090_put_enab_tlv, max98090_sdg_tlv), SOC_SINGLE_TLV("Digital Coarse Volume", M98090_REG_DAI_PLAYBACK_LEVEL, M98090_DVG_SHIFT, M98090_DVG_NUM - 1, 0, max98090_dvg_tlv), @@ -875,7 +877,7 @@ static const char *dmic_mux_text[] = { "ADC", "DMIC" }; 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); + SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum); static const char *max98090_micpre_text[] = { "Off", "On" }; @@ -1175,8 +1177,7 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM, 0, 0, &max98090_mic2_mux), - SND_SOC_DAPM_VIRT_MUX("DMIC Mux", SND_SOC_NOPM, - 0, 0, &max98090_dmic_mux), + SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &max98090_dmic_mux), SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event, @@ -2373,6 +2374,8 @@ static int max98090_runtime_resume(struct device *dev) regcache_cache_only(max98090->regmap, false); + max98090_reset(max98090); + regcache_sync(max98090->regmap); return 0; @@ -2388,9 +2391,34 @@ static int max98090_runtime_suspend(struct device *dev) } #endif +#ifdef CONFIG_PM +static int max98090_resume(struct device *dev) +{ + struct max98090_priv *max98090 = dev_get_drvdata(dev); + unsigned int status; + + regcache_mark_dirty(max98090->regmap); + + max98090_reset(max98090); + + /* clear IRQ status */ + regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status); + + regcache_sync(max98090->regmap); + + return 0; +} + +static int max98090_suspend(struct device *dev) +{ + return 0; +} +#endif + static const struct dev_pm_ops max98090_pm = { SET_RUNTIME_PM_OPS(max98090_runtime_suspend, max98090_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(max98090_suspend, max98090_resume) }; static const struct i2c_device_id max98090_i2c_id[] = { diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 03f0536e6f61..5d4c621dbf99 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -612,7 +612,7 @@ static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum, static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); unsigned int sel = ucontrol->value.integer.value[0]; @@ -626,7 +626,7 @@ static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol, static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = max98095->mic1pre; @@ -636,7 +636,7 @@ static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol, static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); unsigned int sel = ucontrol->value.integer.value[0]; @@ -650,7 +650,7 @@ static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol, static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = max98095->mic2pre; @@ -1737,7 +1737,7 @@ static int max98095_get_eq_channel(const char *name) static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); struct max98095_pdata *pdata = max98095->pdata; int channel = max98095_get_eq_channel(kcontrol->id.name); @@ -1801,7 +1801,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); int channel = max98095_get_eq_channel(kcontrol->id.name); struct max98095_cdata *cdata; @@ -1891,7 +1891,7 @@ static int max98095_get_bq_channel(struct snd_soc_codec *codec, static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); struct max98095_pdata *pdata = max98095->pdata; int channel = max98095_get_bq_channel(codec, kcontrol->id.name); @@ -1952,7 +1952,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); int channel = max98095_get_bq_channel(codec, kcontrol->id.name); struct max98095_cdata *cdata; diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 2c59b1fb69dc..0b0a4ca22da0 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -409,7 +409,7 @@ static const char * const 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); + SOC_DAPM_ENUM("Route", adcl_enum); static const char * const adcr_enum_text[] = { "MC1R", "MC2", "RXINR", "TXIN", @@ -418,7 +418,7 @@ static const char * const 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); + SOC_DAPM_ENUM("Route", adcr_enum); static const struct snd_kcontrol_new samp_ctl = SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0); @@ -478,9 +478,9 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl), SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl), - SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0, &left_input_mux), - SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0, &right_input_mux), SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0, @@ -608,14 +608,6 @@ static struct snd_kcontrol_new mc13783_control_list[] = { static int mc13783_probe(struct snd_soc_codec *codec) { struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = snd_soc_codec_set_cache_io(codec, - dev_get_regmap(codec->dev->parent, NULL)); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } /* these are the reset values */ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893); @@ -735,9 +727,15 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = { } }; +static struct regmap *mc13783_get_regmap(struct device *dev) +{ + return dev_get_regmap(dev->parent, NULL); +} + static struct snd_soc_codec_driver soc_codec_dev_mc13783 = { .probe = mc13783_probe, .remove = mc13783_remove, + .get_regmap = mc13783_get_regmap, .controls = mc13783_control_list, .num_controls = ARRAY_SIZE(mc13783_control_list), .dapm_widgets = mc13783_dapm_widgets, diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index e427544183d7..a722a023c262 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -115,7 +115,7 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec) static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = priv->deemph; @@ -126,7 +126,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol, static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); priv->deemph = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 4b4c0c7bb918..163ec3855fd4 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -269,7 +269,7 @@ 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("DSP Program", pcm512x_dsp_program), SOC_ENUM("Clock Missing Period", pcm512x_clk_missing), SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), @@ -517,6 +517,7 @@ void pcm512x_remove(struct device *dev) } EXPORT_SYMBOL_GPL(pcm512x_remove); +#ifdef CONFIG_PM_RUNTIME static int pcm512x_suspend(struct device *dev) { struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); @@ -578,6 +579,7 @@ static int pcm512x_resume(struct device *dev) return 0; } +#endif const struct dev_pm_ops pcm512x_pm_ops = { SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index d4c229f0233f..30e234708579 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -188,7 +188,7 @@ static unsigned int mic_bst_tlv[] = { static int rt5631_dmic_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = rt5631->dmic_used_flag; @@ -199,7 +199,7 @@ static int rt5631_dmic_get(struct snd_kcontrol *kcontrol, static int rt5631_dmic_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); rt5631->dmic_used_flag = ucontrol->value.integer.value[0]; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 68b4dd622b87..1b452e3b449a 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -824,7 +824,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum, 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); + SOC_DAPM_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); static const char * const rt5640_dac_r2_src[] = { "IF2", @@ -859,7 +859,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum, 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); + SOC_DAPM_ENUM("DAI select", rt5640_dai_iis_map_enum); /* SDI select */ static const char * const rt5640_sdi_sel[] = { diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index d3ed1be5a186..b56caefcf664 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -296,7 +296,7 @@ static int dac_info_volsw(struct snd_kcontrol *kcontrol, static int dac_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int reg; int l; int r; @@ -349,7 +349,7 @@ static int dac_get_volsw(struct snd_kcontrol *kcontrol, static int dac_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int reg; int l; int r; diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 244c097cd905..f26befb0c297 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -208,13 +208,6 @@ out: return err; } -static int si476x_codec_probe(struct snd_soc_codec *codec) -{ - struct regmap *regmap = dev_get_regmap(codec->dev->parent, NULL); - - return snd_soc_codec_set_cache_io(codec, regmap); -} - static struct snd_soc_dai_ops si476x_dai_ops = { .hw_params = si476x_codec_hw_params, .set_fmt = si476x_codec_set_dai_fmt, @@ -238,8 +231,13 @@ static struct snd_soc_dai_driver si476x_dai = { .ops = &si476x_dai_ops, }; +static struct regmap *si476x_get_regmap(struct device *dev) +{ + return dev_get_regmap(dev->parent, NULL); +} + static struct snd_soc_codec_driver soc_codec_dev_si476x = { - .probe = si476x_codec_probe, + .get_regmap = si476x_get_regmap, .dapm_widgets = si476x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets), .dapm_routes = si476x_dapm_routes, diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 12577749b17b..0579d187135b 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -243,7 +243,7 @@ static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol, static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int numcoef = kcontrol->private_value >> 16; int index = kcontrol->private_value & 0xffff; unsigned int cfud; @@ -272,7 +272,7 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); int numcoef = kcontrol->private_value >> 16; int index = kcontrol->private_value & 0xffff; diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c new file mode 100644 index 000000000000..12ebbaf5d95f --- /dev/null +++ b/sound/soc/codecs/sta350.c @@ -0,0 +1,1266 @@ +/* + * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system + * + * Copyright: 2014 Raumfeld GmbH + * Author: Sven Brandau <info@brandau.biz> + * + * based on code from: + * Raumfeld GmbH + * Johannes Stezenbach <js@sig21.net> + * Wolfson Microelectronics PLC. + * Mark Brown <broonie@opensource.wolfsonmicro.com> + * Freescale Semiconductor, Inc. + * Timur Tabi <timur@freescale.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include <sound/sta350.h> +#include "sta350.h" + +#define STA350_RATES (SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000) + +#define STA350_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) + +/* Power-up register defaults */ +static const struct reg_default sta350_regs[] = { + { 0x0, 0x63 }, + { 0x1, 0x80 }, + { 0x2, 0xdf }, + { 0x3, 0x40 }, + { 0x4, 0xc2 }, + { 0x5, 0x5c }, + { 0x6, 0x00 }, + { 0x7, 0xff }, + { 0x8, 0x60 }, + { 0x9, 0x60 }, + { 0xa, 0x60 }, + { 0xb, 0x00 }, + { 0xc, 0x00 }, + { 0xd, 0x00 }, + { 0xe, 0x00 }, + { 0xf, 0x40 }, + { 0x10, 0x80 }, + { 0x11, 0x77 }, + { 0x12, 0x6a }, + { 0x13, 0x69 }, + { 0x14, 0x6a }, + { 0x15, 0x69 }, + { 0x16, 0x00 }, + { 0x17, 0x00 }, + { 0x18, 0x00 }, + { 0x19, 0x00 }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x00 }, + { 0x1e, 0x00 }, + { 0x1f, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x23, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x27, 0x2a }, + { 0x28, 0xc0 }, + { 0x29, 0xf3 }, + { 0x2a, 0x33 }, + { 0x2b, 0x00 }, + { 0x2c, 0x0c }, + { 0x31, 0x00 }, + { 0x36, 0x00 }, + { 0x37, 0x00 }, + { 0x38, 0x00 }, + { 0x39, 0x01 }, + { 0x3a, 0xee }, + { 0x3b, 0xff }, + { 0x3c, 0x7e }, + { 0x3d, 0xc0 }, + { 0x3e, 0x26 }, + { 0x3f, 0x00 }, + { 0x48, 0x00 }, + { 0x49, 0x00 }, + { 0x4a, 0x00 }, + { 0x4b, 0x04 }, + { 0x4c, 0x00 }, +}; + +static const struct regmap_range sta350_write_regs_range[] = { + regmap_reg_range(STA350_CONFA, STA350_AUTO2), + regmap_reg_range(STA350_C1CFG, STA350_FDRC2), + regmap_reg_range(STA350_EQCFG, STA350_EVOLRES), + regmap_reg_range(STA350_NSHAPE, STA350_MISC2), +}; + +static const struct regmap_range sta350_read_regs_range[] = { + regmap_reg_range(STA350_CONFA, STA350_AUTO2), + regmap_reg_range(STA350_C1CFG, STA350_STATUS), + regmap_reg_range(STA350_EQCFG, STA350_EVOLRES), + regmap_reg_range(STA350_NSHAPE, STA350_MISC2), +}; + +static const struct regmap_range sta350_volatile_regs_range[] = { + regmap_reg_range(STA350_CFADDR2, STA350_CFUD), + regmap_reg_range(STA350_STATUS, STA350_STATUS), +}; + +static const struct regmap_access_table sta350_write_regs = { + .yes_ranges = sta350_write_regs_range, + .n_yes_ranges = ARRAY_SIZE(sta350_write_regs_range), +}; + +static const struct regmap_access_table sta350_read_regs = { + .yes_ranges = sta350_read_regs_range, + .n_yes_ranges = ARRAY_SIZE(sta350_read_regs_range), +}; + +static const struct regmap_access_table sta350_volatile_regs = { + .yes_ranges = sta350_volatile_regs_range, + .n_yes_ranges = ARRAY_SIZE(sta350_volatile_regs_range), +}; + +/* regulator power supply names */ +static const char * const sta350_supply_names[] = { + "vdd-dig", /* digital supply, 3.3V */ + "vdd-pll", /* pll supply, 3.3V */ + "vcc" /* power amp supply, 5V - 26V */ +}; + +/* codec private data */ +struct sta350_priv { + struct regmap *regmap; + struct regulator_bulk_data supplies[ARRAY_SIZE(sta350_supply_names)]; + struct sta350_platform_data *pdata; + + unsigned int mclk; + unsigned int format; + + u32 coef_shadow[STA350_COEF_COUNT]; + int shutdown; + + struct gpio_desc *gpiod_nreset; + struct gpio_desc *gpiod_power_down; + + struct mutex coeff_lock; +}; + +static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1); +static const DECLARE_TLV_DB_SCALE(tone_tlv, -1200, 200, 0); + +static const char * const sta350_drc_ac[] = { + "Anti-Clipping", "Dynamic Range Compression" +}; +static const char * const sta350_auto_gc_mode[] = { + "User", "AC no clipping", "AC limited clipping (10%)", + "DRC nighttime listening mode" +}; +static const char * const sta350_auto_xo_mode[] = { + "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", + "200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", + "340Hz", "360Hz" +}; +static const char * const sta350_binary_output[] = { + "FFX 3-state output - normal operation", "Binary output" +}; +static const char * const sta350_limiter_select[] = { + "Limiter Disabled", "Limiter #1", "Limiter #2" +}; +static const char * const sta350_limiter_attack_rate[] = { + "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024", + "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752", + "0.0645", "0.0564", "0.0501", "0.0451" +}; +static const char * const sta350_limiter_release_rate[] = { + "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", + "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", + "0.0134", "0.0117", "0.0110", "0.0104" +}; +static const char * const sta350_noise_shaper_type[] = { + "Third order", "Fourth order" +}; + +static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_attack_tlv, + 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), + 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), +); + +static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_release_tlv, + 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), + 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), + 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), +); + +static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_attack_tlv, + 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), + 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), + 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), +); + +static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_release_tlv, + 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), + 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), + 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), + 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), + 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), +); + +static SOC_ENUM_SINGLE_DECL(sta350_drc_ac_enum, + STA350_CONFD, STA350_CONFD_DRC_SHIFT, + sta350_drc_ac); +static SOC_ENUM_SINGLE_DECL(sta350_noise_shaper_enum, + STA350_CONFE, STA350_CONFE_NSBW_SHIFT, + sta350_noise_shaper_type); +static SOC_ENUM_SINGLE_DECL(sta350_auto_gc_enum, + STA350_AUTO1, STA350_AUTO1_AMGC_SHIFT, + sta350_auto_gc_mode); +static SOC_ENUM_SINGLE_DECL(sta350_auto_xo_enum, + STA350_AUTO2, STA350_AUTO2_XO_SHIFT, + sta350_auto_xo_mode); +static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch1_enum, + STA350_C1CFG, STA350_CxCFG_BO_SHIFT, + sta350_binary_output); +static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch2_enum, + STA350_C2CFG, STA350_CxCFG_BO_SHIFT, + sta350_binary_output); +static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch3_enum, + STA350_C3CFG, STA350_CxCFG_BO_SHIFT, + sta350_binary_output); +static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch1_enum, + STA350_C1CFG, STA350_CxCFG_LS_SHIFT, + sta350_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch2_enum, + STA350_C2CFG, STA350_CxCFG_LS_SHIFT, + sta350_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch3_enum, + STA350_C3CFG, STA350_CxCFG_LS_SHIFT, + sta350_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta350_limiter1_attack_rate_enum, + STA350_L1AR, STA350_LxA_SHIFT, + sta350_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta350_limiter2_attack_rate_enum, + STA350_L2AR, STA350_LxA_SHIFT, + sta350_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta350_limiter1_release_rate_enum, + STA350_L1AR, STA350_LxR_SHIFT, + sta350_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta350_limiter2_release_rate_enum, + STA350_L2AR, STA350_LxR_SHIFT, + sta350_limiter_release_rate); + +/* + * byte array controls for setting biquad, mixer, scaling coefficients; + * for biquads all five coefficients need to be set in one go, + * mixer and pre/postscale coefs can be set individually; + * each coef is 24bit, the bytes are ordered in the same way + * as given in the STA350 data sheet (big endian; b1, b2, a1, a2, b0) + */ + +static int sta350_coefficient_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int numcoef = kcontrol->private_value >> 16; + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = 3 * numcoef; + return 0; +} + +static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + int numcoef = kcontrol->private_value >> 16; + int index = kcontrol->private_value & 0xffff; + unsigned int cfud, val; + int i, ret = 0; + + mutex_lock(&sta350->coeff_lock); + + /* preserve reserved bits in STA350_CFUD */ + regmap_read(sta350->regmap, STA350_CFUD, &cfud); + cfud &= 0xf0; + /* + * chip documentation does not say if the bits are self clearing, + * so do it explicitly + */ + regmap_write(sta350->regmap, STA350_CFUD, cfud); + + regmap_write(sta350->regmap, STA350_CFADDR2, index); + if (numcoef == 1) { + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04); + } else if (numcoef == 5) { + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08); + } else { + ret = -EINVAL; + goto exit_unlock; + } + + for (i = 0; i < 3 * numcoef; i++) { + regmap_read(sta350->regmap, STA350_B1CF1 + i, &val); + ucontrol->value.bytes.data[i] = val; + } + +exit_unlock: + mutex_unlock(&sta350->coeff_lock); + + return ret; +} + +static int sta350_coefficient_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + int numcoef = kcontrol->private_value >> 16; + int index = kcontrol->private_value & 0xffff; + unsigned int cfud; + int i; + + /* preserve reserved bits in STA350_CFUD */ + regmap_read(sta350->regmap, STA350_CFUD, &cfud); + cfud &= 0xf0; + /* + * chip documentation does not say if the bits are self clearing, + * so do it explicitly + */ + regmap_write(sta350->regmap, STA350_CFUD, cfud); + + regmap_write(sta350->regmap, STA350_CFADDR2, index); + for (i = 0; i < numcoef && (index + i < STA350_COEF_COUNT); i++) + sta350->coef_shadow[index + i] = + (ucontrol->value.bytes.data[3 * i] << 16) + | (ucontrol->value.bytes.data[3 * i + 1] << 8) + | (ucontrol->value.bytes.data[3 * i + 2]); + for (i = 0; i < 3 * numcoef; i++) + regmap_write(sta350->regmap, STA350_B1CF1 + i, + ucontrol->value.bytes.data[i]); + if (numcoef == 1) + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01); + else if (numcoef == 5) + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x02); + else + return -EINVAL; + + return 0; +} + +static int sta350_sync_coef_shadow(struct snd_soc_codec *codec) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + unsigned int cfud; + int i; + + /* preserve reserved bits in STA350_CFUD */ + regmap_read(sta350->regmap, STA350_CFUD, &cfud); + cfud &= 0xf0; + + for (i = 0; i < STA350_COEF_COUNT; i++) { + regmap_write(sta350->regmap, STA350_CFADDR2, i); + regmap_write(sta350->regmap, STA350_B1CF1, + (sta350->coef_shadow[i] >> 16) & 0xff); + regmap_write(sta350->regmap, STA350_B1CF2, + (sta350->coef_shadow[i] >> 8) & 0xff); + regmap_write(sta350->regmap, STA350_B1CF3, + (sta350->coef_shadow[i]) & 0xff); + /* + * chip documentation does not say if the bits are + * self-clearing, so do it explicitly + */ + regmap_write(sta350->regmap, STA350_CFUD, cfud); + regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01); + } + return 0; +} + +static int sta350_cache_sync(struct snd_soc_codec *codec) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + unsigned int mute; + int rc; + + /* mute during register sync */ + regmap_read(sta350->regmap, STA350_CFUD, &mute); + regmap_write(sta350->regmap, STA350_MMUTE, mute | STA350_MMUTE_MMUTE); + sta350_sync_coef_shadow(codec); + rc = regcache_sync(sta350->regmap); + regmap_write(sta350->regmap, STA350_MMUTE, mute); + return rc; +} + +#define SINGLE_COEF(xname, index) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = sta350_coefficient_info, \ + .get = sta350_coefficient_get,\ + .put = sta350_coefficient_put, \ + .private_value = index | (1 << 16) } + +#define BIQUAD_COEFS(xname, index) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = sta350_coefficient_info, \ + .get = sta350_coefficient_get,\ + .put = sta350_coefficient_put, \ + .private_value = index | (5 << 16) } + +static const struct snd_kcontrol_new sta350_snd_controls[] = { +SOC_SINGLE_TLV("Master Volume", STA350_MVOL, 0, 0xff, 1, mvol_tlv), +/* VOL */ +SOC_SINGLE_TLV("Ch1 Volume", STA350_C1VOL, 0, 0xff, 1, chvol_tlv), +SOC_SINGLE_TLV("Ch2 Volume", STA350_C2VOL, 0, 0xff, 1, chvol_tlv), +SOC_SINGLE_TLV("Ch3 Volume", STA350_C3VOL, 0, 0xff, 1, chvol_tlv), +/* CONFD */ +SOC_SINGLE("High Pass Filter Bypass Switch", + STA350_CONFD, STA350_CONFD_HPB_SHIFT, 1, 1), +SOC_SINGLE("De-emphasis Filter Switch", + STA350_CONFD, STA350_CONFD_DEMP_SHIFT, 1, 0), +SOC_SINGLE("DSP Bypass Switch", + STA350_CONFD, STA350_CONFD_DSPB_SHIFT, 1, 0), +SOC_SINGLE("Post-scale Link Switch", + STA350_CONFD, STA350_CONFD_PSL_SHIFT, 1, 0), +SOC_SINGLE("Biquad Coefficient Link Switch", + STA350_CONFD, STA350_CONFD_BQL_SHIFT, 1, 0), +SOC_ENUM("Compressor/Limiter Switch", sta350_drc_ac_enum), +SOC_ENUM("Noise Shaper Bandwidth", sta350_noise_shaper_enum), +SOC_SINGLE("Zero-detect Mute Enable Switch", + STA350_CONFD, STA350_CONFD_ZDE_SHIFT, 1, 0), +SOC_SINGLE("Submix Mode Switch", + STA350_CONFD, STA350_CONFD_SME_SHIFT, 1, 0), +/* CONFE */ +SOC_SINGLE("Zero Cross Switch", STA350_CONFE, STA350_CONFE_ZCE_SHIFT, 1, 0), +SOC_SINGLE("Soft Ramp Switch", STA350_CONFE, STA350_CONFE_SVE_SHIFT, 1, 0), +/* MUTE */ +SOC_SINGLE("Master Switch", STA350_MMUTE, STA350_MMUTE_MMUTE_SHIFT, 1, 1), +SOC_SINGLE("Ch1 Switch", STA350_MMUTE, STA350_MMUTE_C1M_SHIFT, 1, 1), +SOC_SINGLE("Ch2 Switch", STA350_MMUTE, STA350_MMUTE_C2M_SHIFT, 1, 1), +SOC_SINGLE("Ch3 Switch", STA350_MMUTE, STA350_MMUTE_C3M_SHIFT, 1, 1), +/* AUTOx */ +SOC_ENUM("Automode GC", sta350_auto_gc_enum), +SOC_ENUM("Automode XO", sta350_auto_xo_enum), +/* CxCFG */ +SOC_SINGLE("Ch1 Tone Control Bypass Switch", + STA350_C1CFG, STA350_CxCFG_TCB_SHIFT, 1, 0), +SOC_SINGLE("Ch2 Tone Control Bypass Switch", + STA350_C2CFG, STA350_CxCFG_TCB_SHIFT, 1, 0), +SOC_SINGLE("Ch1 EQ Bypass Switch", + STA350_C1CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0), +SOC_SINGLE("Ch2 EQ Bypass Switch", + STA350_C2CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0), +SOC_SINGLE("Ch1 Master Volume Bypass Switch", + STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), +SOC_SINGLE("Ch2 Master Volume Bypass Switch", + STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), +SOC_SINGLE("Ch3 Master Volume Bypass Switch", + STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), +SOC_ENUM("Ch1 Binary Output Select", sta350_binary_output_ch1_enum), +SOC_ENUM("Ch2 Binary Output Select", sta350_binary_output_ch2_enum), +SOC_ENUM("Ch3 Binary Output Select", sta350_binary_output_ch3_enum), +SOC_ENUM("Ch1 Limiter Select", sta350_limiter_ch1_enum), +SOC_ENUM("Ch2 Limiter Select", sta350_limiter_ch2_enum), +SOC_ENUM("Ch3 Limiter Select", sta350_limiter_ch3_enum), +/* TONE */ +SOC_SINGLE_RANGE_TLV("Bass Tone Control Volume", + STA350_TONE, STA350_TONE_BTC_SHIFT, 1, 13, 0, tone_tlv), +SOC_SINGLE_RANGE_TLV("Treble Tone Control Volume", + STA350_TONE, STA350_TONE_TTC_SHIFT, 1, 13, 0, tone_tlv), +SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta350_limiter1_attack_rate_enum), +SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta350_limiter2_attack_rate_enum), +SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta350_limiter1_release_rate_enum), +SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta350_limiter2_release_rate_enum), + +/* + * depending on mode, the attack/release thresholds have + * two different enum definitions; provide both + */ +SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", + STA350_L1ATRT, STA350_LxA_SHIFT, + 16, 0, sta350_limiter_ac_attack_tlv), +SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", + STA350_L2ATRT, STA350_LxA_SHIFT, + 16, 0, sta350_limiter_ac_attack_tlv), +SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", + STA350_L1ATRT, STA350_LxR_SHIFT, + 16, 0, sta350_limiter_ac_release_tlv), +SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", + STA350_L2ATRT, STA350_LxR_SHIFT, + 16, 0, sta350_limiter_ac_release_tlv), +SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", + STA350_L1ATRT, STA350_LxA_SHIFT, + 16, 0, sta350_limiter_drc_attack_tlv), +SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", + STA350_L2ATRT, STA350_LxA_SHIFT, + 16, 0, sta350_limiter_drc_attack_tlv), +SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", + STA350_L1ATRT, STA350_LxR_SHIFT, + 16, 0, sta350_limiter_drc_release_tlv), +SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", + STA350_L2ATRT, STA350_LxR_SHIFT, + 16, 0, sta350_limiter_drc_release_tlv), + +BIQUAD_COEFS("Ch1 - Biquad 1", 0), +BIQUAD_COEFS("Ch1 - Biquad 2", 5), +BIQUAD_COEFS("Ch1 - Biquad 3", 10), +BIQUAD_COEFS("Ch1 - Biquad 4", 15), +BIQUAD_COEFS("Ch2 - Biquad 1", 20), +BIQUAD_COEFS("Ch2 - Biquad 2", 25), +BIQUAD_COEFS("Ch2 - Biquad 3", 30), +BIQUAD_COEFS("Ch2 - Biquad 4", 35), +BIQUAD_COEFS("High-pass", 40), +BIQUAD_COEFS("Low-pass", 45), +SINGLE_COEF("Ch1 - Prescale", 50), +SINGLE_COEF("Ch2 - Prescale", 51), +SINGLE_COEF("Ch1 - Postscale", 52), +SINGLE_COEF("Ch2 - Postscale", 53), +SINGLE_COEF("Ch3 - Postscale", 54), +SINGLE_COEF("Thermal warning - Postscale", 55), +SINGLE_COEF("Ch1 - Mix 1", 56), +SINGLE_COEF("Ch1 - Mix 2", 57), +SINGLE_COEF("Ch2 - Mix 1", 58), +SINGLE_COEF("Ch2 - Mix 2", 59), +SINGLE_COEF("Ch3 - Mix 1", 60), +SINGLE_COEF("Ch3 - Mix 2", 61), +}; + +static const struct snd_soc_dapm_widget sta350_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_OUTPUT("LEFT"), +SND_SOC_DAPM_OUTPUT("RIGHT"), +SND_SOC_DAPM_OUTPUT("SUB"), +}; + +static const struct snd_soc_dapm_route sta350_dapm_routes[] = { + { "LEFT", NULL, "DAC" }, + { "RIGHT", NULL, "DAC" }, + { "SUB", NULL, "DAC" }, + { "DAC", NULL, "Playback" }, +}; + +/* MCLK interpolation ratio per fs */ +static struct { + int fs; + int ir; +} interpolation_ratios[] = { + { 32000, 0 }, + { 44100, 0 }, + { 48000, 0 }, + { 88200, 1 }, + { 96000, 1 }, + { 176400, 2 }, + { 192000, 2 }, +}; + +/* MCLK to fs clock ratios */ +static int mcs_ratio_table[3][6] = { + { 768, 512, 384, 256, 128, 576 }, + { 384, 256, 192, 128, 64, 0 }, + { 192, 128, 96, 64, 32, 0 }, +}; + +/** + * sta350_set_dai_sysclk - configure MCLK + * @codec_dai: the codec DAI + * @clk_id: the clock ID (ignored) + * @freq: the MCLK input frequency + * @dir: the clock direction (ignored) + * + * The value of MCLK is used to determine which sample rates are supported + * by the STA350, based on the mcs_ratio_table. + * + * This function must be called by the machine driver's 'startup' function, + * otherwise the list of supported sample rates will not be available in + * time for ALSA. + */ +static int sta350_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "mclk=%u\n", freq); + sta350->mclk = freq; + + return 0; +} + +/** + * sta350_set_dai_fmt - configure the codec for the selected audio format + * @codec_dai: the codec DAI + * @fmt: a SND_SOC_DAIFMT_x value indicating the data format + * + * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the + * codec accordingly. + */ +static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + unsigned int confb = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + sta350->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + confb |= STA350_CONFB_C2IM; + break; + case SND_SOC_DAIFMT_NB_IF: + confb |= STA350_CONFB_C1IM; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(sta350->regmap, STA350_CONFB, + STA350_CONFB_C1IM | STA350_CONFB_C2IM, confb); +} + +/** + * sta350_hw_params - program the STA350 with the given hardware parameters. + * @substream: the audio stream + * @params: the hardware parameters to set + * @dai: the SOC DAI (ignored) + * + * This function programs the hardware with the values provided. + * Specifically, the sample rate and the data format. + */ +static int sta350_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 sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + int i, mcs = -EINVAL, ir = -EINVAL; + unsigned int confa, confb; + unsigned int rate, ratio; + int ret; + + if (!sta350->mclk) { + dev_err(codec->dev, + "sta350->mclk is unset. Unable to determine ratio\n"); + return -EIO; + } + + rate = params_rate(params); + ratio = sta350->mclk / rate; + dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio); + + for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { + if (interpolation_ratios[i].fs == rate) { + ir = interpolation_ratios[i].ir; + break; + } + } + + if (ir < 0) { + dev_err(codec->dev, "Unsupported samplerate: %u\n", rate); + return -EINVAL; + } + + for (i = 0; i < 6; i++) { + if (mcs_ratio_table[ir][i] == ratio) { + mcs = i; + break; + } + } + + if (mcs < 0) { + dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio); + return -EINVAL; + } + + confa = (ir << STA350_CONFA_IR_SHIFT) | + (mcs << STA350_CONFA_MCS_SHIFT); + confb = 0; + + switch (params_width(params)) { + case 24: + dev_dbg(codec->dev, "24bit\n"); + /* fall through */ + case 32: + dev_dbg(codec->dev, "24bit or 32bit\n"); + switch (sta350->format) { + case SND_SOC_DAIFMT_I2S: + confb |= 0x0; + break; + case SND_SOC_DAIFMT_LEFT_J: + confb |= 0x1; + break; + case SND_SOC_DAIFMT_RIGHT_J: + confb |= 0x2; + break; + } + + break; + case 20: + dev_dbg(codec->dev, "20bit\n"); + switch (sta350->format) { + case SND_SOC_DAIFMT_I2S: + confb |= 0x4; + break; + case SND_SOC_DAIFMT_LEFT_J: + confb |= 0x5; + break; + case SND_SOC_DAIFMT_RIGHT_J: + confb |= 0x6; + break; + } + + break; + case 18: + dev_dbg(codec->dev, "18bit\n"); + switch (sta350->format) { + case SND_SOC_DAIFMT_I2S: + confb |= 0x8; + break; + case SND_SOC_DAIFMT_LEFT_J: + confb |= 0x9; + break; + case SND_SOC_DAIFMT_RIGHT_J: + confb |= 0xa; + break; + } + + break; + case 16: + dev_dbg(codec->dev, "16bit\n"); + switch (sta350->format) { + case SND_SOC_DAIFMT_I2S: + confb |= 0x0; + break; + case SND_SOC_DAIFMT_LEFT_J: + confb |= 0xd; + break; + case SND_SOC_DAIFMT_RIGHT_J: + confb |= 0xe; + break; + } + + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(sta350->regmap, STA350_CONFA, + STA350_CONFA_MCS_MASK | STA350_CONFA_IR_MASK, + confa); + if (ret < 0) + return ret; + + ret = regmap_update_bits(sta350->regmap, STA350_CONFB, + STA350_CONFB_SAI_MASK | STA350_CONFB_SAIFB, + confb); + if (ret < 0) + return ret; + + return 0; +} + +static int sta350_startup_sequence(struct sta350_priv *sta350) +{ + if (sta350->gpiod_power_down) + gpiod_set_value(sta350->gpiod_power_down, 1); + + if (sta350->gpiod_nreset) { + gpiod_set_value(sta350->gpiod_nreset, 0); + mdelay(1); + gpiod_set_value(sta350->gpiod_nreset, 1); + mdelay(1); + } + + return 0; +} + +/** + * sta350_set_bias_level - DAPM callback + * @codec: the codec device + * @level: DAPM power level + * + * This is called by ALSA to put the codec into low power mode + * or to wake it up. If the codec is powered off completely + * all registers must be restored after power on. + */ +static int sta350_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + int ret; + + dev_dbg(codec->dev, "level = %d\n", level); + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* Full power on */ + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_PWDN | STA350_CONFF_EAPD, + STA350_CONFF_PWDN | STA350_CONFF_EAPD); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + ret = regulator_bulk_enable( + ARRAY_SIZE(sta350->supplies), + sta350->supplies); + if (ret < 0) { + dev_err(codec->dev, + "Failed to enable supplies: %d\n", + ret); + return ret; + } + sta350_startup_sequence(sta350); + sta350_cache_sync(codec); + } + + /* Power down */ + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_PWDN | STA350_CONFF_EAPD, + 0); + + break; + + case SND_SOC_BIAS_OFF: + /* The chip runs through the power down sequence for us */ + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_PWDN | STA350_CONFF_EAPD, 0); + + /* power down: low */ + if (sta350->gpiod_power_down) + gpiod_set_value(sta350->gpiod_power_down, 0); + + if (sta350->gpiod_nreset) + gpiod_set_value(sta350->gpiod_nreset, 0); + + regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), + sta350->supplies); + break; + } + codec->dapm.bias_level = level; + return 0; +} + +static const struct snd_soc_dai_ops sta350_dai_ops = { + .hw_params = sta350_hw_params, + .set_sysclk = sta350_set_dai_sysclk, + .set_fmt = sta350_set_dai_fmt, +}; + +static struct snd_soc_dai_driver sta350_dai = { + .name = "sta350-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = STA350_RATES, + .formats = STA350_FORMATS, + }, + .ops = &sta350_dai_ops, +}; + +#ifdef CONFIG_PM +static int sta350_suspend(struct snd_soc_codec *codec) +{ + sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int sta350_resume(struct snd_soc_codec *codec) +{ + sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; +} +#else +#define sta350_suspend NULL +#define sta350_resume NULL +#endif + +static int sta350_probe(struct snd_soc_codec *codec) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + struct sta350_platform_data *pdata = sta350->pdata; + int i, ret = 0, thermal = 0; + + ret = regulator_bulk_enable(ARRAY_SIZE(sta350->supplies), + sta350->supplies); + if (ret < 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + ret = sta350_startup_sequence(sta350); + if (ret < 0) { + dev_err(codec->dev, "Failed to startup device\n"); + return ret; + } + + /* CONFA */ + if (!pdata->thermal_warning_recovery) + thermal |= STA350_CONFA_TWAB; + if (!pdata->thermal_warning_adjustment) + thermal |= STA350_CONFA_TWRB; + if (!pdata->fault_detect_recovery) + thermal |= STA350_CONFA_FDRB; + regmap_update_bits(sta350->regmap, STA350_CONFA, + STA350_CONFA_TWAB | STA350_CONFA_TWRB | + STA350_CONFA_FDRB, + thermal); + + /* CONFC */ + regmap_update_bits(sta350->regmap, STA350_CONFC, + STA350_CONFC_OM_MASK, + pdata->ffx_power_output_mode + << STA350_CONFC_OM_SHIFT); + regmap_update_bits(sta350->regmap, STA350_CONFC, + STA350_CONFC_CSZ_MASK, + pdata->drop_compensation_ns + << STA350_CONFC_CSZ_SHIFT); + regmap_update_bits(sta350->regmap, + STA350_CONFC, + STA350_CONFC_OCRB, + pdata->oc_warning_adjustment ? + STA350_CONFC_OCRB : 0); + + /* CONFE */ + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_MPCV, + pdata->max_power_use_mpcc ? + STA350_CONFE_MPCV : 0); + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_MPC, + pdata->max_power_correction ? + STA350_CONFE_MPC : 0); + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_AME, + pdata->am_reduction_mode ? + STA350_CONFE_AME : 0); + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_PWMS, + pdata->odd_pwm_speed_mode ? + STA350_CONFE_PWMS : 0); + regmap_update_bits(sta350->regmap, STA350_CONFE, + STA350_CONFE_DCCV, + pdata->distortion_compensation ? + STA350_CONFE_DCCV : 0); + /* CONFF */ + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_IDE, + pdata->invalid_input_detect_mute ? + STA350_CONFF_IDE : 0); + regmap_update_bits(sta350->regmap, STA350_CONFF, + STA350_CONFF_OCFG_MASK, + pdata->output_conf + << STA350_CONFF_OCFG_SHIFT); + + /* channel to output mapping */ + regmap_update_bits(sta350->regmap, STA350_C1CFG, + STA350_CxCFG_OM_MASK, + pdata->ch1_output_mapping + << STA350_CxCFG_OM_SHIFT); + regmap_update_bits(sta350->regmap, STA350_C2CFG, + STA350_CxCFG_OM_MASK, + pdata->ch2_output_mapping + << STA350_CxCFG_OM_SHIFT); + regmap_update_bits(sta350->regmap, STA350_C3CFG, + STA350_CxCFG_OM_MASK, + pdata->ch3_output_mapping + << STA350_CxCFG_OM_SHIFT); + + /* initialize coefficient shadow RAM with reset values */ + for (i = 4; i <= 49; i += 5) + sta350->coef_shadow[i] = 0x400000; + for (i = 50; i <= 54; i++) + sta350->coef_shadow[i] = 0x7fffff; + sta350->coef_shadow[55] = 0x5a9df7; + sta350->coef_shadow[56] = 0x7fffff; + sta350->coef_shadow[59] = 0x7fffff; + sta350->coef_shadow[60] = 0x400000; + sta350->coef_shadow[61] = 0x400000; + + sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Bias level configuration will have done an extra enable */ + regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); + + return 0; +} + +static int sta350_remove(struct snd_soc_codec *codec) +{ + struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); + + sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); + regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); + + return 0; +} + +static const struct snd_soc_codec_driver sta350_codec = { + .probe = sta350_probe, + .remove = sta350_remove, + .suspend = sta350_suspend, + .resume = sta350_resume, + .set_bias_level = sta350_set_bias_level, + .controls = sta350_snd_controls, + .num_controls = ARRAY_SIZE(sta350_snd_controls), + .dapm_widgets = sta350_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sta350_dapm_widgets), + .dapm_routes = sta350_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sta350_dapm_routes), +}; + +static const struct regmap_config sta350_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = STA350_MISC2, + .reg_defaults = sta350_regs, + .num_reg_defaults = ARRAY_SIZE(sta350_regs), + .cache_type = REGCACHE_RBTREE, + .wr_table = &sta350_write_regs, + .rd_table = &sta350_read_regs, + .volatile_table = &sta350_volatile_regs, +}; + +#ifdef CONFIG_OF +static const struct of_device_id st350_dt_ids[] = { + { .compatible = "st,sta350", }, + { } +}; +MODULE_DEVICE_TABLE(of, st350_dt_ids); + +static const char * const sta350_ffx_modes[] = { + [STA350_FFX_PM_DROP_COMP] = "drop-compensation", + [STA350_FFX_PM_TAPERED_COMP] = "tapered-compensation", + [STA350_FFX_PM_FULL_POWER] = "full-power-mode", + [STA350_FFX_PM_VARIABLE_DROP_COMP] = "variable-drop-compensation", +}; + +static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350) +{ + struct device_node *np = dev->of_node; + struct sta350_platform_data *pdata; + const char *ffx_power_mode; + u16 tmp; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + of_property_read_u8(np, "st,output-conf", + &pdata->output_conf); + of_property_read_u8(np, "st,ch1-output-mapping", + &pdata->ch1_output_mapping); + of_property_read_u8(np, "st,ch2-output-mapping", + &pdata->ch2_output_mapping); + of_property_read_u8(np, "st,ch3-output-mapping", + &pdata->ch3_output_mapping); + + if (of_get_property(np, "st,thermal-warning-recovery", NULL)) + pdata->thermal_warning_recovery = 1; + if (of_get_property(np, "st,thermal-warning-adjustment", NULL)) + pdata->thermal_warning_adjustment = 1; + if (of_get_property(np, "st,fault-detect-recovery", NULL)) + pdata->fault_detect_recovery = 1; + + pdata->ffx_power_output_mode = STA350_FFX_PM_VARIABLE_DROP_COMP; + if (!of_property_read_string(np, "st,ffx-power-output-mode", + &ffx_power_mode)) { + int i, mode = -EINVAL; + + for (i = 0; i < ARRAY_SIZE(sta350_ffx_modes); i++) + if (!strcasecmp(ffx_power_mode, sta350_ffx_modes[i])) + mode = i; + + if (mode < 0) + dev_warn(dev, "Unsupported ffx output mode: %s\n", + ffx_power_mode); + else + pdata->ffx_power_output_mode = mode; + } + + tmp = 140; + of_property_read_u16(np, "st,drop-compensation-ns", &tmp); + pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20; + + if (of_get_property(np, "st,overcurrent-warning-adjustment", NULL)) + pdata->oc_warning_adjustment = 1; + + /* CONFE */ + if (of_get_property(np, "st,max-power-use-mpcc", NULL)) + pdata->max_power_use_mpcc = 1; + + if (of_get_property(np, "st,max-power-correction", NULL)) + pdata->max_power_correction = 1; + + if (of_get_property(np, "st,am-reduction-mode", NULL)) + pdata->am_reduction_mode = 1; + + if (of_get_property(np, "st,odd-pwm-speed-mode", NULL)) + pdata->odd_pwm_speed_mode = 1; + + if (of_get_property(np, "st,distortion-compensation", NULL)) + pdata->distortion_compensation = 1; + + /* CONFF */ + if (of_get_property(np, "st,invalid-input-detect-mute", NULL)) + pdata->invalid_input_detect_mute = 1; + + sta350->pdata = pdata; + + return 0; +} +#endif + +static int sta350_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct sta350_priv *sta350; + int ret, i; + + sta350 = devm_kzalloc(dev, sizeof(struct sta350_priv), GFP_KERNEL); + if (!sta350) + return -ENOMEM; + + mutex_init(&sta350->coeff_lock); + sta350->pdata = dev_get_platdata(dev); + +#ifdef CONFIG_OF + if (dev->of_node) { + ret = sta350_probe_dt(dev, sta350); + if (ret < 0) + return ret; + } +#endif + + /* GPIOs */ + sta350->gpiod_nreset = devm_gpiod_get(dev, "reset"); + if (IS_ERR(sta350->gpiod_nreset)) { + ret = PTR_ERR(sta350->gpiod_nreset); + if (ret != -ENOENT && ret != -ENOSYS) + return ret; + + sta350->gpiod_nreset = NULL; + } else { + gpiod_direction_output(sta350->gpiod_nreset, 0); + } + + sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down"); + if (IS_ERR(sta350->gpiod_power_down)) { + ret = PTR_ERR(sta350->gpiod_power_down); + if (ret != -ENOENT && ret != -ENOSYS) + return ret; + + sta350->gpiod_power_down = NULL; + } else { + gpiod_direction_output(sta350->gpiod_power_down, 0); + } + + /* regulators */ + for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++) + sta350->supplies[i].supply = sta350_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sta350->supplies), + sta350->supplies); + if (ret < 0) { + dev_err(dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + sta350->regmap = devm_regmap_init_i2c(i2c, &sta350_regmap); + if (IS_ERR(sta350->regmap)) { + ret = PTR_ERR(sta350->regmap); + dev_err(dev, "Failed to init regmap: %d\n", ret); + return ret; + } + + i2c_set_clientdata(i2c, sta350); + + ret = snd_soc_register_codec(dev, &sta350_codec, &sta350_dai, 1); + if (ret < 0) + dev_err(dev, "Failed to register codec (%d)\n", ret); + + return ret; +} + +static int sta350_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id sta350_i2c_id[] = { + { "sta350", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sta350_i2c_id); + +static struct i2c_driver sta350_i2c_driver = { + .driver = { + .name = "sta350", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(st350_dt_ids), + }, + .probe = sta350_i2c_probe, + .remove = sta350_i2c_remove, + .id_table = sta350_i2c_id, +}; + +module_i2c_driver(sta350_i2c_driver); + +MODULE_DESCRIPTION("ASoC STA350 driver"); +MODULE_AUTHOR("Sven Brandau <info@brandau.biz>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sta350.h b/sound/soc/codecs/sta350.h new file mode 100644 index 000000000000..c3248f0fad2c --- /dev/null +++ b/sound/soc/codecs/sta350.h @@ -0,0 +1,228 @@ +/* + * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system + * + * Copyright: 2011 Raumfeld GmbH + * Author: Sven Brandau <info@brandau.biz> + * + * based on code from: + * Raumfeld GmbH + * Johannes Stezenbach <js@sig21.net> + * Wolfson Microelectronics PLC. + * Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef _ASOC_STA_350_H +#define _ASOC_STA_350_H + +/* STA50 register addresses */ + +#define STA350_REGISTER_COUNT 0x4D +#define STA350_COEF_COUNT 62 + +#define STA350_CONFA 0x00 +#define STA350_CONFB 0x01 +#define STA350_CONFC 0x02 +#define STA350_CONFD 0x03 +#define STA350_CONFE 0x04 +#define STA350_CONFF 0x05 +#define STA350_MMUTE 0x06 +#define STA350_MVOL 0x07 +#define STA350_C1VOL 0x08 +#define STA350_C2VOL 0x09 +#define STA350_C3VOL 0x0a +#define STA350_AUTO1 0x0b +#define STA350_AUTO2 0x0c +#define STA350_AUTO3 0x0d +#define STA350_C1CFG 0x0e +#define STA350_C2CFG 0x0f +#define STA350_C3CFG 0x10 +#define STA350_TONE 0x11 +#define STA350_L1AR 0x12 +#define STA350_L1ATRT 0x13 +#define STA350_L2AR 0x14 +#define STA350_L2ATRT 0x15 +#define STA350_CFADDR2 0x16 +#define STA350_B1CF1 0x17 +#define STA350_B1CF2 0x18 +#define STA350_B1CF3 0x19 +#define STA350_B2CF1 0x1a +#define STA350_B2CF2 0x1b +#define STA350_B2CF3 0x1c +#define STA350_A1CF1 0x1d +#define STA350_A1CF2 0x1e +#define STA350_A1CF3 0x1f +#define STA350_A2CF1 0x20 +#define STA350_A2CF2 0x21 +#define STA350_A2CF3 0x22 +#define STA350_B0CF1 0x23 +#define STA350_B0CF2 0x24 +#define STA350_B0CF3 0x25 +#define STA350_CFUD 0x26 +#define STA350_MPCC1 0x27 +#define STA350_MPCC2 0x28 +#define STA350_DCC1 0x29 +#define STA350_DCC2 0x2a +#define STA350_FDRC1 0x2b +#define STA350_FDRC2 0x2c +#define STA350_STATUS 0x2d +/* reserved: 0x2d - 0x30 */ +#define STA350_EQCFG 0x31 +#define STA350_EATH1 0x32 +#define STA350_ERTH1 0x33 +#define STA350_EATH2 0x34 +#define STA350_ERTH2 0x35 +#define STA350_CONFX 0x36 +#define STA350_SVCA 0x37 +#define STA350_SVCB 0x38 +#define STA350_RMS0A 0x39 +#define STA350_RMS0B 0x3a +#define STA350_RMS0C 0x3b +#define STA350_RMS1A 0x3c +#define STA350_RMS1B 0x3d +#define STA350_RMS1C 0x3e +#define STA350_EVOLRES 0x3f +/* reserved: 0x40 - 0x47 */ +#define STA350_NSHAPE 0x48 +#define STA350_CTXB4B1 0x49 +#define STA350_CTXB7B5 0x4a +#define STA350_MISC1 0x4b +#define STA350_MISC2 0x4c + +/* 0x00 CONFA */ +#define STA350_CONFA_MCS_MASK 0x03 +#define STA350_CONFA_MCS_SHIFT 0 +#define STA350_CONFA_IR_MASK 0x18 +#define STA350_CONFA_IR_SHIFT 3 +#define STA350_CONFA_TWRB BIT(5) +#define STA350_CONFA_TWAB BIT(6) +#define STA350_CONFA_FDRB BIT(7) + +/* 0x01 CONFB */ +#define STA350_CONFB_SAI_MASK 0x0f +#define STA350_CONFB_SAI_SHIFT 0 +#define STA350_CONFB_SAIFB BIT(4) +#define STA350_CONFB_DSCKE BIT(5) +#define STA350_CONFB_C1IM BIT(6) +#define STA350_CONFB_C2IM BIT(7) + +/* 0x02 CONFC */ +#define STA350_CONFC_OM_MASK 0x03 +#define STA350_CONFC_OM_SHIFT 0 +#define STA350_CONFC_CSZ_MASK 0x3c +#define STA350_CONFC_CSZ_SHIFT 2 +#define STA350_CONFC_OCRB BIT(7) + +/* 0x03 CONFD */ +#define STA350_CONFD_HPB_SHIFT 0 +#define STA350_CONFD_DEMP_SHIFT 1 +#define STA350_CONFD_DSPB_SHIFT 2 +#define STA350_CONFD_PSL_SHIFT 3 +#define STA350_CONFD_BQL_SHIFT 4 +#define STA350_CONFD_DRC_SHIFT 5 +#define STA350_CONFD_ZDE_SHIFT 6 +#define STA350_CONFD_SME_SHIFT 7 + +/* 0x04 CONFE */ +#define STA350_CONFE_MPCV BIT(0) +#define STA350_CONFE_MPCV_SHIFT 0 +#define STA350_CONFE_MPC BIT(1) +#define STA350_CONFE_MPC_SHIFT 1 +#define STA350_CONFE_NSBW BIT(2) +#define STA350_CONFE_NSBW_SHIFT 2 +#define STA350_CONFE_AME BIT(3) +#define STA350_CONFE_AME_SHIFT 3 +#define STA350_CONFE_PWMS BIT(4) +#define STA350_CONFE_PWMS_SHIFT 4 +#define STA350_CONFE_DCCV BIT(5) +#define STA350_CONFE_DCCV_SHIFT 5 +#define STA350_CONFE_ZCE BIT(6) +#define STA350_CONFE_ZCE_SHIFT 6 +#define STA350_CONFE_SVE BIT(7) +#define STA350_CONFE_SVE_SHIFT 7 + +/* 0x05 CONFF */ +#define STA350_CONFF_OCFG_MASK 0x03 +#define STA350_CONFF_OCFG_SHIFT 0 +#define STA350_CONFF_IDE BIT(2) +#define STA350_CONFF_BCLE BIT(3) +#define STA350_CONFF_LDTE BIT(4) +#define STA350_CONFF_ECLE BIT(5) +#define STA350_CONFF_PWDN BIT(6) +#define STA350_CONFF_EAPD BIT(7) + +/* 0x06 MMUTE */ +#define STA350_MMUTE_MMUTE 0x01 +#define STA350_MMUTE_MMUTE_SHIFT 0 +#define STA350_MMUTE_C1M 0x02 +#define STA350_MMUTE_C1M_SHIFT 1 +#define STA350_MMUTE_C2M 0x04 +#define STA350_MMUTE_C2M_SHIFT 2 +#define STA350_MMUTE_C3M 0x08 +#define STA350_MMUTE_C3M_SHIFT 3 +#define STA350_MMUTE_LOC_MASK 0xC0 +#define STA350_MMUTE_LOC_SHIFT 6 + +/* 0x0b AUTO1 */ +#define STA350_AUTO1_AMGC_MASK 0x30 +#define STA350_AUTO1_AMGC_SHIFT 4 + +/* 0x0c AUTO2 */ +#define STA350_AUTO2_AMAME 0x01 +#define STA350_AUTO2_AMAM_MASK 0x0e +#define STA350_AUTO2_AMAM_SHIFT 1 +#define STA350_AUTO2_XO_MASK 0xf0 +#define STA350_AUTO2_XO_SHIFT 4 + +/* 0x0d AUTO3 */ +#define STA350_AUTO3_PEQ_MASK 0x1f +#define STA350_AUTO3_PEQ_SHIFT 0 + +/* 0x0e 0x0f 0x10 CxCFG */ +#define STA350_CxCFG_TCB_SHIFT 0 +#define STA350_CxCFG_EQBP_SHIFT 1 +#define STA350_CxCFG_VBP_SHIFT 2 +#define STA350_CxCFG_BO_SHIFT 3 +#define STA350_CxCFG_LS_SHIFT 4 +#define STA350_CxCFG_OM_MASK 0xc0 +#define STA350_CxCFG_OM_SHIFT 6 + +/* 0x11 TONE */ +#define STA350_TONE_BTC_SHIFT 0 +#define STA350_TONE_TTC_SHIFT 4 + +/* 0x12 0x13 0x14 0x15 limiter attack/release */ +#define STA350_LxA_SHIFT 0 +#define STA350_LxR_SHIFT 4 + +/* 0x26 CFUD */ +#define STA350_CFUD_W1 0x01 +#define STA350_CFUD_WA 0x02 +#define STA350_CFUD_R1 0x04 +#define STA350_CFUD_RA 0x08 + + +/* biquad filter coefficient table offsets */ +#define STA350_C1_BQ_BASE 0 +#define STA350_C2_BQ_BASE 20 +#define STA350_CH_BQ_NUM 4 +#define STA350_BQ_NUM_COEF 5 +#define STA350_XO_HP_BQ_BASE 40 +#define STA350_XO_LP_BQ_BASE 45 +#define STA350_C1_PRESCALE 50 +#define STA350_C2_PRESCALE 51 +#define STA350_C1_POSTSCALE 52 +#define STA350_C2_POSTSCALE 53 +#define STA350_C3_POSTSCALE 54 +#define STA350_TW_POSTSCALE 55 +#define STA350_C1_MIX1 56 +#define STA350_C1_MIX2 57 +#define STA350_C2_MIX1 58 +#define STA350_C2_MIX2 59 +#define STA350_C3_MIX1 60 +#define STA350_C3_MIX2 61 + +#endif /* _ASOC_STA_350_H */ diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index a895a5e4bdf2..d48491a4a19d 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -272,7 +272,7 @@ static int tas5086_set_deemph(struct snd_soc_codec *codec) static int tas5086_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = priv->deemph; @@ -283,7 +283,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol, static int tas5086_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); priv->deemph = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 20864ee8793b..686b8b85b956 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -82,7 +82,7 @@ static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0); static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); u16 val, reg; val = (ucontrol->value.integer.value[0] & 0x07); @@ -105,7 +105,7 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol, static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); u16 val; val = snd_soc_read(codec, TLV320AIC23_ANLG) & (0x1C0); diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index fa158cfe9b32..d1929de641e2 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -376,7 +376,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w, reg = AIC31XX_ADCFLAG; break; default: - dev_err(w->codec->dev, "Unknown widget '%s' calling %s/n", + dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n", w->name, __func__); return -EINVAL; } diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index b1835103e9b4..d7349bc89ad3 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1399,7 +1399,6 @@ static int aic3x_probe(struct snd_soc_codec *codec) } aic3x_add_widgets(codec); - list_add(&aic3x->list, &reset_list); return 0; @@ -1569,7 +1568,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aic3x, &aic3x_dai, 1); - return ret; + + if (ret != 0) + goto err_gpio; + + list_add(&aic3x->list, &reset_list); + + return 0; err_gpio: if (gpio_is_valid(aic3x->gpio_reset) && diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 6bfc8a17331b..517055ab65ef 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -442,7 +442,7 @@ static int dac33_playback_event(struct snd_soc_dapm_widget *w, static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = dac33->fifo_mode; @@ -453,7 +453,7 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); int ret = 0; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 975e0f760ac1..69e12a311ba2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -830,7 +830,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int shift = mc->shift; unsigned int rshift = mc->rshift; @@ -859,7 +859,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int shift = mc->shift; unsigned int rshift = mc->rshift; @@ -888,7 +888,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -915,7 +915,7 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -956,7 +956,7 @@ static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum, static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); if (twl4030->configured) { diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index bd3a20647fdf..0f6067f04e29 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -484,7 +484,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum, static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = priv->hs_power_mode; @@ -495,7 +495,7 @@ static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol, static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int high_perf = ucontrol->value.enumerated.item[0]; int ret = 0; @@ -512,7 +512,7 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol, static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = priv->pll_power_mode; @@ -523,7 +523,7 @@ static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol, static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); priv->pll_power_mode = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index 6be5f80b65f1..4ead0dc02b87 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -172,7 +172,7 @@ out: static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wl1273->mode; @@ -190,7 +190,7 @@ static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" }; static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); if (wl1273->mode == ucontrol->value.integer.value[0]) @@ -214,7 +214,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route); static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: enter.\n", __func__); @@ -227,7 +227,7 @@ static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol, static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); int val, r = 0; @@ -251,7 +251,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings); static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: enter.\n", __func__); @@ -264,7 +264,7 @@ static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol, static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); int r; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 83a2c872925c..a4c352cc3464 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -607,7 +607,7 @@ static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); ucontrol->value.enumerated.item[0] = wm2000->anc_active; @@ -618,7 +618,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol, static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); int anc_active = ucontrol->value.enumerated.item[0]; int ret; @@ -640,7 +640,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); ucontrol->value.enumerated.item[0] = wm2000->spk_ena; @@ -651,7 +651,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); int val = ucontrol->value.enumerated.item[0]; int ret; diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 2e721e06671b..cdea9d9c1631 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1083,7 +1083,7 @@ static int wm2200_mixer_values[] = { #define WM2200_MUX_CTL_DECL(name) \ const struct snd_kcontrol_new name##_mux = \ - SOC_DAPM_VALUE_ENUM("Route", name##_enum) + SOC_DAPM_ENUM("Route", name##_enum) #define WM2200_MIXER_ENUMS(name, base_reg) \ static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg); \ @@ -1207,7 +1207,7 @@ WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE); WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE); #define WM2200_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) #define WM2200_MIXER_WIDGETS(name, name_str) \ WM2200_MUX(name_str " Input 1", &name##_in1_mux), \ diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index eca983fad891..91a9ea2a2056 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -390,7 +390,7 @@ static int wm5100_mixer_values[] = { #define WM5100_MUX_CTL_DECL(name) \ const struct snd_kcontrol_new name##_mux = \ - SOC_DAPM_VALUE_ENUM("Route", name##_enum) + SOC_DAPM_ENUM("Route", name##_enum) #define WM5100_MIXER_ENUMS(name, base_reg) \ static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg); \ @@ -448,7 +448,7 @@ WM5100_MIXER_ENUMS(LHPF3, WM5100_HPLP3MIX_INPUT_1_SOURCE); WM5100_MIXER_ENUMS(LHPF4, WM5100_HPLP4MIX_INPUT_1_SOURCE); #define WM5100_MUX(name, ctrl) \ - SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) #define WM5100_MIXER_WIDGETS(name, name_str) \ WM5100_MUX(name_str " Input 1", &name##_in1_mux), \ diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index dcf1d12cfef8..289b64d89abd 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -764,8 +764,8 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), -SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -814,9 +814,9 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]), -SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]), -SOC_VALUE_ENUM("EPOUT OSR", wm5102_hpout_osr[2]), +SOC_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]), +SOC_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]), +SOC_ENUM("EPOUT OSR", wm5102_hpout_osr[2]), SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE, ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0), @@ -970,7 +970,7 @@ static const struct soc_enum wm5102_aec_loopback = wm5102_aec_loopback_values); static const struct snd_kcontrol_new wm5102_aec_loopback_mux = - SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5102_aec_loopback); + SOC_DAPM_ENUM("AEC Loopback", wm5102_aec_loopback); static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, @@ -1204,7 +1204,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, ARIZONA_DSP_WIDGETS(DSP1, "DSP1"), -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5102_aec_loopback_mux), @@ -1760,10 +1760,6 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); int ret; - ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap); - if (ret != 0) - return ret; - ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2); if (ret != 0) return ret; @@ -1802,9 +1798,17 @@ static unsigned int wm5102_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_5R, }; +static struct regmap *wm5102_get_regmap(struct device *dev) +{ + struct wm5102_priv *priv = dev_get_drvdata(dev); + + return priv->core.arizona->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm5102 = { .probe = wm5102_codec_probe, .remove = wm5102_codec_remove, + .get_regmap = wm5102_get_regmap, .idle_bias_off = true, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index df5a38dd8328..2e5fcb559e90 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -324,13 +324,13 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), -SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), -SOC_VALUE_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]), -SOC_VALUE_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]), -SOC_VALUE_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]), -SOC_VALUE_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), -SOC_VALUE_ENUM("ASRC RATE 1", arizona_asrc_rate1), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]), +SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]), +SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]), +SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), +SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1), ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), @@ -367,6 +367,11 @@ SOC_SINGLE("HPOUT2 SC Protect Switch", ARIZONA_HP2_SHORT_CIRCUIT_CTRL, SOC_SINGLE("HPOUT3 SC Protect Switch", ARIZONA_HP3_SHORT_CIRCUIT_CTRL, ARIZONA_HP3_SC_ENA_SHIFT, 1, 0), +SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, + ARIZONA_OUT5_OSR_SHIFT, 1, 0), +SOC_SINGLE("SPKDAT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_6L, + ARIZONA_OUT6_OSR_SHIFT, 1, 0), + SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L, ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1), SOC_DOUBLE_R("HPOUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L, @@ -592,7 +597,7 @@ static const struct soc_enum wm5110_aec_loopback = wm5110_aec_loopback_values); static const struct snd_kcontrol_new wm5110_aec_loopback_mux = - SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5110_aec_loopback); + SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback); static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, @@ -774,7 +779,7 @@ SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3, SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3, ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5110_aec_loopback_mux), @@ -1589,10 +1594,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) priv->core.arizona->dapm = &codec->dapm; - ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap); - if (ret != 0) - return ret; - arizona_init_spk(codec); arizona_init_gpio(codec); @@ -1633,9 +1634,17 @@ static unsigned int wm5110_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_6R, }; +static struct regmap *wm5110_get_regmap(struct device *dev) +{ + struct wm5110_priv *priv = dev_get_drvdata(dev); + + return priv->core.arizona->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .probe = wm5110_codec_probe, .remove = wm5110_codec_remove, + .get_regmap = wm5110_get_regmap, .idle_bias_off = true, diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 757256bf7672..392285edb595 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -302,7 +302,7 @@ static int pga_event(struct snd_soc_dapm_widget *w, static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out = NULL; struct soc_mixer_control *mc = @@ -345,7 +345,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol, static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out1 = &wm8350_priv->out1; struct wm8350_output *out2 = &wm8350_priv->out2; @@ -1505,8 +1505,6 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; - snd_soc_codec_set_cache_io(codec, wm8350->regmap); - /* Put the codec into reset if it wasn't already */ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); @@ -1608,11 +1606,19 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *wm8350_get_regmap(struct device *dev) +{ + struct wm8350 *wm8350 = dev_get_platdata(dev); + + return wm8350->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { .probe = wm8350_codec_probe, .remove = wm8350_codec_remove, .suspend = wm8350_suspend, .resume = wm8350_resume, + .get_regmap = wm8350_get_regmap, .set_bias_level = wm8350_set_bias_level, .controls = wm8350_snd_controls, diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 146564feaea0..06e913d3fea1 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -93,7 +93,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0); static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; @@ -1318,8 +1318,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) priv->wm8400 = wm8400; priv->codec = codec; - snd_soc_codec_set_cache_io(codec, wm8400->regmap); - ret = devm_regulator_bulk_get(wm8400->dev, ARRAY_SIZE(power), &power[0]); if (ret != 0) { @@ -1361,11 +1359,19 @@ static int wm8400_codec_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *wm8400_get_regmap(struct device *dev) +{ + struct wm8400 *wm8400 = dev_get_platdata(dev); + + return wm8400->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { .probe = wm8400_codec_probe, .remove = wm8400_codec_remove, .suspend = wm8400_suspend, .resume = wm8400_resume, + .get_regmap = wm8400_get_regmap, .set_bias_level = wm8400_set_bias_level, .controls = wm8400_snd_controls, diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index af7ed8b5d4e1..7665ff6aea6d 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -252,7 +252,7 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index d74f43975b90..763b265d9528 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -119,7 +119,7 @@ static int wm8731_set_deemph(struct snd_soc_codec *codec) static int wm8731_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8731->deemph; @@ -130,7 +130,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol, static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; int ret = 0; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index cbb8d55052a4..53e57b4049a8 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -234,7 +234,7 @@ SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase), static int wm8753_get_dai(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8753->dai_func; @@ -244,7 +244,7 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol, static int wm8753_set_dai(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); u16 ioctl; diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index ee76f0fb4299..589455c3bfcd 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -106,7 +106,7 @@ static int txsrc_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec; unsigned int src; - codec = snd_kcontrol_chip(kcontrol); + codec = snd_soc_kcontrol_codec(kcontrol); src = snd_soc_read(codec, WM8804_SPDTX4); if (src & 0x40) ucontrol->value.integer.value[0] = 1; @@ -122,7 +122,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec; unsigned int src, txpwr; - codec = snd_kcontrol_chip(kcontrol); + codec = snd_soc_kcontrol_codec(kcontrol); if (ucontrol->value.integer.value[0] != 0 && ucontrol->value.integer.value[0] != 1) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b0084a127d18..b84940c359a1 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -439,7 +439,7 @@ static int wm8903_set_deemph(struct snd_soc_codec *codec) static int wm8903_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8903->deemph; @@ -450,7 +450,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol, static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; int ret = 0; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 49c35c36935e..f7c549949c54 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -391,7 +391,7 @@ static void wm8904_set_drc(struct snd_soc_codec *codec) static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_pdata *pdata = wm8904->pdata; int value = ucontrol->value.integer.value[0]; @@ -409,7 +409,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol, static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8904->drc_cfg; @@ -462,7 +462,7 @@ static void wm8904_set_retune_mobile(struct snd_soc_codec *codec) static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_pdata *pdata = wm8904->pdata; int value = ucontrol->value.integer.value[0]; @@ -480,7 +480,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg; @@ -520,7 +520,7 @@ static int wm8904_set_deemph(struct snd_soc_codec *codec) static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8904->deemph; @@ -530,7 +530,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, static int wm8904_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; @@ -570,7 +570,7 @@ static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5, static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int val; int ret; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index fecd4e4f4c57..7e443c4f6f85 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -390,7 +390,7 @@ static int wm8955_set_deemph(struct snd_soc_codec *codec) static int wm8955_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8955->deemph; @@ -400,7 +400,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol, static int wm8955_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 7ac2e511403c..b2ebb104d879 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -456,7 +456,7 @@ static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif) static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; @@ -478,7 +478,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg; @@ -500,7 +500,7 @@ static int wm8958_mbc_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int mbc = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc]; @@ -512,7 +512,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int mbc = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0]) @@ -546,7 +546,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol, static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; @@ -568,7 +568,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8994->vss_cfg; @@ -579,7 +579,7 @@ static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol, static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; @@ -601,7 +601,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg; @@ -623,7 +623,7 @@ static int wm8958_vss_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int vss = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8994->vss_ena[vss]; @@ -635,7 +635,7 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int vss = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0]) @@ -684,7 +684,7 @@ static int wm8958_hpf_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int hpf = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (hpf < 3) @@ -699,7 +699,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int hpf = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (hpf < 3) { @@ -746,7 +746,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol, static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; @@ -768,7 +768,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg; @@ -790,7 +790,7 @@ static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int eq = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq]; @@ -802,7 +802,7 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int eq = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0]) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index d04e9cad445c..a145d0431b63 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -178,7 +178,7 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec) static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8960->deemph; @@ -188,7 +188,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index ba761fc96d2f..ca2fda9d72be 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -152,6 +152,7 @@ static struct reg_default wm8962_reg[] = { { 40, 0x0000 }, /* R40 - SPKOUTL volume */ { 41, 0x0000 }, /* R41 - SPKOUTR volume */ + { 49, 0x0010 }, /* R49 - Class D Control 1 */ { 51, 0x0003 }, /* R51 - Class D Control 2 */ { 56, 0x0506 }, /* R56 - Clocking 4 */ @@ -793,7 +794,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg) case WM8962_ALC2: case WM8962_THERMAL_SHUTDOWN_STATUS: case WM8962_ADDITIONAL_CONTROL_4: - case WM8962_CLASS_D_CONTROL_1: case WM8962_DC_SERVO_6: case WM8962_INTERRUPT_STATUS_1: case WM8962_INTERRUPT_STATUS_2: @@ -1550,7 +1550,7 @@ static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int shift = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift); @@ -1562,7 +1562,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int shift = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); int old = wm8962->dsp2_ena; int ret = 0; @@ -1600,7 +1600,7 @@ out: static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int ret; /* Apply the update (if any) */ @@ -1630,7 +1630,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol, static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int ret; /* Apply the update (if any) */ @@ -2927,13 +2927,22 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, static int wm8962_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - int val; + int val, ret; if (mute) - val = WM8962_DAC_MUTE; + val = WM8962_DAC_MUTE | WM8962_DAC_MUTE_ALT; else val = 0; + /** + * The DAC mute bit is mirrored in two registers, update both to keep + * the register cache consistent. + */ + ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1, + WM8962_DAC_MUTE_ALT, val); + if (ret < 0) + return ret; + return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1, WM8962_DAC_MUTE, val); } diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h index a1a5d5294c19..910aafd09d21 100644 --- a/sound/soc/codecs/wm8962.h +++ b/sound/soc/codecs/wm8962.h @@ -1954,6 +1954,10 @@ #define WM8962_SPKOUTL_ENA_MASK 0x0040 /* SPKOUTL_ENA */ #define WM8962_SPKOUTL_ENA_SHIFT 6 /* SPKOUTL_ENA */ #define WM8962_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */ +#define WM8962_DAC_MUTE_ALT 0x0010 /* DAC_MUTE */ +#define WM8962_DAC_MUTE_ALT_MASK 0x0010 /* DAC_MUTE */ +#define WM8962_DAC_MUTE_ALT_SHIFT 4 /* DAC_MUTE */ +#define WM8962_DAC_MUTE_ALT_WIDTH 1 /* DAC_MUTE */ #define WM8962_SPKOUTL_PGA_MUTE 0x0002 /* SPKOUTL_PGA_MUTE */ #define WM8962_SPKOUTL_PGA_MUTE_MASK 0x0002 /* SPKOUTL_PGA_MUTE */ #define WM8962_SPKOUTL_PGA_MUTE_SHIFT 1 /* SPKOUTL_PGA_MUTE */ diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 2b9bfa53efbf..19d5baa38f5c 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -552,7 +552,7 @@ static const struct snd_soc_dapm_route wm8983_audio_map[] = { static int eqmode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg; reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF); @@ -567,7 +567,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol, static int eqmode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int regpwr2, regpwr3; unsigned int reg_eq; diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 5473dc969585..ad23ffb8346c 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -526,7 +526,7 @@ static const struct snd_soc_dapm_route wm8985_dapm_routes[] = { static int eqmode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg; reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF); @@ -541,7 +541,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol, static int eqmode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int regpwr2, regpwr3; unsigned int reg_eq; diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 3a1ae4f5164d..d3fea46d58e8 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -268,7 +268,7 @@ static const struct soc_enum wm8988_lline_enum = wm8988_line_texts, wm8988_line_values); static const struct snd_kcontrol_new wm8988_left_line_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); + SOC_DAPM_ENUM("Route", wm8988_lline_enum); static const struct soc_enum wm8988_rline_enum = SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7, @@ -276,7 +276,7 @@ static const struct soc_enum wm8988_rline_enum = wm8988_line_texts, wm8988_line_values); static const struct snd_kcontrol_new wm8988_right_line_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); + SOC_DAPM_ENUM("Route", wm8988_lline_enum); /* Left Mixer */ static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = { @@ -304,7 +304,7 @@ static const struct soc_enum wm8988_lpga_enum = wm8988_pga_sel, wm8988_pga_val); static const struct snd_kcontrol_new wm8988_left_pga_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_lpga_enum); + SOC_DAPM_ENUM("Route", wm8988_lpga_enum); /* Right PGA Mux */ static const struct soc_enum wm8988_rpga_enum = @@ -313,7 +313,7 @@ static const struct soc_enum wm8988_rpga_enum = wm8988_pga_sel, wm8988_pga_val); static const struct snd_kcontrol_new wm8988_right_pga_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_rpga_enum); + SOC_DAPM_ENUM("Route", wm8988_rpga_enum); /* Differential Mux */ static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"}; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index c413c1991453..b5c1f0f07058 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -132,7 +132,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0); static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 844cc4a60d66..b8fd284fc0c0 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -154,7 +154,7 @@ static const unsigned int out_sidetone_tlv[] = { static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int reg = kcontrol->private_value & 0xff; int ret; u16 val; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 6303537f54c6..247b39013fba 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -298,7 +298,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); int mask, ret; /* Can't enable both ADC and DAC paths simultaneously */ @@ -355,7 +355,7 @@ static int wm8994_get_drc(const char *name) static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; struct wm8994_pdata *pdata = &control->pdata; @@ -378,7 +378,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int drc = wm8994_get_drc(kcontrol->id.name); @@ -462,7 +462,7 @@ static int wm8994_get_retune_mobile_block(const char *name) static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; struct wm8994_pdata *pdata = &control->pdata; @@ -485,7 +485,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int block = wm8994_get_retune_mobile_block(kcontrol->id.name); @@ -1347,10 +1347,10 @@ static const char *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); + SOC_DAPM_ENUM("ADCL Mux", adc_enum); static const struct snd_kcontrol_new adcr_mux = - SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum); + SOC_DAPM_ENUM("ADCR Mux", adc_enum); static const struct snd_kcontrol_new left_speaker_mixer[] = { SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0), @@ -1651,15 +1651,15 @@ SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0), }; static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] = { -SND_SOC_DAPM_VIRT_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux, +SND_SOC_DAPM_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux, adc_mux_ev, SND_SOC_DAPM_PRE_PMU), -SND_SOC_DAPM_VIRT_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux, +SND_SOC_DAPM_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux, adc_mux_ev, SND_SOC_DAPM_PRE_PMU), }; static const struct snd_soc_dapm_widget wm8994_adc_widgets[] = { -SND_SOC_DAPM_VIRT_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), -SND_SOC_DAPM_VIRT_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), +SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), +SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), }; static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { @@ -3999,8 +3999,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->hubs.codec = codec; - snd_soc_codec_set_cache_io(codec, control->regmap); - mutex_init(&wm8994->accdet_lock); INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, wm1811_jackdet_bootstrap); @@ -4434,11 +4432,19 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) return 0; } +static struct regmap *wm8994_get_regmap(struct device *dev) +{ + struct wm8994 *control = dev_get_drvdata(dev->parent); + + return control->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm8994 = { .probe = wm8994_codec_probe, .remove = wm8994_codec_remove, .suspend = wm8994_codec_suspend, .resume = wm8994_codec_resume, + .get_regmap = wm8994_get_regmap, .set_bias_level = wm8994_set_bias_level, }; diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index d3152cf5bd56..863a2c38bcb5 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -885,10 +885,10 @@ static const char *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); + SOC_DAPM_ENUM("ADCL Mux", adc_enum); static const struct snd_kcontrol_new adcr_mux = - SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum); + SOC_DAPM_ENUM("ADCR Mux", adc_enum); static const char *spk_src_text[] = { "DAC1L", "DAC1R", "DAC2L", "DAC2R" @@ -948,10 +948,8 @@ static const struct snd_soc_dapm_widget wm8995_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture", 0, WM8995_POWER_MANAGEMENT_3, 10, 0), - SND_SOC_DAPM_VIRT_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0, - &adcl_mux), - SND_SOC_DAPM_VIRT_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, - &adcr_mux), + SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0, &adcl_mux), + SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, &adcr_mux), SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8995_POWER_MANAGEMENT_3, 5, 0), SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8995_POWER_MANAGEMENT_3, 4, 0), diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index c6cbb3b8ace9..69266332760e 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -412,7 +412,7 @@ static int wm8996_get_retune_mobile_block(const char *name) static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); struct wm8996_pdata *pdata = &wm8996->pdata; int block = wm8996_get_retune_mobile_block(kcontrol->id.name); @@ -434,7 +434,7 @@ static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); int block = wm8996_get_retune_mobile_block(kcontrol->id.name); diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 004186b6bd48..bb9b47b956aa 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -245,8 +245,8 @@ SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), -SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -286,8 +286,8 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_VALUE_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]), -SOC_VALUE_ENUM("EPOUT OSR", wm8997_hpout_osr[1]), +SOC_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]), +SOC_ENUM("EPOUT OSR", wm8997_hpout_osr[1]), SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), @@ -405,7 +405,7 @@ static const struct soc_enum wm8997_aec_loopback = wm8997_aec_loopback_values); static const struct snd_kcontrol_new wm8997_aec_loopback_mux = - SOC_DAPM_VALUE_ENUM("AEC Loopback", wm8997_aec_loopback); + SOC_DAPM_ENUM("AEC Loopback", wm8997_aec_loopback); static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, @@ -604,7 +604,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX8_ENA_SHIFT, 0), -SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm8997_aec_loopback_mux), @@ -1051,11 +1051,6 @@ static struct snd_soc_dai_driver wm8997_dai[] = { static int wm8997_codec_probe(struct snd_soc_codec *codec) { struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap); - if (ret != 0) - return ret; arizona_init_spk(codec); @@ -1086,9 +1081,17 @@ static unsigned int wm8997_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_5R, }; +static struct regmap *wm8997_get_regmap(struct device *dev) +{ + struct wm8997_priv *priv = dev_get_drvdata(dev); + + return priv->core.arizona->regmap; +} + static struct snd_soc_codec_driver soc_codec_dev_wm8997 = { .probe = wm8997_codec_probe, .remove = wm8997_codec_remove, + .get_regmap = wm8997_get_regmap, .idle_bias_off = true, diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index d18eff31fbbc..185eb97769e7 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -340,7 +340,7 @@ static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6, static int speaker_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg; reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); @@ -361,7 +361,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol, static int speaker_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT); unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index bb5f7b4e3ebb..ff15eec3ab2f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -242,7 +242,7 @@ struct wm_coeff_ctl { static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); @@ -254,7 +254,7 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); @@ -1625,7 +1625,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, break; default: break; - }; + } return 0; } diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index b6209662ab13..916817fe6632 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -337,7 +337,7 @@ static void enable_dc_servo(struct snd_soc_codec *codec) static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); int ret; diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index a8ec1fc3e4d0..50a098749b9e 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -18,7 +18,7 @@ config SND_DAVINCI_SOC_GENERIC_EVM config SND_AM33XX_SOC_EVM tristate "SoC Audio for the AM33XX chip based boards" - depends on SND_DAVINCI_SOC && SOC_AM33XX + depends on SND_DAVINCI_SOC && SOC_AM33XX && I2C select SND_DAVINCI_SOC_GENERIC_EVM help Say Y or M if you want to add support for SoC audio on AM33XX @@ -28,7 +28,7 @@ config SND_AM33XX_SOC_EVM config SND_DAVINCI_SOC_EVM tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" - depends on SND_DAVINCI_SOC + depends on SND_DAVINCI_SOC && I2C depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM select SND_DAVINCI_SOC_GENERIC_EVM help @@ -56,7 +56,7 @@ endchoice config SND_DM6467_SOC_EVM tristate "SoC Audio support for DaVinci DM6467 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM + depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM select SND_SOC_SPDIF @@ -65,7 +65,7 @@ config SND_DM6467_SOC_EVM config SND_DA830_SOC_EVM tristate "SoC Audio support for DA830/OMAP-L137 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM + depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM help @@ -74,7 +74,7 @@ config SND_DA830_SOC_EVM config SND_DA850_SOC_EVM tristate "SoC Audio support for DA850/OMAP-L138 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM + depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM help Say Y if you want to add support for SoC audio on TI diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index ebe82947bab3..7682af31d6e6 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -757,7 +757,6 @@ static int davinci_i2s_remove(struct platform_device *pdev) struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev); snd_soc_unregister_component(&pdev->dev); - davinci_soc_platform_unregister(&pdev->dev); clk_disable(dev->clk); clk_put(dev->clk); diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 4f75cac462d1..14058dc6eaf8 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -36,6 +36,9 @@ #include "davinci-pcm.h" #include "davinci-mcasp.h" +#include "../omap/omap-pcm.h" + +#define MCASP_MAX_AFIFO_DEPTH 64 struct davinci_mcasp_context { u32 txfmtctl; @@ -269,25 +272,51 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); int ret = 0; + u32 data_delay; + bool fs_pol_rising; + bool inv_fs = false; pm_runtime_get_sync(mcasp->dev); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + /* 1st data bit occur one ACLK cycle after the frame sync */ + data_delay = 1; + break; case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_AC97: mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + /* No delay after FS */ + data_delay = 0; break; - default: + case SND_SOC_DAIFMT_I2S: /* configure a full-word SYNC pulse (LRCLK) */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); - - /* make 1st data bit occur one ACLK cycle after the frame sync */ - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(1)); - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(1)); + /* 1st data bit occur one ACLK cycle after the frame sync */ + data_delay = 1; + /* FS need to be inverted */ + inv_fs = true; break; + case SND_SOC_DAIFMT_LEFT_J: + /* configure a full-word SYNC pulse (LRCLK) */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + /* No delay after FS */ + data_delay = 0; + break; + default: + ret = -EINVAL; + goto out; } + mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay), + FSXDLY(3)); + mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay), + FSRDLY(3)); + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* codec is clock and frame slave */ @@ -325,7 +354,6 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); mcasp->bclk_master = 0; break; - default: ret = -EINVAL; goto out; @@ -334,39 +362,38 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_NF: mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = true; break; - case SND_SOC_DAIFMT_NB_IF: mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = false; break; - case SND_SOC_DAIFMT_IB_IF: mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = false; break; - case SND_SOC_DAIFMT_NB_NF: mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = true; break; - default: ret = -EINVAL; - break; + goto out; + } + + if (inv_fs) + fs_pol_rising = !fs_pol_rising; + + if (fs_pol_rising) { + mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + } else { + mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); } out: pm_runtime_put_sync(mcasp->dev); @@ -464,17 +491,19 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, } static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, - int channels) + int period_words, int channels) { + struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream]; + struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream]; int i; u8 tx_ser = 0; u8 rx_ser = 0; - u8 ser; u8 slots = mcasp->tdm_slots; u8 max_active_serializers = (channels + slots - 1) / slots; + int active_serializers, numevt, n; u32 reg; /* Default configuration */ - if (mcasp->version != MCASP_VERSION_4) + if (mcasp->version < MCASP_VERSION_3) mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); /* All PINS as McASP */ @@ -505,37 +534,71 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, } } - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - ser = tx_ser; - else - ser = rx_ser; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + active_serializers = tx_ser; + numevt = mcasp->txnumevt; + reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; + } else { + active_serializers = rx_ser; + numevt = mcasp->rxnumevt; + reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; + } - if (ser < max_active_serializers) { + if (active_serializers < max_active_serializers) { dev_warn(mcasp->dev, "stream has more channels (%d) than are " - "enabled in mcasp (%d)\n", channels, ser * slots); + "enabled in mcasp (%d)\n", channels, + active_serializers * slots); return -EINVAL; } - if (mcasp->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (mcasp->txnumevt * tx_ser > 64) - mcasp->txnumevt = 1; - - reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; - mcasp_mod_bits(mcasp, reg, tx_ser, NUMDMA_MASK); - mcasp_mod_bits(mcasp, reg, ((mcasp->txnumevt * tx_ser) << 8), - NUMEVT_MASK); + /* AFIFO is not in use */ + if (!numevt) { + /* Configure the burst size for platform drivers */ + if (active_serializers > 1) { + /* + * If more than one serializers are in use we have one + * DMA request to provide data for all serializers. + * For example if three serializers are enabled the DMA + * need to transfer three words per DMA request. + */ + dma_params->fifo_level = active_serializers; + dma_data->maxburst = active_serializers; + } else { + dma_params->fifo_level = 0; + dma_data->maxburst = 0; + } + return 0; } - if (mcasp->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) { - if (mcasp->rxnumevt * rx_ser > 64) - mcasp->rxnumevt = 1; - - reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; - mcasp_mod_bits(mcasp, reg, rx_ser, NUMDMA_MASK); - mcasp_mod_bits(mcasp, reg, ((mcasp->rxnumevt * rx_ser) << 8), - NUMEVT_MASK); + if (period_words % active_serializers) { + dev_err(mcasp->dev, "Invalid combination of period words and " + "active serializers: %d, %d\n", period_words, + active_serializers); + return -EINVAL; } + /* + * Calculate the optimal AFIFO depth for platform side: + * The number of words for numevt need to be in steps of active + * serializers. + */ + n = numevt % active_serializers; + if (n) + numevt += (active_serializers - n); + while (period_words % numevt && numevt > 0) + numevt -= active_serializers; + if (numevt <= 0) + numevt = active_serializers; + + mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK); + mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK); + + /* Configure the burst size for platform drivers */ + if (numevt == 1) + numevt = 0; + dma_params->fifo_level = numevt; + dma_data->maxburst = numevt; + return 0; } @@ -607,27 +670,24 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[substream->stream]; - struct snd_dmaengine_dai_dma_data *dma_data = - &mcasp->dma_data[substream->stream]; int word_length; - u8 fifo_level; - u8 slots = mcasp->tdm_slots; - u8 active_serializers; int channels = params_channels(params); + int period_size = params_period_size(params); int ret; /* 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"); + dev_err(mcasp->dev, "Can't produce required BCLK\n"); return -EINVAL; } davinci_mcasp_set_clkdiv( cpu_dai, 1, mcasp->sysclk_freq / bclk_freq); } - ret = mcasp_common_hw_param(mcasp, substream->stream, channels); + ret = mcasp_common_hw_param(mcasp, substream->stream, + period_size * channels, channels); if (ret) return ret; @@ -671,21 +731,11 @@ 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) + if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level) dma_params->acnt = 4; else dma_params->acnt = dma_params->data_type; - dma_params->fifo_level = fifo_level; - dma_data->maxburst = fifo_level; - davinci_config_channel_size(mcasp, word_length); return 0; @@ -716,22 +766,7 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, return ret; } -static int davinci_mcasp_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); - - if (mcasp->version == MCASP_VERSION_4) - snd_soc_dai_set_dma_data(dai, substream, - &mcasp->dma_data[substream->stream]); - else - snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params); - - return 0; -} - static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { - .startup = davinci_mcasp_startup, .trigger = davinci_mcasp_trigger, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, @@ -739,6 +774,25 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { .set_sysclk = davinci_mcasp_set_sysclk, }; +static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) +{ + struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + + if (mcasp->version == MCASP_VERSION_4) { + /* Using dmaengine PCM */ + dai->playback_dma_data = + &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dai->capture_dma_data = + &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; + } else { + /* Using davinci-pcm */ + dai->playback_dma_data = mcasp->dma_params; + dai->capture_dma_data = mcasp->dma_params; + } + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int davinci_mcasp_suspend(struct snd_soc_dai *dai) { @@ -792,6 +846,7 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai) static struct snd_soc_dai_driver davinci_mcasp_dai[] = { { .name = "davinci-mcasp.0", + .probe = davinci_mcasp_dai_probe, .suspend = davinci_mcasp_suspend, .resume = davinci_mcasp_resume, .playback = { @@ -811,6 +866,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }, { .name = "davinci-mcasp.1", + .probe = davinci_mcasp_dai_probe, .playback = { .channels_min = 1, .channels_max = 384, @@ -1078,7 +1134,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (!mcasp->base) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; - goto err_release_clk; + goto err; } mcasp->op_mode = pdata->op_mode; @@ -1159,25 +1215,37 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp_reparent_fck(pdev); - ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, - &davinci_mcasp_dai[pdata->op_mode], 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &davinci_mcasp_component, + &davinci_mcasp_dai[pdata->op_mode], 1); if (ret != 0) - goto err_release_clk; + goto err; - if (mcasp->version != MCASP_VERSION_4) { + switch (mcasp->version) { + case MCASP_VERSION_1: + case MCASP_VERSION_2: + case MCASP_VERSION_3: ret = davinci_soc_platform_register(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_component; - } + break; + case MCASP_VERSION_4: + ret = omap_pcm_platform_register(&pdev->dev); + break; + default: + dev_err(&pdev->dev, "Invalid McASP version: %d\n", + mcasp->version); + ret = -EINVAL; + break; + } + + if (ret) { + dev_err(&pdev->dev, "register PCM failed: %d\n", ret); + goto err; } return 0; -err_unregister_component: - snd_soc_unregister_component(&pdev->dev); -err_release_clk: +err: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return ret; @@ -1185,12 +1253,6 @@ err_release_clk: static int davinci_mcasp_remove(struct platform_device *pdev) { - struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev); - - snd_soc_unregister_component(&pdev->dev); - if (mcasp->version != MCASP_VERSION_4) - davinci_soc_platform_unregister(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 8fed757d6087..98fbc451892a 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -283,6 +283,7 @@ */ #define FIFO_ENABLE BIT(16) #define NUMEVT_MASK (0xFF << 8) +#define NUMEVT(x) (((x) & 0xFF) << 8) #define NUMDMA_MASK (0xFF) #endif /* DAVINCI_MCASP_H */ diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 14145cdf8a11..7809e9d935fc 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -852,16 +852,10 @@ static struct snd_soc_platform_driver davinci_soc_platform = { int davinci_soc_platform_register(struct device *dev) { - return snd_soc_register_platform(dev, &davinci_soc_platform); + return devm_snd_soc_register_platform(dev, &davinci_soc_platform); } EXPORT_SYMBOL_GPL(davinci_soc_platform_register); -void davinci_soc_platform_unregister(struct device *dev) -{ - snd_soc_unregister_platform(dev); -} -EXPORT_SYMBOL_GPL(davinci_soc_platform_unregister); - MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index fbb710c76c08..0fe2346a9aa2 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -29,7 +29,13 @@ struct davinci_pcm_dma_params { unsigned int fifo_level; }; +#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC) int davinci_soc_platform_register(struct device *dev); -void davinci_soc_platform_unregister(struct device *dev); +#else +static inline int davinci_soc_platform_register(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_SND_DAVINCI_SOC */ #endif diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 30587c0cdbd2..77aef05588c3 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -258,7 +258,6 @@ static int davinci_vcif_probe(struct platform_device *pdev) static int davinci_vcif_remove(struct platform_device *pdev) { snd_soc_unregister_component(&pdev->dev); - davinci_soc_platform_unregister(&pdev->dev); return 0; } diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index c8e5db1414d7..496ce2eb2f1f 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -258,10 +258,16 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return -EINVAL; } - if (ratio == 1) { + /* Only EXTAL source can be output directly without using PSR and PM */ + if (ratio == 1 && clksrc == esai_priv->extalclk) { /* Bypass all the dividers if not being needed */ ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO; goto out; + } else if (ratio < 2) { + /* The ratio should be no less than 2 if using other sources */ + dev_err(dai->dev, "failed to derive required HCK%c rate\n", + tx ? 'T' : 'R'); + return -EINVAL; } ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0); @@ -307,7 +313,8 @@ static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) return -EINVAL; } - if (esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) { + /* The ratio should be contented by FP alone if bypassing PM and PSR */ + if (!esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) { dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n"); return -EINVAL; } @@ -454,12 +461,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, } if (!dai->active) { - /* Reset Port C */ - regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, - ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, - ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO)); - /* Set synchronous mode */ regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR, ESAI_SAICR_SYNC, esai_priv->synchronous ? @@ -519,6 +520,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); + /* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO)); return 0; } diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h index b1266790d117..605a10b2112b 100644 --- a/sound/soc/fsl/fsl_spdif.h +++ b/sound/soc/fsl/fsl_spdif.h @@ -144,8 +144,8 @@ enum spdif_gainsel { /* SPDIF Clock register */ #define STC_SYSCLK_DIV_OFFSET 11 -#define STC_SYSCLK_DIV_MASK (0x1ff << STC_TXCLK_SRC_OFFSET) -#define STC_SYSCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK) +#define STC_SYSCLK_DIV_MASK (0x1ff << STC_SYSCLK_DIV_OFFSET) +#define STC_SYSCLK_DIV(x) ((((x) - 1) << STC_SYSCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK) #define STC_TXCLK_SRC_OFFSET 8 #define STC_TXCLK_SRC_MASK (0x7 << STC_TXCLK_SRC_OFFSET) #define STC_TXCLK_SRC_SET(x) ((x << STC_TXCLK_SRC_OFFSET) & STC_TXCLK_SRC_MASK) diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index ac869931d7f1..267717aa96c1 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -145,7 +145,7 @@ static const struct file_operations audmux_debugfs_fops = { .llseek = default_llseek, }; -static void __init audmux_debugfs_init(void) +static void audmux_debugfs_init(void) { int i; char buf[20]; diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index eff97c8e5218..10df4c8d78e6 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -100,12 +100,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) snd_soc_dapm_ignore_suspend(dapm, "SPORP"); snd_soc_dapm_ignore_suspend(dapm, "SPORN"); - snd_soc_dapm_enable_pin(dapm, "Headset Mic"); - snd_soc_dapm_enable_pin(dapm, "Headphone"); - snd_soc_dapm_enable_pin(dapm, "Speaker"); - snd_soc_dapm_enable_pin(dapm, "Internal Mic"); - - snd_soc_dapm_sync(dapm); return ret; } diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c index 54345a2a7386..94c2c33ffe49 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/haswell.c @@ -89,8 +89,6 @@ static struct snd_soc_ops haswell_rt5640_ops = { static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); struct sst_hsw *haswell = pdata->dsp; int ret; @@ -104,10 +102,6 @@ static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) return ret; } - /* always connected */ - snd_soc_dapm_enable_pin(dapm, "Headphones"); - snd_soc_dapm_enable_pin(dapm, "Mic"); - return 0; } diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c index 5d06eecb6198..18aee77f8d4a 100644 --- a/sound/soc/intel/sst-acpi.c +++ b/sound/soc/intel/sst-acpi.c @@ -138,6 +138,7 @@ static int sst_acpi_probe(struct platform_device *pdev) sst_pdata = &sst_acpi->sst_pdata; sst_pdata->id = desc->sst_id; + sst_pdata->dma_dev = dev; sst_acpi->desc = desc; sst_acpi->mach = mach; diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c index a50bf7fc0e3a..adf0aca5aca6 100644 --- a/sound/soc/intel/sst-baytrail-dsp.c +++ b/sound/soc/intel/sst-baytrail-dsp.c @@ -324,7 +324,7 @@ static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata) memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET, &pdata->fw_base, sizeof(u32)); - ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); + ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32)); if (ret) return ret; diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index d0eaeee21be4..0d31dbbf4806 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c @@ -542,16 +542,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, void *data) { struct sst_byt_stream *stream; + struct sst_dsp *sst = byt->dsp; + unsigned long flags; stream = kzalloc(sizeof(*stream), GFP_KERNEL); if (stream == NULL) return NULL; + spin_lock_irqsave(&sst->spinlock, flags); list_add(&stream->node, &byt->stream_list); stream->notify_position = notify_position; stream->pdata = data; stream->byt = byt; stream->str_id = id; + spin_unlock_irqrestore(&sst->spinlock, flags); return stream; } @@ -630,6 +634,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) { u64 header; int ret = 0; + struct sst_dsp *sst = byt->dsp; + unsigned long flags; if (!stream->commited) goto out; @@ -644,8 +650,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) stream->commited = false; out: + spin_lock_irqsave(&sst->spinlock, flags); list_del(&stream->node); kfree(stream); + spin_unlock_irqrestore(&sst->spinlock, flags); return ret; } diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h index fe8e81aad646..401213455497 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/sst-dsp-priv.h @@ -136,7 +136,7 @@ struct sst_module_data { enum sst_data_type data_type; /* type of module data */ u32 size; /* size in bytes */ - u32 offset; /* offset in FW file */ + int32_t offset; /* offset in FW file */ u32 data_offset; /* offset in ADSP memory space */ void *data; /* module data */ }; @@ -228,6 +228,7 @@ struct sst_dsp { spinlock_t spinlock; /* IPC locking */ struct mutex mutex; /* DSP FW lock */ struct device *dev; + struct device *dma_dev; void *thread_context; int irq; u32 id; diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index 0c129fd85ecf..0b715b20a2d7 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c @@ -337,6 +337,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev, spin_lock_init(&sst->spinlock); mutex_init(&sst->mutex); sst->dev = dev; + sst->dma_dev = pdata->dma_dev; sst->thread_context = sst_dev->thread_context; sst->sst_dev = sst_dev; sst->id = pdata->id; diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index 74052b59485c..e44423be66c4 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h @@ -169,6 +169,7 @@ struct sst_pdata { u32 dma_base; u32 dma_size; int dma_engine; + struct device *dma_dev; /* DSP */ u32 id; diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index f7687107cf7f..928f228c38e7 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -57,14 +57,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, sst_fw->private = private; sst_fw->size = fw->size; - err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32)); - if (err < 0) { - kfree(sst_fw); - return NULL; - } - /* allocate DMA buffer to store FW data */ - sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size, + sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size, &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); if (!sst_fw->dma_buf) { dev_err(dsp->dev, "error: DMA alloc failed\n"); @@ -106,7 +100,7 @@ void sst_fw_free(struct sst_fw *sst_fw) list_del(&sst_fw->list); mutex_unlock(&dsp->mutex); - dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf, + dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf, sst_fw->dmable_fw_paddr); kfree(sst_fw); } @@ -202,6 +196,9 @@ static int block_alloc_contiguous(struct sst_module *module, size -= block->size; } + list_for_each_entry(block, &tmp, list) + list_add(&block->module_list, &module->block_list); + list_splice(&tmp, &dsp->used_block_list); return 0; } @@ -247,8 +244,7 @@ static int block_alloc(struct sst_module *module, /* do we span > 1 blocks */ if (data->size > block->size) { ret = block_alloc_contiguous(module, data, - block->offset + block->size, - data->size - block->size); + block->offset, data->size); if (ret == 0) return ret; } @@ -344,7 +340,7 @@ static int block_alloc_fixed(struct sst_module *module, err = block_alloc_contiguous(module, data, block->offset + block->size, - data->size - block->size + data->offset - block->offset); + data->size - block->size); if (err < 0) return -ENOMEM; @@ -371,15 +367,10 @@ static int block_alloc_fixed(struct sst_module *module, if (data->offset >= block->offset && data->offset < block_end) { err = block_alloc_contiguous(module, data, - block->offset + block->size, - data->size - block->size); + block->offset, data->size); if (err < 0) return -ENOMEM; - /* add block */ - block->data_type = data->data_type; - list_move(&block->list, &dsp->used_block_list); - list_add(&block->module_list, &module->block_list); return 0; } diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index f5ebf36af889..535f517629fd 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -433,7 +433,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) int ret = -ENODEV, i, j, region_count; u32 offset, size; - dev = sst->dev; + dev = sst->dma_dev; switch (sst->id) { case SST_DEV_ID_LYNX_POINT: @@ -466,7 +466,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) return ret; } - ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31)); if (ret) return ret; diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index f46bb4ddde6f..e7996b39a484 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -617,7 +617,7 @@ static void hsw_notification_work(struct work_struct *work) case IPC_POSITION_CHANGED: trace_ipc_notification("DSP stream position changed for", stream->reply.stream_hw_id); - sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos)); + sst_dsp_inbox_read(hsw->dsp, pos, sizeof(*pos)); if (stream->notify_position) stream->notify_position(stream, stream->pdata); @@ -991,7 +991,8 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream return -EINVAL; sst_dsp_read(hsw->dsp, volume, - stream->reply.volume_register_address[channel], sizeof(volume)); + stream->reply.volume_register_address[channel], + sizeof(*volume)); return 0; } @@ -1158,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, void *data) { struct sst_hsw_stream *stream; + struct sst_dsp *sst = hsw->dsp; + unsigned long flags; stream = kzalloc(sizeof(*stream), GFP_KERNEL); if (stream == NULL) return NULL; + spin_lock_irqsave(&sst->spinlock, flags); list_add(&stream->node, &hsw->stream_list); stream->notify_position = notify_position; stream->pdata = data; @@ -1171,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, /* work to process notification messages */ INIT_WORK(&stream->notify_work, hsw_notification_work); + spin_unlock_irqrestore(&sst->spinlock, flags); return stream; } @@ -1179,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) { u32 header; int ret = 0; + struct sst_dsp *sst = hsw->dsp; + unsigned long flags; /* dont free DSP streams that are not commited */ if (!stream->commited) @@ -1200,8 +1207,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) trace_hsw_stream_free_req(stream, &stream->free_req); out: + cancel_work_sync(&stream->notify_work); + spin_lock_irqsave(&sst->spinlock, flags); list_del(&stream->node); kfree(stream); + spin_unlock_irqrestore(&sst->spinlock, flags); return ret; } @@ -1537,10 +1547,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream) } /* Stream pointer positions */ -int sst_hsw_get_dsp_position(struct sst_hsw *hsw, +u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, struct sst_hsw_stream *stream) { - return stream->rpos.position; + u32 rpos; + + sst_dsp_read(hsw->dsp, &rpos, + stream->reply.read_position_register_address, sizeof(rpos)); + + return rpos; +} + +/* Stream presentation (monotonic) positions */ +u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, + struct sst_hsw_stream *stream) +{ + u64 ppos; + + sst_dsp_read(hsw->dsp, &ppos, + stream->reply.presentation_position_register_address, + sizeof(ppos)); + + return ppos; } int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, @@ -1609,7 +1637,7 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, trace_ipc_request("PM enter Dx state", state); ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), - dx, sizeof(dx)); + dx, sizeof(*dx)); if (ret < 0) { dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); return ret; diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index d517929ccc38..2ac194a6d04b 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -464,7 +464,9 @@ int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 *position); int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 position); -int sst_hsw_get_dsp_position(struct sst_hsw *hsw, +u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, + struct sst_hsw_stream *stream); +u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, struct sst_hsw_stream *stream); /* HW port config */ diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 0a32dd13a23d..ce27b507d5ef 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -99,6 +99,7 @@ struct hsw_pcm_data { struct snd_compr_stream *cstream; unsigned int wpos; struct mutex mutex; + bool allocated; }; /* private data for the driver */ @@ -107,12 +108,14 @@ struct hsw_priv_data { struct sst_hsw *hsw; /* page tables */ - unsigned char *pcm_pg[HSW_PCM_COUNT][2]; + struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; /* DAI data */ struct hsw_pcm_data pcm[HSW_PCM_COUNT]; }; +static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data); + static inline u32 hsw_mixer_to_ipc(unsigned int value) { if (value >= ARRAY_SIZE(volume_map)) @@ -136,7 +139,7 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value) static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct hsw_priv_data *pdata = @@ -174,7 +177,7 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct hsw_priv_data *pdata = @@ -206,7 +209,7 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, static int hsw_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -231,7 +234,7 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol, static int hsw_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); struct sst_hsw *hsw = pdata->hsw; unsigned int volume = 0; @@ -273,28 +276,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { }; /* Create DMA buffer page table for DSP */ -static int create_adsp_page_table(struct hsw_priv_data *pdata, - struct snd_soc_pcm_runtime *rtd, - unsigned char *dma_area, size_t size, int pcm, int stream) +static int create_adsp_page_table(struct snd_pcm_substream *substream, + struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd, + unsigned char *dma_area, size_t size, int pcm) { - int i, pages; + struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); + int i, pages, stream = substream->stream; - if (size % PAGE_SIZE) - pages = (size / PAGE_SIZE) + 1; - else - pages = size / PAGE_SIZE; + pages = snd_sgbuf_aligned_pages(size); dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", dma_area, size, pages); for (i = 0; i < pages; i++) { u32 idx = (((i << 2) + i)) >> 1; - u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT; + u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; u32 *pg_table; dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); - pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx); + pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx); if (i & 1) *pg_table |= (pfn << 4); @@ -317,12 +318,36 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, struct sst_hsw *hsw = pdata->hsw; struct sst_module *module_data; struct sst_dsp *dsp; + struct snd_dma_buffer *dmab; enum sst_hsw_stream_type stream_type; enum sst_hsw_stream_path_id path_id; u32 rate, bits, map, pages, module_id; u8 channels; int ret; + /* check if we are being called a subsequent time */ + if (pcm_data->allocated) { + ret = sst_hsw_stream_reset(hsw, pcm_data->stream); + if (ret < 0) + dev_dbg(rtd->dev, "error: reset stream failed %d\n", + ret); + + ret = sst_hsw_stream_free(hsw, pcm_data->stream); + if (ret < 0) { + dev_dbg(rtd->dev, "error: free stream failed %d\n", + ret); + return ret; + } + pcm_data->allocated = false; + + pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id, + hsw_notify_pointer, pcm_data); + if (pcm_data->stream == NULL) { + dev_err(rtd->dev, "error: failed to create stream\n"); + return -EINVAL; + } + } + /* stream direction */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) path_id = SST_HSW_STREAM_PATH_SSP0_OUT; @@ -416,8 +441,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } - ret = create_adsp_page_table(pdata, rtd, runtime->dma_area, - runtime->dma_bytes, rtd->cpu_dai->id, substream->stream); + dmab = snd_pcm_get_dma_buf(substream); + + ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area, + runtime->dma_bytes, rtd->cpu_dai->id); if (ret < 0) return ret; @@ -430,9 +457,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, pages = runtime->dma_bytes / PAGE_SIZE; ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, - virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]), + pdata->dmab[rtd->cpu_dai->id][substream->stream].addr, pages, runtime->dma_bytes, 0, - (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT)); + snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT); if (ret < 0) { dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret); return ret; @@ -474,6 +501,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); return ret; } + pcm_data->allocated = true; ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); if (ret < 0) @@ -541,12 +569,14 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); struct sst_hsw *hsw = pdata->hsw; snd_pcm_uframes_t offset; + uint64_t ppos; + u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); - offset = bytes_to_frames(runtime, - sst_hsw_get_dsp_position(hsw, pcm_data->stream)); + offset = bytes_to_frames(runtime, position); + ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); - dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", - frames_to_bytes(runtime, (u32)offset)); + dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n", + position, ppos); return offset; } @@ -606,6 +636,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); goto out; } + pcm_data->allocated = 0; pcm_data->stream = NULL; out: @@ -621,7 +652,7 @@ static struct snd_pcm_ops hsw_pcm_ops = { .hw_free = hsw_pcm_hw_free, .trigger = hsw_pcm_trigger, .pointer = hsw_pcm_pointer, - .mmap = snd_pcm_lib_default_mmap, + .page = snd_pcm_sgbuf_ops_page, }; static void hsw_pcm_free(struct snd_pcm *pcm) @@ -632,17 +663,16 @@ static void hsw_pcm_free(struct snd_pcm *pcm) static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; + struct snd_soc_platform *platform = rtd->platform; + struct sst_pdata *pdata = dev_get_platdata(platform->dev); + struct device *dev = pdata->dma_dev; int ret = 0; - ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { ret = snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV, - rtd->card->dev, + SNDRV_DMA_TYPE_DEV_SG, + dev, hsw_pcm_hardware.buffer_bytes_max, hsw_pcm_hardware.buffer_bytes_max); if (ret) { @@ -742,11 +772,14 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) { struct sst_pdata *pdata = dev_get_platdata(platform->dev); struct hsw_priv_data *priv_data; - int i; + struct device *dma_dev; + int i, ret = 0; if (!pdata) return -ENODEV; + dma_dev = pdata->dma_dev; + priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); priv_data->hsw = pdata->dsp; snd_soc_platform_set_drvdata(platform, priv_data); @@ -758,15 +791,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) /* playback */ if (hsw_dais[i].playback.channels_min) { - priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA); - if (priv_data->pcm_pg[i][0] == NULL) + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, + PAGE_SIZE, &priv_data->dmab[i][0]); + if (ret < 0) goto err; } /* capture */ if (hsw_dais[i].capture.channels_min) { - priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA); - if (priv_data->pcm_pg[i][1] == NULL) + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, + PAGE_SIZE, &priv_data->dmab[i][1]); + if (ret < 0) goto err; } } @@ -776,11 +811,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) err: for (;i >= 0; i--) { if (hsw_dais[i].playback.channels_min) - kfree(priv_data->pcm_pg[i][0]); + snd_dma_free_pages(&priv_data->dmab[i][0]); if (hsw_dais[i].capture.channels_min) - kfree(priv_data->pcm_pg[i][1]); + snd_dma_free_pages(&priv_data->dmab[i][1]); } - return -ENOMEM; + return ret; } static int hsw_pcm_remove(struct snd_soc_platform *platform) @@ -791,9 +826,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform) for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { if (hsw_dais[i].playback.channels_min) - kfree(priv_data->pcm_pg[i][0]); + snd_dma_free_pages(&priv_data->dmab[i][0]); if (hsw_dais[i].capture.channels_min) - kfree(priv_data->pcm_pg[i][1]); + snd_dma_free_pages(&priv_data->dmab[i][1]); } return 0; diff --git a/sound/soc/jz4740/Makefile b/sound/soc/jz4740/Makefile index be873c1b0c20..d32c540555c4 100644 --- a/sound/soc/jz4740/Makefile +++ b/sound/soc/jz4740/Makefile @@ -1,10 +1,8 @@ # # Jz4740 Platform Support # -snd-soc-jz4740-objs := jz4740-pcm.o snd-soc-jz4740-i2s-objs := jz4740-i2s.o -obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o # Jz4740 Machine Support diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c index d213832b0c72..844b8415a011 100644 --- a/sound/soc/kirkwood/kirkwood-t5325.c +++ b/sound/soc/kirkwood/kirkwood-t5325.c @@ -52,18 +52,6 @@ static const struct snd_soc_dapm_route t5325_route[] = { { "MIC2", NULL, "Mic Jack" }, }; -static int t5325_dai_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_enable_pin(dapm, "Mic Jack"); - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Speaker"); - - return 0; -} - static struct snd_soc_dai_link t5325_dai[] = { { .name = "ALC5621", @@ -74,7 +62,6 @@ static struct snd_soc_dai_link t5325_dai[] = { .codec_name = "alc562x-codec.0-001a", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, .ops = &t5325_ops, - .init = t5325_dai_init, }, }; diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 56a5219c0a00..669f84d9b76e 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -38,7 +38,6 @@ #include "omap-mcbsp.h" #include "../codecs/cx20442.h" - /* Board specific DAPM widgets */ static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = { /* Handset */ @@ -90,17 +89,23 @@ static const unsigned short ams_delta_audio_mode_pins[] = { static unsigned short ams_delta_audio_agc; +/* + * Used for passing a codec structure pointer + * from the board initialization code to the tty line discipline. + */ +static struct snd_soc_codec *cx20442_codec; + static int ams_delta_set_audio_mode(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; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = &card->dapm; struct soc_enum *control = (struct soc_enum *)kcontrol->private_value; unsigned short pins; int pin, changed = 0; /* Refuse any mode changes if we are not able to control the codec. */ - if (!codec->hw_write) + if (!cx20442_codec->hw_write) return -EUNATCH; if (ucontrol->value.enumerated.item[0] >= control->items) @@ -166,8 +171,8 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol, static int ams_delta_get_audio_mode(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; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = &card->dapm; unsigned short pins, mode; pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") << @@ -270,12 +275,6 @@ static void cx81801_timeout(unsigned long data) ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0); } -/* - * Used for passing a codec structure pointer - * from the board initialization code to the tty line discipline. - */ -static struct snd_soc_codec *cx20442_codec; - /* Line discipline .open() */ static int cx81801_open(struct tty_struct *tty) { @@ -302,7 +301,7 @@ static int cx81801_open(struct tty_struct *tty) static void cx81801_close(struct tty_struct *tty) { struct snd_soc_codec *codec = tty->disc_data; - struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_dapm_context *dapm = &codec->card->dapm; del_timer_sync(&cx81801_timer); @@ -475,15 +474,14 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream) static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = &card->dapm; int ret; /* Codec is ready, now add/activate board specific controls */ /* Store a pointer to the codec structure for tty ldisc use */ - cx20442_codec = codec; + cx20442_codec = rtd->codec; /* Set up digital mute if not provided by the codec */ if (!codec_dai->driver->ops) { @@ -520,41 +518,12 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) return 0; } - /* Add board specific DAPM widgets and routes */ - ret = snd_soc_dapm_new_controls(dapm, ams_delta_dapm_widgets, - ARRAY_SIZE(ams_delta_dapm_widgets)); - if (ret) { - dev_warn(card->dev, - "Failed to register DAPM controls, " - "will continue without any.\n"); - return 0; - } - - ret = snd_soc_dapm_add_routes(dapm, ams_delta_audio_map, - ARRAY_SIZE(ams_delta_audio_map)); - if (ret) { - dev_warn(card->dev, - "Failed to set up DAPM routes, " - "will continue with codec default map.\n"); - return 0; - } - /* Set up initial pin 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_disable_pin(dapm, "AGCOUT"); - /* Add virtual switch */ - ret = snd_soc_add_codec_controls(codec, ams_delta_audio_controls, - ARRAY_SIZE(ams_delta_audio_controls)); - if (ret) - dev_warn(card->dev, - "Failed to register audio mode control, " - "will continue without it.\n"); - return 0; } @@ -576,6 +545,13 @@ static struct snd_soc_card ams_delta_audio_card = { .owner = THIS_MODULE, .dai_link = &ams_delta_dai_link, .num_links = 1, + + .controls = ams_delta_audio_controls, + .num_controls = ARRAY_SIZE(ams_delta_audio_controls), + .dapm_widgets = ams_delta_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ams_delta_dapm_widgets), + .dapm_routes = ams_delta_audio_map, + .num_dapm_routes = ARRAY_SIZE(ams_delta_audio_map), }; /* Module init/exit */ diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 07b8b7bc9d20..c3711b582d5f 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -232,6 +232,12 @@ static struct snd_soc_platform_driver omap_soc_platform = { .pcm_free = omap_pcm_free_dma_buffers, }; +int omap_pcm_platform_register(struct device *dev) +{ + return devm_snd_soc_register_platform(dev, &omap_soc_platform); +} +EXPORT_SYMBOL_GPL(omap_pcm_platform_register); + static int omap_pcm_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h new file mode 100644 index 000000000000..c1d2f31d71e9 --- /dev/null +++ b/sound/soc/omap/omap-pcm.h @@ -0,0 +1,30 @@ +/* + * omap-pcm.h - OMAP PCM driver + * + * Copyright (C) 2014 Texas Instruments, Inc. + * + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> + * + * 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 __OMAP_PCM_H__ +#define __OMAP_PCM_H__ + +#if IS_ENABLED(CONFIG_SND_OMAP_SOC) +int omap_pcm_platform_register(struct device *dev); +#else +static inline int omap_pcm_platform_register(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_SND_OMAP_SOC */ + +#endif /* __OMAP_PCM_H__ */ diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index cf604a2faa18..02181bb70400 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -121,7 +121,7 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, * |A| <~~clk~~+ * |P| <--- TWL4030 <--------- Line In and MICs */ -static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { +static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = { SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0, omap3pandora_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), @@ -130,22 +130,18 @@ static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_LINE("Line Out", NULL), -}; -static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = { SND_SOC_DAPM_MIC("Mic (internal)", NULL), SND_SOC_DAPM_MIC("Mic (external)", NULL), SND_SOC_DAPM_LINE("Line In", NULL), }; -static const struct snd_soc_dapm_route omap3pandora_out_map[] = { +static const struct snd_soc_dapm_route omap3pandora_map[] = { {"PCM DAC", NULL, "APLL Enable"}, {"Headphone Amplifier", NULL, "PCM DAC"}, {"Line Out", NULL, "PCM DAC"}, {"Headphone Jack", NULL, "Headphone Amplifier"}, -}; -static const struct snd_soc_dapm_route omap3pandora_in_map[] = { {"AUXL", NULL, "Line In"}, {"AUXR", NULL, "Line In"}, @@ -160,7 +156,6 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; /* All TWL4030 output pins are floating */ snd_soc_dapm_nc_pin(dapm, "EARPIECE"); @@ -174,20 +169,13 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "HFR"); snd_soc_dapm_nc_pin(dapm, "VIBRA"); - ret = snd_soc_dapm_new_controls(dapm, omap3pandora_out_dapm_widgets, - ARRAY_SIZE(omap3pandora_out_dapm_widgets)); - if (ret < 0) - return ret; - - return snd_soc_dapm_add_routes(dapm, omap3pandora_out_map, - ARRAY_SIZE(omap3pandora_out_map)); + return 0; } static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; /* Not comnnected */ snd_soc_dapm_nc_pin(dapm, "HSMIC"); @@ -195,13 +183,7 @@ static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "DIGIMIC0"); snd_soc_dapm_nc_pin(dapm, "DIGIMIC1"); - ret = snd_soc_dapm_new_controls(dapm, omap3pandora_in_dapm_widgets, - ARRAY_SIZE(omap3pandora_in_dapm_widgets)); - if (ret < 0) - return ret; - - return snd_soc_dapm_add_routes(dapm, omap3pandora_in_map, - ARRAY_SIZE(omap3pandora_in_map)); + return 0; } static struct snd_soc_ops omap3pandora_ops = { @@ -241,6 +223,11 @@ static struct snd_soc_card snd_soc_card_omap3pandora = { .owner = THIS_MODULE, .dai_link = omap3pandora_dai, .num_links = ARRAY_SIZE(omap3pandora_dai), + + .dapm_widgets = omap3pandora_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets), + .dapm_routes = omap3pandora_map, + .num_dapm_routes = ARRAY_SIZE(omap3pandora_map), }; static struct platform_device *omap3pandora_snd_device; diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 7fb3d4b10370..2b4641123142 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -237,9 +237,6 @@ static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event), SND_SOC_DAPM_MIC("HS Mic", NULL), SND_SOC_DAPM_LINE("FM Transmitter", NULL), -}; - -static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = { SND_SOC_DAPM_SPK("Earphone", NULL), }; @@ -253,9 +250,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"DMic Rate 64", NULL, "Mic Bias"}, {"Mic Bias", NULL, "DMic"}, -}; -static const struct snd_soc_dapm_route audio_mapb[] = { {"b LINE2R", NULL, "MONO_LOUT"}, {"Earphone", NULL, "b HPLOUT"}, @@ -281,9 +276,6 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = { SOC_ENUM_EXT("Jack Function", rx51_enum[2], rx51_get_jack, rx51_set_jack), SOC_DAPM_PIN_SWITCH("FM Transmitter"), -}; - -static const struct snd_kcontrol_new aic34_rx51_controlsb[] = { SOC_DAPM_PIN_SWITCH("Earphone"), }; @@ -298,19 +290,6 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "MIC3R"); snd_soc_dapm_nc_pin(dapm, "LINE1R"); - /* Add RX-51 specific controls */ - err = snd_soc_add_card_controls(rtd->card, aic34_rx51_controls, - ARRAY_SIZE(aic34_rx51_controls)); - if (err < 0) - return err; - - /* Add RX-51 specific widgets */ - snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets, - ARRAY_SIZE(aic34_dapm_widgets)); - - /* Set up RX-51 specific audio path audio_map */ - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - err = tpa6130a2_add_controls(codec); if (err < 0) return err; @@ -333,24 +312,6 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) return err; } -static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm) -{ - int err; - - err = snd_soc_add_card_controls(dapm->card, aic34_rx51_controlsb, - ARRAY_SIZE(aic34_rx51_controlsb)); - if (err < 0) - return err; - - err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb, - ARRAY_SIZE(aic34_dapm_widgetsb)); - if (err < 0) - return 0; - - return snd_soc_dapm_add_routes(dapm, audio_mapb, - ARRAY_SIZE(audio_mapb)); -} - /* Digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link rx51_dai[] = { { @@ -371,7 +332,6 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = { { .name = "TLV320AIC34b", .codec_name = "tlv320aic3x-codec.2-0019", - .init = rx51_aic34b_init, }, }; @@ -392,6 +352,13 @@ static struct snd_soc_card rx51_sound_card = { .num_aux_devs = ARRAY_SIZE(rx51_aux_dev), .codec_conf = rx51_codec_conf, .num_configs = ARRAY_SIZE(rx51_codec_conf), + + .controls = aic34_rx51_controls, + .num_controls = ARRAY_SIZE(aic34_rx51_controls), + .dapm_widgets = aic34_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aic34_dapm_widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), }; static struct platform_device *rx51_snd_device; diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 08acdc236bf8..c8dd53f9c35d 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c @@ -50,11 +50,6 @@ static int brownstone_wm8994_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_enable_pin(dapm, "Ext Spk"); - snd_soc_dapm_enable_pin(dapm, "Headset Stereophone"); - snd_soc_dapm_enable_pin(dapm, "Headset Mic"); - snd_soc_dapm_enable_pin(dapm, "Main Mic"); - /* set endpoints to not connected */ snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); snd_soc_dapm_nc_pin(dapm, "HPOUT2N"); @@ -70,8 +65,6 @@ static int brownstone_wm8994_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); snd_soc_dapm_nc_pin(dapm, "IN2LN"); - snd_soc_dapm_sync(dapm); - return 0; } diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 3284c4b901cb..17f9521ff6ea 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -79,14 +79,6 @@ static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; int err; - /* connected pins */ - if (machine_is_palmld()) - snd_soc_dapm_enable_pin(dapm, "MIC1"); - snd_soc_dapm_enable_pin(dapm, "HPOUTL"); - snd_soc_dapm_enable_pin(dapm, "HPOUTR"); - snd_soc_dapm_enable_pin(dapm, "LOUT2"); - snd_soc_dapm_enable_pin(dapm, "ROUT2"); - /* not connected pins */ snd_soc_dapm_nc_pin(dapm, "OUT3"); snd_soc_dapm_nc_pin(dapm, "MONOOUT"); diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index c6bdc6c0eff6..21f340065318 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -230,7 +230,6 @@ static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "LLINEIN"); snd_soc_dapm_nc_pin(dapm, "RLINEIN"); - snd_soc_dapm_enable_pin(dapm, "MICIN"); return 0; } diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c index 0b535b570622..9d7c5b7e9539 100644 --- a/sound/soc/pxa/ttc-dkb.c +++ b/sound/soc/pxa/ttc-dkb.c @@ -78,10 +78,6 @@ static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - /* connected pins */ - snd_soc_dapm_enable_pin(dapm, "Ext Speaker"); - snd_soc_dapm_enable_pin(dapm, "Ext Mic 1"); - snd_soc_dapm_enable_pin(dapm, "Ext Mic 3"); snd_soc_dapm_disable_pin(dapm, "Headset Mic 2"); snd_soc_dapm_disable_pin(dapm, "Headset Stereophone"); diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index 88b09e022503..9f2fb69dbaae 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c @@ -176,11 +176,6 @@ static struct platform_device *s3c24xx_snd_device; static int h1940_uda1380_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_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Speaker"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, &hp_jack); diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 2982d9e7f268..5b3e504d3a32 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c @@ -221,11 +221,6 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, static int rx1950_uda1380_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_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Speaker"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, &hp_jack); diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c index d8a0543cae5e..2d30b7b6818a 100644 --- a/sound/soc/samsung/s3c24xx_simtec_hermes.c +++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c @@ -63,14 +63,6 @@ static const struct snd_soc_dapm_route base_map[] = { */ static int simtec_hermes_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_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Line In"); - snd_soc_dapm_enable_pin(dapm, "Line Out"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - simtec_audio_init(rtd); return 0; diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c index 1ac0d7a63a3a..83f6c7d49cd6 100644 --- a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c +++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c @@ -52,14 +52,6 @@ static const struct snd_soc_dapm_route base_map[] = { */ static int simtec_tlv320aic23_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_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Line In"); - snd_soc_dapm_enable_pin(dapm, "Line Out"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - simtec_audio_init(rtd); return 0; diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index c3b2adafb7b5..df55db5d3554 100644 --- a/sound/soc/samsung/smartq_wm8987.c +++ b/sound/soc/samsung/smartq_wm8987.c @@ -162,8 +162,6 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "ROUT1"); /* set endpoints to default off mode */ - snd_soc_dapm_enable_pin(dapm, "Internal Speaker"); - snd_soc_dapm_enable_pin(dapm, "Internal Mic"); snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); /* Headphone jack detection */ diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 682eb4f7ba0c..fc25cc00f0f2 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -89,18 +89,6 @@ static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - /* HeadPhone */ - snd_soc_dapm_enable_pin(dapm, "HPOUT1R"); - snd_soc_dapm_enable_pin(dapm, "HPOUT1L"); - - /* MicIn */ - snd_soc_dapm_enable_pin(dapm, "IN1LN"); - snd_soc_dapm_enable_pin(dapm, "IN1RN"); - - /* LineIn */ - snd_soc_dapm_enable_pin(dapm, "IN2LN"); - snd_soc_dapm_enable_pin(dapm, "IN2RN"); - /* Other pins NC */ snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); snd_soc_dapm_nc_pin(dapm, "HPOUT2N"); diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 215b668166be..89424470a1f3 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -197,13 +197,12 @@ static void rsnd_dma_complete(void *data) * rsnd_dai_pointer_update() will be called twice, * ant it will breaks io->byte_pos */ - - rsnd_dai_pointer_update(io, io->byte_per_period); - if (dma->submit_loop) rsnd_dma_continue(dma); rsnd_unlock(priv, flags); + + rsnd_dai_pointer_update(io, io->byte_per_period); } static void __rsnd_dma_start(struct rsnd_dma *dma) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 6232b7d307aa..4d0720ed5a90 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -258,7 +258,7 @@ static int rsnd_src_init(struct rsnd_mod *mod, { struct rsnd_src *src = rsnd_mod_to_src(mod); - clk_enable(src->clk); + clk_prepare_enable(src->clk); return 0; } @@ -269,7 +269,7 @@ static int rsnd_src_quit(struct rsnd_mod *mod, { struct rsnd_src *src = rsnd_mod_to_src(mod); - clk_disable(src->clk); + clk_disable_unprepare(src->clk); return 0; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 4b7e20603dd7..1d8387c25bd8 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -171,7 +171,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, u32 cr; if (0 == ssi->usrcnt) { - clk_enable(ssi->clk); + clk_prepare_enable(ssi->clk); if (rsnd_dai_is_clk_master(rdai)) { if (rsnd_ssi_clk_from_parent(ssi)) @@ -230,7 +230,7 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, rsnd_ssi_master_clk_stop(ssi); } - clk_disable(ssi->clk); + clk_disable_unprepare(ssi->clk); } dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod)); diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index bfed3e4c45ff..3fa77d5f9b75 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -162,8 +162,6 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) i, codec_drv->reg_word_size) == val) continue; - WARN_ON(!snd_soc_codec_writable_register(codec, i)); - ret = snd_soc_write(codec, i, val); if (ret) return ret; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 91083e6a6b38..10f7f1da2aca 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -203,7 +203,6 @@ static int soc_compr_free(struct snd_compr_stream *cstream) if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); - cpu_dai->runtime = NULL; if (cstream->direction == SND_COMPRESS_PLAYBACK) { if (snd_soc_runtime_ignore_pmdown_time(rtd)) { @@ -317,8 +316,9 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) cmd == SND_COMPR_TRIGGER_DRAIN) { if (platform->driver->compr_ops && - platform->driver->compr_ops->trigger) - return platform->driver->compr_ops->trigger(cstream, cmd); + platform->driver->compr_ops->trigger) + return platform->driver->compr_ops->trigger(cstream, + cmd); } if (cstream->direction == SND_COMPRESS_PLAYBACK) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 051c006281f5..a53698266d57 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -154,22 +154,15 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf, step = codec->driver->reg_cache_step; for (i = 0; i < codec->driver->reg_cache_size; i += step) { - if (!snd_soc_codec_readable_register(codec, i)) - continue; - if (codec->driver->display_register) { - count += codec->driver->display_register(codec, buf + count, - PAGE_SIZE - count, i); - } else { - /* only support larger than PAGE_SIZE bytes debugfs - * entries for the default case */ - if (p >= pos) { - if (total + len >= count - 1) - break; - format_register_str(codec, i, buf + total, len); - total += len; - } - p += len; + /* only support larger than PAGE_SIZE bytes debugfs + * entries for the default case */ + if (p >= pos) { + if (total + len >= count - 1) + break; + format_register_str(codec, i, buf + total, len); + total += len; } + p += len; } total = min(total, count - 1); @@ -663,8 +656,8 @@ int snd_soc_suspend(struct device *dev) codec->driver->suspend(codec); codec->suspended = 1; codec->cache_sync = 1; - if (codec->using_regmap) - regcache_mark_dirty(codec->control_data); + if (codec->component.regmap) + regcache_mark_dirty(codec->component.regmap); /* deactivate pins to sleep state */ pinctrl_pm_select_sleep_state(codec->dev); break; @@ -854,14 +847,47 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); static const struct snd_soc_dai_ops null_dai_ops = { }; +static struct snd_soc_codec *soc_find_codec(const struct device_node *codec_of_node, + const char *codec_name) +{ + struct snd_soc_codec *codec; + + list_for_each_entry(codec, &codec_list, list) { + if (codec_of_node) { + if (codec->dev->of_node != codec_of_node) + continue; + } else { + if (strcmp(codec->name, codec_name)) + continue; + } + + return codec; + } + + return NULL; +} + +static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec, + const char *codec_dai_name) +{ + struct snd_soc_dai *codec_dai; + + list_for_each_entry(codec_dai, &codec->component.dai_list, list) { + if (!strcmp(codec_dai->name, codec_dai_name)) { + return codec_dai; + } + } + + return NULL; +} + 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; + struct snd_soc_dai *cpu_dai; const char *platform_name; dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); @@ -889,42 +915,24 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) return -EPROBE_DEFER; } - /* Find CODEC from registered CODECs */ - list_for_each_entry(codec, &codec_list, list) { - if (dai_link->codec_of_node) { - if (codec->dev->of_node != dai_link->codec_of_node) - continue; - } else { - if (strcmp(codec->name, dai_link->codec_name)) - continue; - } - - rtd->codec = codec; - - /* - * CODEC found, so find CODEC DAI from registered DAIs from - * this CODEC - */ - 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; - } - } - - if (!rtd->codec_dai) { - dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", - dai_link->codec_dai_name); - return -EPROBE_DEFER; - } - } - + /* Find CODEC from registered list */ + rtd->codec = soc_find_codec(dai_link->codec_of_node, + dai_link->codec_name); if (!rtd->codec) { dev_err(card->dev, "ASoC: CODEC %s not registered\n", dai_link->codec_name); return -EPROBE_DEFER; } + /* Find CODEC DAI from registered list */ + rtd->codec_dai = soc_find_codec_dai(rtd->codec, + dai_link->codec_dai_name); + if (!rtd->codec_dai) { + dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", + dai_link->codec_dai_name); + return -EPROBE_DEFER; + } + /* if there's no platform we match on the empty platform */ platform_name = dai_link->platform_name; if (!platform_name && !dai_link->platform_of_node) @@ -995,6 +1003,23 @@ static void soc_remove_codec(struct snd_soc_codec *codec) module_put(codec->dev->driver->owner); } +static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) +{ + int err; + + if (codec_dai && codec_dai->probed && + codec_dai->driver->remove_order == order) { + if (codec_dai->driver->remove) { + err = codec_dai->driver->remove(codec_dai); + if (err < 0) + dev_err(codec_dai->dev, + "ASoC: failed to remove %s: %d\n", + codec_dai->name, err); + } + codec_dai->probed = 0; + } +} + static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; @@ -1010,18 +1035,7 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) } /* remove the CODEC DAI */ - if (codec_dai && codec_dai->probed && - codec_dai->driver->remove_order == order) { - if (codec_dai->driver->remove) { - err = codec_dai->driver->remove(codec_dai); - if (err < 0) - dev_err(codec_dai->dev, - "ASoC: failed to remove %s: %d\n", - codec_dai->name, err); - } - codec_dai->probed = 0; - list_del(&codec_dai->card_list); - } + soc_remove_codec_dai(codec_dai, order); /* remove the cpu_dai */ if (cpu_dai && cpu_dai->probed && @@ -1034,7 +1048,6 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) cpu_dai->name, err); } cpu_dai->probed = 0; - list_del(&cpu_dai->card_list); if (!cpu_dai->codec) { snd_soc_dapm_free(&cpu_dai->dapm); @@ -1104,10 +1117,12 @@ static void soc_set_name_prefix(struct snd_soc_card *card, for (i = 0; i < card->num_configs; i++) { struct snd_soc_codec_conf *map = &card->codec_conf[i]; - if (map->dev_name && !strcmp(codec->name, map->dev_name)) { - codec->name_prefix = map->name_prefix; - break; - } + if (map->of_node && codec->dev->of_node != map->of_node) + continue; + if (map->dev_name && strcmp(codec->name, map->dev_name)) + continue; + codec->name_prefix = map->name_prefix; + break; } } @@ -1127,26 +1142,31 @@ static int soc_probe_codec(struct snd_soc_card *card, soc_init_codec_debugfs(codec); - if (driver->dapm_widgets) - snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, - driver->num_dapm_widgets); + if (driver->dapm_widgets) { + ret = snd_soc_dapm_new_controls(&codec->dapm, + driver->dapm_widgets, + driver->num_dapm_widgets); - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(dai, &codec->component.dai_list, list) - snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); + if (ret != 0) { + dev_err(codec->dev, + "Failed to create new controls %d\n", ret); + goto err_probe; + } + } - codec->dapm.idle_bias_off = driver->idle_bias_off; + /* Create DAPM widgets for each DAI stream */ + list_for_each_entry(dai, &codec->component.dai_list, list) { + ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); - if (!codec->write && dev_get_regmap(codec->dev, NULL)) { - /* Set the default I/O up try regmap */ - ret = snd_soc_codec_set_cache_io(codec, NULL); - if (ret < 0) { + if (ret != 0) { dev_err(codec->dev, - "Failed to set cache I/O: %d\n", ret); + "Failed to create DAI widgets %d\n", ret); goto err_probe; } } + codec->dapm.idle_bias_off = driver->idle_bias_off; + if (driver->probe) { ret = driver->probe(codec); if (ret < 0) { @@ -1366,6 +1386,66 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, return 0; } +static int soc_probe_codec_dai(struct snd_soc_card *card, + struct snd_soc_dai *codec_dai, + int order) +{ + int ret; + + if (!codec_dai->probed && codec_dai->driver->probe_order == order) { + if (codec_dai->driver->probe) { + ret = codec_dai->driver->probe(codec_dai); + if (ret < 0) { + dev_err(codec_dai->dev, + "ASoC: failed to probe CODEC DAI %s: %d\n", + codec_dai->name, ret); + return ret; + } + } + + /* mark codec_dai as probed and add to card dai list */ + codec_dai->probed = 1; + } + + return 0; +} + +static int soc_link_dai_widgets(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link, + struct snd_soc_dai *cpu_dai, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_dapm_widget *play_w, *capture_w; + int ret; + + /* link the DAI widgets */ + play_w = codec_dai->playback_widget; + capture_w = cpu_dai->capture_widget; + if (play_w && capture_w) { + ret = snd_soc_dapm_new_pcm(card, dai_link->params, + capture_w, play_w); + if (ret != 0) { + dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", + play_w->name, capture_w->name, ret); + return ret; + } + } + + play_w = cpu_dai->playback_widget; + capture_w = codec_dai->capture_widget; + if (play_w && capture_w) { + ret = snd_soc_dapm_new_pcm(card, dai_link->params, + capture_w, play_w); + if (ret != 0) { + dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", + play_w->name, capture_w->name, ret); + return ret; + } + } + + return 0; +} + static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; @@ -1374,7 +1454,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dapm_widget *play_w, *capture_w; int ret; dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", @@ -1410,26 +1489,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) } } cpu_dai->probed = 1; - /* mark cpu_dai as probed and add to card dai list */ - list_add(&cpu_dai->card_list, &card->dai_dev_list); } /* probe the CODEC DAI */ - if (!codec_dai->probed && codec_dai->driver->probe_order == order) { - if (codec_dai->driver->probe) { - ret = codec_dai->driver->probe(codec_dai); - if (ret < 0) { - dev_err(codec_dai->dev, - "ASoC: failed to probe CODEC DAI %s: %d\n", - codec_dai->name, ret); - return ret; - } - } - - /* mark codec_dai as probed and add to card dai list */ - codec_dai->probed = 1; - list_add(&codec_dai->card_list, &card->dai_dev_list); - } + ret = soc_probe_codec_dai(card, codec_dai, order); + if (ret) + return ret; /* complete DAI probe during last probe */ if (order != SND_SOC_COMP_ORDER_LAST) @@ -1467,29 +1532,10 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) codec2codec_close_delayed_work); /* link the DAI widgets */ - play_w = codec_dai->playback_widget; - capture_w = cpu_dai->capture_widget; - if (play_w && capture_w) { - ret = snd_soc_dapm_new_pcm(card, dai_link->params, - capture_w, play_w); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); - return ret; - } - } - - play_w = cpu_dai->playback_widget; - capture_w = codec_dai->capture_widget; - if (play_w && capture_w) { - ret = snd_soc_dapm_new_pcm(card, dai_link->params, - capture_w, play_w); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); - return ret; - } - } + ret = soc_link_dai_widgets(card, dai_link, + cpu_dai, codec_dai); + if (ret) + return ret; } } @@ -1501,14 +1547,15 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) } #ifdef CONFIG_SND_SOC_AC97_BUS -static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) +static int soc_register_ac97_codec(struct snd_soc_codec *codec, + struct snd_soc_dai *codec_dai) { int ret; /* Only instantiate AC97 if not already done by the adaptor * for the generic AC97 subsystem. */ - if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) { + if (codec_dai->driver->ac97_control && !codec->ac97_registered) { /* * It is possible that the AC97 device is already registered to * the device subsystem. This happens when the device is created @@ -1517,76 +1564,101 @@ static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) * * In those cases we don't try to register the device again. */ - if (!rtd->codec->ac97_created) + if (!codec->ac97_created) return 0; - ret = soc_ac97_dev_register(rtd->codec); + ret = soc_ac97_dev_register(codec); if (ret < 0) { - dev_err(rtd->codec->dev, + dev_err(codec->dev, "ASoC: AC97 device register failed: %d\n", ret); return ret; } - rtd->codec->ac97_registered = 1; + codec->ac97_registered = 1; } return 0; } -static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec) +static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) +{ + return soc_register_ac97_codec(rtd->codec, rtd->codec_dai); +} + +static void soc_unregister_ac97_codec(struct snd_soc_codec *codec) { if (codec->ac97_registered) { soc_ac97_dev_unregister(codec); codec->ac97_registered = 0; } } + +static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) +{ + soc_unregister_ac97_codec(rtd->codec); +} #endif -static int soc_check_aux_dev(struct snd_soc_card *card, int num) +static struct snd_soc_codec *soc_find_matching_codec(struct snd_soc_card *card, + int num) { struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; struct snd_soc_codec *codec; - /* find CODEC from registered CODECs*/ + /* find CODEC from registered CODECs */ list_for_each_entry(codec, &codec_list, list) { - if (!strcmp(codec->name, aux_dev->codec_name)) - return 0; + if (aux_dev->codec_of_node && + (codec->dev->of_node != aux_dev->codec_of_node)) + continue; + if (aux_dev->codec_name && strcmp(codec->name, aux_dev->codec_name)) + continue; + return codec; } - dev_err(card->dev, "ASoC: %s not registered\n", aux_dev->codec_name); + return NULL; +} + +static int soc_check_aux_dev(struct snd_soc_card *card, int num) +{ + struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; + const char *codecname = aux_dev->codec_name; + struct snd_soc_codec *codec = soc_find_matching_codec(card, num); + + if (codec) + return 0; + if (aux_dev->codec_of_node) + codecname = of_node_full_name(aux_dev->codec_of_node); + dev_err(card->dev, "ASoC: %s not registered\n", codecname); return -EPROBE_DEFER; } static int soc_probe_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - struct snd_soc_codec *codec; + const char *codecname = aux_dev->codec_name; int ret = -ENODEV; + struct snd_soc_codec *codec = soc_find_matching_codec(card, num); - /* find CODEC from registered CODECs*/ - list_for_each_entry(codec, &codec_list, list) { - if (!strcmp(codec->name, aux_dev->codec_name)) { - if (codec->probed) { - dev_err(codec->dev, - "ASoC: codec already probed"); - ret = -EBUSY; - goto out; - } - goto found; - } + if (!codec) { + if (aux_dev->codec_of_node) + codecname = of_node_full_name(aux_dev->codec_of_node); + + /* codec not found */ + dev_err(card->dev, "ASoC: codec %s not found", codecname); + return -EPROBE_DEFER; + } + + if (codec->probed) { + dev_err(codec->dev, "ASoC: codec already probed"); + return -EBUSY; } - /* codec not found */ - dev_err(card->dev, "ASoC: codec %s not found", aux_dev->codec_name); - return -EPROBE_DEFER; -found: ret = soc_probe_codec(card, codec); if (ret < 0) return ret; ret = soc_post_component_init(card, codec, num, 1); -out: return ret; } @@ -1837,7 +1909,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: failed to register AC97: %d\n", ret); while (--i >= 0) - soc_unregister_ac97_dai_link(card->rtd[i].codec); + soc_unregister_ac97_dai_link(&card->rtd[i]); goto probe_aux_dev_err; } } @@ -1980,92 +2052,6 @@ static struct platform_driver soc_driver = { }; /** - * snd_soc_codec_volatile_register: Report if a register is volatile. - * - * @codec: CODEC to query. - * @reg: Register to query. - * - * Boolean function indiciating if a CODEC register is volatile. - */ -int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - if (codec->volatile_register) - return codec->volatile_register(codec, reg); - else - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register); - -/** - * snd_soc_codec_readable_register: Report if a register is readable. - * - * @codec: CODEC to query. - * @reg: Register to query. - * - * Boolean function indicating if a CODEC register is readable. - */ -int snd_soc_codec_readable_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - if (codec->readable_register) - return codec->readable_register(codec, reg); - else - return 1; -} -EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register); - -/** - * snd_soc_codec_writable_register: Report if a register is writable. - * - * @codec: CODEC to query. - * @reg: Register to query. - * - * Boolean function indicating if a CODEC register is writable. - */ -int snd_soc_codec_writable_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - if (codec->writable_register) - return codec->writable_register(codec, reg); - else - return 1; -} -EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register); - -int snd_soc_platform_read(struct snd_soc_platform *platform, - unsigned int reg) -{ - unsigned int ret; - - if (!platform->driver->read) { - dev_err(platform->dev, "ASoC: platform has no read back\n"); - return -1; - } - - ret = platform->driver->read(platform, reg); - dev_dbg(platform->dev, "read %x => %x\n", reg, ret); - trace_snd_soc_preg_read(platform, reg, ret); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_platform_read); - -int snd_soc_platform_write(struct snd_soc_platform *platform, - unsigned int reg, unsigned int val) -{ - if (!platform->driver->write) { - dev_err(platform->dev, "ASoC: platform has no write back\n"); - return -1; - } - - dev_dbg(platform->dev, "write %x = %x\n", reg, val); - trace_snd_soc_preg_write(platform, reg, val); - return platform->driver->write(platform, reg, val); -} -EXPORT_SYMBOL_GPL(snd_soc_platform_write); - -/** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec * @ops: AC97 bus operations @@ -2153,28 +2139,28 @@ static int snd_soc_ac97_parse_pinctl(struct device *dev, p = devm_pinctrl_get(dev); if (IS_ERR(p)) { dev_err(dev, "Failed to get pinctrl\n"); - return PTR_RET(p); + return PTR_ERR(p); } cfg->pctl = p; state = pinctrl_lookup_state(p, "ac97-reset"); if (IS_ERR(state)) { dev_err(dev, "Can't find pinctrl state ac97-reset\n"); - return PTR_RET(state); + return PTR_ERR(state); } cfg->pstate_reset = state; state = pinctrl_lookup_state(p, "ac97-warm-reset"); if (IS_ERR(state)) { dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); - return PTR_RET(state); + return PTR_ERR(state); } cfg->pstate_warm_reset = state; state = pinctrl_lookup_state(p, "ac97-running"); if (IS_ERR(state)) { dev_err(dev, "Can't find pinctrl state ac97-running\n"); - return PTR_RET(state); + return PTR_ERR(state); } cfg->pstate_run = state; @@ -2273,7 +2259,7 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) { mutex_lock(&codec->mutex); #ifdef CONFIG_SND_SOC_AC97_BUS - soc_unregister_ac97_dai_link(codec); + soc_unregister_ac97_codec(codec); #endif kfree(codec->ac97->bus); kfree(codec->ac97); @@ -2283,118 +2269,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); -unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg) -{ - unsigned int ret; - - ret = codec->read(codec, reg); - dev_dbg(codec->dev, "read %x => %x\n", reg, ret); - trace_snd_soc_reg_read(codec, reg, ret); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_read); - -unsigned int snd_soc_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int val) -{ - dev_dbg(codec->dev, "write %x = %x\n", reg, val); - trace_snd_soc_reg_write(codec, reg, val); - return codec->write(codec, reg, val); -} -EXPORT_SYMBOL_GPL(snd_soc_write); - -/** - * snd_soc_update_bits - update codec register bits - * @codec: audio codec - * @reg: codec register - * @mask: register mask - * @value: new value - * - * Writes new register value. - * - * Returns 1 for change, 0 for no change, or negative error code. - */ -int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, - unsigned int mask, unsigned int value) -{ - bool change; - unsigned int old, new; - int ret; - - if (codec->using_regmap) { - ret = regmap_update_bits_check(codec->control_data, reg, - mask, value, &change); - } else { - ret = snd_soc_read(codec, reg); - if (ret < 0) - return ret; - - old = ret; - new = (old & ~mask) | (value & mask); - change = old != new; - if (change) - ret = snd_soc_write(codec, reg, new); - } - - if (ret < 0) - return ret; - - return change; -} -EXPORT_SYMBOL_GPL(snd_soc_update_bits); - -/** - * snd_soc_update_bits_locked - update codec register bits - * @codec: audio codec - * @reg: codec register - * @mask: register mask - * @value: new value - * - * Writes new register value, and takes the codec mutex. - * - * Returns 1 for change else 0. - */ -int snd_soc_update_bits_locked(struct snd_soc_codec *codec, - unsigned short reg, unsigned int mask, - unsigned int value) -{ - int change; - - mutex_lock(&codec->mutex); - change = snd_soc_update_bits(codec, reg, mask, value); - mutex_unlock(&codec->mutex); - - return change; -} -EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked); - -/** - * snd_soc_test_bits - test register for change - * @codec: audio codec - * @reg: codec register - * @mask: register mask - * @value: new value - * - * Tests a register with a new value and checks if the new value is - * different from the old value. - * - * Returns 1 for change else 0. - */ -int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, - unsigned int mask, unsigned int value) -{ - int change; - unsigned int old, new; - - old = snd_soc_read(codec, reg); - new = (old & ~mask) | value; - change = old != new; - - return change; -} -EXPORT_SYMBOL_GPL(snd_soc_test_bits); - /** * snd_soc_cnew - create new control * @_template: control template @@ -2491,7 +2365,7 @@ int snd_soc_add_codec_controls(struct snd_soc_codec *codec, struct snd_card *card = codec->card->snd_card; return snd_soc_add_controls(card, codec->dev, controls, num_controls, - codec->name_prefix, codec); + codec->name_prefix, &codec->component); } EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls); @@ -2511,7 +2385,7 @@ int snd_soc_add_platform_controls(struct snd_soc_platform *platform, struct snd_card *card = platform->card->snd_card; return snd_soc_add_controls(card, platform->dev, controls, num_controls, - NULL, platform); + NULL, &platform->component); } EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls); @@ -2595,12 +2469,15 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int val, item; unsigned int reg_val; + int ret; - reg_val = snd_soc_read(codec, e->reg); + ret = snd_soc_component_read(component, e->reg, ®_val); + if (ret) + return ret; val = (reg_val >> e->shift_l) & e->mask; item = snd_soc_enum_val_to_item(e, val); ucontrol->value.enumerated.item[0] = item; @@ -2626,7 +2503,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int *item = ucontrol->value.enumerated.item; unsigned int val; @@ -2643,38 +2520,48 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, mask |= e->mask << e->shift_r; } - return snd_soc_update_bits_locked(codec, e->reg, mask, val); + return snd_soc_component_update_bits(component, e->reg, mask, val); } EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); /** * snd_soc_read_signed - Read a codec register and interprete as signed value - * @codec: codec + * @component: component * @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. + * @signed_val: Pointer to where the read value should be stored * * 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 the register value as signed int. + * Returns 0 on sucess, otherwise an error value */ -static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg, - unsigned int mask, unsigned int shift, unsigned int sign_bit) +static int snd_soc_read_signed(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, unsigned int shift, + unsigned int sign_bit, int *signed_val) { int ret; unsigned int val; - val = (snd_soc_read(codec, reg) >> shift) & mask; + ret = snd_soc_component_read(component, reg, &val); + if (ret < 0) + return ret; - if (!sign_bit) - return val; + val = (val >> shift) & mask; + + if (!sign_bit) { + *signed_val = val; + return 0; + } /* non-negative number */ - if (!(val & BIT(sign_bit))) - return val; + if (!(val & BIT(sign_bit))) { + *signed_val = val; + return 0; + } ret = val; @@ -2686,7 +2573,9 @@ static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg, */ ret |= ~((int)(BIT(sign_bit) - 1)); - return ret; + *signed_val = ret; + + return 0; } /** @@ -2735,9 +2624,9 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw); int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -2747,25 +2636,32 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, int sign_bit = mc->sign_bit; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; + int val; + int ret; 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; + ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = val - min; if (invert) ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0]; if (snd_soc_volsw_is_stereo(mc)) { if (reg == reg2) - ucontrol->value.integer.value[1] = - snd_soc_read_signed(codec, reg, mask, rshift, - sign_bit) - min; + ret = snd_soc_read_signed(component, reg, mask, rshift, + sign_bit, &val); else - ucontrol->value.integer.value[1] = - snd_soc_read_signed(codec, reg2, mask, shift, - sign_bit) - min; + ret = snd_soc_read_signed(component, reg2, mask, shift, + sign_bit, &val); + if (ret) + return ret; + + ucontrol->value.integer.value[1] = val - min; if (invert) ucontrol->value.integer.value[1] = max - ucontrol->value.integer.value[1]; @@ -2788,9 +2684,9 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw); int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -2825,12 +2721,13 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, type_2r = true; } } - err = snd_soc_update_bits_locked(codec, reg, val_mask, val); + err = snd_soc_component_update_bits(component, reg, val_mask, val); if (err < 0) return err; if (type_2r) - err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2); + err = snd_soc_component_update_bits(component, reg2, val_mask, + val2); return err; } @@ -2849,10 +2746,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw); int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; @@ -2860,13 +2756,23 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, int max = mc->max; int min = mc->min; int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int val; + int ret; - ucontrol->value.integer.value[0] = - ((snd_soc_read(codec, reg) >> shift) - min) & mask; + ret = snd_soc_component_read(component, reg, &val); + if (ret < 0) + return ret; - if (snd_soc_volsw_is_stereo(mc)) - ucontrol->value.integer.value[1] = - ((snd_soc_read(codec, reg2) >> rshift) - min) & mask; + ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask; + + if (snd_soc_volsw_is_stereo(mc)) { + ret = snd_soc_component_read(component, reg2, &val); + if (ret < 0) + return ret; + + val = ((val >> rshift) - min) & mask; + ucontrol->value.integer.value[1] = val; + } return 0; } @@ -2884,7 +2790,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -2896,13 +2802,13 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, int min = mc->min; int mask = (1 << (fls(min + max) - 1)) - 1; int err = 0; - unsigned short val, val_mask, val2 = 0; + unsigned int val, val_mask, val2 = 0; val_mask = mask << shift; val = (ucontrol->value.integer.value[0] + min) & mask; val = val << shift; - err = snd_soc_update_bits_locked(codec, reg, val_mask, val); + err = snd_soc_component_update_bits(component, reg, val_mask, val); if (err < 0) return err; @@ -2911,10 +2817,10 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, val2 = (ucontrol->value.integer.value[1] + min) & mask; val2 = val2 << rshift; - if (snd_soc_update_bits_locked(codec, reg2, val_mask, val2)) - return err; + err = snd_soc_component_update_bits(component, reg2, val_mask, + val2); } - return 0; + return err; } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); @@ -2961,10 +2867,15 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; + unsigned int val; int min = mc->min; - int val = snd_soc_read(codec, reg); + int ret; + + ret = snd_soc_component_read(component, reg, &val); + if (ret) + return ret; ucontrol->value.integer.value[0] = ((signed char)(val & 0xff))-min; @@ -2988,7 +2899,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; int min = mc->min; unsigned int val; @@ -2996,7 +2907,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, val = (ucontrol->value.integer.value[0]+min) & 0xff; val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; - return snd_soc_update_bits_locked(codec, reg, 0xffff, val); + return snd_soc_component_update_bits(component, reg, 0xffff, val); } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); @@ -3045,7 +2956,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; unsigned int rreg = mc->rreg; unsigned int shift = mc->shift; @@ -3062,7 +2973,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, val_mask = mask << shift; val = val << shift; - ret = snd_soc_update_bits_locked(codec, reg, val_mask, val); + ret = snd_soc_component_update_bits(component, reg, val_mask, val); if (ret < 0) return ret; @@ -3073,7 +2984,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, val_mask = mask << shift; val = val << shift; - ret = snd_soc_update_bits_locked(codec, rreg, val_mask, val); + ret = snd_soc_component_update_bits(component, rreg, val_mask, + val); } return ret; @@ -3092,9 +3004,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; unsigned int rreg = mc->rreg; unsigned int shift = mc->shift; @@ -3102,9 +3014,14 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; + unsigned int val; + int ret; - ucontrol->value.integer.value[0] = - (snd_soc_read(codec, reg) >> shift) & mask; + ret = snd_soc_component_read(component, reg, &val); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = (val >> shift) & mask; if (invert) ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0]; @@ -3112,8 +3029,11 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] - min; if (snd_soc_volsw_is_stereo(mc)) { - ucontrol->value.integer.value[1] = - (snd_soc_read(codec, rreg) >> shift) & mask; + ret = snd_soc_component_read(component, rreg, &val); + if (ret) + return ret; + + ucontrol->value.integer.value[1] = (val >> shift) & mask; if (invert) ucontrol->value.integer.value[1] = max - ucontrol->value.integer.value[1]; @@ -3167,11 +3087,11 @@ EXPORT_SYMBOL_GPL(snd_soc_limit_volume); int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_bytes *params = (void *)kcontrol->private_value; uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = params->num_regs * codec->val_bytes; + uinfo->count = params->num_regs * component->val_bytes; return 0; } @@ -3180,20 +3100,20 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_info); int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_bytes *params = (void *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int ret; - if (codec->using_regmap) - ret = regmap_raw_read(codec->control_data, params->base, + if (component->regmap) + ret = regmap_raw_read(component->regmap, params->base, ucontrol->value.bytes.data, - params->num_regs * codec->val_bytes); + params->num_regs * component->val_bytes); else ret = -EINVAL; /* Hide any masked bytes to ensure consistent data reporting */ if (ret == 0 && params->mask) { - switch (codec->val_bytes) { + switch (component->val_bytes) { case 1: ucontrol->value.bytes.data[0] &= ~params->mask; break; @@ -3217,16 +3137,16 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_get); int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_bytes *params = (void *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); int ret, len; unsigned int val, mask; void *data; - if (!codec->using_regmap) + if (!component->regmap) return -EINVAL; - len = params->num_regs * codec->val_bytes; + len = params->num_regs * component->val_bytes; data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); if (!data) @@ -3238,27 +3158,27 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, * copy. */ if (params->mask) { - ret = regmap_read(codec->control_data, params->base, &val); + ret = regmap_read(component->regmap, params->base, &val); if (ret != 0) goto out; val &= params->mask; - switch (codec->val_bytes) { + switch (component->val_bytes) { case 1: ((u8 *)data)[0] &= ~params->mask; ((u8 *)data)[0] |= val; break; case 2: mask = ~params->mask; - ret = regmap_parse_val(codec->control_data, + ret = regmap_parse_val(component->regmap, &mask, &mask); if (ret != 0) goto out; ((u16 *)data)[0] &= mask; - ret = regmap_parse_val(codec->control_data, + ret = regmap_parse_val(component->regmap, &val, &val); if (ret != 0) goto out; @@ -3267,14 +3187,14 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, break; case 4: mask = ~params->mask; - ret = regmap_parse_val(codec->control_data, + ret = regmap_parse_val(component->regmap, &mask, &mask); if (ret != 0) goto out; ((u32 *)data)[0] &= mask; - ret = regmap_parse_val(codec->control_data, + ret = regmap_parse_val(component->regmap, &val, &val); if (ret != 0) goto out; @@ -3287,7 +3207,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, } } - ret = regmap_raw_write(codec->control_data, params->base, + ret = regmap_raw_write(component->regmap, params->base, data, len); out: @@ -3297,6 +3217,18 @@ out: } EXPORT_SYMBOL_GPL(snd_soc_bytes_put); +int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *ucontrol) +{ + struct soc_bytes_ext *params = (void *)kcontrol->private_value; + + ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; + ucontrol->count = params->max; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext); + /** * snd_soc_info_xr_sx - signed multi register info callback * @kcontrol: mreg control @@ -3338,24 +3270,27 @@ EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx); int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mreg_control *mc = (struct soc_mreg_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int regbase = mc->regbase; unsigned int regcount = mc->regcount; - unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE; + unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; unsigned int regwmask = (1<<regwshift)-1; unsigned int invert = mc->invert; unsigned long mask = (1UL<<mc->nbits)-1; long min = mc->min; long max = mc->max; long val = 0; - unsigned long regval; + unsigned int regval; unsigned int i; + int ret; for (i = 0; i < regcount; i++) { - regval = snd_soc_read(codec, regbase+i) & regwmask; - val |= regval << (regwshift*(regcount-i-1)); + ret = snd_soc_component_read(component, regbase+i, ®val); + if (ret) + return ret; + val |= (regval & regwmask) << (regwshift*(regcount-i-1)); } val &= mask; if (min < 0 && val > max) @@ -3384,12 +3319,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx); int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mreg_control *mc = (struct soc_mreg_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int regbase = mc->regbase; unsigned int regcount = mc->regcount; - unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE; + unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; unsigned int regwmask = (1<<regwshift)-1; unsigned int invert = mc->invert; unsigned long mask = (1UL<<mc->nbits)-1; @@ -3404,7 +3339,7 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, for (i = 0; i < regcount; i++) { regval = (val >> (regwshift*(regcount-i-1))) & regwmask; regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; - err = snd_soc_update_bits_locked(codec, regbase+i, + err = snd_soc_component_update_bits(component, regbase+i, regmask, regval); if (err < 0) return err; @@ -3426,14 +3361,21 @@ EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx); int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; unsigned int shift = mc->shift; unsigned int mask = 1 << shift; unsigned int invert = mc->invert != 0; - unsigned int val = snd_soc_read(codec, reg) & mask; + unsigned int val; + int ret; + + ret = snd_soc_component_read(component, reg, &val); + if (ret) + return ret; + + val &= mask; if (shift != 0 && val != 0) val = val >> shift; @@ -3456,9 +3398,9 @@ EXPORT_SYMBOL_GPL(snd_soc_get_strobe); int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; unsigned int shift = mc->shift; unsigned int mask = 1 << shift; @@ -3468,12 +3410,11 @@ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, unsigned int val2 = (strobe ^ invert) ? 0 : mask; int err; - err = snd_soc_update_bits_locked(codec, reg, mask, val1); + err = snd_soc_component_update_bits(component, reg, mask, val1); if (err < 0) return err; - err = snd_soc_update_bits_locked(codec, reg, mask, val2); - return err; + return snd_soc_component_update_bits(component, reg, mask, val2); } EXPORT_SYMBOL_GPL(snd_soc_put_strobe); @@ -3821,7 +3762,6 @@ int snd_soc_register_card(struct snd_soc_card *card) for (i = 0; i < card->num_links; i++) card->rtd[i].dai_link = &card->dai_link[i]; - INIT_LIST_HEAD(&card->list); INIT_LIST_HEAD(&card->dapm_dirty); card->instantiated = 0; mutex_init(&card->mutex); @@ -4037,6 +3977,8 @@ __snd_soc_register_component(struct device *dev, return -ENOMEM; } + mutex_init(&cmpnt->io_mutex); + cmpnt->name = fmt_single_name(dev, &cmpnt->id); if (!cmpnt->name) { dev_err(dev, "ASoC: Failed to simplifying name\n"); @@ -4084,12 +4026,25 @@ int snd_soc_register_component(struct device *dev, } cmpnt->ignore_pmdown_time = true; + cmpnt->registered_as_component = true; return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL, dai_drv, num_dai, true); } EXPORT_SYMBOL_GPL(snd_soc_register_component); +static void __snd_soc_unregister_component(struct snd_soc_component *cmpnt) +{ + snd_soc_unregister_dais(cmpnt); + + mutex_lock(&client_mutex); + list_del(&cmpnt->list); + mutex_unlock(&client_mutex); + + dev_dbg(cmpnt->dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); + kfree(cmpnt->name); +} + /** * snd_soc_unregister_component - Unregister a component from the ASoC core * @@ -4099,22 +4054,33 @@ void snd_soc_unregister_component(struct device *dev) struct snd_soc_component *cmpnt; list_for_each_entry(cmpnt, &component_list, list) { - if (dev == cmpnt->dev) + if (dev == cmpnt->dev && cmpnt->registered_as_component) goto found; } return; found: - snd_soc_unregister_dais(cmpnt); + __snd_soc_unregister_component(cmpnt); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_component); - mutex_lock(&client_mutex); - list_del(&cmpnt->list); - mutex_unlock(&client_mutex); +static int snd_soc_platform_drv_write(struct snd_soc_component *component, + unsigned int reg, unsigned int val) +{ + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); - kfree(cmpnt->name); + return platform->driver->write(platform, reg, val); +} + +static int snd_soc_platform_drv_read(struct snd_soc_component *component, + unsigned int reg, unsigned int *val) +{ + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); + + *val = platform->driver->read(platform, reg); + + return 0; } -EXPORT_SYMBOL_GPL(snd_soc_unregister_component); /** * snd_soc_add_platform - Add a platform to the ASoC core @@ -4125,6 +4091,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_component); int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, const struct snd_soc_platform_driver *platform_drv) { + int ret; + /* create platform component name */ platform->name = fmt_single_name(dev, &platform->id); if (platform->name == NULL) @@ -4134,8 +4102,22 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->driver = platform_drv; platform->dapm.dev = dev; platform->dapm.platform = platform; + platform->dapm.component = &platform->component; platform->dapm.stream_event = platform_drv->stream_event; - mutex_init(&platform->mutex); + if (platform_drv->write) + platform->component.write = snd_soc_platform_drv_write; + if (platform_drv->read) + platform->component.read = snd_soc_platform_drv_read; + + /* register component */ + ret = __snd_soc_register_component(dev, &platform->component, + &platform_drv->component_driver, + NULL, NULL, 0, false); + if (ret < 0) { + dev_err(platform->component.dev, + "ASoC: Failed to register component: %d\n", ret); + return ret; + } mutex_lock(&client_mutex); list_add(&platform->list, &platform_list); @@ -4178,6 +4160,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform); */ void snd_soc_remove_platform(struct snd_soc_platform *platform) { + __snd_soc_unregister_component(&platform->component); + mutex_lock(&client_mutex); list_del(&platform->list); mutex_unlock(&client_mutex); @@ -4252,6 +4236,24 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) stream->formats |= codec_format_map[i]; } +static int snd_soc_codec_drv_write(struct snd_soc_component *component, + unsigned int reg, unsigned int val) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->write(codec, reg, val); +} + +static int snd_soc_codec_drv_read(struct snd_soc_component *component, + unsigned int reg, unsigned int *val) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + *val = codec->driver->read(codec, reg); + + return 0; +} + /** * snd_soc_register_codec - Register a codec with the ASoC core * @@ -4263,6 +4265,7 @@ int snd_soc_register_codec(struct device *dev, int num_dai) { struct snd_soc_codec *codec; + struct regmap *regmap; int ret, i; dev_dbg(dev, "codec register %s\n", dev_name(dev)); @@ -4278,22 +4281,40 @@ int snd_soc_register_codec(struct device *dev, goto fail_codec; } - codec->write = codec_drv->write; - codec->read = codec_drv->read; - codec->volatile_register = codec_drv->volatile_register; - codec->readable_register = codec_drv->readable_register; - codec->writable_register = codec_drv->writable_register; + if (codec_drv->write) + codec->component.write = snd_soc_codec_drv_write; + if (codec_drv->read) + codec->component.read = snd_soc_codec_drv_read; 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; + codec->dapm.component = &codec->component; codec->dapm.seq_notifier = codec_drv->seq_notifier; codec->dapm.stream_event = codec_drv->stream_event; codec->dev = dev; codec->driver = codec_drv; - codec->num_dai = num_dai; + codec->component.val_bytes = codec_drv->reg_word_size; mutex_init(&codec->mutex); + if (!codec->component.write) { + if (codec_drv->get_regmap) + regmap = codec_drv->get_regmap(dev); + else + regmap = dev_get_regmap(dev, NULL); + + if (regmap) { + ret = snd_soc_component_init_io(&codec->component, + regmap); + if (ret) { + dev_err(codec->dev, + "Failed to set cache I/O:%d\n", + ret); + return ret; + } + } + } + for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); fixup_codec_formats(&dai_drv[i].capture); @@ -4343,7 +4364,7 @@ void snd_soc_unregister_codec(struct device *dev) return; found: - snd_soc_unregister_component(dev); + __snd_soc_unregister_component(&codec->component); mutex_lock(&client_mutex); list_del(&codec->list); @@ -4698,7 +4719,7 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, if (id < 0 || id >= pos->num_dai) { ret = -EINVAL; - break; + continue; } ret = 0; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c8a780d0d057..a74b9bf23d9f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -254,7 +254,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, static void dapm_kcontrol_free(struct snd_kcontrol *kctl) { struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl); - kfree(data->widget); kfree(data->wlist); kfree(data); } @@ -379,86 +378,24 @@ static void dapm_reset(struct snd_soc_card *card) static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, unsigned int *value) { - if (w->codec) { - *value = snd_soc_read(w->codec, reg); - return 0; - } else if (w->platform) { - *value = snd_soc_platform_read(w->platform, reg); - return 0; - } - - dev_err(w->dapm->dev, "ASoC: no valid widget read method\n"); - return -1; -} - -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); - else if (w->platform) - return snd_soc_platform_write(w->platform, reg, val); - - dev_err(w->dapm->dev, "ASoC: no valid widget write method\n"); - return -1; -} - -static inline void soc_widget_lock(struct snd_soc_dapm_widget *w) -{ - if (w->codec && !w->codec->using_regmap) - mutex_lock(&w->codec->mutex); - else if (w->platform) - mutex_lock(&w->platform->mutex); + if (!w->dapm->component) + return -EIO; + return snd_soc_component_read(w->dapm->component, reg, value); } -static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w) +static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, + int reg, unsigned int mask, unsigned int value) { - if (w->codec && !w->codec->using_regmap) - mutex_unlock(&w->codec->mutex); - else if (w->platform) - mutex_unlock(&w->platform->mutex); + if (!w->dapm->component) + return -EIO; + return snd_soc_component_update_bits_async(w->dapm->component, reg, + mask, value); } static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) { - if (dapm->codec && dapm->codec->using_regmap) - regmap_async_complete(dapm->codec->control_data); -} - -static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w, - unsigned short reg, unsigned int mask, unsigned int value) -{ - bool change; - unsigned int old, new; - int ret; - - if (w->codec && w->codec->using_regmap) { - ret = regmap_update_bits_check_async(w->codec->control_data, - reg, mask, value, - &change); - if (ret != 0) - return ret; - } else { - soc_widget_lock(w); - ret = soc_widget_read(w, reg, &old); - if (ret < 0) { - soc_widget_unlock(w); - return ret; - } - - new = (old & ~mask) | (value & mask); - change = old != new; - if (change) { - ret = soc_widget_write(w, reg, new); - if (ret < 0) { - soc_widget_unlock(w); - return ret; - } - } - soc_widget_unlock(w); - } - - return change; + if (dapm->component) + snd_soc_component_async_complete(dapm->component); } /** @@ -1121,26 +1058,6 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, } /* - * Handler for generic register modifier widget. - */ -int dapm_reg_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - unsigned int val; - - if (SND_SOC_DAPM_EVENT_ON(event)) - val = w->on_val; - else - val = w->off_val; - - soc_widget_update_bits_locked(w, -(w->reg + 1), - w->mask << w->shift, val << w->shift); - - return 0; -} -EXPORT_SYMBOL_GPL(dapm_reg_event); - -/* * Handler for regulator supply widget. */ int dapm_regulator_event(struct snd_soc_dapm_widget *w, @@ -1429,7 +1346,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card, "pop test : Applying 0x%x/0x%x to %x in %dms\n", value, mask, reg, card->pop_time); pop_wait(card->pop_time); - soc_widget_update_bits_locked(w, reg, mask, value); + soc_widget_update_bits(w, reg, mask, value); } list_for_each_entry(w, pending, power_list) { @@ -1575,8 +1492,7 @@ static void dapm_widget_update(struct snd_soc_card *card) if (!w) return; - ret = soc_widget_update_bits_locked(w, update->reg, update->mask, - update->val); + ret = soc_widget_update_bits(w, update->reg, update->mask, update->val); if (ret < 0) dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", w->name, ret); @@ -1613,8 +1529,11 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) "ASoC: Failed to turn on bias: %d\n", ret); } - /* Prepare for a STADDBY->ON or ON->STANDBY transition */ - if (d->bias_level != d->target_bias_level) { + /* Prepare for a transition to ON or away from ON */ + if ((d->target_bias_level == SND_SOC_BIAS_ON && + d->bias_level != SND_SOC_BIAS_ON) || + (d->target_bias_level != SND_SOC_BIAS_ON && + d->bias_level == SND_SOC_BIAS_ON)) { ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); if (ret != 0) dev_err(d->dev, @@ -2444,8 +2363,7 @@ err: } static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_route *route, - unsigned int is_prefixed) + const struct snd_soc_dapm_route *route) { struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; @@ -2455,7 +2373,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, char prefixed_source[80]; int ret; - if (dapm->codec && dapm->codec->name_prefix && !is_prefixed) { + if (dapm->codec && dapm->codec->name_prefix) { snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", dapm->codec->name_prefix, route->sink); sink = prefixed_sink; @@ -2583,7 +2501,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); for (i = 0; i < num; i++) { - r = snd_soc_dapm_add_route(dapm, route, false); + r = snd_soc_dapm_add_route(dapm, route); if (r < 0) { dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n", route->source, @@ -2855,22 +2773,19 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); change = dapm_kcontrol_set_value(kcontrol, val); - - if (reg != SND_SOC_NOPM) { - mask = mask << shift; - val = val << shift; - - change = snd_soc_test_bits(codec, reg, mask, val); - } - if (change) { if (reg != SND_SOC_NOPM) { - update.kcontrol = kcontrol; - update.reg = reg; - update.mask = mask; - update.val = val; + mask = mask << shift; + val = val << shift; + + if (snd_soc_test_bits(codec, reg, mask, val)) { + update.kcontrol = kcontrol; + update.reg = reg; + update.mask = mask; + update.val = val; + card->update = &update; + } - card->update = &update; } ret = soc_dapm_mixer_update_power(card, kcontrol, connect); @@ -3309,11 +3224,11 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct snd_soc_dapm_route routes[2]; struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; size_t len; char *link_name; + int ret; len = strlen(source->name) + strlen(sink->name) + 2; link_name = devm_kzalloc(card->dev, len, GFP_KERNEL); @@ -3340,15 +3255,10 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, w->params = params; - memset(&routes, 0, sizeof(routes)); - - routes[0].source = source->name; - routes[0].sink = link_name; - routes[1].source = link_name; - routes[1].sink = sink->name; - - return snd_soc_dapm_add_routes(&card->dapm, routes, - ARRAY_SIZE(routes)); + ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL); + if (ret) + return ret; + return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL); } int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, @@ -3406,6 +3316,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) { struct snd_soc_dapm_widget *dai_w, *w; + struct snd_soc_dapm_widget *src, *sink; struct snd_soc_dai *dai; /* For each DAI widget... */ @@ -3436,25 +3347,15 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) if (!w->sname || !strstr(w->sname, dai_w->name)) continue; - if (dai->driver->playback.stream_name && - strstr(w->sname, - dai->driver->playback.stream_name)) { - dev_dbg(dai->dev, "%s -> %s\n", - dai->playback_widget->name, w->name); - - snd_soc_dapm_add_path(w->dapm, - dai->playback_widget, w, NULL, NULL); - } - - if (dai->driver->capture.stream_name && - strstr(w->sname, - dai->driver->capture.stream_name)) { - dev_dbg(dai->dev, "%s -> %s\n", - w->name, dai->capture_widget->name); - - snd_soc_dapm_add_path(w->dapm, w, - dai->capture_widget, NULL, NULL); + if (dai_w->id == snd_soc_dapm_dai_in) { + src = dai_w; + sink = w; + } else { + src = w; + sink = dai_w; } + dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name); + snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL); } } @@ -3464,20 +3365,21 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd = card->rtd; + struct snd_soc_dapm_widget *sink, *source; struct snd_soc_dai *cpu_dai, *codec_dai; - struct snd_soc_dapm_route r; int i; - memset(&r, 0, sizeof(r)); - /* for each BE DAI link... */ for (i = 0; i < card->num_rtd; i++) { rtd = &card->rtd[i]; cpu_dai = rtd->cpu_dai; codec_dai = rtd->codec_dai; - /* dynamic FE links have no fixed DAI mapping */ - if (rtd->dai_link->dynamic) + /* + * dynamic FE links have no fixed DAI mapping. + * CODEC<->CODEC links have no direct connection. + */ + if (rtd->dai_link->dynamic || rtd->dai_link->params) continue; /* there is no point in connecting BE DAI links with dummies */ @@ -3487,55 +3389,49 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) /* connect BE DAI playback if widgets are valid */ if (codec_dai->playback_widget && cpu_dai->playback_widget) { - r.source = cpu_dai->playback_widget->name; - r.sink = codec_dai->playback_widget->name; + source = cpu_dai->playback_widget; + sink = codec_dai->playback_widget; dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - cpu_dai->codec->name, r.source, - codec_dai->platform->name, r.sink); + cpu_dai->codec->name, source->name, + codec_dai->platform->name, sink->name); - snd_soc_dapm_add_route(&card->dapm, &r, true); + snd_soc_dapm_add_path(&card->dapm, source, sink, + NULL, NULL); } /* connect BE DAI capture if widgets are valid */ if (codec_dai->capture_widget && cpu_dai->capture_widget) { - r.source = codec_dai->capture_widget->name; - r.sink = cpu_dai->capture_widget->name; + source = codec_dai->capture_widget; + sink = cpu_dai->capture_widget; dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - codec_dai->codec->name, r.source, - cpu_dai->platform->name, r.sink); + codec_dai->codec->name, source->name, + cpu_dai->platform->name, sink->name); - snd_soc_dapm_add_route(&card->dapm, &r, true); + snd_soc_dapm_add_path(&card->dapm, source, sink, + NULL, NULL); } - } } -static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, +static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, int event) { + struct snd_soc_dapm_widget *w; - struct snd_soc_dapm_widget *w_cpu, *w_codec; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - w_cpu = cpu_dai->playback_widget; - w_codec = codec_dai->playback_widget; - } else { - w_cpu = cpu_dai->capture_widget; - w_codec = codec_dai->capture_widget; - } - - if (w_cpu) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + w = dai->playback_widget; + else + w = dai->capture_widget; - dapm_mark_dirty(w_cpu, "stream event"); + if (w) { + dapm_mark_dirty(w, "stream event"); switch (event) { case SND_SOC_DAPM_STREAM_START: - w_cpu->active = 1; + w->active = 1; break; case SND_SOC_DAPM_STREAM_STOP: - w_cpu->active = 0; + w->active = 0; break; case SND_SOC_DAPM_STREAM_SUSPEND: case SND_SOC_DAPM_STREAM_RESUME: @@ -3544,25 +3440,13 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, break; } } +} - if (w_codec) { - - dapm_mark_dirty(w_codec, "stream event"); - - switch (event) { - case SND_SOC_DAPM_STREAM_START: - w_codec->active = 1; - break; - case SND_SOC_DAPM_STREAM_STOP: - w_codec->active = 0; - break; - case SND_SOC_DAPM_STREAM_SUSPEND: - case SND_SOC_DAPM_STREAM_RESUME: - case SND_SOC_DAPM_STREAM_PAUSE_PUSH: - case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: - break; - } - } +static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, + int event) +{ + soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); + soc_dapm_dai_stream_event(rtd->codec_dai, stream, event); dapm_power_widgets(rtd->card, event); } diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c index 7ac745df1412..e94aa0277250 100644 --- a/sound/soc/soc-devres.c +++ b/sound/soc/soc-devres.c @@ -52,6 +52,40 @@ int devm_snd_soc_register_component(struct device *dev, } EXPORT_SYMBOL_GPL(devm_snd_soc_register_component); +static void devm_platform_release(struct device *dev, void *res) +{ + snd_soc_unregister_platform(*(struct device **)res); +} + +/** + * devm_snd_soc_register_platform - resource managed platform registration + * @dev: Device used to manage platform + * @platform: platform to register + * + * Register a platform driver with automatic unregistration when the device is + * unregistered. + */ +int devm_snd_soc_register_platform(struct device *dev, + const struct snd_soc_platform_driver *platform_drv) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_platform_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_soc_register_platform(dev, platform_drv); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} + static void devm_card_release(struct device *dev, void *res) { snd_soc_unregister_card(*(struct snd_soc_card **)res); diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 260efc8466fc..7767fbd73eb7 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -17,77 +17,285 @@ #include <linux/export.h> #include <sound/soc.h> -#include <trace/events/asoc.h> +/** + * snd_soc_component_read() - Read register value + * @component: Component to read from + * @reg: Register to read + * @val: Pointer to where the read value is stored + * + * Return: 0 on success, a negative error code otherwise. + */ +int snd_soc_component_read(struct snd_soc_component *component, + unsigned int reg, unsigned int *val) +{ + int ret; + + if (component->regmap) + ret = regmap_read(component->regmap, reg, val); + else if (component->read) + ret = component->read(component, reg, val); + else + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_read); -#ifdef CONFIG_REGMAP -static int hw_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) +/** + * snd_soc_component_write() - Write register value + * @component: Component to write to + * @reg: Register to write + * @val: Value to write to the register + * + * Return: 0 on success, a negative error code otherwise. + */ +int snd_soc_component_write(struct snd_soc_component *component, + unsigned int reg, unsigned int val) { - return regmap_write(codec->control_data, reg, value); + if (component->regmap) + return regmap_write(component->regmap, reg, val); + else if (component->write) + return component->write(component, reg, val); + else + return -EIO; } +EXPORT_SYMBOL_GPL(snd_soc_component_write); -static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) +static int snd_soc_component_update_bits_legacy( + struct snd_soc_component *component, unsigned int reg, + unsigned int mask, unsigned int val, bool *change) { + unsigned int old, new; int ret; - unsigned int val; - ret = regmap_read(codec->control_data, reg, &val); - if (ret == 0) - return val; + if (!component->read || !component->write) + return -EIO; + + mutex_lock(&component->io_mutex); + + ret = component->read(component, reg, &old); + if (ret < 0) + goto out_unlock; + + new = (old & ~mask) | (val & mask); + *change = old != new; + if (*change) + ret = component->write(component, reg, new); +out_unlock: + mutex_unlock(&component->io_mutex); + + return ret; +} + +/** + * snd_soc_component_update_bits() - Perform read/modify/write cycle + * @component: Component to update + * @reg: Register to update + * @mask: Mask that specifies which bits to update + * @val: New value for the bits specified by mask + * + * Return: 1 if the operation was successful and the value of the register + * changed, 0 if the operation was successful, but the value did not change. + * Returns a negative error code otherwise. + */ +int snd_soc_component_update_bits(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, unsigned int val) +{ + bool change; + int ret; + + if (component->regmap) + ret = regmap_update_bits_check(component->regmap, reg, mask, + val, &change); + else + ret = snd_soc_component_update_bits_legacy(component, reg, + mask, val, &change); + + if (ret < 0) + return ret; + return change; +} +EXPORT_SYMBOL_GPL(snd_soc_component_update_bits); + +/** + * snd_soc_component_update_bits_async() - Perform asynchronous + * read/modify/write cycle + * @component: Component to update + * @reg: Register to update + * @mask: Mask that specifies which bits to update + * @val: New value for the bits specified by mask + * + * This function is similar to snd_soc_component_update_bits(), but the update + * operation is scheduled asynchronously. This means it may not be completed + * when the function returns. To make sure that all scheduled updates have been + * completed snd_soc_component_async_complete() must be called. + * + * Return: 1 if the operation was successful and the value of the register + * changed, 0 if the operation was successful, but the value did not change. + * Returns a negative error code otherwise. + */ +int snd_soc_component_update_bits_async(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, unsigned int val) +{ + bool change; + int ret; + + if (component->regmap) + ret = regmap_update_bits_check_async(component->regmap, reg, + mask, val, &change); else + ret = snd_soc_component_update_bits_legacy(component, reg, + mask, val, &change); + + if (ret < 0) + return ret; + return change; +} +EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async); + +/** + * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed + * @component: Component for which to wait + * + * This function blocks until all asynchronous I/O which has previously been + * scheduled using snd_soc_component_update_bits_async() has completed. + */ +void snd_soc_component_async_complete(struct snd_soc_component *component) +{ + if (component->regmap) + regmap_async_complete(component->regmap); +} +EXPORT_SYMBOL_GPL(snd_soc_component_async_complete); + +/** + * snd_soc_component_test_bits - Test register for change + * @component: component + * @reg: Register to test + * @mask: Mask that specifies which bits to test + * @value: Value to test against + * + * Tests a register with a new value and checks if the new value is + * different from the old value. + * + * Return: 1 for change, otherwise 0. + */ +int snd_soc_component_test_bits(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, unsigned int value) +{ + unsigned int old, new; + int ret; + + ret = snd_soc_component_read(component, reg, &old); + if (ret < 0) + return ret; + new = (old & ~mask) | value; + return old != new; +} +EXPORT_SYMBOL_GPL(snd_soc_component_test_bits); + +unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg) +{ + unsigned int val; + int ret; + + ret = snd_soc_component_read(&codec->component, reg, &val); + if (ret < 0) return -1; + + return val; } +EXPORT_SYMBOL_GPL(snd_soc_read); + +int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int val) +{ + return snd_soc_component_write(&codec->component, reg, val); +} +EXPORT_SYMBOL_GPL(snd_soc_write); /** - * snd_soc_codec_set_cache_io: Set up standard I/O functions. + * snd_soc_update_bits - update codec register bits + * @codec: audio codec + * @reg: codec register + * @mask: register mask + * @value: new value * - * @codec: CODEC to configure. - * @map: Register map to write to + * Writes new register value. * - * Register formats are frequently shared between many I2C and SPI - * devices. In order to promote code reuse the ASoC core provides - * some standard implementations of CODEC read and write operations - * which can be set up using this function. + * Returns 1 for change, 0 for no change, or negative error code. + */ +int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg, + unsigned int mask, unsigned int value) +{ + return snd_soc_component_update_bits(&codec->component, reg, mask, + value); +} +EXPORT_SYMBOL_GPL(snd_soc_update_bits); + +/** + * snd_soc_test_bits - test register for change + * @codec: audio codec + * @reg: codec register + * @mask: register mask + * @value: new value * - * The caller is responsible for allocating and initialising the - * actual cache. + * Tests a register with a new value and checks if the new value is + * different from the old value. * - * Note that at present this code cannot be used by CODECs with - * volatile registers. + * Returns 1 for change else 0. */ -int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, - struct regmap *regmap) +int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg, + unsigned int mask, unsigned int value) +{ + return snd_soc_component_test_bits(&codec->component, reg, mask, value); +} +EXPORT_SYMBOL_GPL(snd_soc_test_bits); + +int snd_soc_platform_read(struct snd_soc_platform *platform, + unsigned int reg) { + unsigned int val; int ret; - /* Device has made its own regmap arrangements */ - if (!regmap) - codec->control_data = dev_get_regmap(codec->dev, NULL); - else - codec->control_data = regmap; + ret = snd_soc_component_read(&platform->component, reg, &val); + if (ret < 0) + return -1; + + return val; +} +EXPORT_SYMBOL_GPL(snd_soc_platform_read); + +int snd_soc_platform_write(struct snd_soc_platform *platform, + unsigned int reg, unsigned int val) +{ + return snd_soc_component_write(&platform->component, reg, val); +} +EXPORT_SYMBOL_GPL(snd_soc_platform_write); - if (IS_ERR(codec->control_data)) - return PTR_ERR(codec->control_data); +/** + * snd_soc_component_init_io() - Initialize regmap IO + * + * @component: component to initialize + * @regmap: regmap instance to use for IO operations + * + * Return: 0 on success, a negative error code otherwise + */ +int snd_soc_component_init_io(struct snd_soc_component *component, + struct regmap *regmap) +{ + int ret; - codec->write = hw_write; - codec->read = hw_read; + if (!regmap) + return -EINVAL; - ret = regmap_get_val_bytes(codec->control_data); + ret = regmap_get_val_bytes(regmap); /* Errors are legitimate for non-integer byte * multiples */ if (ret > 0) - codec->val_bytes = ret; + component->val_bytes = ret; - codec->using_regmap = true; + component->regmap = regmap; return 0; } -EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); -#else -int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, - struct regmap *regmap) -{ - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); -#endif +EXPORT_SYMBOL_GPL(snd_soc_component_init_io); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2cedf09f6d96..903d737c352f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -555,7 +555,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) if (platform->driver->ops && platform->driver->ops->close) platform->driver->ops->close(substream); - cpu_dai->runtime = NULL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (snd_soc_runtime_ignore_pmdown_time(rtd)) { @@ -819,6 +818,13 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (ret < 0) return ret; } + + if (rtd->dai_link->ops && rtd->dai_link->ops->trigger) { + ret = rtd->dai_link->ops->trigger(substream, cmd); + if (ret < 0) + return ret; + } + return 0; } @@ -1675,7 +1681,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; break; case SNDRV_PCM_TRIGGER_SUSPEND: - if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) + if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) continue; if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c index 25a7f8211ecf..de087ee3458a 100644 --- a/sound/soc/tegra/tegra_wm9712.c +++ b/sound/soc/tegra/tegra_wm9712.c @@ -50,9 +50,7 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); - - return snd_soc_dapm_sync(dapm); + return snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); } static struct snd_soc_dai_link tegra_wm9712_dai = { diff --git a/sound/usb/card.c b/sound/usb/card.c index 893d5a1afc3c..c3b5b7dca1c3 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -651,7 +651,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) int err = -ENODEV; down_read(&chip->shutdown_rwsem); - if (chip->probing) + if (chip->probing && chip->in_pm) err = 0; else if (!chip->shutdown) err = usb_autopm_get_interface(chip->pm_intf); @@ -663,7 +663,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) void snd_usb_autosuspend(struct snd_usb_audio *chip) { down_read(&chip->shutdown_rwsem); - if (!chip->shutdown && !chip->probing) + if (!chip->shutdown && !chip->probing && !chip->in_pm) usb_autopm_put_interface(chip->pm_intf); up_read(&chip->shutdown_rwsem); } @@ -695,8 +695,9 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) chip->autosuspended = 1; } - list_for_each_entry(mixer, &chip->mixer_list, list) - snd_usb_mixer_suspend(mixer); + if (chip->num_suspended_intf == 1) + list_for_each_entry(mixer, &chip->mixer_list, list) + snd_usb_mixer_suspend(mixer); return 0; } @@ -711,6 +712,8 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) return 0; if (--chip->num_suspended_intf) return 0; + + chip->in_pm = 1; /* * ALSA leaves material resumption to user space * we just notify and restart the mixers @@ -726,6 +729,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) chip->autosuspended = 0; err_out: + chip->in_pm = 0; return err; } diff --git a/sound/usb/card.h b/sound/usb/card.h index 9867ab866857..97acb906acc2 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -92,6 +92,7 @@ struct snd_usb_endpoint { unsigned int curframesize; /* current packet size in frames (for capture) */ unsigned int syncmaxsize; /* sync endpoint packet size */ unsigned int fill_max:1; /* fill max packet size always */ + unsigned int udh01_fb_quirk:1; /* corrupted feedback data */ unsigned int datainterval; /* log_2 of data packet interval */ unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */ unsigned char silence_value; diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index e70a87e0d9fe..289f582c9130 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -471,6 +471,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, ep->syncinterval = 3; ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize); + + if (chip->usb_id == USB_ID(0x0644, 0x8038) /* TEAC UD-H01 */ && + ep->syncmaxsize == 4) + ep->udh01_fb_quirk = 1; } list_add_tail(&ep->list, &chip->ep_list); @@ -1105,7 +1109,16 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, if (f == 0) return; - if (unlikely(ep->freqshift == INT_MIN)) { + if (unlikely(sender->udh01_fb_quirk)) { + /* + * The TEAC UD-H01 firmware sometimes changes the feedback value + * by +/- 0x1.0000. + */ + if (f < ep->freqn - 0x8000) + f += 0x10000; + else if (f > ep->freqn + 0x8000) + f -= 0x10000; + } else if (unlikely(ep->freqshift == INT_MIN)) { /* * The first time we see a feedback value, determine its format * by shifting it left or right until it matches the nominal diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 131336d40492..c62a1659106d 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1501,9 +1501,8 @@ static void retire_playback_urb(struct snd_usb_substream *subs, * The error should be lower than 2ms since the estimate relies * on two reads of a counter updated every ms. */ - if (printk_ratelimit() && - abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) - dev_dbg(&subs->dev->dev, + if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) + dev_dbg_ratelimited(&subs->dev->dev, "delay: estimated %d, actual %d\n", est_delay, subs->last_delay); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 25c4c7e217de..91d0380431b4 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -40,6 +40,7 @@ struct snd_usb_audio { struct rw_semaphore shutdown_rwsem; unsigned int shutdown:1; unsigned int probing:1; + unsigned int in_pm:1; unsigned int autosuspended:1; unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ |