diff options
Diffstat (limited to 'sound')
94 files changed, 1960 insertions, 699 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ecdf30eb5879..4aba7646dd9c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -173,7 +173,7 @@ const char *snd_hda_get_jack_type(u32 cfg) "Line Out", "Speaker", "HP Out", "CD", "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", "Line In", "Aux", "Mic", "Telephony", - "SPDIF In", "Digitial In", "Reserved", "Other" + "SPDIF In", "Digital In", "Reserved", "Other" }; return jack_types[(cfg & AC_DEFCFG_DEVICE) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 7dd846380a50..d0d7ac1e99d2 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -320,7 +320,7 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, unsigned char *buf, int *eld_size) { int i; - int ret; + int ret = 0; int size; /* diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 43c2ea539561..2dbe767be16b 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -740,7 +740,7 @@ EXPORT_SYMBOL_HDA(snd_hda_activate_path); static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path) { struct hda_gen_spec *spec = codec->spec; - bool changed; + bool changed = false; int i; if (!spec->power_down_unused || path->active) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 418bfc0eb0a3..bcd40ee488e3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -134,8 +134,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " * this may give more power-saving, but will take longer time to * wake up. */ -static int power_save_controller = -1; -module_param(power_save_controller, bint, 0644); +static bool power_save_controller = 1; +module_param(power_save_controller, bool, 0644); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); #endif /* CONFIG_PM */ @@ -2931,8 +2931,6 @@ static int azx_runtime_idle(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; - if (power_save_controller > 0) - return 0; if (!power_save_controller || !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) return -EBUSY; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 78e1827d0a95..de8ac5c07fd0 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1196,7 +1196,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) _snd_printd(SND_PR_VERBOSE, "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); + codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid); if (eld->eld_valid) { if (snd_hdmi_get_eld(codec, pin_nid, eld->eld_buffer, diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 563c24df4d6f..f15c36bde540 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3440,7 +3440,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec) const hda_nid_t *ssids; if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || - codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) + codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670 || + codec->vendor_id == 0x10ec0671) ssids = alc663_ssids; else ssids = alc662_ssids; @@ -3894,6 +3895,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 }, { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, + { .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 }, { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 }, { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index e13580d6c476..f3fdfa07fcb9 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -533,6 +533,49 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, break; case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + /* + * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks. + * + * The SSC transmit clock is obtained from the BCLK signal on + * on the TK line, and the SSC receive clock is + * generated from the transmit clock. + * + * Data is transferred on first BCLK after LRC pulse rising + * edge.If stereo, the right channel data is contiguous with + * the left channel data. + */ + rcmr = SSC_BF(RCMR_PERIOD, 0) + | SSC_BF(RCMR_STTDLY, START_DELAY) + | SSC_BF(RCMR_START, SSC_START_RISING_RF) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, SSC_CKS_PIN); + + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(RFMR_FSLEN, 0) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, 0) + | SSC_BF(TCMR_STTDLY, START_DELAY) + | SSC_BF(TCMR_START, SSC_START_RISING_RF) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) + | SSC_BF(TCMR_CKO, SSC_CKO_NONE) + | SSC_BF(TCMR_CKS, SSC_CKS_PIN); + + tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(TFMR_FSLEN, 0) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + break; + default: printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", ssc_p->daifmt); @@ -707,13 +750,18 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .ops = &atmel_ssc_dai_ops, }; +static const struct snd_soc_component_driver atmel_ssc_component = { + .name = "atmel-ssc", +}; + static int asoc_ssc_init(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct ssc_device *ssc = platform_get_drvdata(pdev); int ret; - ret = snd_soc_register_dai(dev, &atmel_ssc_dai); + ret = snd_soc_register_component(dev, &atmel_ssc_component, + &atmel_ssc_dai, 1); if (ret) { dev_err(dev, "Could not register DAI: %d\n", ret); goto err; @@ -732,7 +780,7 @@ static int asoc_ssc_init(struct device *dev) return 0; err_unregister_dai: - snd_soc_unregister_dai(dev); + snd_soc_unregister_component(dev); err: return ret; } @@ -747,7 +795,7 @@ static void asoc_ssc_exit(struct device *dev) else atmel_pcm_pdc_platform_unregister(dev); - snd_soc_unregister_dai(dev); + snd_soc_unregister_component(dev); } /** diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index ea7d9d157022..44b8dcecf571 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -223,6 +223,10 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = { .ops = &alchemy_ac97c_ops, }; +static const struct snd_soc_component_driver au1xac97c_component = { + .name = "au1xac97c", +}; + static int au1xac97c_drvprobe(struct platform_device *pdev) { int ret; @@ -268,7 +272,8 @@ static int au1xac97c_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver); + ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component, + &au1xac97c_dai_driver, 1); if (ret) return ret; @@ -280,7 +285,7 @@ static int au1xac97c_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */ diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c index 072448afc219..b3f37f6edbcb 100644 --- a/sound/soc/au1x/i2sc.c +++ b/sound/soc/au1x/i2sc.c @@ -225,6 +225,10 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = { .ops = &au1xi2s_dai_ops, }; +static const struct snd_soc_component_driver au1xi2s_component = { + .name = "au1xi2s", +}; + static int au1xi2s_drvprobe(struct platform_device *pdev) { struct resource *iores, *dmares; @@ -260,14 +264,15 @@ static int au1xi2s_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - return snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver); + return snd_soc_register_component(&pdev->dev, &au1xi2s_component, + &au1xi2s_dai_driver, 1); } static int au1xi2s_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */ diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 6ba07e365967..8f1862aa7333 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -361,6 +361,10 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { .ops = &au1xpsc_ac97_dai_ops, }; +static const struct snd_soc_component_driver au1xpsc_ac97_component = { + .name = "au1xpsc-ac97", +}; + static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) { int ret; @@ -419,7 +423,8 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, wd); - ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv); + ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component, + &wd->dai_drv, 1); if (ret) return ret; @@ -431,7 +436,7 @@ static int au1xpsc_ac97_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); /* disable PSC completely */ au_writel(0, AC97_CFG(wd)); diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 360b4e50d7c8..fe923a7bdc39 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -288,6 +288,10 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = { .ops = &au1xpsc_i2s_dai_ops, }; +static const struct snd_soc_component_driver au1xpsc_i2s_component = { + .name = "au1xpsc-i2s", +}; + static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) { struct resource *iores, *dmares; @@ -350,14 +354,15 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, wd); - return snd_soc_register_dai(&pdev->dev, &wd->dai_drv); + return snd_soc_register_component(&pdev->dev, &au1xpsc_i2s_component, + &wd->dai_drv, 1); } static int au1xpsc_i2s_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); au_writel(0, I2S_CFG(wd)); au_sync(); diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 8e41bcb020eb..490217325975 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -282,6 +282,10 @@ static struct snd_soc_dai_driver bfin_ac97_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }; +static const struct snd_soc_component_driver bfin_ac97_component = { + .name = "bfin-ac97", +}; + static int asoc_bfin_ac97_probe(struct platform_device *pdev) { struct sport_device *sport_handle; @@ -331,7 +335,8 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev) goto sport_config_err; } - ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai); + ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component, + &bfin_ac97_dai, 1); if (ret) { pr_err("Failed to register DAI: %d\n", ret); goto sport_config_err; @@ -356,7 +361,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev) { struct sport_device *sport_handle = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); sport_done(sport_handle); #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 168d88bccb41..dd0c2a4f83a3 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -245,6 +245,10 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = { .ops = &bf5xx_i2s_dai_ops, }; +static const struct snd_soc_component_driver bf5xx_i2s_component = { + .name = "bf5xx-i2s", +}; + static int bf5xx_i2s_probe(struct platform_device *pdev) { struct sport_device *sport_handle; @@ -257,7 +261,8 @@ static int bf5xx_i2s_probe(struct platform_device *pdev) return -ENODEV; /* register with the ASoC layers */ - ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component, + &bf5xx_i2s_dai, 1); if (ret) { pr_err("Failed to register DAI: %d\n", ret); sport_done(sport_handle); @@ -273,7 +278,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev) pr_debug("%s enter\n", __func__); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); sport_done(sport_handle); return 0; diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c index c1e516ec53ad..69e9a3e935bd 100644 --- a/sound/soc/blackfin/bf5xx-tdm.c +++ b/sound/soc/blackfin/bf5xx-tdm.c @@ -249,6 +249,10 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = { .ops = &bf5xx_tdm_dai_ops, }; +static const struct snd_soc_component_driver bf5xx_tdm_component = { + .name = "bf5xx-tdm", +}; + static int bfin_tdm_probe(struct platform_device *pdev) { struct sport_device *sport_handle; @@ -282,7 +286,8 @@ static int bfin_tdm_probe(struct platform_device *pdev) goto sport_config_err; } - ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai); + ret = snd_soc_register_component(&pdev->dev, &bf5xx_tdm_component, + &bf5xx_tdm_dai, 1); if (ret) { pr_err("Failed to register DAI: %d\n", ret); goto sport_config_err; @@ -299,7 +304,7 @@ static int bfin_tdm_remove(struct platform_device *pdev) { struct sport_device *sport_handle = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); sport_done(sport_handle); return 0; diff --git a/sound/soc/blackfin/bf6xx-i2s.c b/sound/soc/blackfin/bf6xx-i2s.c index 8f337972f438..c02405cc007d 100644 --- a/sound/soc/blackfin/bf6xx-i2s.c +++ b/sound/soc/blackfin/bf6xx-i2s.c @@ -186,6 +186,10 @@ static struct snd_soc_dai_driver bfin_i2s_dai = { .ops = &bfin_i2s_dai_ops, }; +static const struct snd_soc_component_driver bfin_i2s_component = { + .name = "bfin-i2s", +}; + static int bfin_i2s_probe(struct platform_device *pdev) { struct sport_device *sport; @@ -197,7 +201,8 @@ static int bfin_i2s_probe(struct platform_device *pdev) return -ENODEV; /* register with the ASoC layers */ - ret = snd_soc_register_dai(dev, &bfin_i2s_dai); + ret = snd_soc_register_component(dev, &bfin_i2s_component, + &bfin_i2s_dai, 1); if (ret) { dev_err(dev, "Failed to register DAI: %d\n", ret); sport_delete(sport); @@ -212,7 +217,7 @@ static int bfin_i2s_remove(struct platform_device *pdev) { struct sport_device *sport = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); sport_delete(sport); return 0; diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index 8d3088647e44..7798fbd5e81d 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c @@ -354,6 +354,10 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = { .ops = &ep93xx_ac97_dai_ops, }; +static const struct snd_soc_component_driver ep93xx_ac97_component = { + .name = "ep93xx-ac97", +}; + static int ep93xx_ac97_probe(struct platform_device *pdev) { struct ep93xx_ac97_info *info; @@ -391,7 +395,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev) ep93xx_ac97_info = info; platform_set_drvdata(pdev, info); - ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai); + ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component, + &ep93xx_ac97_dai, 1); if (ret) goto fail; @@ -408,7 +413,7 @@ static int ep93xx_ac97_remove(struct platform_device *pdev) { struct ep93xx_ac97_info *info = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); /* disable the AC97 controller */ ep93xx_ac97_write_reg(info, AC97GCR, 0); diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 83075b3c180c..5c1102e9e159 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -366,6 +366,10 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = { .ops = &ep93xx_i2s_dai_ops, }; +static const struct snd_soc_component_driver ep93xx_i2s_component = { + .name = "ep93xx-i2s", +}; + static int ep93xx_i2s_probe(struct platform_device *pdev) { struct ep93xx_i2s_info *info; @@ -405,7 +409,8 @@ static int ep93xx_i2s_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, info); info->dma_data = ep93xx_i2s_dma_data; - err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai); + err = snd_soc_register_component(&pdev->dev, &ep93xx_i2s_component, + &ep93xx_i2s_dai, 1); if (err) goto fail_put_lrclk; @@ -426,7 +431,7 @@ static int ep93xx_i2s_remove(struct platform_device *pdev) { struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); dev_set_drvdata(&pdev->dev, NULL); clk_put(info->lrclk); clk_put(info->sclk); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 45b72561c615..cf7b9897fa6b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -26,6 +26,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AK4641 if I2C select SND_SOC_AK4642 if I2C select SND_SOC_AK4671 if I2C + select SND_SOC_AK5386 select SND_SOC_ALC5623 if I2C select SND_SOC_ALC5632 if I2C select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC @@ -203,6 +204,9 @@ config SND_SOC_AK4642 config SND_SOC_AK4671 tristate +config SND_SOC_AK5386 + tristate + config SND_SOC_ALC5623 tristate config SND_SOC_ALC5632 @@ -324,7 +328,7 @@ config SND_SOC_TLV320AIC23 tristate config SND_SOC_TLV320AIC26 - tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE + tristate depends on SPI config SND_SOC_TLV320AIC32X4 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 6a3b3c3b8b41..3a7ec1c39741 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -14,6 +14,7 @@ snd-soc-ak4535-objs := ak4535.o snd-soc-ak4641-objs := ak4641.o snd-soc-ak4642-objs := ak4642.o snd-soc-ak4671-objs := ak4671.o +snd-soc-ak5386-objs := ak5386.o snd-soc-arizona-objs := arizona.o snd-soc-cq93vc-objs := cq93vc.o snd-soc-cs42l51-objs := cs42l51.o @@ -137,6 +138,7 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o +obj-$(CONFIG_SND_SOC_AK5386) += snd-soc-ak5386.o obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 068b3ae56a17..1aa10ddf3a61 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -133,6 +133,8 @@ struct adau1373 { #define ADAU1373_DAI_FORMAT_DSP 0x3 #define ADAU1373_BCLKDIV_SOURCE BIT(5) +#define ADAU1373_BCLKDIV_SR_MASK (0x07 << 2) +#define ADAU1373_BCLKDIV_BCLK_MASK 0x03 #define ADAU1373_BCLKDIV_32 0x03 #define ADAU1373_BCLKDIV_64 0x02 #define ADAU1373_BCLKDIV_128 0x01 @@ -937,7 +939,8 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream, adau1373_dai->enable_src = (div != 0); snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id), - ~ADAU1373_BCLKDIV_SOURCE, (div << 2) | ADAU1373_BCLKDIV_64); + ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK, + (div << 2) | ADAU1373_BCLKDIV_64); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 6f6c335a5baa..c7cfdf957e4d 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -55,6 +55,7 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int format) { struct snd_soc_codec *codec = codec_dai->codec; + struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); int val = 0; int ret; @@ -77,9 +78,9 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) return -EINVAL; - ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1, - AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1, - val); + ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, + AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1, + val); if (ret < 0) return ret; @@ -91,11 +92,12 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - int val = 0; + struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); + int ret, val = 0; /* set the IEC958 bits: consumer mode, no copyright bit */ val |= IEC958_AES0_CON_NOT_COPYRIGHT; - snd_soc_write(codec, AK4104_REG_CHN_STATUS(0), val); + regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val); val = 0; @@ -132,11 +134,33 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - return snd_soc_write(codec, AK4104_REG_CHN_STATUS(3), val); + ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val); + if (ret < 0) + return ret; + + /* enable transmitter */ + ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, + AK4104_TX_TXE, AK4104_TX_TXE); + if (ret < 0) + return ret; + + return 0; +} + +static int ak4104_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); + + /* disable transmitter */ + return regmap_update_bits(ak4104->regmap, AK4104_REG_TX, + AK4104_TX_TXE, 0); } static const struct snd_soc_dai_ops ak4101_dai_ops = { .hw_params = ak4104_hw_params, + .hw_free = ak4104_hw_free, .set_fmt = ak4104_set_dai_fmt, }; @@ -160,20 +184,17 @@ static int ak4104_probe(struct snd_soc_codec *codec) int ret; codec->control_data = ak4104->regmap; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); - if (ret != 0) - return ret; /* set power-up and non-reset bits */ - ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1, - AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, - AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); + 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; /* enable transmitter */ - ret = snd_soc_update_bits(codec, AK4104_REG_TX, - AK4104_TX_TXE, AK4104_TX_TXE); + ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, + AK4104_TX_TXE, AK4104_TX_TXE); if (ret < 0) return ret; @@ -182,8 +203,10 @@ static int ak4104_probe(struct snd_soc_codec *codec) static int ak4104_remove(struct snd_soc_codec *codec) { - snd_soc_update_bits(codec, AK4104_REG_CONTROL1, - AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); + struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); + + regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, + AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); return 0; } diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c new file mode 100644 index 000000000000..1f303983ae02 --- /dev/null +++ b/sound/soc/codecs/ak5386.c @@ -0,0 +1,152 @@ +/* + * ALSA SoC driver for + * Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC + * + * (c) 2013 Daniel Mack <zonque@gmail.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. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> +#include <sound/soc.h> +#include <sound/pcm.h> +#include <sound/initval.h> + +struct ak5386_priv { + int reset_gpio; +}; + +static struct snd_soc_codec_driver soc_codec_ak5386; + +static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + + format &= SND_SOC_DAIFMT_FORMAT_MASK; + if (format != SND_SOC_DAIFMT_LEFT_J && + format != SND_SOC_DAIFMT_I2S) { + dev_err(codec->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + return 0; +} + +static int ak5386_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 ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); + + /* + * From the datasheet: + * + * All external clocks (MCLK, SCLK and LRCK) must be present unless + * PDN pin = “L”. If these clocks are not provided, the AK5386 may + * draw excess current due to its use of internal dynamically + * refreshed logic. If the external clocks are not present, place + * the AK5386 in power-down mode (PDN pin = “L”). + */ + + if (gpio_is_valid(priv->reset_gpio)) + gpio_set_value(priv->reset_gpio, 1); + + return 0; +} + +static int ak5386_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); + + if (gpio_is_valid(priv->reset_gpio)) + gpio_set_value(priv->reset_gpio, 0); + + return 0; +} + +static const struct snd_soc_dai_ops ak5386_dai_ops = { + .set_fmt = ak5386_set_dai_fmt, + .hw_params = ak5386_hw_params, + .hw_free = ak5386_hw_free, +}; + +static struct snd_soc_dai_driver ak5386_dai = { + .name = "ak5386-hifi", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE, + }, + .ops = &ak5386_dai_ops, +}; + +#ifdef CONFIG_OF +static const struct of_device_id ak5386_dt_ids[] = { + { .compatible = "asahi-kasei,ak5386", }, + { } +}; +MODULE_DEVICE_TABLE(of, ak5386_dt_ids); +#endif + +static int ak5386_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ak5386_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->reset_gpio = -EINVAL; + dev_set_drvdata(dev, priv); + + if (of_match_device(of_match_ptr(ak5386_dt_ids), dev)) + priv->reset_gpio = of_get_named_gpio(dev->of_node, + "reset-gpio", 0); + + if (gpio_is_valid(priv->reset_gpio)) + if (devm_gpio_request_one(dev, priv->reset_gpio, + GPIOF_OUT_INIT_LOW, + "AK5386 Reset")) + priv->reset_gpio = -EINVAL; + + return snd_soc_register_codec(dev, &soc_codec_ak5386, + &ak5386_dai, 1); +} + +static int ak5386_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver ak5386_driver = { + .probe = ak5386_probe, + .remove = ak5386_remove, + .driver = { + .name = "ak5386", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ak5386_dt_ids), + }, +}; + +module_platform_driver(ak5386_driver); + +MODULE_DESCRIPTION("ASoC driver for AK5386 ADC"); +MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ac948a671ea6..389f23253831 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include <linux/delay.h> #include <linux/gcd.h> #include <linux/module.h> #include <linux/pm_runtime.h> @@ -65,6 +66,163 @@ #define arizona_aif_dbg(_dai, fmt, ...) \ dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) +static int arizona_spk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = w->codec; + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + bool manual_ena = false; + int val; + + switch (arizona->type) { + case WM5102: + switch (arizona->rev) { + case 0: + break; + default: + manual_ena = true; + break; + } + default: + break; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (!priv->spk_ena && manual_ena) { + snd_soc_write(codec, 0x4f5, 0x25a); + priv->spk_ena_pending = true; + } + break; + case SND_SOC_DAPM_POST_PMU: + val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3); + if (val & ARIZONA_SPK_SHUTDOWN_STS) { + dev_crit(arizona->dev, + "Speaker not enabled due to temperature\n"); + return -EBUSY; + } + + snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, + 1 << w->shift, 1 << w->shift); + + if (priv->spk_ena_pending) { + msleep(75); + snd_soc_write(codec, 0x4f5, 0xda); + priv->spk_ena_pending = false; + priv->spk_ena++; + } + break; + case SND_SOC_DAPM_PRE_PMD: + if (manual_ena) { + priv->spk_ena--; + if (!priv->spk_ena) + snd_soc_write(codec, 0x4f5, 0x25a); + } + + snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, + 1 << w->shift, 0); + break; + case SND_SOC_DAPM_POST_PMD: + if (manual_ena) { + if (!priv->spk_ena) + snd_soc_write(codec, 0x4f5, 0x0da); + } + break; + } + + return 0; +} + +static irqreturn_t arizona_thermal_warn(int irq, void *data) +{ + struct arizona *arizona = data; + unsigned int val; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3, + &val); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read thermal status: %d\n", + ret); + } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) { + dev_crit(arizona->dev, "Thermal warning\n"); + } + + return IRQ_HANDLED; +} + +static irqreturn_t arizona_thermal_shutdown(int irq, void *data) +{ + struct arizona *arizona = data; + unsigned int val; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3, + &val); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read thermal status: %d\n", + ret); + } else if (val & ARIZONA_SPK_SHUTDOWN_STS) { + dev_crit(arizona->dev, "Thermal shutdown\n"); + ret = regmap_update_bits(arizona->regmap, + ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT4L_ENA | + ARIZONA_OUT4R_ENA, 0); + if (ret != 0) + dev_crit(arizona->dev, + "Failed to disable speaker outputs: %d\n", + ret); + } + + return IRQ_HANDLED; +} + +static const struct snd_soc_dapm_widget arizona_spkl = + SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM, + ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + +static const struct snd_soc_dapm_widget arizona_spkr = + SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM, + ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + +int arizona_init_spk(struct snd_soc_codec *codec) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + int ret; + + ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1); + if (ret != 0) + return ret; + + ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1); + if (ret != 0) + return ret; + + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN, + "Thermal warning", arizona_thermal_warn, + arizona); + if (ret != 0) + dev_err(arizona->dev, + "Failed to get thermal warning IRQ: %d\n", + ret); + + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN, + "Thermal shutdown", arizona_thermal_shutdown, + arizona); + if (ret != 0) + dev_err(arizona->dev, + "Failed to get thermal shutdown IRQ: %d\n", + ret); + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_spk); + const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "None", "Tone Generator 1", @@ -274,6 +432,33 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values); const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0); EXPORT_SYMBOL_GPL(arizona_mixer_tlv); +const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = { + "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate", +}; +EXPORT_SYMBOL_GPL(arizona_rate_text); + +const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = { + 0, 1, 2, 8, +}; +EXPORT_SYMBOL_GPL(arizona_rate_val); + + +const struct soc_enum arizona_isrc_fsl[] = { + SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2, + ARIZONA_ISRC1_FSL_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2, + ARIZONA_ISRC2_FSL_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2, + ARIZONA_ISRC3_FSL_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), +}; +EXPORT_SYMBOL_GPL(arizona_isrc_fsl); + static const char *arizona_vol_ramp_text[] = { "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", "15ms/6dB", "30ms/6dB", @@ -332,9 +517,27 @@ const struct soc_enum arizona_ng_hold = 4, arizona_ng_hold_text); EXPORT_SYMBOL_GPL(arizona_ng_hold); +static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + unsigned int val; + int i; + + if (ena) + val = ARIZONA_IN_VU; + else + val = 0; + + for (i = 0; i < priv->num_inputs; i++) + snd_soc_update_bits(codec, + ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4), + ARIZONA_IN_VU, val); +} + int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); unsigned int reg; if (w->shift % 2) @@ -343,13 +546,29 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8); switch (event) { + case SND_SOC_DAPM_PRE_PMU: + priv->in_pending++; + break; case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0); + + /* If this is the last input pending then allow VU */ + priv->in_pending--; + if (priv->in_pending == 0) { + msleep(1); + arizona_in_set_vu(w->codec, 1); + } break; case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, - ARIZONA_IN1L_MUTE); + snd_soc_update_bits(w->codec, reg, + ARIZONA_IN1L_MUTE | ARIZONA_IN_VU, + ARIZONA_IN1L_MUTE | ARIZONA_IN_VU); break; + case SND_SOC_DAPM_POST_PMD: + /* Disable volume updates if no inputs are enabled */ + reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES); + if (reg == 0) + arizona_in_set_vu(w->codec, 0); } return 0; @@ -360,10 +579,61 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + case ARIZONA_OUT1R_ENA_SHIFT: + case ARIZONA_OUT2L_ENA_SHIFT: + case ARIZONA_OUT2R_ENA_SHIFT: + case ARIZONA_OUT3L_ENA_SHIFT: + case ARIZONA_OUT3R_ENA_SHIFT: + msleep(17); + break; + + default: + break; + } + break; + } + return 0; } EXPORT_SYMBOL_GPL(arizona_out_ev); +int arizona_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); + unsigned int mask = 1 << w->shift; + unsigned int val; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = mask; + break; + case SND_SOC_DAPM_PRE_PMD: + val = 0; + break; + default: + return -EINVAL; + } + + /* Store the desired state for the HP outputs */ + priv->arizona->hp_ena &= ~mask; + priv->arizona->hp_ena |= val; + + /* Force off if HPDET magic is active */ + if (priv->arizona->hpdet_magic) + val = 0; + + snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val); + + return arizona_out_ev(w, kcontrol, event); +} +EXPORT_SYMBOL_GPL(arizona_hp_ev); + static unsigned int arizona_sysclk_48k_rates[] = { 6144000, 12288000, @@ -469,27 +739,27 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, break; case 11289600: case 12288000: - val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 22579200: case 24576000: - val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 45158400: case 49152000: - val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 67737600: case 73728000: - val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 90316800: case 98304000: - val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 135475200: case 147456000: - val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 0: dev_dbg(arizona->dev, "%s cleared\n", name); @@ -783,7 +1053,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, struct arizona *arizona = priv->arizona; int base = dai->driver->base; const int *rates; - int i, ret; + int i, ret, val; int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1]; int bclk, lrclk, wl, frame, bclk_target; @@ -799,6 +1069,13 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, bclk_target *= chan_limit; } + /* Force stereo for I2S mode */ + val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); + if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) { + arizona_aif_dbg(dai, "Forcing stereo mode\n"); + bclk_target *= 2; + } + for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { if (rates[i] >= bclk_target && rates[i] % params_rate(params) == 0) { @@ -955,6 +1232,16 @@ static struct { { 1000000, 13500000, 0, 1 }, }; +static struct { + unsigned int min; + unsigned int max; + u16 gain; +} fll_gains[] = { + { 0, 256000, 0 }, + { 256000, 1000000, 2 }, + { 1000000, 13500000, 4 }, +}; + struct arizona_fll_cfg { int n; int theta; @@ -962,6 +1249,7 @@ struct arizona_fll_cfg { int refdiv; int outdiv; int fratio; + int gain; }; static int arizona_calc_fll(struct arizona_fll *fll, @@ -1021,6 +1309,18 @@ static int arizona_calc_fll(struct arizona_fll *fll, return -EINVAL; } + for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { + if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { + cfg->gain = fll_gains[i].gain; + break; + } + } + if (i == ARRAY_SIZE(fll_gains)) { + arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", + Fref); + return -EINVAL; + } + cfg->n = target / (ratio * Fref); if (target % (ratio * Fref)) { @@ -1048,13 +1348,15 @@ static int arizona_calc_fll(struct arizona_fll *fll, cfg->n, cfg->theta, cfg->lambda); arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv); + arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain); return 0; } static void arizona_apply_fll(struct arizona *arizona, unsigned int base, - struct arizona_fll_cfg *cfg, int source) + struct arizona_fll_cfg *cfg, int source, + bool sync) { regmap_update_bits(arizona->regmap, base + 3, ARIZONA_FLL1_THETA_MASK, cfg->theta); @@ -1069,87 +1371,84 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); + if (sync) + regmap_update_bits(arizona->regmap, base + 0x7, + ARIZONA_FLL1_GAIN_MASK, + cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + else + regmap_update_bits(arizona->regmap, base + 0x9, + ARIZONA_FLL1_GAIN_MASK, + cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + regmap_update_bits(arizona->regmap, base + 2, ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, ARIZONA_FLL1_CTRL_UPD | cfg->n); } -int arizona_set_fll(struct arizona_fll *fll, int source, - unsigned int Fref, unsigned int Fout) +static bool arizona_is_enabled_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; - struct arizona_fll_cfg cfg, sync; - unsigned int reg, val; - int syncsrc; - bool ena; + unsigned int reg; int ret; - if (fll->fref == Fref && fll->fout == Fout) - return 0; - ret = regmap_read(arizona->regmap, fll->base + 1, ®); if (ret != 0) { arizona_fll_err(fll, "Failed to read current state: %d\n", ret); return ret; } - ena = reg & ARIZONA_FLL1_ENA; - if (Fout) { - /* Do we have a 32kHz reference? */ - regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); - switch (val & ARIZONA_CLK_32K_SRC_MASK) { - case ARIZONA_CLK_SRC_MCLK1: - case ARIZONA_CLK_SRC_MCLK2: - syncsrc = val & ARIZONA_CLK_32K_SRC_MASK; - break; - default: - syncsrc = -1; - } + return reg & ARIZONA_FLL1_ENA; +} - if (source == syncsrc) - syncsrc = -1; +static void arizona_enable_fll(struct arizona_fll *fll, + struct arizona_fll_cfg *ref, + struct arizona_fll_cfg *sync) +{ + struct arizona *arizona = fll->arizona; + int ret; - if (syncsrc >= 0) { - ret = arizona_calc_fll(fll, &sync, Fref, Fout); - if (ret != 0) - return ret; + /* + * If we have both REFCLK and SYNCCLK then enable both, + * otherwise apply the SYNCCLK settings to REFCLK. + */ + if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) { + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + + arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, + false); + if (fll->sync_src >= 0) + arizona_apply_fll(arizona, fll->base + 0x10, sync, + fll->sync_src, true); + } else if (fll->sync_src >= 0) { + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + + arizona_apply_fll(arizona, fll->base, sync, + fll->sync_src, false); - ret = arizona_calc_fll(fll, &cfg, 32768, Fout); - if (ret != 0) - return ret; - } else { - ret = arizona_calc_fll(fll, &cfg, Fref, Fout); - if (ret != 0) - return ret; - } - } else { - regmap_update_bits(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, 0); regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, 0); - - if (ena) - pm_runtime_put_autosuspend(arizona->dev); - - fll->fref = Fref; - fll->fout = Fout; - - return 0; - } - - regmap_update_bits(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - - if (syncsrc >= 0) { - arizona_apply_fll(arizona, fll->base, &cfg, syncsrc); - arizona_apply_fll(arizona, fll->base + 0x10, &sync, source); } else { - arizona_apply_fll(arizona, fll->base, &cfg, source); + arizona_fll_err(fll, "No clocks provided\n"); + return; } - if (!ena) + /* + * Increase the bandwidth if we're not using a low frequency + * sync source. + */ + if (fll->sync_src >= 0 && fll->sync_freq > 100000) + regmap_update_bits(arizona->regmap, fll->base + 0x17, + ARIZONA_FLL1_SYNC_BW, 0); + else + regmap_update_bits(arizona->regmap, fll->base + 0x17, + ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW); + + if (!arizona_is_enabled_fll(fll)) pm_runtime_get(arizona->dev); /* Clear any pending completions */ @@ -1157,7 +1456,8 @@ int arizona_set_fll(struct arizona_fll *fll, int source, regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); - if (syncsrc >= 0) + if (fll->ref_src >= 0 && fll->sync_src >= 0 && + fll->ref_src != fll->sync_src) regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); @@ -1166,10 +1466,88 @@ int arizona_set_fll(struct arizona_fll *fll, int source, msecs_to_jiffies(250)); if (ret == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); +} + +static void arizona_disable_fll(struct arizona_fll *fll) +{ + struct arizona *arizona = fll->arizona; + bool change; + + regmap_update_bits_check(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_ENA, 0, &change); + regmap_update_bits(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, 0); + + if (change) + pm_runtime_put_autosuspend(arizona->dev); +} + +int arizona_set_fll_refclk(struct arizona_fll *fll, int source, + unsigned int Fref, unsigned int Fout) +{ + struct arizona_fll_cfg ref, sync; + int ret; + + if (fll->ref_src == source && fll->ref_freq == Fref) + return 0; + + if (fll->fout && Fref > 0) { + ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); + if (ret != 0) + return ret; + + if (fll->sync_src >= 0) { + ret = arizona_calc_fll(fll, &sync, fll->sync_freq, + fll->fout); + if (ret != 0) + return ret; + } + } + + fll->ref_src = source; + fll->ref_freq = Fref; - fll->fref = Fref; + if (fll->fout && Fref > 0) { + arizona_enable_fll(fll, &ref, &sync); + } + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); + +int arizona_set_fll(struct arizona_fll *fll, int source, + unsigned int Fref, unsigned int Fout) +{ + struct arizona_fll_cfg ref, sync; + int ret; + + if (fll->sync_src == source && + fll->sync_freq == Fref && fll->fout == Fout) + return 0; + + if (Fout) { + if (fll->ref_src >= 0) { + ret = arizona_calc_fll(fll, &ref, fll->ref_freq, + Fout); + if (ret != 0) + return ret; + } + + ret = arizona_calc_fll(fll, &sync, Fref, Fout); + if (ret != 0) + return ret; + } + + fll->sync_src = source; + fll->sync_freq = Fref; fll->fout = Fout; + if (Fout) { + arizona_enable_fll(fll, &ref, &sync); + } else { + arizona_disable_fll(fll); + } + return 0; } EXPORT_SYMBOL_GPL(arizona_set_fll); @@ -1178,12 +1556,26 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, int ok_irq, struct arizona_fll *fll) { int ret; + unsigned int val; init_completion(&fll->ok); fll->id = id; fll->base = base; fll->arizona = arizona; + fll->sync_src = ARIZONA_FLL_SRC_NONE; + + /* Configure default refclk to 32kHz if we have one */ + regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); + switch (val & ARIZONA_CLK_32K_SRC_MASK) { + case ARIZONA_CLK_SRC_MCLK1: + case ARIZONA_CLK_SRC_MCLK2: + fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK; + break; + default: + fll->ref_src = ARIZONA_FLL_SRC_NONE; + } + fll->ref_freq = 32768; snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id); snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 116372c91f5d..af39f1006427 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -32,6 +32,7 @@ #define ARIZONA_CLK_SRC_AIF2BCLK 0x9 #define ARIZONA_CLK_SRC_AIF3BCLK 0xa +#define ARIZONA_FLL_SRC_NONE -1 #define ARIZONA_FLL_SRC_MCLK1 0 #define ARIZONA_FLL_SRC_MCLK2 1 #define ARIZONA_FLL_SRC_SLIMCLK 3 @@ -48,6 +49,14 @@ #define ARIZONA_MIXER_VOL_SHIFT 1 #define ARIZONA_MIXER_VOL_WIDTH 7 +#define ARIZONA_CLK_6MHZ 0 +#define ARIZONA_CLK_12MHZ 1 +#define ARIZONA_CLK_24MHZ 2 +#define ARIZONA_CLK_49MHZ 3 +#define ARIZONA_CLK_73MHZ 4 +#define ARIZONA_CLK_98MHZ 5 +#define ARIZONA_CLK_147MHZ 6 + #define ARIZONA_MAX_DAI 4 #define ARIZONA_MAX_ADSP 4 @@ -64,6 +73,12 @@ struct arizona_priv { int sysclk; int asyncclk; struct arizona_dai_priv dai[ARIZONA_MAX_DAI]; + + int num_inputs; + unsigned int in_pending; + + unsigned int spk_ena:2; + unsigned int spk_ena_pending:1; }; #define ARIZONA_NUM_MIXER_INPUTS 99 @@ -165,6 +180,12 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MIXER_ROUTES(name, name "L"), \ ARIZONA_MIXER_ROUTES(name, name "R") +#define ARIZONA_RATE_ENUM_SIZE 4 +extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; +extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; + +extern const struct soc_enum arizona_isrc_fsl[]; + extern const struct soc_enum arizona_in_vi_ramp; extern const struct soc_enum arizona_in_vd_ramp; @@ -184,6 +205,9 @@ extern int arizona_in_ev(struct snd_soc_dapm_widget *w, extern int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event); extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir); @@ -198,8 +222,12 @@ struct arizona_fll { unsigned int base; unsigned int vco_mult; struct completion ok; - unsigned int fref; + unsigned int fout; + int sync_src; + unsigned int sync_freq; + int ref_src; + unsigned int ref_freq; char lock_name[ARIZONA_FLL_NAME_LEN]; char clock_ok_name[ARIZONA_FLL_NAME_LEN]; @@ -207,9 +235,13 @@ struct arizona_fll { extern int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, int ok_irq, struct arizona_fll *fll); +extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, + unsigned int Fref, unsigned int Fout); extern int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout); +extern int arizona_init_spk(struct snd_soc_codec *codec); + extern int arizona_init_dai(struct arizona_priv *priv, int dai); int arizona_set_output_mode(struct snd_soc_codec *codec, int output, diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 2415a4118dbd..03036b326732 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -39,17 +39,15 @@ /* * CS4271 registers - * High byte represents SPI chip address (0x10) + write command (0) - * Low byte - codec register address */ -#define CS4271_MODE1 0x2001 /* Mode Control 1 */ -#define CS4271_DACCTL 0x2002 /* DAC Control */ -#define CS4271_DACVOL 0x2003 /* DAC Volume & Mixing Control */ -#define CS4271_VOLA 0x2004 /* DAC Channel A Volume Control */ -#define CS4271_VOLB 0x2005 /* DAC Channel B Volume Control */ -#define CS4271_ADCCTL 0x2006 /* ADC Control */ -#define CS4271_MODE2 0x2007 /* Mode Control 2 */ -#define CS4271_CHIPID 0x2008 /* Chip ID */ +#define CS4271_MODE1 0x01 /* Mode Control 1 */ +#define CS4271_DACCTL 0x02 /* DAC Control */ +#define CS4271_DACVOL 0x03 /* DAC Volume & Mixing Control */ +#define CS4271_VOLA 0x04 /* DAC Channel A Volume Control */ +#define CS4271_VOLB 0x05 /* DAC Channel B Volume Control */ +#define CS4271_ADCCTL 0x06 /* ADC Control */ +#define CS4271_MODE2 0x07 /* Mode Control 2 */ +#define CS4271_CHIPID 0x08 /* Chip ID */ #define CS4271_FIRSTREG CS4271_MODE1 #define CS4271_LASTREG CS4271_MODE2 @@ -144,23 +142,27 @@ * Array do not include Chip ID, as codec driver does not use * registers read operations at all */ -static const u8 cs4271_dflt_reg[CS4271_NR_REGS] = { - 0, - 0, - CS4271_DACCTL_AMUTE, - CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, - 0, - 0, - 0, - 0, +static const struct reg_default cs4271_reg_defaults[] = { + { CS4271_MODE1, 0, }, + { CS4271_DACCTL, CS4271_DACCTL_AMUTE, }, + { CS4271_DACVOL, CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, }, + { CS4271_VOLA, 0, }, + { CS4271_VOLB, 0, }, + { CS4271_ADCCTL, 0, }, + { CS4271_MODE2, 0, }, }; +static bool cs4271_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == CS4271_CHIPID; +} + struct cs4271_private { /* SND_SOC_I2C or SND_SOC_SPI */ - enum snd_soc_control_type bus_type; unsigned int mclk; bool master; bool deemph; + struct regmap *regmap; /* Current sample rate for de-emphasis control */ int rate; /* GPIO driving Reset pin, if any */ @@ -210,14 +212,14 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_LEFT_J: val |= CS4271_MODE1_DAC_DIF_LJ; - ret = snd_soc_update_bits(codec, CS4271_ADCCTL, + ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL, CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ); if (ret < 0) return ret; break; case SND_SOC_DAIFMT_I2S: val |= CS4271_MODE1_DAC_DIF_I2S; - ret = snd_soc_update_bits(codec, CS4271_ADCCTL, + ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL, CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S); if (ret < 0) return ret; @@ -227,7 +229,7 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - ret = snd_soc_update_bits(codec, CS4271_MODE1, + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1, CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val); if (ret < 0) return ret; @@ -252,7 +254,7 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec) val <<= 4; } - ret = snd_soc_update_bits(codec, CS4271_DACCTL, + ret = regmap_update_bits(cs4271->regmap, CS4271_DACCTL, CS4271_DACCTL_DEM_MASK, val); if (ret < 0) return ret; @@ -341,14 +343,14 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, !dai->capture_active) || (substream->stream == SNDRV_PCM_STREAM_CAPTURE && !dai->playback_active)) { - ret = snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_PDN, - CS4271_MODE2_PDN); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, + CS4271_MODE2_PDN); if (ret < 0) return ret; - ret = snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_PDN, 0); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, 0); if (ret < 0) return ret; } @@ -378,7 +380,7 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, val |= cs4271_clk_tab[i].ratio_mask; - ret = snd_soc_update_bits(codec, CS4271_MODE1, + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1, CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val); if (ret < 0) return ret; @@ -386,22 +388,29 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, return cs4271_set_deemph(codec); } -static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute) +static int cs4271_mute_stream(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_codec *codec = dai->codec; + struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); int ret; int val_a = 0; int val_b = 0; + if (stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + if (mute) { val_a = CS4271_VOLA_MUTE; val_b = CS4271_VOLB_MUTE; } - ret = snd_soc_update_bits(codec, CS4271_VOLA, CS4271_VOLA_MUTE, val_a); + ret = regmap_update_bits(cs4271->regmap, CS4271_VOLA, + CS4271_VOLA_MUTE, val_a); if (ret < 0) return ret; - ret = snd_soc_update_bits(codec, CS4271_VOLB, CS4271_VOLB_MUTE, val_b); + + ret = regmap_update_bits(cs4271->regmap, CS4271_VOLB, + CS4271_VOLB_MUTE, val_b); if (ret < 0) return ret; @@ -436,7 +445,7 @@ static const struct snd_soc_dai_ops cs4271_dai_ops = { .hw_params = cs4271_hw_params, .set_sysclk = cs4271_set_dai_sysclk, .set_fmt = cs4271_set_dai_fmt, - .digital_mute = cs4271_digital_mute, + .mute_stream = cs4271_mute_stream, }; static struct snd_soc_dai_driver cs4271_dai = { @@ -463,25 +472,33 @@ static struct snd_soc_dai_driver cs4271_dai = { static int cs4271_soc_suspend(struct snd_soc_codec *codec) { int ret; + struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); + /* Set power-down bit */ - ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, - CS4271_MODE2_PDN); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, CS4271_MODE2_PDN); if (ret < 0) return ret; + return 0; } static int cs4271_soc_resume(struct snd_soc_codec *codec) { int ret; + struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); + /* Restore codec state */ - ret = snd_soc_cache_sync(codec); + ret = regcache_sync(cs4271->regmap); if (ret < 0) return ret; + /* then disable the power-down bit */ - ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, 0); if (ret < 0) return ret; + return 0; } #else @@ -542,40 +559,22 @@ static int cs4271_probe(struct snd_soc_codec *codec) cs4271->gpio_nreset = gpio_nreset; - /* - * In case of I2C, chip address specified in board data. - * So cache IO operations use 8 bit codec register address. - * In case of SPI, chip address and register address - * passed together as 16 bit value. - * Anyway, register address is masked with 0xFF inside - * soc-cache code. - */ - if (cs4271->bus_type == SND_SOC_SPI) - ret = snd_soc_codec_set_cache_io(codec, 16, 8, - cs4271->bus_type); - else - ret = snd_soc_codec_set_cache_io(codec, 8, 8, - cs4271->bus_type); - if (ret) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } - - ret = snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_PDN | CS4271_MODE2_CPEN, - CS4271_MODE2_PDN | CS4271_MODE2_CPEN); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN | CS4271_MODE2_CPEN, + CS4271_MODE2_PDN | CS4271_MODE2_CPEN); if (ret < 0) return ret; - ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, 0); if (ret < 0) return ret; /* Power-up sequence requires 85 uS */ udelay(85); if (amutec_eq_bmutec) - snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_MUTECAEQUB, - CS4271_MODE2_MUTECAEQUB); + regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_MUTECAEQUB, + CS4271_MODE2_MUTECAEQUB); return snd_soc_add_codec_controls(codec, cs4271_snd_controls, ARRAY_SIZE(cs4271_snd_controls)); @@ -597,13 +596,24 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { .remove = cs4271_remove, .suspend = cs4271_soc_suspend, .resume = cs4271_soc_resume, - .reg_cache_default = cs4271_dflt_reg, - .reg_cache_size = ARRAY_SIZE(cs4271_dflt_reg), - .reg_word_size = sizeof(cs4271_dflt_reg[0]), - .compress_type = SND_SOC_FLAT_COMPRESSION, }; #if defined(CONFIG_SPI_MASTER) + +static const struct regmap_config cs4271_spi_regmap = { + .reg_bits = 16, + .val_bits = 8, + .max_register = CS4271_LASTREG, + .read_flag_mask = 0x21, + .write_flag_mask = 0x20, + + .reg_defaults = cs4271_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = cs4271_volatile_reg, +}; + static int cs4271_spi_probe(struct spi_device *spi) { struct cs4271_private *cs4271; @@ -613,7 +623,9 @@ static int cs4271_spi_probe(struct spi_device *spi) return -ENOMEM; spi_set_drvdata(spi, cs4271); - cs4271->bus_type = SND_SOC_SPI; + cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); + if (IS_ERR(cs4271->regmap)) + return PTR_ERR(cs4271->regmap); return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271, &cs4271_dai, 1); @@ -643,6 +655,18 @@ static const struct i2c_device_id cs4271_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); +static const struct regmap_config cs4271_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = CS4271_LASTREG, + + .reg_defaults = cs4271_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = cs4271_volatile_reg, +}; + static int cs4271_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -653,7 +677,9 @@ static int cs4271_i2c_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, cs4271); - cs4271->bus_type = SND_SOC_I2C; + cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); + if (IS_ERR(cs4271->regmap)) + return PTR_ERR(cs4271->regmap); return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271, &cs4271_dai, 1); diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 6361dab48bd1..3b20c86cdb01 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1180,7 +1180,11 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, priv->config[id].mmcc &= 0xC0; priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc; priv->config[id].spc &= 0xFC; - priv->config[id].spc |= MCK_SCLK_MCLK; + /* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */ + if (priv->mclk >= 6400000) + priv->config[id].spc |= MCK_SCLK_64FS; + else + priv->config[id].spc |= MCK_SCLK_MCLK; } else { /* CS42L73 Slave */ priv->config[id].spc &= 0xFC; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index fc176044994d..fc176044994d 100755..100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index 7e103f249053..7e103f249053 100755..100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index f2d61a187830..566ea3256e2d 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -159,6 +159,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: width = SI476X_PCM_FORMAT_S8; + break; case SNDRV_PCM_FORMAT_S16_LE: width = SI476X_PCM_FORMAT_S16_LE; break; diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index ddc98f02ecbd..57ba315d0c84 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1565,7 +1565,7 @@ static int wm2200_probe(struct snd_soc_codec *codec) return ret; } - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2); + ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2); if (ret != 0) return ret; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index b82bbf584146..e895d3939eef 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -36,9 +36,6 @@ struct wm5102_priv { struct arizona_priv core; struct arizona_fll fll[2]; - - unsigned int spk_ena:2; - unsigned int spk_ena_pending:1; }; static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); @@ -584,7 +581,7 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - struct arizona *arizona = dev_get_drvdata(codec->dev); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); struct regmap *regmap = codec->control_data; const struct reg_default *patch = NULL; int i, patch_size; @@ -615,6 +612,26 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, return 0; } +static const char *wm5102_osr_text[] = { + "Low power", "Normal", "High performance", +}; + +static const unsigned int wm5102_osr_val[] = { + 0x0, 0x3, 0x5, +}; + +static const struct soc_enum wm5102_hpout_osr[] = { + SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, + ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, + wm5102_osr_text, wm5102_osr_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, + ARIZONA_OUT2_OSR_SHIFT, 0x7, 3, + wm5102_osr_text, wm5102_osr_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, + ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, + wm5102_osr_text, wm5102_osr_val), +}; + #define WM5102_NG_SRC(name, base) \ SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ @@ -745,6 +762,9 @@ 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]), + ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -761,6 +781,8 @@ ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE), +SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L, + ARIZONA_OUT4_OSR_SHIFT, 1, 0), SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, ARIZONA_OUT5_OSR_SHIFT, 1, 0), @@ -790,6 +812,10 @@ 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("HPOUT3 OSR", wm5102_hpout_osr[2]), + SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), @@ -828,47 +854,6 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), }; -static int wm5102_spk_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_codec *codec = w->codec; - struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec); - - if (arizona->rev < 1) - return 0; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - if (!wm5102->spk_ena) { - snd_soc_write(codec, 0x4f5, 0x25a); - wm5102->spk_ena_pending = true; - } - break; - case SND_SOC_DAPM_POST_PMU: - if (wm5102->spk_ena_pending) { - msleep(75); - snd_soc_write(codec, 0x4f5, 0xda); - wm5102->spk_ena_pending = false; - wm5102->spk_ena++; - } - break; - case SND_SOC_DAPM_PRE_PMD: - wm5102->spk_ena--; - if (!wm5102->spk_ena) - snd_soc_write(codec, 0x4f5, 0x25a); - break; - case SND_SOC_DAPM_POST_PMD: - if (!wm5102->spk_ena) - snd_soc_write(codec, 0x4f5, 0x0da); - break; - } - - return 0; -} - - ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE); @@ -984,22 +969,28 @@ SND_SOC_DAPM_INPUT("IN3R"), SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), @@ -1131,11 +1122,11 @@ ARIZONA_DSP_WIDGETS(DSP1, "DSP1"), SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux), -SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, @@ -1146,12 +1137,6 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1, SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), @@ -1494,6 +1479,12 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout); case WM5102_FLL2: return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout); + case WM5102_FLL1_REFCLK: + return arizona_set_fll_refclk(&wm5102->fll[0], source, Fref, + Fout); + case WM5102_FLL2_REFCLK: + return arizona_set_fll_refclk(&wm5102->fll[1], source, Fref, + Fout); default: return -EINVAL; } @@ -1581,10 +1572,12 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1); + ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2); if (ret != 0) return ret; + arizona_init_spk(codec); + snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); priv->core.arizona->dapm = &codec->dapm; @@ -1604,13 +1597,6 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec) #define WM5102_DIG_VU 0x0200 static unsigned int wm5102_digital_vu[] = { - ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_DAC_DIGITAL_VOLUME_1L, ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_DAC_DIGITAL_VOLUME_2L, @@ -1653,6 +1639,7 @@ static int wm5102_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wm5102); wm5102->core.arizona = arizona; + wm5102->core.num_inputs = 6; wm5102->core.adsp[0].part = "wm5102"; wm5102->core.adsp[0].num = 1; @@ -1677,6 +1664,12 @@ static int wm5102_probe(struct platform_device *pdev) ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK, &wm5102->fll[1]); + /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */ + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2, + ARIZONA_SAMPLE_RATE_2_MASK, 0x11); + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3, + ARIZONA_SAMPLE_RATE_3_MASK, 0x12); + for (i = 0; i < ARRAY_SIZE(wm5102_dai); i++) arizona_init_dai(&wm5102->core, i); diff --git a/sound/soc/codecs/wm5102.h b/sound/soc/codecs/wm5102.h index d30477f3070c..adb38040f661 100644 --- a/sound/soc/codecs/wm5102.h +++ b/sound/soc/codecs/wm5102.h @@ -15,7 +15,9 @@ #include "arizona.h" -#define WM5102_FLL1 1 -#define WM5102_FLL2 2 +#define WM5102_FLL1 1 +#define WM5102_FLL2 2 +#define WM5102_FLL1_REFCLK 3 +#define WM5102_FLL2_REFCLK 4 #endif diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index cdeb301da1f6..731884e04776 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -416,28 +416,36 @@ SND_SOC_DAPM_INPUT("IN4R"), SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), @@ -551,11 +559,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, @@ -569,12 +577,6 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), @@ -880,6 +882,12 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout); case WM5110_FLL2: return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout); + case WM5110_FLL1_REFCLK: + return arizona_set_fll_refclk(&wm5110->fll[0], source, Fref, + Fout); + case WM5110_FLL2_REFCLK: + return arizona_set_fll_refclk(&wm5110->fll[1], source, Fref, + Fout); default: return -EINVAL; } @@ -987,15 +995,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) #define WM5110_DIG_VU 0x0200 static unsigned int wm5110_digital_vu[] = { - ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_ADC_DIGITAL_VOLUME_4L, - ARIZONA_ADC_DIGITAL_VOLUME_4R, - ARIZONA_DAC_DIGITAL_VOLUME_1L, ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_DAC_DIGITAL_VOLUME_2L, @@ -1040,6 +1039,7 @@ static int wm5110_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wm5110); wm5110->core.arizona = arizona; + wm5110->core.num_inputs = 8; for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++) wm5110->fll[i].vco_mult = 3; diff --git a/sound/soc/codecs/wm5110.h b/sound/soc/codecs/wm5110.h index 75e9351ccab0..e6c0cd4235c5 100644 --- a/sound/soc/codecs/wm5110.h +++ b/sound/soc/codecs/wm5110.h @@ -15,7 +15,9 @@ #include "arizona.h" -#define WM5110_FLL1 1 -#define WM5110_FLL2 2 +#define WM5110_FLL1 1 +#define WM5110_FLL2 2 +#define WM5110_FLL1_REFCLK 3 +#define WM5110_FLL2_REFCLK 4 #endif diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 134e41c870b9..f8a31ad0b203 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1083,6 +1083,8 @@ static const struct snd_soc_dapm_route wm8903_intercon[] = { { "ROP", NULL, "Right Speaker PGA" }, { "RON", NULL, "Right Speaker PGA" }, + { "Charge Pump", NULL, "CLK_DSP" }, + { "Left Headphone Output PGA", NULL, "Charge Pump" }, { "Right Headphone Output PGA", NULL, "Charge Pump" }, { "Left Line Output PGA", NULL, "Charge Pump" }, diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f3f7e75f8628..3470b649c0b2 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -31,6 +31,7 @@ #include <linux/mfd/arizona/registers.h> +#include "arizona.h" #include "wm_adsp.h" #define adsp_crit(_dsp, fmt, ...) \ @@ -193,17 +194,25 @@ static void wm_adsp_buf_free(struct list_head *list) #define WM_ADSP_NUM_FW 4 +#define WM_ADSP_FW_MBC_VSS 0 +#define WM_ADSP_FW_TX 1 +#define WM_ADSP_FW_TX_SPK 2 +#define WM_ADSP_FW_RX_ANC 3 + static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { - "MBC/VSS", "Tx", "Tx Speaker", "Rx ANC" + [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", + [WM_ADSP_FW_TX] = "Tx", + [WM_ADSP_FW_TX_SPK] = "Tx Speaker", + [WM_ADSP_FW_RX_ANC] = "Rx ANC", }; static struct { const char *file; } wm_adsp_fw[WM_ADSP_NUM_FW] = { - { .file = "mbc-vss" }, - { .file = "tx" }, - { .file = "tx-spk" }, - { .file = "rx-anc" }, + [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, + [WM_ADSP_FW_TX] = { .file = "tx" }, + [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, + [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, }; static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, @@ -246,17 +255,52 @@ static const struct soc_enum wm_adsp_fw_enum[] = { SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), }; -const struct snd_kcontrol_new wm_adsp_fw_controls[] = { +const struct snd_kcontrol_new wm_adsp1_fw_controls[] = { + SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], + wm_adsp_fw_get, wm_adsp_fw_put), +}; +EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls); + +#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA) +static const struct soc_enum wm_adsp2_rate_enum[] = { + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), +}; + +const struct snd_kcontrol_new wm_adsp2_fw_controls[] = { SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]), SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]), SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]), SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]), }; -EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); +EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls); +#endif static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, int type) @@ -549,13 +593,30 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) buf_size = sizeof(adsp1_id); algs = be32_to_cpu(adsp1_id.algs); + dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", - be32_to_cpu(adsp1_id.fw.id), + dsp->fw_id, (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, be32_to_cpu(adsp1_id.fw.ver) & 0xff, algs); + region = kzalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return -ENOMEM; + region->type = WMFW_ADSP1_ZM; + region->alg = be32_to_cpu(adsp1_id.fw.id); + region->base = be32_to_cpu(adsp1_id.zm); + list_add_tail(®ion->list, &dsp->alg_regions); + + region = kzalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return -ENOMEM; + region->type = WMFW_ADSP1_DM; + region->alg = be32_to_cpu(adsp1_id.fw.id); + region->base = be32_to_cpu(adsp1_id.dm); + list_add_tail(®ion->list, &dsp->alg_regions); + pos = sizeof(adsp1_id) / 2; term = pos + ((sizeof(*adsp1_alg) * algs) / 2); break; @@ -573,13 +634,38 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) buf_size = sizeof(adsp2_id); algs = be32_to_cpu(adsp2_id.algs); + dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", - be32_to_cpu(adsp2_id.fw.id), + dsp->fw_id, (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, be32_to_cpu(adsp2_id.fw.ver) & 0xff, algs); + region = kzalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return -ENOMEM; + region->type = WMFW_ADSP2_XM; + region->alg = be32_to_cpu(adsp2_id.fw.id); + region->base = be32_to_cpu(adsp2_id.xm); + list_add_tail(®ion->list, &dsp->alg_regions); + + region = kzalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return -ENOMEM; + region->type = WMFW_ADSP2_YM; + region->alg = be32_to_cpu(adsp2_id.fw.id); + region->base = be32_to_cpu(adsp2_id.ym); + list_add_tail(®ion->list, &dsp->alg_regions); + + region = kzalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return -ENOMEM; + region->type = WMFW_ADSP2_ZM; + region->alg = be32_to_cpu(adsp2_id.fw.id); + region->base = be32_to_cpu(adsp2_id.zm); + list_add_tail(®ion->list, &dsp->alg_regions); + pos = sizeof(adsp2_id) / 2; term = pos + ((sizeof(*adsp2_alg) * algs) / 2); break; @@ -781,8 +867,24 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) case (WMFW_INFO_TEXT << 8): break; case (WMFW_ABSOLUTE << 8): - region_name = "register"; - reg = offset; + /* + * Old files may use this for global + * coefficients. + */ + if (le32_to_cpu(blk->id) == dsp->fw_id && + offset == 0) { + region_name = "global coefficients"; + mem = wm_adsp_find_region(dsp, type); + if (!mem) { + adsp_err(dsp, "No ZM\n"); + break; + } + reg = wm_adsp_region_to_reg(mem, 0); + + } else { + region_name = "register"; + reg = offset; + } break; case WMFW_ADSP1_DM: @@ -828,7 +930,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) &buf_list); if (!buf) { adsp_err(dsp, "Out of memory\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out_fw; } adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", @@ -865,7 +968,7 @@ out_fw: wm_adsp_buf_free(&buf_list); out: kfree(file); - return 0; + return ret; } int wm_adsp1_init(struct wm_adsp *adsp) diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index cb8871a3ec00..fea514627526 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -46,6 +46,8 @@ struct wm_adsp { struct list_head alg_regions; + int fw_id; + const struct wm_adsp_region *mem; int num_mems; @@ -65,7 +67,8 @@ struct wm_adsp { .shift = num, .event = wm_adsp2_event, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } -extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; +extern const struct snd_kcontrol_new wm_adsp1_fw_controls[]; +extern const struct snd_kcontrol_new wm_adsp2_fw_controls[]; int wm_adsp1_init(struct wm_adsp *adsp); int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs); diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 821831207180..ebe82947bab3 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -645,6 +645,10 @@ static struct snd_soc_dai_driver davinci_i2s_dai = { }; +static const struct snd_soc_component_driver davinci_i2s_component = { + .name = "davinci-i2s", +}; + static int davinci_i2s_probe(struct platform_device *pdev) { struct snd_platform_data *pdata = pdev->dev.platform_data; @@ -727,20 +731,21 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, dev); - ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component, + &davinci_i2s_dai, 1); if (ret != 0) goto err_release_clk; ret = davinci_soc_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_release_clk: clk_disable(dev->clk); clk_put(dev->clk); @@ -751,7 +756,7 @@ static int davinci_i2s_remove(struct platform_device *pdev) { struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); davinci_soc_platform_unregister(&pdev->dev); clk_disable(dev->clk); diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 9321e5c9d8c1..aeb3a6627d6a 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -235,6 +235,8 @@ #define DISMOD (val)(val<<2) #define TXSTATE BIT(4) #define RXSTATE BIT(5) +#define SRMOD_MASK 3 +#define SRMOD_INACTIVE 0 /* * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits @@ -643,26 +645,33 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev, /* mapping of the XSSZ bit-field as described in the datasheet */ fmt = (word_length >> 1) - 1; - mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, - RXSSZ(fmt), RXSSZ(0x0F)); - mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, - TXSSZ(fmt), TXSSZ(0x0F)); - mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXROT(rotate), - TXROT(7)); - mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXROT(rotate), - RXROT(7)); + if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) { + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, + RXSSZ(fmt), RXSSZ(0x0F)); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, + TXSSZ(fmt), TXSSZ(0x0F)); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, + TXROT(rotate), TXROT(7)); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, + RXROT(rotate), RXROT(7)); + mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, + mask); + } + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask); - mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, mask); return 0; } -static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) +static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream, + int channels) { int i; u8 tx_ser = 0; u8 rx_ser = 0; - + u8 ser; + u8 slots = dev->tdm_slots; + u8 max_active_serializers = (channels + slots - 1) / slots; /* Default configuration */ mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); @@ -682,17 +691,33 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) for (i = 0; i < dev->num_serializer; i++) { mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i), dev->serial_dir[i]); - if (dev->serial_dir[i] == TX_MODE) { + if (dev->serial_dir[i] == TX_MODE && + tx_ser < max_active_serializers) { mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AXR(i)); tx_ser++; - } else if (dev->serial_dir[i] == RX_MODE) { + } else if (dev->serial_dir[i] == RX_MODE && + rx_ser < max_active_serializers) { mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AXR(i)); rx_ser++; + } else { + mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i), + SRMOD_INACTIVE, SRMOD_MASK); } } + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + ser = tx_ser; + else + ser = rx_ser; + + if (ser < max_active_serializers) { + dev_warn(dev->dev, "stream has more channels (%d) than are " + "enabled in mcasp (%d)\n", channels, ser * slots); + return -EINVAL; + } + if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) { if (dev->txnumevt * tx_ser > 64) dev->txnumevt = 1; @@ -729,6 +754,8 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); } } + + return 0; } static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) @@ -772,12 +799,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) /* S/PDIF */ static void davinci_hw_dit_param(struct davinci_audio_dev *dev) { - /* Set the PDIR for Serialiser as output */ - mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX); - - /* TXMASK for 24 bits */ - mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF); - /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 and LSB first */ mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, @@ -812,8 +833,14 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, &dev->dma_params[substream->stream]; int word_length; u8 fifo_level; + u8 slots = dev->tdm_slots; + int channels; + struct snd_interval *pcm_channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + channels = pcm_channels->min; - davinci_hw_common_param(dev, substream->stream); + if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL) + return -EINVAL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) fifo_level = dev->txnumevt; else @@ -862,6 +889,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, dma_params->acnt = dma_params->data_type; dma_params->fifo_level = fifo_level; + dma_params->active_serializers = (channels + slots - 1) / slots; davinci_config_channel_size(dev, word_length); return 0; @@ -936,13 +964,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { .name = "davinci-mcasp.0", .playback = { .channels_min = 2, - .channels_max = 2, + .channels_max = 32 * 16, .rates = DAVINCI_MCASP_RATES, .formats = DAVINCI_MCASP_PCM_FMTS, }, .capture = { .channels_min = 2, - .channels_max = 2, + .channels_max = 32 * 16, .rates = DAVINCI_MCASP_RATES, .formats = DAVINCI_MCASP_PCM_FMTS, }, @@ -962,6 +990,10 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }; +static const struct snd_soc_component_driver davinci_mcasp_component = { + .name = "davinci-mcasp", +}; + static const struct of_device_id mcasp_dt_ids[] = { { .compatible = "ti,dm646x-mcasp-audio", @@ -1015,8 +1047,16 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( pdata->op_mode = val; ret = of_property_read_u32(np, "tdm-slots", &val); - if (ret >= 0) + if (ret >= 0) { + if (val < 2 || val > 32) { + dev_err(&pdev->dev, + "tdm-slots must be in rage [2-32]\n"); + ret = -EINVAL; + goto nodata; + } + pdata->tdm_slots = val; + } ret = of_property_read_u32(np, "num-serializer", &val); if (ret >= 0) @@ -1170,7 +1210,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; dev_set_drvdata(&pdev->dev, dev); - ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]); + ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, + &davinci_mcasp_dai[pdata->op_mode], 1); if (ret != 0) goto err_release_clk; @@ -1178,13 +1219,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev) ret = davinci_soc_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_release_clk: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1194,7 +1235,7 @@ err_release_clk: static int davinci_mcasp_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); davinci_soc_platform_unregister(&pdev->dev); pm_runtime_put_sync(&pdev->dev); diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index afab81f844ae..078031d61167 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -181,6 +181,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) unsigned short acnt; unsigned int count; unsigned int fifo_level; + unsigned char serializers = prtd->params->active_serializers; period_size = snd_pcm_lib_period_bytes(substream); dma_offset = prtd->period * period_size; @@ -194,14 +195,14 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) data_type = prtd->params->data_type; count = period_size / data_type; if (fifo_level) - count /= fifo_level; + count /= fifo_level * serializers; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { src = dma_pos; dst = prtd->params->dma_addr; src_bidx = data_type; - dst_bidx = 0; - src_cidx = data_type * fifo_level; + dst_bidx = 4; + src_cidx = data_type * fifo_level * serializers; dst_cidx = 0; } else { src = prtd->params->dma_addr; @@ -209,7 +210,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) src_bidx = 0; dst_bidx = data_type; src_cidx = 0; - dst_cidx = data_type * fifo_level; + dst_cidx = data_type * fifo_level * serializers; } acnt = prtd->params->acnt; @@ -223,9 +224,10 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0, ASYNC); else - edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level, - count, fifo_level, - ABSYNC); + edma_set_transfer_params(prtd->asp_link[0], acnt, + fifo_level * serializers, + count, fifo_level * serializers, + ABSYNC); } static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index b6ef7039dd09..32d7634d7b26 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -27,6 +27,7 @@ struct davinci_pcm_dma_params { unsigned char data_type; /* xfer data type */ unsigned char convert_mono_stereo; unsigned int fifo_level; + unsigned char active_serializers; /* num. of active audio serializers */ }; int davinci_soc_platform_register(struct device *dev); diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 07bde2e6f84e..30587c0cdbd2 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -204,6 +204,10 @@ static struct snd_soc_dai_driver davinci_vcif_dai = { }; +static const struct snd_soc_component_driver davinci_vcif_component = { + .name = "davinci-vcif", +}; + static int davinci_vcif_probe(struct platform_device *pdev) { struct davinci_vc *davinci_vc = pdev->dev.platform_data; @@ -234,7 +238,8 @@ static int davinci_vcif_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, davinci_vcif_dev); - ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai); + ret = snd_soc_register_component(&pdev->dev, &davinci_vcif_component, + &davinci_vcif_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "could not register dai\n"); return ret; @@ -243,7 +248,7 @@ static int davinci_vcif_probe(struct platform_device *pdev) ret = davinci_soc_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return ret; } @@ -252,7 +257,7 @@ static int davinci_vcif_probe(struct platform_device *pdev) static int davinci_vcif_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); davinci_soc_platform_unregister(&pdev->dev); return 0; diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index deb30d59965e..593a3ea12d4c 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -297,6 +297,10 @@ static struct snd_soc_dai_ops dw_i2s_dai_ops = { .trigger = dw_i2s_trigger, }; +static const struct snd_soc_component_driver dw_i2s_component = { + .name = "dw-i2s", +}; + #ifdef CONFIG_PM static int dw_i2s_suspend(struct snd_soc_dai *dai) @@ -413,7 +417,8 @@ static int dw_i2s_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); - ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, + dw_i2s_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "not able to register dai\n"); goto err_set_drvdata; @@ -434,7 +439,7 @@ static int dw_i2s_remove(struct platform_device *pdev) { struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); dev_set_drvdata(&pdev->dev, NULL); clk_put(dev->clk); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 8a7eac4bf651..42366d776f62 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -577,6 +577,10 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = { .ops = &fsl_ssi_dai_ops, }; +static const struct snd_soc_component_driver fsl_ssi_component = { + .name = "fsl-ssi", +}; + /* Show the statistics of a flag only if its interrupt is enabled. The * compiler will optimze this code to a no-op if the interrupt is not * enabled. @@ -790,7 +794,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) /* Register with ASoC */ dev_set_drvdata(&pdev->dev, ssi_private); - ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv); + ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component, + &ssi_private->cpu_dai_drv, 1); if (ret) { dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); goto error_dev; @@ -843,7 +848,7 @@ done: error_dai: if (ssi_private->ssi_on_imx) platform_device_unregister(ssi_private->imx_pcm_pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); error_dev: dev_set_drvdata(&pdev->dev, NULL); @@ -881,7 +886,7 @@ static int fsl_ssi_remove(struct platform_device *pdev) clk_disable_unprepare(ssi_private->clk); clk_put(ssi_private->clk); } - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); device_remove_file(&pdev->dev, &ssi_private->dev_attr); free_irq(ssi_private->irq, ssi_private); diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index dce05b613bd3..77300d163b96 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -413,6 +413,10 @@ static struct snd_soc_dai_driver imx_ac97_dai = { .ops = &imx_ssi_pcm_dai_ops, }; +static const struct snd_soc_component_driver imx_component = { + .name = DRV_NAME, +}; + static void setup_channel_to_ac97(struct imx_ssi *imx_ssi) { void __iomem *base = imx_ssi->base; @@ -496,6 +500,8 @@ static void imx_ssi_ac97_reset(struct snd_ac97 *ac97) if (imx_ssi->ac97_reset) imx_ssi->ac97_reset(ac97); + /* First read sometimes fails, do a dummy read */ + imx_ssi_ac97_read(ac97, 0); } static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97) @@ -504,6 +510,9 @@ static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97) if (imx_ssi->ac97_warm_reset) imx_ssi->ac97_warm_reset(ac97); + + /* First read sometimes fails, do a dummy read */ + imx_ssi_ac97_read(ac97, 0); } struct snd_ac97_bus_ops soc_ac97_ops = { @@ -593,7 +602,8 @@ static int imx_ssi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ssi); - ret = snd_soc_register_dai(&pdev->dev, dai); + ret = snd_soc_register_component(&pdev->dev, &imx_component, + dai, 1); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); goto failed_register; @@ -634,7 +644,7 @@ failed_pdev_alloc: failed_pdev_fiq_add: platform_device_put(ssi->soc_platform_pdev_fiq); failed_pdev_fiq_alloc: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); failed_register: release_mem_region(res->start, resource_size(res)); failed_get_resource: @@ -652,7 +662,7 @@ static int imx_ssi_remove(struct platform_device *pdev) platform_device_unregister(ssi->soc_platform_pdev); platform_device_unregister(ssi->soc_platform_pdev_fiq); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); if (ssi->flags & IMX_SSI_USE_AC97) ac97_ssi = NULL; diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index a4aec0488dd3..4141b35ef0bb 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -270,6 +270,9 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = { .ops = &psc_ac97_digital_ops, } }; +static const struct snd_soc_component_driver psc_ac97_component = { + .name = DRV_NAME, +}; /* --------------------------------------------------------------------- @@ -287,7 +290,8 @@ static int psc_ac97_of_probe(struct platform_device *op) if (rc != 0) return rc; - rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai)); + rc = snd_soc_register_component(&op->dev, &psc_ac97_component, + psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai)); if (rc != 0) { dev_err(&op->dev, "Failed to register DAI\n"); return rc; @@ -313,7 +317,7 @@ static int psc_ac97_of_probe(struct platform_device *op) static int psc_ac97_of_remove(struct platform_device *op) { mpc5200_audio_dma_destroy(op); - snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai)); + snd_soc_unregister_component(&op->dev); return 0; } diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index b95b966f25a0..f4efaadb80a2 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -148,6 +148,10 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{ .ops = &psc_i2s_dai_ops, } }; +static const struct snd_soc_component_driver psc_i2s_component = { + .name = "mpc5200-i2s", +}; + /* --------------------------------------------------------------------- * OF platform bus binding code: * - Probe/remove operations @@ -163,7 +167,8 @@ static int psc_i2s_of_probe(struct platform_device *op) if (rc != 0) return rc; - rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); + rc = snd_soc_register_component(&op->dev, &psc_i2s_component, + psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); if (rc != 0) { pr_err("Failed to register DAI\n"); return rc; @@ -208,7 +213,7 @@ static int psc_i2s_of_probe(struct platform_device *op) static int psc_i2s_of_remove(struct platform_device *op) { mpc5200_audio_dma_destroy(op); - snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai)); + snd_soc_unregister_component(&op->dev); return 0; } diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index 8e52c1485df3..eb4373840bb6 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -51,7 +51,7 @@ static struct snd_soc_card pcm030_card = { .num_links = ARRAY_SIZE(pcm030_fabric_dai), }; -static int __init pcm030_fabric_probe(struct platform_device *op) +static int pcm030_fabric_probe(struct platform_device *op) { struct device_node *np = op->dev.of_node; struct device_node *platform_np; diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 6cef491f4823..9a126441c5f3 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -425,6 +425,10 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = { .resume = jz4740_i2s_resume, }; +static const struct snd_soc_component_driver jz4740_i2s_component = { + .name = "jz4740-i2s", +}; + static int jz4740_i2s_dev_probe(struct platform_device *pdev) { struct jz4740_i2s *i2s; @@ -469,7 +473,8 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, i2s); - ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &jz4740_i2s_component, + &jz4740_i2s_dai, 1); if (ret) { dev_err(&pdev->dev, "Failed to register DAI\n"); @@ -496,7 +501,7 @@ static int jz4740_i2s_dev_remove(struct platform_device *pdev) { struct jz4740_i2s *i2s = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(i2s->clk_i2s); clk_put(i2s->clk_aic); diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index c74c89065493..befe68f59285 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -451,6 +451,10 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { .ops = &kirkwood_i2s_dai_ops, }; +static const struct snd_soc_component_driver kirkwood_i2s_component = { + .name = DRV_NAME, +}; + static int kirkwood_i2s_dev_probe(struct platform_device *pdev) { struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; @@ -524,10 +528,11 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128; } - err = snd_soc_register_dai(&pdev->dev, soc_dai); + err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, + soc_dai, 1); if (!err) return 0; - dev_err(&pdev->dev, "snd_soc_register_dai failed\n"); + dev_err(&pdev->dev, "snd_soc_register_component failed\n"); if (!IS_ERR(priv->extclk)) { clk_disable_unprepare(priv->extclk); @@ -542,7 +547,7 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev) { struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); if (!IS_ERR(priv->extclk)) { clk_disable_unprepare(priv->extclk); diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index a263cbed8624..392fc0b8f5b8 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -1,7 +1,7 @@ /* * sst_platform.c - Intel MID Platform driver * - * Copyright (C) 2010-2012 Intel Corp + * Copyright (C) 2010-2013 Intel Corp * Author: Vinod Koul <vinod.koul@intel.com> * Author: Harsha Priya <priya.harsha@intel.com> * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -165,6 +165,10 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { }, }; +static const struct snd_soc_component_driver sst_component = { + .name = "sst", +}; + /* helper functions */ static inline void sst_set_stream_status(struct sst_runtime_stream *stream, int state) @@ -652,11 +656,21 @@ static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream, return stream->compr_ops->get_codec_caps(codec); } +static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct sst_runtime_stream *stream = + cstream->runtime->private_data; + + return stream->compr_ops->set_metadata(stream->id, metadata); +} + static struct snd_compr_ops sst_platform_compr_ops = { .open = sst_platform_compr_open, .free = sst_platform_compr_free, .set_params = sst_platform_compr_set_params, + .set_metadata = sst_platform_compr_set_metadata, .trigger = sst_platform_compr_trigger, .pointer = sst_platform_compr_pointer, .ack = sst_platform_compr_ack, @@ -683,7 +697,7 @@ static int sst_platform_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_register_dais(&pdev->dev, + ret = snd_soc_register_component(&pdev->dev, &sst_component, sst_platform_dai, ARRAY_SIZE(sst_platform_dai)); if (ret) { pr_err("registering cpu dais failed\n"); @@ -695,7 +709,7 @@ static int sst_platform_probe(struct platform_device *pdev) static int sst_platform_remove(struct platform_device *pdev) { - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai)); + snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); pr_debug("sst_platform_remove success\n"); return 0; diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h index d61c5d514ffa..cacc9066ec52 100644 --- a/sound/soc/mid-x86/sst_platform.h +++ b/sound/soc/mid-x86/sst_platform.h @@ -124,6 +124,8 @@ struct compress_sst_ops { int (*close) (unsigned int str_id); int (*get_caps) (struct snd_compr_caps *caps); int (*get_codec_caps) (struct snd_compr_codec_caps *codec); + int (*set_metadata) (unsigned int str_id, + struct snd_compr_metadata *mdata); }; diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index f13bd8730b0f..abf4ddf4ed89 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -627,6 +627,10 @@ static struct snd_soc_dai_driver mxs_saif_dai = { .ops = &mxs_saif_dai_ops, }; +static const struct snd_soc_component_driver mxs_saif_component = { + .name = "mxs-saif", +}; + static irqreturn_t mxs_saif_irq(int irq, void *dev_id) { struct mxs_saif *saif = dev_id; @@ -763,7 +767,8 @@ static int mxs_saif_probe(struct platform_device *pdev) platform_set_drvdata(pdev, saif); - ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai); + ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component, + &mxs_saif_dai, 1); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); return ret; @@ -778,7 +783,7 @@ static int mxs_saif_probe(struct platform_device *pdev) return 0; failed_pdev_alloc: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return ret; } @@ -786,7 +791,7 @@ failed_pdev_alloc: static int mxs_saif_remove(struct platform_device *pdev) { mxs_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 0418467a4848..fe3285ceaf5b 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -314,6 +314,10 @@ static struct snd_soc_dai_driver nuc900_ac97_dai = { .ops = &nuc900_ac97_dai_ops, }; +static const struct snd_soc_component_driver nuc900_ac97_component = { + .name = "nuc900-ac97", +}; + static int nuc900_ac97_drvprobe(struct platform_device *pdev) { struct nuc900_audio *nuc900_audio; @@ -361,7 +365,8 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev) nuc900_ac97_data = nuc900_audio; - ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai); + ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component, + &nuc900_ac97_dai, 1); if (ret) goto out3; @@ -384,7 +389,7 @@ out0: static int nuc900_ac97_drvremove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(nuc900_ac97_data->clk); iounmap(nuc900_ac97_data->mmio); diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index a2597fab33a3..2ad0370146fd 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -444,6 +444,10 @@ static struct snd_soc_dai_driver omap_dmic_dai = { .ops = &omap_dmic_dai_ops, }; +static const struct snd_soc_component_driver omap_dmic_component = { + .name = "omap-dmic", +}; + static int asoc_dmic_probe(struct platform_device *pdev) { struct omap_dmic *dmic; @@ -495,7 +499,8 @@ static int asoc_dmic_probe(struct platform_device *pdev) if (IS_ERR(dmic->io_base)) return PTR_ERR(dmic->io_base); - ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai); + ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component, + &omap_dmic_dai, 1); if (ret) goto err_put_clk; @@ -510,7 +515,7 @@ static int asoc_dmic_remove(struct platform_device *pdev) { struct omap_dmic *dmic = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(dmic->fclk); return 0; diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c index b4bfab9f33e8..ced3b88b44d4 100644 --- a/sound/soc/omap/omap-hdmi.c +++ b/sound/soc/omap/omap-hdmi.c @@ -260,6 +260,10 @@ static struct snd_soc_dai_driver omap_hdmi_dai = { .ops = &omap_hdmi_dai_ops, }; +static const struct snd_soc_component_driver omap_hdmi_component = { + .name = DRV_NAME, +}; + static int omap_hdmi_probe(struct platform_device *pdev) { int ret; @@ -317,7 +321,8 @@ static int omap_hdmi_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, hdmi_data); - ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai); + ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component, + &omap_hdmi_dai, 1); return ret; } @@ -326,7 +331,7 @@ static int omap_hdmi_remove(struct platform_device *pdev) { struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); if (hdmi_data == NULL) { dev_err(&pdev->dev, "cannot obtain HDMi data\n"); diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 1e7b3e89e04f..eadbfb6b5000 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -584,6 +584,10 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = { .ops = &mcbsp_dai_ops, }; +static const struct snd_soc_component_driver omap_mcbsp_component = { + .name = "omap-mcbsp", +}; + static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -791,7 +795,8 @@ static int asoc_mcbsp_probe(struct platform_device *pdev) ret = omap_mcbsp_init(pdev); if (!ret) - return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai); + return snd_soc_register_component(&pdev->dev, &omap_mcbsp_component, + &omap_mcbsp_dai, 1); return ret; } @@ -800,7 +805,7 @@ static int asoc_mcbsp_remove(struct platform_device *pdev) { struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); if (mcbsp->pdata->ops && mcbsp->pdata->ops->free) mcbsp->pdata->ops->free(mcbsp->id); diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 49f102a1dbae..eb05c7ed6d05 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -444,6 +444,10 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = { .ops = &omap_mcpdm_dai_ops, }; +static const struct snd_soc_component_driver omap_mcpdm_component = { + .name = "omap-mcpdm", +}; + void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd, u8 rx1, u8 rx2) { @@ -501,12 +505,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) mcpdm->dev = &pdev->dev; - return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); + return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component, + &omap_mcpdm_dai, 1); } static int asoc_mcpdm_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 9140c4abafbc..a64779980177 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -405,6 +405,10 @@ struct snd_soc_dai_driver mmp_sspa_dai = { .ops = &mmp_sspa_dai_ops, }; +static const struct snd_soc_component_driver mmp_sspa_component = { + .name = "mmp-sspa", +}; + static int asoc_mmp_sspa_probe(struct platform_device *pdev) { struct sspa_priv *priv; @@ -450,7 +454,8 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev) priv->dai_fmt = (unsigned int) -1; platform_set_drvdata(pdev, priv); - return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai); + return snd_soc_register_component(&pdev->dev, &mmp_sspa_component, + &mmp_sspa_dai, 1); } static int asoc_mmp_sspa_remove(struct platform_device *pdev) @@ -460,7 +465,7 @@ static int asoc_mmp_sspa_remove(struct platform_device *pdev) clk_disable(priv->audio_clk); clk_put(priv->audio_clk); clk_put(priv->sysclk); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index d3eb0c2eec77..6f4dd7543e82 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -794,14 +794,19 @@ static struct snd_soc_dai_driver pxa_ssp_dai = { .ops = &pxa_ssp_dai_ops, }; +static const struct snd_soc_component_driver pxa_ssp_component = { + .name = "pxa-ssp", +}; + static int asoc_ssp_probe(struct platform_device *pdev) { - return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai); + return snd_soc_register_component(&pdev->dev, &pxa_ssp_component, + &pxa_ssp_dai, 1); } static int asoc_ssp_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 4b0a009bd683..57ea8e6c5488 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -47,6 +47,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { .warm_reset = pxa2xx_ac97_warm_reset, .reset = pxa2xx_ac97_cold_reset, }; +EXPORT_SYMBOL_GPL(soc_ac97_ops); static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { .name = "AC97 PCM Stereo out", @@ -232,7 +233,9 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { }, }; -EXPORT_SYMBOL_GPL(soc_ac97_ops); +static const struct snd_soc_component_driver pxa_ac97_component = { + .name = "pxa-ac97", +}; static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) { @@ -245,13 +248,13 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) * driver to do interesting things with the clocking to get us up * and running. */ - return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai_driver, - ARRAY_SIZE(pxa_ac97_dai_driver)); + return snd_soc_register_component(&pdev->dev, &pxa_ac97_component, + pxa_ac97_dai_driver, ARRAY_SIZE(pxa_ac97_dai_driver)); } static int pxa2xx_ac97_dev_remove(struct platform_device *pdev) { - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai_driver)); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 6b1a06f67564..f7ca71664112 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -360,14 +360,19 @@ static struct snd_soc_dai_driver pxa_i2s_dai = { .symmetric_rates = 1, }; +static const struct snd_soc_component_driver pxa_i2s_component = { + .name = "pxa-i2s", +}; + static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) { - return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai); + return snd_soc_register_component(&pdev->dev, &pxa_i2s_component, + &pxa_i2s_dai, 1); } static int pxa2xx_i2s_drv_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c index fee4d477a49c..73bb99f0109a 100644 --- a/sound/soc/s6000/s6000-i2s.c +++ b/sound/soc/s6000/s6000-i2s.c @@ -436,6 +436,10 @@ static struct snd_soc_dai_driver s6000_i2s_dai = { .ops = &s6000_i2s_dai_ops, }; +static const struct snd_soc_component_driver s6000_i2s_component = { + .name = "s6000-i2s", +}; + static int s6000_i2s_probe(struct platform_device *pdev) { struct s6000_i2s_dev *dev; @@ -543,7 +547,8 @@ static int s6000_i2s_probe(struct platform_device *pdev) S6_I2S_INT_UNDERRUN | S6_I2S_INT_OVERRUN); - ret = snd_soc_register_dai(&pdev->dev, &s6000_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &s6000_i2s_component, + &s6000_i2s_dai, 1); if (ret) goto err_release_dev; @@ -572,7 +577,7 @@ static void s6000_i2s_remove(struct platform_device *pdev) struct resource *region; void __iomem *mmio = dev->scbbase; - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); s6000_i2s_stop_channel(dev, 0); s6000_i2s_stop_channel(dev, 1); diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 0df3c5644cfa..32ff594954bc 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -370,6 +370,10 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = { }, }; +static const struct snd_soc_component_driver s3c_ac97_component = { + .name = "s3c-ac97", +}; + static int s3c_ac97_probe(struct platform_device *pdev) { struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res; @@ -457,8 +461,8 @@ static int s3c_ac97_probe(struct platform_device *pdev) goto err4; } - ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai, - ARRAY_SIZE(s3c_ac97_dai)); + ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component, + s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); if (ret) goto err5; @@ -470,7 +474,7 @@ static int s3c_ac97_probe(struct platform_device *pdev) return 0; err6: - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai)); + snd_soc_unregister_component(&pdev->dev); err5: free_irq(irq_res->start, NULL); err4: @@ -490,7 +494,7 @@ static int s3c_ac97_remove(struct platform_device *pdev) struct resource *mem_res, *irq_res; asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai)); + snd_soc_unregister_component(&pdev->dev); irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (irq_res) diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index d37ede58e0a8..415ad81999c4 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -218,6 +218,10 @@ static struct snd_soc_dai_driver voice_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE,}, }; +static const struct snd_soc_component_driver voice_component = { + .name = "goni-voice", +}; + static struct snd_soc_ops goni_voice_ops = { .hw_params = goni_voice_hw_params, }; @@ -270,7 +274,8 @@ static int __init goni_init(void) return -ENOMEM; /* register voice DAI here */ - ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai); + ret = snd_soc_register_component(&goni_snd_device->dev, &voice_component, + &voice_dai, 1); if (ret) { platform_device_put(goni_snd_device); return ret; @@ -280,7 +285,7 @@ static int __init goni_init(void) ret = platform_device_add(goni_snd_device); if (ret) { - snd_soc_unregister_dai(&goni_snd_device->dev); + snd_soc_unregister_component(&goni_snd_device->dev); platform_device_put(goni_snd_device); } @@ -289,7 +294,7 @@ static int __init goni_init(void) static void __exit goni_exit(void) { - snd_soc_unregister_dai(&goni_snd_device->dev); + snd_soc_unregister_component(&goni_snd_device->dev); platform_device_unregister(goni_snd_device); } diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index d7231e336a7c..abbcbe4b429c 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -963,6 +963,10 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { .delay = i2s_delay, }; +static const struct snd_soc_component_driver samsung_i2s_component = { + .name = "samsung-i2s", +}; + #define SAMSUNG_I2S_RATES SNDRV_PCM_RATE_8000_96000 #define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ @@ -972,6 +976,7 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) { struct i2s_dai *i2s; + int ret; i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL); if (i2s == NULL) @@ -996,15 +1001,17 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) i2s->i2s_dai_drv.capture.channels_max = 2; i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES; i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; + dev_set_drvdata(&i2s->pdev->dev, i2s); } else { /* Create a new platform_device for Secondary */ - i2s->pdev = platform_device_register_resndata(NULL, - "samsung-i2s-sec", -1, NULL, 0, NULL, 0); + i2s->pdev = platform_device_alloc("samsung-i2s-sec", -1); if (IS_ERR(i2s->pdev)) return NULL; - } - /* Pre-assign snd_soc_dai_set_drvdata */ - dev_set_drvdata(&i2s->pdev->dev, i2s); + platform_set_drvdata(i2s->pdev, i2s); + ret = platform_device_add(i2s->pdev); + if (ret < 0) + return NULL; + } return i2s; } @@ -1107,8 +1114,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (samsung_dai_type == TYPE_SEC) { sec_dai = dev_get_drvdata(&pdev->dev); - snd_soc_register_dai(&sec_dai->pdev->dev, - &sec_dai->i2s_dai_drv); + if (!sec_dai) { + dev_err(&pdev->dev, "Unable to get drvdata\n"); + return -EFAULT; + } + snd_soc_register_component(&sec_dai->pdev->dev, + &samsung_i2s_component, + &sec_dai->i2s_dai_drv, 1); asoc_dma_platform_register(&pdev->dev); return 0; } @@ -1237,7 +1249,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) } } - snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv); + snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component, + &pri_dai->i2s_dai_drv, 1); pm_runtime_enable(&pdev->dev); @@ -1276,7 +1289,7 @@ static int samsung_i2s_remove(struct platform_device *pdev) i2s->sec_dai = NULL; asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 13bab79ad93d..1566afe9ef52 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -490,6 +490,10 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = { }, }; +static const struct snd_soc_component_driver s3c_pcm_component = { + .name = "s3c-pcm", +}; + static int s3c_pcm_dev_probe(struct platform_device *pdev) { struct s3c_pcm_info *pcm; @@ -583,7 +587,8 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]); + ret = snd_soc_register_component(&pdev->dev, &s3c_pcm_component, + &s3c_pcm_dai[pdev->id], 1); if (ret != 0) { dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret); goto err5; @@ -598,7 +603,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) return 0; err6: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); err5: clk_disable_unprepare(pcm->pclk); clk_put(pcm->pclk); @@ -619,7 +624,7 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev) struct resource *mem_res; asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index 7a73380b3560..20e98d1dded2 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -731,8 +731,9 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) #define s3c2412_i2s_resume NULL #endif -int s3c_i2sv2_register_dai(struct device *dev, int id, - struct snd_soc_dai_driver *drv) +int s3c_i2sv2_register_component(struct device *dev, int id, + struct snd_soc_component_driver *cmp_drv, + struct snd_soc_dai_driver *dai_drv) { struct snd_soc_dai_ops *ops = drv->ops; @@ -750,8 +751,8 @@ int s3c_i2sv2_register_dai(struct device *dev, int id, drv->suspend = s3c2412_i2s_suspend; drv->resume = s3c2412_i2s_resume; - return snd_soc_register_dai(dev, drv); + return snd_soc_register_component(dev, cmp_drv, dai_drv, 1); } -EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai); +EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component); MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index f8297d9bb8a3..90abab364b49 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h @@ -92,7 +92,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, unsigned long base); /** - * s3c_i2sv2_register_dai - register dai with soc core + * s3c_i2sv2_register_component - register component and dai with soc core * @dev: DAI device * @id: DAI ID * @drv: The driver structure to register @@ -100,7 +100,8 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, * Fill in any missing fields and then register the given dai with the * soc core. */ -extern int s3c_i2sv2_register_dai(struct device *dev, int id, - struct snd_soc_dai_driver *drv); +extern int s3c_i2sv2_register_component(struct device *dev, int id, + struct snd_soc_component_driver *cmp_drv, + struct snd_soc_dai_driver *dai_drv); #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */ diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 221337716393..47e23864ea72 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -160,11 +160,17 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = { .ops = &s3c2412_i2s_dai_ops, }; +static const struct snd_soc_component_driver s3c2412_i2s_component = { + .name = "s3c2412-i2s", +}; + static int s3c2412_iis_dev_probe(struct platform_device *pdev) { int ret = 0; - ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); + ret = s3c_i2sv2_register_component(&pdev->dev, -1, + &s3c2412_i2s_component, + &s3c2412_i2s_dai); if (ret) { pr_err("failed to register the dai\n"); return ret; @@ -178,14 +184,14 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) return 0; err: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return ret; } static int s3c2412_iis_dev_remove(struct platform_device *pdev) { asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 13f6dd1ceb00..5403176b2aa3 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -465,11 +465,16 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = { .ops = &s3c24xx_i2s_dai_ops, }; +static const struct snd_soc_component_driver s3c24xx_i2s_component = { + .name = "s3c24xx-i2s", +}; + static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { int ret = 0; - ret = snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component, + &s3c24xx_i2s_dai, 1); if (ret) { pr_err("failed to register the dai\n"); return ret; @@ -483,14 +488,14 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) return 0; err: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return ret; } static int s3c24xx_iis_dev_remove(struct platform_device *pdev) { asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 5008e5bd6ed8..2e5ebb2f1982 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -357,6 +357,10 @@ static struct snd_soc_dai_driver samsung_spdif_dai = { .resume = spdif_resume, }; +static const struct snd_soc_component_driver samsung_spdif_component = { + .name = "samsung-spdif", +}; + static int spdif_probe(struct platform_device *pdev) { struct s3c_audio_pdata *spdif_pdata; @@ -424,7 +428,8 @@ static int spdif_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, spdif); - ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai); + ret = snd_soc_register_component(&pdev->dev, &samsung_spdif_component, + &samsung_spdif_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "fail to register dai\n"); goto err4; @@ -445,7 +450,7 @@ static int spdif_probe(struct platform_device *pdev) return 0; err5: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); err4: iounmap(spdif->regs); err3: @@ -466,7 +471,7 @@ static int spdif_remove(struct platform_device *pdev) struct resource *mem_res; asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); iounmap(spdif->regs); diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 19eff8fc4fdd..1a8b03e4b41b 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -342,8 +342,8 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static struct snd_soc_platform sh7760_soc_platform = { - .pcm_ops = &camelot_pcm_ops, +static struct snd_soc_platform_driver sh7760_soc_platform = { + .ops = &camelot_pcm_ops, .pcm_new = camelot_pcm_new, .pcm_free = camelot_pcm_free, }; diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index c724026a246f..254c6375f7a1 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1886,6 +1886,10 @@ static struct snd_soc_platform_driver fsi_soc_platform = { .pcm_free = fsi_pcm_free, }; +static const struct snd_soc_component_driver fsi_soc_component = { + .name = "fsi", +}; + /* * platform function */ @@ -2046,10 +2050,10 @@ static int fsi_probe(struct platform_device *pdev) goto exit_fsib; } - ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai, - ARRAY_SIZE(fsi_soc_dai)); + ret = snd_soc_register_component(&pdev->dev, &fsi_soc_component, + fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); if (ret < 0) { - dev_err(&pdev->dev, "cannot snd dai register\n"); + dev_err(&pdev->dev, "cannot snd component register\n"); goto exit_snd_soc; } @@ -2074,7 +2078,7 @@ static int fsi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); + snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); fsi_stream_remove(&master->fsia); diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 4cc2d64ef476..af19f77b7bf0 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -310,15 +310,19 @@ static struct snd_soc_dai_driver sh4_hac_dai[] = { #endif }; +static const struct snd_soc_component_driver sh4_hac_component = { + .name = "sh4-hac", +}; + static int hac_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_dais(&pdev->dev, sh4_hac_dai, - ARRAY_SIZE(sh4_hac_dai)); + return snd_soc_register_component(&pdev->dev, &sh4_hac_component, + sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); } static int hac_soc_platform_remove(struct platform_device *pdev) { - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai)); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c index 8526e1edaf45..5014a884afee 100644 --- a/sound/soc/sh/migor.c +++ b/sound/soc/sh/migor.c @@ -153,7 +153,7 @@ static int migor_dai_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link migor_dai = { .name = "wm8978", .stream_name = "WM8978", - .cpu_dai_name = "siu-i2s-dai", + .cpu_dai_name = "siu-pcm-audio", .codec_dai_name = "wm8978-hifi", .platform_name = "siu-pcm-audio", .codec_name = "wm8978.0-001a", diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c index 34facdc9e4ac..9dc24ffa892a 100644 --- a/sound/soc/sh/siu_dai.c +++ b/sound/soc/sh/siu_dai.c @@ -726,6 +726,10 @@ static struct snd_soc_dai_driver siu_i2s_dai = { .ops = &siu_dai_ops, }; +static const struct snd_soc_component_driver siu_i2s_component = { + .name = "siu-i2s", +}; + static int siu_probe(struct platform_device *pdev) { const struct firmware *fw_entry; @@ -783,7 +787,8 @@ static int siu_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, info); /* register using ARRAY version so we can keep dai name */ - ret = snd_soc_register_dais(&pdev->dev, &siu_i2s_dai, 1); + ret = snd_soc_register_component(&pdev->dev, &siu_i2s_component, + &siu_i2s_dai, 1); if (ret < 0) goto edaiinit; @@ -796,7 +801,7 @@ static int siu_probe(struct platform_device *pdev) return ret; esocregp: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); edaiinit: iounmap(info->reg); emapreg: @@ -823,7 +828,7 @@ static int siu_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); iounmap(info->reg); iounmap(info->yram); diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index c8e73a703934..e889405ebd38 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -379,15 +379,19 @@ static struct snd_soc_dai_driver sh4_ssi_dai[] = { #endif }; +static const struct snd_soc_component_driver sh4_ssi_component = { + .name = "sh4-ssi", +}; + static int sh4_soc_dai_probe(struct platform_device *pdev) { - return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai, - ARRAY_SIZE(sh4_ssi_dai)); + return snd_soc_register_component(&pdev->dev, &sh4_ssi_component, + sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); } static int sh4_soc_dai_remove(struct platform_device *pdev) { - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai)); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index b5b3db71e253..29093a306ea2 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -211,19 +211,27 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) - goto out; + goto err; } if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); if (ret < 0) - goto out; + goto err; } snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_START); -out: + /* cancel any delayed stream shutdown that is pending */ + rtd->pop_wait = 0; + mutex_unlock(&rtd->pcm_mutex); + + cancel_delayed_work_sync(&rtd->delayed_work); + + return ret; + +err: mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -322,11 +330,38 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, return ret; } +static int sst_compr_set_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata) + ret = platform->driver->compr_ops->set_metadata(cstream, metadata); + + return ret; +} + +static int sst_compr_get_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata) + ret = platform->driver->compr_ops->get_metadata(cstream, metadata); + + return ret; +} /* ASoC Compress operations */ static struct snd_compr_ops soc_compr_ops = { .open = soc_compr_open, .free = soc_compr_free, .set_params = soc_compr_set_params, + .set_metadata = sst_compr_set_metadata, + .get_metadata = sst_compr_get_metadata, .get_params = soc_compr_get_params, .trigger = soc_compr_trigger, .pointer = soc_compr_pointer, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b7e84a7cd9ee..7bf21a1035ea 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -58,6 +58,7 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(dai_list); static LIST_HEAD(platform_list); static LIST_HEAD(codec_list); +static LIST_HEAD(component_list); /* * This is a timeout to do a DAPM powerdown after a stream is closed(). @@ -2963,7 +2964,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, val = val << shift; ret = snd_soc_update_bits_locked(codec, reg, val_mask, val); - if (ret != 0) + if (ret < 0) return ret; if (snd_soc_volsw_is_stereo(mc)) { @@ -3140,7 +3141,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, if (params->mask) { ret = regmap_read(codec->control_data, params->base, &val); if (ret != 0) - return ret; + goto out; val &= params->mask; @@ -3158,13 +3159,15 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, ((u32 *)data)[0] |= cpu_to_be32(val); break; default: - return -EINVAL; + ret = -EINVAL; + goto out; } } ret = regmap_raw_write(codec->control_data, params->base, data, len); +out: kfree(data); return ret; @@ -3738,7 +3741,7 @@ static inline char *fmt_multiple_name(struct device *dev, * * @dai: DAI to register */ -int snd_soc_register_dai(struct device *dev, +static int snd_soc_register_dai(struct device *dev, struct snd_soc_dai_driver *dai_drv) { struct snd_soc_codec *codec; @@ -3785,14 +3788,13 @@ int snd_soc_register_dai(struct device *dev, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_register_dai); /** * snd_soc_unregister_dai - Unregister a DAI from the ASoC core * * @dai: DAI to unregister */ -void snd_soc_unregister_dai(struct device *dev) +static void snd_soc_unregister_dai(struct device *dev) { struct snd_soc_dai *dai; @@ -3811,7 +3813,6 @@ found: kfree(dai->name); kfree(dai); } -EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); /** * snd_soc_register_dais - Register multiple DAIs with the ASoC core @@ -3819,7 +3820,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); * @dai: Array of DAIs to register * @count: Number of DAIs */ -int snd_soc_register_dais(struct device *dev, +static int snd_soc_register_dais(struct device *dev, struct snd_soc_dai_driver *dai_drv, size_t count) { struct snd_soc_codec *codec; @@ -3883,7 +3884,6 @@ err: return ret; } -EXPORT_SYMBOL_GPL(snd_soc_register_dais); /** * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core @@ -3891,14 +3891,13 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais); * @dai: Array of DAIs to unregister * @count: Number of DAIs */ -void snd_soc_unregister_dais(struct device *dev, size_t count) +static void snd_soc_unregister_dais(struct device *dev, size_t count) { int i; for (i = 0; i < count; i++) snd_soc_unregister_dai(dev); } -EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); /** * snd_soc_register_platform - Register a platform with the ASoC core @@ -3906,7 +3905,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); * @platform: platform to register */ int snd_soc_register_platform(struct device *dev, - struct snd_soc_platform_driver *platform_drv) + const struct snd_soc_platform_driver *platform_drv) { struct snd_soc_platform *platform; @@ -4022,8 +4021,8 @@ int snd_soc_register_codec(struct device *dev, /* create CODEC component name */ codec->name = fmt_single_name(dev, &codec->id); if (codec->name == NULL) { - kfree(codec); - return -ENOMEM; + ret = -ENOMEM; + goto fail_codec; } if (codec_drv->compress_type) @@ -4062,7 +4061,7 @@ int snd_soc_register_codec(struct device *dev, reg_size, GFP_KERNEL); if (!codec->reg_def_copy) { ret = -ENOMEM; - goto fail; + goto fail_codec_name; } } } @@ -4086,18 +4085,22 @@ int snd_soc_register_codec(struct device *dev, mutex_unlock(&client_mutex); /* register any DAIs */ - if (num_dai) { - ret = snd_soc_register_dais(dev, dai_drv, num_dai); - if (ret < 0) - dev_err(codec->dev, "ASoC: Failed to regster" - " DAIs: %d\n", ret); + ret = snd_soc_register_dais(dev, dai_drv, num_dai); + if (ret < 0) { + dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto fail_codec_name; } dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name); return 0; -fail: +fail_codec_name: + mutex_lock(&client_mutex); + list_del(&codec->list); + mutex_unlock(&client_mutex); + kfree(codec->name); +fail_codec: kfree(codec); return ret; } @@ -4111,7 +4114,6 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec); void snd_soc_unregister_codec(struct device *dev) { struct snd_soc_codec *codec; - int i; list_for_each_entry(codec, &codec_list, list) { if (dev == codec->dev) @@ -4120,9 +4122,7 @@ void snd_soc_unregister_codec(struct device *dev) return; found: - if (codec->num_dai) - for (i = 0; i < codec->num_dai; i++) - snd_soc_unregister_dai(dev); + snd_soc_unregister_dais(dev, codec->num_dai); mutex_lock(&client_mutex); list_del(&codec->list); @@ -4137,6 +4137,92 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); + +/** + * snd_soc_register_component - Register a component with the ASoC core + * + */ +int snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + struct snd_soc_component *cmpnt; + int ret; + + dev_dbg(dev, "component register %s\n", dev_name(dev)); + + cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); + if (!cmpnt) { + dev_err(dev, "ASoC: Failed to allocate memory\n"); + return -ENOMEM; + } + + cmpnt->name = fmt_single_name(dev, &cmpnt->id); + if (!cmpnt->name) { + dev_err(dev, "ASoC: Failed to simplifying name\n"); + return -ENOMEM; + } + + cmpnt->dev = dev; + cmpnt->driver = cmpnt_drv; + cmpnt->num_dai = num_dai; + + /* + * snd_soc_register_dai() uses fmt_single_name(), and + * snd_soc_register_dais() uses fmt_multiple_name() + * for dai->name which is used for name based matching + */ + if (1 == num_dai) + ret = snd_soc_register_dai(dev, dai_drv); + else + ret = snd_soc_register_dais(dev, dai_drv, num_dai); + if (ret < 0) { + dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto error_component_name; + } + + mutex_lock(&client_mutex); + list_add(&cmpnt->list, &component_list); + mutex_unlock(&client_mutex); + + dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); + + return ret; + +error_component_name: + kfree(cmpnt->name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_register_component); + +/** + * snd_soc_unregister_component - Unregister a component from the ASoC core + * + */ +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) + goto found; + } + return; + +found: + snd_soc_unregister_dais(dev, cmpnt->num_dai); + + mutex_lock(&client_mutex); + list_del(&cmpnt->list); + mutex_unlock(&client_mutex); + + dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); + kfree(cmpnt->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_component); + /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname) @@ -4197,7 +4283,6 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, dev_err(card->dev, "ASoC: Property '%s' index %d could not be read: %d\n", propname, 2 * i, ret); - kfree(routes); return -EINVAL; } ret = of_property_read_string_index(np, propname, @@ -4206,7 +4291,6 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, dev_err(card->dev, "ASoC: Property '%s' index %d could not be read: %d\n", propname, (2 * i) + 1, ret); - kfree(routes); return -EINVAL; } } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1d6a9b3ceb27..21779a6a781a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -504,17 +504,27 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, return 0; } -/* create new dapm mixer control */ -static int dapm_new_mixer(struct snd_soc_dapm_widget *w) +/* + * Determine if a kcontrol is shared. If it is, look it up. If it isn't, + * create it. Either way, add the widget into the control's widget list + */ +static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, + int kci, struct snd_soc_dapm_path *path) { struct snd_soc_dapm_context *dapm = w->dapm; - int i, ret = 0; - size_t name_len, prefix_len; - struct snd_soc_dapm_path *path; struct snd_card *card = dapm->card->snd_card; const char *prefix; + size_t prefix_len; + int shared; + struct snd_kcontrol *kcontrol; struct snd_soc_dapm_widget_list *wlist; + int wlistentries; size_t wlistsize; + bool wname_in_long_name, kcname_in_long_name; + size_t name_len; + char *long_name; + const char *name; + int ret; if (dapm->codec) prefix = dapm->codec->name_prefix; @@ -526,103 +536,141 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) else prefix_len = 0; - /* add kcontrol */ - for (i = 0; i < w->num_kcontrols; i++) { + shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci], + &kcontrol); - /* match name */ - list_for_each_entry(path, &w->sources, list_sink) { + if (kcontrol) { + wlist = kcontrol->private_data; + wlistentries = wlist->num_widgets + 1; + } else { + wlist = NULL; + wlistentries = 1; + } - /* mixer/mux paths name must match control name */ - if (path->name != (char *)w->kcontrol_news[i].name) - continue; + wlistsize = sizeof(struct snd_soc_dapm_widget_list) + + wlistentries * sizeof(struct snd_soc_dapm_widget *); + wlist = krealloc(wlist, wlistsize, GFP_KERNEL); + if (wlist == NULL) { + dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n", + w->name); + return -ENOMEM; + } + wlist->num_widgets = wlistentries; + wlist->widgets[wlistentries - 1] = w; - if (w->kcontrols[i]) { - path->kcontrol = w->kcontrols[i]; - continue; + if (!kcontrol) { + if (shared) { + wname_in_long_name = false; + kcname_in_long_name = true; + } else { + switch (w->id) { + case snd_soc_dapm_switch: + case snd_soc_dapm_mixer: + wname_in_long_name = true; + kcname_in_long_name = true; + break; + case snd_soc_dapm_mixer_named_ctl: + wname_in_long_name = false; + kcname_in_long_name = true; + break; + case snd_soc_dapm_mux: + case snd_soc_dapm_virt_mux: + case snd_soc_dapm_value_mux: + wname_in_long_name = true; + kcname_in_long_name = false; + break; + default: + kfree(wlist); + return -EINVAL; } + } + + if (wname_in_long_name && kcname_in_long_name) { + name_len = strlen(w->name) - prefix_len + 1 + + strlen(w->kcontrol_news[kci].name) + 1; - wlistsize = sizeof(struct snd_soc_dapm_widget_list) + - sizeof(struct snd_soc_dapm_widget *), - wlist = kzalloc(wlistsize, GFP_KERNEL); - if (wlist == NULL) { - dev_err(dapm->dev, - "ASoC: can't allocate widget list for %s\n", - w->name); + long_name = kmalloc(name_len, GFP_KERNEL); + if (long_name == NULL) { + kfree(wlist); return -ENOMEM; } - wlist->num_widgets = 1; - wlist->widgets[0] = w; - - /* add dapm control with long name. - * for dapm_mixer this is the concatenation of the - * mixer and kcontrol name. - * for dapm_mixer_named_ctl this is simply the - * kcontrol name. + + /* + * The control will get a prefix from the control + * creation process but we're also using the same + * prefix for widgets so cut the prefix off the + * front of the widget name. */ - name_len = strlen(w->kcontrol_news[i].name) + 1; - if (w->id != snd_soc_dapm_mixer_named_ctl) - name_len += 1 + strlen(w->name); + snprintf(long_name, name_len, "%s %s", + w->name + prefix_len, + w->kcontrol_news[kci].name); + long_name[name_len - 1] = '\0'; + + name = long_name; + } else if (wname_in_long_name) { + long_name = NULL; + name = w->name + prefix_len; + } else { + long_name = NULL; + name = w->kcontrol_news[kci].name; + } - path->long_name = kmalloc(name_len, GFP_KERNEL); + kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name, + prefix); + ret = snd_ctl_add(card, kcontrol); + if (ret < 0) { + dev_err(dapm->dev, + "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", + w->name, name, ret); + kfree(wlist); + kfree(long_name); + return ret; + } - if (path->long_name == NULL) { - kfree(wlist); - return -ENOMEM; - } + path->long_name = long_name; + } - switch (w->id) { - default: - /* The control will get a prefix from - * the control creation process but - * we're also using the same prefix - * for widgets so cut the prefix off - * the front of the widget name. - */ - snprintf((char *)path->long_name, name_len, - "%s %s", w->name + prefix_len, - w->kcontrol_news[i].name); - break; - case snd_soc_dapm_mixer_named_ctl: - snprintf((char *)path->long_name, name_len, - "%s", w->kcontrol_news[i].name); - break; - } + kcontrol->private_data = wlist; + w->kcontrols[kci] = kcontrol; + path->kcontrol = kcontrol; - ((char *)path->long_name)[name_len - 1] = '\0'; + return 0; +} - path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], - wlist, path->long_name, - prefix); - ret = snd_ctl_add(card, path->kcontrol); - if (ret < 0) { - dev_err(dapm->dev, "ASoC: failed to add widget" - " %s dapm kcontrol %s: %d\n", - w->name, path->long_name, ret); - kfree(wlist); - kfree(path->long_name); - path->long_name = NULL; - return ret; +/* create new dapm mixer control */ +static int dapm_new_mixer(struct snd_soc_dapm_widget *w) +{ + int i, ret; + struct snd_soc_dapm_path *path; + + /* add kcontrol */ + for (i = 0; i < w->num_kcontrols; i++) { + /* match name */ + list_for_each_entry(path, &w->sources, list_sink) { + /* mixer/mux paths name must match control name */ + if (path->name != (char *)w->kcontrol_news[i].name) + continue; + + if (w->kcontrols[i]) { + path->kcontrol = w->kcontrols[i]; + continue; } - w->kcontrols[i] = path->kcontrol; + + ret = dapm_create_or_share_mixmux_kcontrol(w, i, path); + if (ret < 0) + return ret; } } - return ret; + + return 0; } /* create new dapm mux control */ static int dapm_new_mux(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_dapm_path *path = NULL; - struct snd_kcontrol *kcontrol; - struct snd_card *card = dapm->card->snd_card; - const char *prefix; - size_t prefix_len; + struct snd_soc_dapm_path *path; int ret; - struct snd_soc_dapm_widget_list *wlist; - int shared, wlistentries; - size_t wlistsize; - const char *name; if (w->num_kcontrols != 1) { dev_err(dapm->dev, @@ -631,65 +679,19 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) return -EINVAL; } - shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0], - &kcontrol); - if (kcontrol) { - wlist = kcontrol->private_data; - wlistentries = wlist->num_widgets + 1; - } else { - wlist = NULL; - wlistentries = 1; - } - wlistsize = sizeof(struct snd_soc_dapm_widget_list) + - wlistentries * sizeof(struct snd_soc_dapm_widget *), - wlist = krealloc(wlist, wlistsize, GFP_KERNEL); - if (wlist == NULL) { - dev_err(dapm->dev, - "ASoC: can't allocate widget list for %s\n", w->name); - return -ENOMEM; - } - wlist->num_widgets = wlistentries; - wlist->widgets[wlistentries - 1] = w; - - if (!kcontrol) { - if (dapm->codec) - prefix = dapm->codec->name_prefix; - else - prefix = NULL; - - if (shared) { - name = w->kcontrol_news[0].name; - prefix_len = 0; - } else { - name = w->name; - if (prefix) - prefix_len = strlen(prefix) + 1; - else - prefix_len = 0; - } - - /* - * The control will get a prefix from the control creation - * process but we're also using the same prefix for widgets so - * cut the prefix off the front of the widget name. - */ - kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist, - name + prefix_len, prefix); - ret = snd_ctl_add(card, kcontrol); - if (ret < 0) { - dev_err(dapm->dev, "ASoC: failed to add kcontrol %s: %d\n", - w->name, ret); - kfree(wlist); - return ret; - } + path = list_first_entry(&w->sources, struct snd_soc_dapm_path, + list_sink); + if (!path) { + dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name); + return -EINVAL; } - kcontrol->private_data = wlist; - - w->kcontrols[0] = kcontrol; + ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path); + if (ret < 0) + return ret; list_for_each_entry(path, &w->sources, list_sink) - path->kcontrol = kcontrol; + path->kcontrol = w->kcontrols[0]; return 0; } @@ -705,14 +707,33 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) } /* reset 'walked' bit for each dapm path */ -static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm) +static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm, + struct list_head *sink) { struct snd_soc_dapm_path *p; - list_for_each_entry(p, &dapm->card->paths, list) - p->walked = 0; + list_for_each_entry(p, sink, list_source) { + if (p->walked) { + p->walked = 0; + dapm_clear_walk_output(dapm, &p->sink->sinks); + } + } +} + +static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm, + struct list_head *source) +{ + struct snd_soc_dapm_path *p; + + list_for_each_entry(p, source, list_sink) { + if (p->walked) { + p->walked = 0; + dapm_clear_walk_input(dapm, &p->source->sources); + } + } } + /* We implement power down on suspend by checking the power state of * the ALSA card - when we are suspending the ALSA state for the card * is set to D3. @@ -831,6 +852,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, if (path->weak) continue; + if (path->walking) + return 1; + if (path->walked) continue; @@ -838,6 +862,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, if (path->sink && path->connect) { path->walked = 1; + path->walking = 1; /* do we need to add this widget to the list ? */ if (list) { @@ -847,11 +872,14 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, dev_err(widget->dapm->dev, "ASoC: could not add widget %s\n", widget->name); + path->walking = 0; return con; } } con += is_connected_output_ep(path->sink, list); + + path->walking = 0; } } @@ -931,6 +959,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, if (path->weak) continue; + if (path->walking) + return 1; + if (path->walked) continue; @@ -938,6 +969,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, if (path->source && path->connect) { path->walked = 1; + path->walking = 1; /* do we need to add this widget to the list ? */ if (list) { @@ -947,11 +979,14 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, dev_err(widget->dapm->dev, "ASoC: could not add widget %s\n", widget->name); + path->walking = 0; return con; } } con += is_connected_input_ep(path->source, list); + + path->walking = 0; } } @@ -981,13 +1016,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); dapm_reset(card); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { paths = is_connected_output_ep(dai->playback_widget, list); - else + dapm_clear_walk_output(&card->dapm, + &dai->playback_widget->sinks); + } else { paths = is_connected_input_ep(dai->capture_widget, list); + dapm_clear_walk_input(&card->dapm, + &dai->capture_widget->sources); + } trace_snd_soc_dapm_connected(paths, stream); - dapm_clear_walk(&card->dapm); mutex_unlock(&card->dapm_mutex); return paths; @@ -1090,9 +1129,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) DAPM_UPDATE_STAT(w, power_checks); in = is_connected_input_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_input(w->dapm, &w->sources); out = is_connected_output_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_output(w->dapm, &w->sinks); return out != 0 && in != 0; } @@ -1115,7 +1154,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) if (w->active) { in = is_connected_input_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_input(w->dapm, &w->sources); return in != 0; } else { return dapm_generic_check_power(w); @@ -1131,7 +1170,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) if (w->active) { out = is_connected_output_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_output(w->dapm, &w->sinks); return out != 0; } else { return dapm_generic_check_power(w); @@ -1163,8 +1202,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) return 1; } - dapm_clear_walk(w->dapm); - return 0; } @@ -1745,9 +1782,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, return -ENOMEM; in = is_connected_input_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_input(w->dapm, &w->sources); out = is_connected_output_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_output(w->dapm, &w->sinks); ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", w->name, w->power ? "On" : "Off", @@ -3123,7 +3160,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, break; } - dapm->n_widgets++; w->dapm = dapm; w->codec = dapm->codec; w->platform = dapm->platform; diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 29183ef2b93d..8ca9ecc5ac57 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -158,10 +158,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, return -EINVAL; } - if (IS_ERR(codec->control_data)) - return PTR_ERR(codec->control_data); - - return 0; + return PTR_RET(codec->control_data); } EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); #else diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index c7c4b20395bb..14d57e89bcba 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -170,6 +170,10 @@ struct snd_soc_dai_driver spdif_in_dai = { .ops = &spdif_in_dai_ops, }; +static const struct snd_soc_component_driver spdif_in_component = { + .name = "spdif-in", +}; + static irqreturn_t spdif_in_irq(int irq, void *arg) { struct spdif_in_dev *host = (struct spdif_in_dev *)arg; @@ -258,7 +262,8 @@ static int spdif_in_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_register_dai(&pdev->dev, &spdif_in_dai); + ret = snd_soc_register_component(&pdev->dev, &spdif_in_component, + &spdif_in_dai, 1); if (ret != 0) { clk_put(host->clk); return ret; @@ -271,7 +276,7 @@ static int spdif_in_remove(struct platform_device *pdev) { struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); dev_set_drvdata(&pdev->dev, NULL); clk_put(host->clk); diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c index 5eac4cda2fd7..1e3c3dda3598 100644 --- a/sound/soc/spear/spdif_out.c +++ b/sound/soc/spear/spdif_out.c @@ -270,6 +270,10 @@ static struct snd_soc_dai_driver spdif_out_dai = { .ops = &spdif_out_dai_ops, }; +static const struct snd_soc_component_driver spdif_out_component = { + .name = "spdif-out", +}; + static int spdif_out_probe(struct platform_device *pdev) { struct spdif_out_dev *host; @@ -314,7 +318,8 @@ static int spdif_out_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, host); - ret = snd_soc_register_dai(&pdev->dev, &spdif_out_dai); + ret = snd_soc_register_component(&pdev->dev, &spdif_out_component, + &spdif_out_dai, 1); if (ret != 0) { clk_put(host->clk); return ret; @@ -327,7 +332,7 @@ static int spdif_out_remove(struct platform_device *pdev) { struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); dev_set_drvdata(&pdev->dev, NULL); clk_put(host->clk); diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index db75d72c4805..23fb09addd21 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -135,9 +135,9 @@ static void spear_pcm_free(struct snd_pcm *pcm) static u64 spear_pcm_dmamask = DMA_BIT_MASK(32); -static int spear_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) +static int spear_pcm_new(struct snd_soc_pcm_runtime *rtd) { + struct snd_card *card = rtd->card->snd_card; int ret; if (!card->dev->dma_mask) @@ -145,16 +145,16 @@ static int spear_pcm_new(struct snd_card *card, if (!card->dev->coherent_dma_mask) card->dev->coherent_dma_mask = DMA_BIT_MASK(32); - if (dai->driver->playback.channels_min) { - ret = spear_pcm_preallocate_dma_buffer(pcm, + if (rtd->cpu_dai->driver->playback.channels_min) { + ret = spear_pcm_preallocate_dma_buffer(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, spear_pcm_hardware.buffer_bytes_max); if (ret) return ret; } - if (dai->driver->capture.channels_min) { - ret = spear_pcm_preallocate_dma_buffer(pcm, + if (rtd->cpu_dai->driver->capture.channels_min) { + ret = spear_pcm_preallocate_dma_buffer(rtd->pcm, SNDRV_PCM_STREAM_CAPTURE, spear_pcm_hardware.buffer_bytes_max); if (ret) diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 2d7b8c2719ce..2f70ea7f6618 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -249,6 +249,10 @@ static struct snd_soc_dai_driver tegra20_ac97_dai = { .ops = &tegra20_ac97_dai_ops, }; +static const struct snd_soc_component_driver tegra20_ac97_component = { + .name = DRV_NAME, +}; + static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -399,7 +403,8 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) ac97->capture_dma_data.maxburst = 4; ac97->capture_dma_data.slave_id = of_dma[0]; - ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1); + ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component, + &tegra20_ac97_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -409,7 +414,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev); @@ -435,8 +440,8 @@ err_asoc_utils_fini: tegra_asoc_utils_fini(&ac97->util_data); err_unregister_pcm: tegra_pcm_platform_unregister(&pdev->dev); -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_clk_put: clk_put(ac97->clk_ac97); err: @@ -448,7 +453,7 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev) struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); tegra_asoc_utils_fini(&ac97->util_data); diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index e6651e0eaeed..52af7f6fb37f 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -277,6 +277,10 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { .symmetric_rates = 1, }; +static const struct snd_soc_component_driver tegra20_i2s_component = { + .name = DRV_NAME, +}; + static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -420,7 +424,8 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = snd_soc_register_dai(&pdev->dev, &i2s->dai); + ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component, + &i2s->dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -430,13 +435,13 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_i2s_runtime_suspend(&pdev->dev); @@ -457,7 +462,7 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev) tegra20_i2s_runtime_suspend(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(i2s->clk_i2s); diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index b7b4743cc94d..5eaa12cdc6eb 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -183,6 +183,10 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = { .ops = &tegra20_spdif_dai_ops, }; +static const struct snd_soc_component_driver tegra20_spdif_component = { + .name = DRV_NAME, +}; + static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -330,7 +334,8 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai); + ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component, + &tegra20_spdif_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -340,13 +345,13 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_spdif_runtime_suspend(&pdev->dev); @@ -367,7 +372,7 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev) tegra20_spdif_runtime_suspend(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(spdif->clk_spdif_out); diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 857ec21e3c7d..31d092d83c71 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -337,6 +337,10 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { .symmetric_rates = 1, }; +static const struct snd_soc_component_driver tegra30_i2s_component = { + .name = DRV_NAME, +}; + static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -465,7 +469,8 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = snd_soc_register_dai(&pdev->dev, &i2s->dai); + ret = snd_soc_register_component(&pdev->dev, &tegra30_i2s_component, + &i2s->dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -475,13 +480,13 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra30_i2s_runtime_suspend(&pdev->dev); @@ -502,7 +507,7 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev) tegra30_i2s_runtime_suspend(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(i2s->clk_i2s); diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index f91d08bc1753..6d1c70c3d753 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -43,8 +43,6 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_INTERLEAVED, .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels_min = 2, @@ -111,26 +109,6 @@ static int tegra_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - return snd_dmaengine_pcm_trigger(substream, - SNDRV_PCM_TRIGGER_START); - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - return snd_dmaengine_pcm_trigger(substream, - SNDRV_PCM_TRIGGER_STOP); - default: - return -EINVAL; - } - return 0; -} - static int tegra_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -148,7 +126,7 @@ static struct snd_pcm_ops tegra_pcm_ops = { .ioctl = snd_pcm_lib_ioctl, .hw_params = tegra_pcm_hw_params, .hw_free = tegra_pcm_hw_free, - .trigger = tegra_pcm_trigger, + .trigger = snd_dmaengine_pcm_trigger, .pointer = snd_dmaengine_pcm_pointer, .mmap = tegra_pcm_mmap, }; diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c index 68d42403d9b5..6839f88167d0 100644 --- a/sound/soc/tegra/tegra_wm9712.c +++ b/sound/soc/tegra/tegra_wm9712.c @@ -55,7 +55,7 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link tegra_wm9712_dai = { .name = "AC97 HiFi", .stream_name = "AC97 HiFi", - .cpu_dai_name = "tegra-ac97-pcm", + .cpu_dai_name = "tegra20-ac97", .codec_dai_name = "wm9712-hifi", .codec_name = "wm9712-codec", .init = tegra_wm9712_init, diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index 16ab69635e2e..8a2840304d28 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c @@ -170,6 +170,10 @@ static struct snd_soc_dai_driver txx9aclc_ac97_dai = { }, }; +static const struct snd_soc_component_driver txx9aclc_ac97_component = { + .name = "txx9aclc-ac97", +}; + static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) { struct txx9aclc_plat_drvdata *drvdata; @@ -205,12 +209,13 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) if (err < 0) return err; - return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai); + return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component, + &txx9aclc_ac97_dai, 1); } static int txx9aclc_ac97_dev_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 94a3e5705aaa..f1e8a5ecb00b 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -768,6 +768,11 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = { }, }; +static const struct snd_soc_component_driver ux500_msp_component = { + .name = "ux500-msp", +}; + + static int ux500_msp_drv_probe(struct platform_device *pdev) { struct ux500_msp_i2s_drvdata *drvdata; @@ -825,8 +830,8 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, drvdata); - ret = snd_soc_register_dai(&pdev->dev, - &ux500_msp_dai_drv[drvdata->msp->id]); + ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component, + &ux500_msp_dai_drv[drvdata->msp->id], 1); if (ret < 0) { dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n", __func__, drvdata->msp->id); @@ -844,7 +849,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) return 0; err_reg_plat: - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); + snd_soc_unregister_component(&pdev->dev); err_init_msp: clk_put(drvdata->clk); err_clk: @@ -861,7 +866,7 @@ static int ux500_msp_drv_remove(struct platform_device *pdev) ux500_pcm_unregister_platform(pdev); - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); + snd_soc_unregister_component(&pdev->dev); devm_regulator_put(drvdata->reg_vape); prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s"); diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 5e634a2eb282..9e2703a25156 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -253,7 +253,7 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, { struct usb_device *dev = chip->dev; unsigned char data[4]; - int err, crate; + int err, cur_rate, prev_rate; int clock = snd_usb_clock_find_source(chip, fmt->clock); if (clock < 0) @@ -266,6 +266,19 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, return -ENXIO; } + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, + snd_usb_ctrl_intf(chip) | (clock << 8), + data, sizeof(data)); + if (err < 0) { + snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", + dev->devnum, iface, fmt->altsetting); + prev_rate = 0; + } else { + prev_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + } + data[0] = rate; data[1] = rate >> 8; data[2] = rate >> 16; @@ -280,19 +293,31 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, return err; } - if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - UAC2_CS_CONTROL_SAM_FREQ << 8, - snd_usb_ctrl_intf(chip) | (clock << 8), - data, sizeof(data))) < 0) { + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, + snd_usb_ctrl_intf(chip) | (clock << 8), + data, sizeof(data)); + if (err < 0) { snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", dev->devnum, iface, fmt->altsetting); - return err; + cur_rate = 0; + } else { + cur_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); } - crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); - if (crate != rate) - snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); + if (cur_rate != rate) { + snd_printd(KERN_WARNING + "current rate %d is different from the runtime rate %d\n", + cur_rate, rate); + } + + /* Some devices doesn't respond to sample rate changes while the + * interface is active. */ + if (rate != prev_rate) { + usb_set_interface(dev, iface, 0); + usb_set_interface(dev, iface, fmt->altsetting); + } return 0; } |