summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/atmel/ac97c.c9
-rw-r--r--sound/core/control.c2
-rw-r--r--sound/core/seq/Kconfig4
-rw-r--r--sound/core/seq/seq_clientmgr.c13
-rw-r--r--sound/core/seq/seq_queue.c14
-rw-r--r--sound/core/seq/seq_queue.h2
-rw-r--r--sound/firewire/iso-resources.c7
-rw-r--r--sound/firewire/motu/motu.c1
-rw-r--r--sound/pci/emu10k1/emufx.c14
-rw-r--r--sound/pci/fm801.c4
-rw-r--r--sound/pci/hda/patch_conexant.c2
-rw-r--r--sound/pci/hda/patch_hdmi.c27
-rw-r--r--sound/pci/hda/patch_realtek.c146
-rw-r--r--sound/soc/atmel/atmel-classd.c1
-rw-r--r--sound/soc/atmel/atmel-pdmic.c1
-rw-r--r--sound/soc/au1x/db1200.c2
-rw-r--r--sound/soc/au1x/dbdma2.c2
-rw-r--r--sound/soc/au1x/dma.c2
-rw-r--r--sound/soc/au1x/psc-ac97.c2
-rw-r--r--sound/soc/au1x/psc-i2s.c2
-rw-r--r--sound/soc/bcm/cygnus-ssp.c237
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c2
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c2
-rw-r--r--sound/soc/blackfin/bf6xx-i2s.c2
-rw-r--r--sound/soc/blackfin/bf6xx-sport.c38
-rw-r--r--sound/soc/cirrus/edb93xx.c2
-rw-r--r--sound/soc/cirrus/snappercl15.c2
-rw-r--r--sound/soc/codecs/88pm860x-codec.c2
-rw-r--r--sound/soc/codecs/Kconfig15
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/ab8500-codec.c2
-rw-r--r--sound/soc/codecs/ac97.c2
-rw-r--r--sound/soc/codecs/ad1836.c2
-rw-r--r--sound/soc/codecs/ad193x.c2
-rw-r--r--sound/soc/codecs/ad1980.c2
-rw-r--r--sound/soc/codecs/ad73311.c2
-rw-r--r--sound/soc/codecs/adau1373.c2
-rw-r--r--sound/soc/codecs/adau1701.c2
-rw-r--r--sound/soc/codecs/adau1977.c8
-rw-r--r--sound/soc/codecs/adav80x.c2
-rw-r--r--sound/soc/codecs/ads117x.c2
-rw-r--r--sound/soc/codecs/ak4104.c2
-rw-r--r--sound/soc/codecs/ak4535.c2
-rw-r--r--sound/soc/codecs/ak4554.c2
-rw-r--r--sound/soc/codecs/ak4613.c2
-rw-r--r--sound/soc/codecs/ak4641.c2
-rw-r--r--sound/soc/codecs/ak4642.c2
-rw-r--r--sound/soc/codecs/ak4671.c2
-rw-r--r--sound/soc/codecs/ak5386.c2
-rw-r--r--sound/soc/codecs/alc5623.c2
-rw-r--r--sound/soc/codecs/arizona.c4
-rw-r--r--sound/soc/codecs/bt-sco.c2
-rw-r--r--sound/soc/codecs/cq93vc.c2
-rw-r--r--sound/soc/codecs/cs35l33.c14
-rw-r--r--sound/soc/codecs/cs35l34.c5
-rw-r--r--sound/soc/codecs/cs35l35.c2
-rw-r--r--sound/soc/codecs/cs4271.c2
-rw-r--r--sound/soc/codecs/cs42l42.c11
-rw-r--r--sound/soc/codecs/cs42l51.c2
-rw-r--r--sound/soc/codecs/cs43130.c2690
-rw-r--r--sound/soc/codecs/cs43130.h546
-rw-r--r--sound/soc/codecs/cs4349.c2
-rw-r--r--sound/soc/codecs/cs47l24.c6
-rw-r--r--sound/soc/codecs/cs53l30.c17
-rw-r--r--sound/soc/codecs/cx20442.c2
-rw-r--r--sound/soc/codecs/da7210.c2
-rw-r--r--sound/soc/codecs/da7213.c2
-rw-r--r--sound/soc/codecs/da7218.c2
-rw-r--r--sound/soc/codecs/da7219.c2
-rw-r--r--sound/soc/codecs/da732x.c2
-rw-r--r--sound/soc/codecs/da9055.c2
-rw-r--r--sound/soc/codecs/dmic.c54
-rw-r--r--sound/soc/codecs/es7134.c2
-rw-r--r--sound/soc/codecs/es8316.c4
-rw-r--r--sound/soc/codecs/es8328.c2
-rw-r--r--sound/soc/codecs/hdac_hdmi.c43
-rw-r--r--sound/soc/codecs/hdmi-codec.c47
-rw-r--r--sound/soc/codecs/ics43432.c2
-rw-r--r--sound/soc/codecs/inno_rk3036.c4
-rw-r--r--sound/soc/codecs/isabelle.c2
-rw-r--r--sound/soc/codecs/jz4740.c2
-rw-r--r--sound/soc/codecs/lm4857.c2
-rw-r--r--sound/soc/codecs/lm49453.c2
-rw-r--r--sound/soc/codecs/max9768.c2
-rw-r--r--sound/soc/codecs/max98088.c2
-rw-r--r--sound/soc/codecs/max98090.c2
-rw-r--r--sound/soc/codecs/max98095.c2
-rw-r--r--sound/soc/codecs/max98357a.c2
-rw-r--r--sound/soc/codecs/max98371.c14
-rw-r--r--sound/soc/codecs/max9850.c2
-rw-r--r--sound/soc/codecs/max9860.c2
-rw-r--r--sound/soc/codecs/max9867.c4
-rw-r--r--sound/soc/codecs/max98926.c8
-rw-r--r--sound/soc/codecs/max98927.c87
-rw-r--r--sound/soc/codecs/mc13783.c2
-rw-r--r--sound/soc/codecs/ml26124.c2
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c417
-rw-r--r--sound/soc/codecs/msm8916-wcd-digital.c39
-rw-r--r--sound/soc/codecs/nau8540.c2
-rw-r--r--sound/soc/codecs/nau8810.c2
-rw-r--r--sound/soc/codecs/nau8824.c2
-rw-r--r--sound/soc/codecs/nau8825.c28
-rw-r--r--sound/soc/codecs/pcm1681.c2
-rw-r--r--sound/soc/codecs/pcm179x.c2
-rw-r--r--sound/soc/codecs/pcm3008.c2
-rw-r--r--sound/soc/codecs/pcm512x.c2
-rw-r--r--sound/soc/codecs/rt274.c1229
-rw-r--r--sound/soc/codecs/rt274.h217
-rw-r--r--sound/soc/codecs/rt286.c2
-rw-r--r--sound/soc/codecs/rt298.c2
-rw-r--r--sound/soc/codecs/rt5514-spi.c146
-rw-r--r--sound/soc/codecs/rt5514-spi.h7
-rw-r--r--sound/soc/codecs/rt5514.c174
-rw-r--r--sound/soc/codecs/rt5514.h22
-rw-r--r--sound/soc/codecs/rt5616.c4
-rw-r--r--sound/soc/codecs/rt5631.c2
-rw-r--r--sound/soc/codecs/rt5640.c2
-rw-r--r--sound/soc/codecs/rt5645.c45
-rw-r--r--sound/soc/codecs/rt5651.c2
-rw-r--r--sound/soc/codecs/rt5659.c4
-rw-r--r--sound/soc/codecs/rt5660.c2
-rw-r--r--sound/soc/codecs/rt5663.c282
-rw-r--r--sound/soc/codecs/rt5663.h2
-rw-r--r--sound/soc/codecs/rt5665.c59
-rw-r--r--sound/soc/codecs/rt5665.h25
-rw-r--r--sound/soc/codecs/rt5670.c64
-rw-r--r--sound/soc/codecs/rt5677.c81
-rw-r--r--sound/soc/codecs/rt5677.h30
-rw-r--r--sound/soc/codecs/sgtl5000.c6
-rw-r--r--sound/soc/codecs/si476x.c2
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c12
-rw-r--r--sound/soc/codecs/sn95031.c2
-rw-r--r--sound/soc/codecs/spdif_receiver.c2
-rw-r--r--sound/soc/codecs/spdif_transmitter.c2
-rw-r--r--sound/soc/codecs/ssm2518.c2
-rw-r--r--sound/soc/codecs/ssm2602.c2
-rw-r--r--sound/soc/codecs/ssm4567.c2
-rw-r--r--sound/soc/codecs/sta32x.c3
-rw-r--r--sound/soc/codecs/stac9766.c2
-rw-r--r--sound/soc/codecs/tas2552.c13
-rw-r--r--sound/soc/codecs/tas5086.c2
-rw-r--r--sound/soc/codecs/tas5720.c4
-rw-r--r--sound/soc/codecs/tlv320aic23.c2
-rw-r--r--sound/soc/codecs/tlv320aic26.c2
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c2
-rw-r--r--sound/soc/codecs/tlv320aic32x4-i2c.c2
-rw-r--r--sound/soc/codecs/tlv320aic32x4-spi.c2
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c208
-rw-r--r--sound/soc/codecs/tlv320aic32x4.h3
-rw-r--r--sound/soc/codecs/tlv320aic3x.c47
-rw-r--r--sound/soc/codecs/tlv320aic3x.h8
-rw-r--r--sound/soc/codecs/tlv320dac33.c2
-rw-r--r--sound/soc/codecs/twl4030.c2
-rw-r--r--sound/soc/codecs/twl6040.c6
-rw-r--r--sound/soc/codecs/uda134x.c2
-rw-r--r--sound/soc/codecs/uda1380.c2
-rw-r--r--sound/soc/codecs/wl1273.c2
-rw-r--r--sound/soc/codecs/wm5102.c4
-rw-r--r--sound/soc/codecs/wm5110.c4
-rw-r--r--sound/soc/codecs/zx_aud96p22.c4
-rw-r--r--sound/soc/davinci/davinci-mcasp.c6
-rw-r--r--sound/soc/davinci/davinci-vcif.c5
-rw-r--r--sound/soc/dwc/dwc-i2s.c6
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c2
-rw-r--r--sound/soc/fsl/fsl_asrc.c2
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c6
-rw-r--r--sound/soc/fsl/fsl_dma.c11
-rw-r--r--sound/soc/fsl/fsl_esai.c2
-rw-r--r--sound/soc/fsl/fsl_spdif.c2
-rw-r--r--sound/soc/fsl/fsl_ssi.c4
-rw-r--r--sound/soc/fsl/imx-audmux.c16
-rw-r--r--sound/soc/fsl/imx-es8328.c3
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c6
-rw-r--r--sound/soc/fsl/imx-ssi.c4
-rw-r--r--sound/soc/fsl/mpc5200_dma.c4
-rw-r--r--sound/soc/generic/audio-graph-card.c13
-rw-r--r--sound/soc/generic/audio-graph-scu-card.c18
-rw-r--r--sound/soc/generic/simple-card-utils.c19
-rw-r--r--sound/soc/generic/simple-card.c10
-rw-r--r--sound/soc/generic/simple-scu-card.c5
-rw-r--r--sound/soc/hisilicon/hi6210-i2s.c2
-rw-r--r--sound/soc/img/img-i2s-in.c2
-rw-r--r--sound/soc/img/img-i2s-out.c2
-rw-r--r--sound/soc/img/img-parallel-out.c2
-rw-r--r--sound/soc/img/img-spdif-in.c2
-rw-r--r--sound/soc/img/img-spdif-out.c2
-rw-r--r--sound/soc/intel/Kconfig3
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c10
-rw-r--r--sound/soc/intel/atom/sst/sst_drv_interface.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_pci.c2
-rw-r--r--sound/soc/intel/baytrail/sst-baytrail-pcm.c4
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c86
-rw-r--r--sound/soc/intel/boards/byt-max98090.c12
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c10
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c310
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c94
-rw-r--r--sound/soc/intel/boards/mfld_machine.c4
-rw-r--r--sound/soc/intel/haswell/sst-haswell-pcm.c2
-rw-r--r--sound/soc/intel/skylake/Makefile5
-rw-r--r--sound/soc/intel/skylake/bxt-sst.c14
-rw-r--r--sound/soc/intel/skylake/cnl-sst-dsp.c274
-rw-r--r--sound/soc/intel/skylake/cnl-sst-dsp.h112
-rw-r--r--sound/soc/intel/skylake/cnl-sst.c497
-rw-r--r--sound/soc/intel/skylake/skl-messages.c167
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c82
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h12
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst.c12
-rw-r--r--sound/soc/intel/skylake/skl-topology.c741
-rw-r--r--sound/soc/intel/skylake/skl-topology.h83
-rw-r--r--sound/soc/intel/skylake/skl.c34
-rw-r--r--sound/soc/intel/skylake/skl.h3
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c21
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c2
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c11
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c2
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c15
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c1
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c1
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c1
-rw-r--r--sound/soc/mxs/mxs-saif.c13
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c1
-rw-r--r--sound/soc/nuc900/nuc900-pcm.c4
-rw-r--r--sound/soc/omap/ams-delta.c10
-rw-r--r--sound/soc/omap/omap-pcm.c4
-rw-r--r--sound/soc/omap/omap-twl4030.c13
-rw-r--r--sound/soc/omap/rx51.c9
-rw-r--r--sound/soc/pxa/Kconfig1
-rw-r--r--sound/soc/pxa/hx4700.c8
-rw-r--r--sound/soc/pxa/mmp-pcm.c4
-rw-r--r--sound/soc/pxa/mmp-sspa.c2
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c4
-rw-r--r--sound/soc/qcom/apq8016_sbc.c58
-rw-r--r--sound/soc/qcom/lpass-platform.c4
-rw-r--r--sound/soc/qcom/storm.c1
-rw-r--r--sound/soc/rockchip/Kconfig2
-rw-r--r--sound/soc/rockchip/rk3288_hdmi_analog.c4
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c270
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c4
-rw-r--r--sound/soc/rockchip/rockchip_pdm.c2
-rw-r--r--sound/soc/samsung/h1940_uda1380.c9
-rw-r--r--sound/soc/samsung/i2s.c45
-rw-r--r--sound/soc/samsung/idma.c4
-rw-r--r--sound/soc/samsung/jive_wm8750.c2
-rw-r--r--sound/soc/samsung/odroid.c50
-rw-r--r--sound/soc/samsung/pcm.c8
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c10
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c14
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.h7
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c15
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c11
-rw-r--r--sound/soc/samsung/s3c24xx_simtec.c2
-rw-r--r--sound/soc/samsung/s3c24xx_uda134x.c3
-rw-r--r--sound/soc/samsung/smartq_wm8987.c9
-rw-r--r--sound/soc/samsung/smdk_spdif.c2
-rw-r--r--sound/soc/samsung/spdif.c8
-rw-r--r--sound/soc/samsung/tm2_wm5110.c4
-rw-r--r--sound/soc/sh/dma-sh7760.c6
-rw-r--r--sound/soc/sh/fsi.c12
-rw-r--r--sound/soc/sh/hac.c2
-rw-r--r--sound/soc/sh/migor.c2
-rw-r--r--sound/soc/sh/rcar/adg.c11
-rw-r--r--sound/soc/sh/rcar/core.c109
-rw-r--r--sound/soc/sh/rcar/ctu.c5
-rw-r--r--sound/soc/sh/rcar/dma.c2
-rw-r--r--sound/soc/sh/rcar/dvc.c5
-rw-r--r--sound/soc/sh/rcar/gen.c4
-rw-r--r--sound/soc/sh/rcar/mix.c5
-rw-r--r--sound/soc/sh/rcar/rsnd.h1
-rw-r--r--sound/soc/sh/rcar/src.c14
-rw-r--r--sound/soc/sh/rcar/ssi.c141
-rw-r--r--sound/soc/sh/rcar/ssiu.c2
-rw-r--r--sound/soc/sh/siu_dai.c2
-rw-r--r--sound/soc/sh/siu_pcm.c2
-rw-r--r--sound/soc/soc-compress.c23
-rw-r--r--sound/soc/soc-core.c348
-rw-r--r--sound/soc/soc-jack.c76
-rw-r--r--sound/soc/soc-pcm.c79
-rw-r--r--sound/soc/soc-utils.c2
-rw-r--r--sound/soc/spear/spdif_in.c12
-rw-r--r--sound/soc/spear/spdif_out.c4
-rw-r--r--sound/soc/stm/stm32_i2s.c2
-rw-r--r--sound/soc/stm/stm32_sai.c2
-rw-r--r--sound/soc/stm/stm32_spdifrx.c2
-rw-r--r--sound/soc/sunxi/sun4i-codec.c15
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c455
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c14
-rw-r--r--sound/soc/sunxi/sun8i-codec.c4
-rw-r--r--sound/soc/tegra/Kconfig42
-rw-r--r--sound/soc/tegra/tegra30_ahub.c4
-rw-r--r--sound/soc/tegra/tegra30_i2s.c2
-rw-r--r--sound/soc/tegra/tegra_alc5632.c14
-rw-r--r--sound/soc/tegra/tegra_max98090.c19
-rw-r--r--sound/soc/tegra/tegra_rt5640.c14
-rw-r--r--sound/soc/tegra/tegra_rt5677.c19
-rw-r--r--sound/soc/tegra/tegra_sgtl5000.c1
-rw-r--r--sound/soc/tegra/tegra_wm8753.c1
-rw-r--r--sound/soc/tegra/tegra_wm8903.c7
-rw-r--r--sound/soc/tegra/tegra_wm9712.c1
-rw-r--r--sound/soc/tegra/trimslice.c1
-rw-r--r--sound/soc/txx9/txx9aclc.c4
-rw-r--r--sound/soc/ux500/mop500.c5
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c2
-rw-r--r--sound/usb/mixer.c2
-rw-r--r--sound/usb/mixer.h1
-rw-r--r--sound/usb/mixer_quirks.c6
-rw-r--r--sound/usb/quirks.c14
309 files changed, 10482 insertions, 1954 deletions
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index 9d2c9d9af688..d78405329ceb 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -783,7 +783,9 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "no peripheral clock\n");
return PTR_ERR(pclk);
}
- clk_prepare_enable(pclk);
+ retval = clk_prepare_enable(pclk);
+ if (retval)
+ goto err_prepare_enable;
retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
SNDRV_DEFAULT_STR1, THIS_MODULE,
@@ -879,6 +881,7 @@ err_request_irq:
snd_card_free(card);
err_snd_card_new:
clk_disable_unprepare(pclk);
+err_prepare_enable:
clk_put(pclk);
return retval;
}
@@ -897,9 +900,9 @@ static int atmel_ac97c_resume(struct device *pdev)
{
struct snd_card *card = dev_get_drvdata(pdev);
struct atmel_ac97c *chip = card->private_data;
+ int ret = clk_prepare_enable(chip->pclk);
- clk_prepare_enable(chip->pclk);
- return 0;
+ return ret;
}
static SIMPLE_DEV_PM_OPS(atmel_ac97c_pm, atmel_ac97c_suspend, atmel_ac97c_resume);
diff --git a/sound/core/control.c b/sound/core/control.c
index 3c6be1452e35..4525e127afd9 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1137,7 +1137,7 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
mutex_lock(&ue->card->user_ctl_lock);
change = ue->tlv_data_size != size;
if (!change)
- change = memcmp(ue->tlv_data, new_data, size);
+ change = memcmp(ue->tlv_data, new_data, size) != 0;
kfree(ue->tlv_data);
ue->tlv_data = new_data;
ue->tlv_data_size = size;
diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig
index a536760a94c2..45c1336c6597 100644
--- a/sound/core/seq/Kconfig
+++ b/sound/core/seq/Kconfig
@@ -47,10 +47,10 @@ config SND_SEQ_HRTIMER_DEFAULT
timer.
config SND_SEQ_MIDI_EVENT
- def_tristate SND_RAWMIDI
+ tristate
config SND_SEQ_MIDI
- tristate
+ def_tristate SND_RAWMIDI
select SND_SEQ_MIDI_EVENT
config SND_SEQ_MIDI_EMUL
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 272c55fe17c8..ea2d0ae85bd3 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1502,16 +1502,11 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
{
struct snd_seq_queue_info *info = arg;
- int result;
struct snd_seq_queue *q;
- result = snd_seq_queue_alloc(client->number, info->locked, info->flags);
- if (result < 0)
- return result;
-
- q = queueptr(result);
- if (q == NULL)
- return -EINVAL;
+ q = snd_seq_queue_alloc(client->number, info->locked, info->flags);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
info->queue = q->queue;
info->locked = q->locked;
@@ -1521,7 +1516,7 @@ static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
if (!info->name[0])
snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue);
strlcpy(q->name, info->name, sizeof(q->name));
- queuefree(q);
+ snd_use_lock_free(&q->use_lock);
return 0;
}
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 450c5187eecb..79e0c5604ef8 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -184,22 +184,26 @@ void __exit snd_seq_queues_delete(void)
static void queue_use(struct snd_seq_queue *queue, int client, int use);
/* allocate a new queue -
- * return queue index value or negative value for error
+ * return pointer to new queue or ERR_PTR(-errno) for error
+ * The new queue's use_lock is set to 1. It is the caller's responsibility to
+ * call snd_use_lock_free(&q->use_lock).
*/
-int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
{
struct snd_seq_queue *q;
q = queue_new(client, locked);
if (q == NULL)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
q->info_flags = info_flags;
queue_use(q, client, 1);
+ snd_use_lock_use(&q->use_lock);
if (queue_list_add(q) < 0) {
+ snd_use_lock_free(&q->use_lock);
queue_delete(q);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
- return q->queue;
+ return q;
}
/* delete a queue - queue must be owned by the client */
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
index 30c8111477f6..719093489a2c 100644
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -71,7 +71,7 @@ void snd_seq_queues_delete(void);
/* create new queue (constructor) */
-int snd_seq_queue_alloc(int client, int locked, unsigned int flags);
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int flags);
/* delete queue (destructor) */
int snd_seq_queue_delete(int client, int queueid);
diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c
index f0e4d502d604..066b5df666f4 100644
--- a/sound/firewire/iso-resources.c
+++ b/sound/firewire/iso-resources.c
@@ -210,9 +210,14 @@ EXPORT_SYMBOL(fw_iso_resources_update);
*/
void fw_iso_resources_free(struct fw_iso_resources *r)
{
- struct fw_card *card = fw_parent_device(r->unit)->card;
+ struct fw_card *card;
int bandwidth, channel;
+ /* Not initialized. */
+ if (r->unit == NULL)
+ return;
+ card = fw_parent_device(r->unit)->card;
+
mutex_lock(&r->mutex);
if (r->allocated) {
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index bf779cfeef0d..59a270406353 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -128,6 +128,7 @@ static void do_registration(struct work_struct *work)
return;
error:
snd_motu_transaction_unregister(motu);
+ snd_motu_stream_destroy_duplex(motu);
snd_card_free(motu->card);
dev_info(&motu->unit->device,
"Sound card registration failed: %d\n", err);
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index dc585959ca32..a2b56b188be4 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -698,10 +698,18 @@ static int copy_gctl(struct snd_emu10k1 *emu,
{
struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
- if (emu->support_tlv)
- return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl));
+ if (emu->support_tlv) {
+ if (in_kernel)
+ memcpy(gctl, (void *)&_gctl[idx], sizeof(*gctl));
+ else if (copy_from_user(gctl, &_gctl[idx], sizeof(*gctl)))
+ return -EFAULT;
+ return 0;
+ }
+
octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
- if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
+ if (in_kernel)
+ memcpy(gctl, (void *)&octl[idx], sizeof(*octl));
+ else if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
return -EFAULT;
gctl->tlv = NULL;
return 0;
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 2e402ece4c86..8e6b04b39dcc 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1235,8 +1235,6 @@ static int snd_fm801_create(struct snd_card *card,
}
}
- snd_fm801_chip_init(chip);
-
if ((chip->tea575x_tuner & TUNER_ONLY) == 0) {
if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
@@ -1248,6 +1246,8 @@ static int snd_fm801_create(struct snd_card *card,
pci_set_master(pci);
}
+ snd_fm801_chip_init(chip);
+
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_fm801_free(chip);
return err;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 63bc894ddf5e..a81aacf684b2 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -933,6 +933,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
@@ -946,6 +947,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI),
SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index d549f35f39d3..53f9311370de 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -3733,11 +3733,15 @@ HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI", patch_atihdmi),
HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI", patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI", patch_nvhdmi_2ch),
HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI", patch_nvhdmi_8ch_7x),
HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI", patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi),
@@ -3764,17 +3768,40 @@ HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI", patch_nvhdmi_2ch),
HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI", patch_nvhdmi_2ch),
HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi),
HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi),
HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 45d58fc1df39..217bb582aff1 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2296,6 +2296,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
+ SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
@@ -3838,6 +3839,17 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
}
}
+static struct coef_fw alc225_pre_hsmode[] = {
+ UPDATE_COEF(0x4a, 1<<8, 0),
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
+ UPDATE_COEF(0x63, 3<<14, 3<<14),
+ UPDATE_COEF(0x4a, 3<<4, 2<<4),
+ UPDATE_COEF(0x4a, 3<<10, 3<<10),
+ UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+ UPDATE_COEF(0x4a, 3<<10, 0),
+ {}
+};
+
static void alc_headset_mode_unplugged(struct hda_codec *codec)
{
static struct coef_fw coef0255[] = {
@@ -3873,6 +3885,10 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
UPDATE_COEF(0x67, 0x2000, 0),
{}
};
+ static struct coef_fw coef0298[] = {
+ UPDATE_COEF(0x19, 0x1300, 0x0300),
+ {}
+ };
static struct coef_fw coef0292[] = {
WRITE_COEF(0x76, 0x000e),
WRITE_COEF(0x6c, 0x2400),
@@ -3895,13 +3911,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
{}
};
static struct coef_fw coef0225[] = {
- UPDATE_COEF(0x4a, 1<<8, 0),
- UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
- UPDATE_COEF(0x63, 3<<14, 3<<14),
- UPDATE_COEF(0x4a, 3<<4, 2<<4),
- UPDATE_COEF(0x4a, 3<<10, 3<<10),
- UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
- UPDATE_COEF(0x4a, 3<<10, 0),
+ UPDATE_COEF(0x63, 3<<14, 0),
{}
};
static struct coef_fw coef0274[] = {
@@ -3935,7 +3945,10 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
break;
case 0x10ec0286:
case 0x10ec0288:
+ alc_process_coef_fw(codec, coef0288);
+ break;
case 0x10ec0298:
+ alc_process_coef_fw(codec, coef0298);
alc_process_coef_fw(codec, coef0288);
break;
case 0x10ec0292:
@@ -3976,6 +3989,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
{}
};
static struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x4f, 0x00c0, 0),
UPDATE_COEF(0x50, 0x2000, 0),
UPDATE_COEF(0x56, 0x0006, 0),
UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
@@ -4039,7 +4053,6 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
case 0x10ec0286:
case 0x10ec0288:
case 0x10ec0298:
- alc_update_coef_idx(codec, 0x4f, 0x000c, 0);
snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
alc_process_coef_fw(codec, coef0288);
snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
@@ -4072,6 +4085,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
case 0x10ec0225:
case 0x10ec0295:
case 0x10ec0299:
+ alc_process_coef_fw(codec, alc225_pre_hsmode);
alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
alc_process_coef_fw(codec, coef0225);
@@ -4084,7 +4098,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
static void alc_headset_mode_default(struct hda_codec *codec)
{
static struct coef_fw coef0225[] = {
- UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+ UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
+ UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
+ UPDATE_COEF(0x49, 3<<8, 0<<8),
+ UPDATE_COEF(0x4a, 3<<4, 3<<4),
+ UPDATE_COEF(0x63, 3<<14, 0),
+ UPDATE_COEF(0x67, 0xf000, 0x3000),
{}
};
static struct coef_fw coef0255[] = {
@@ -4138,6 +4157,7 @@ static void alc_headset_mode_default(struct hda_codec *codec)
case 0x10ec0225:
case 0x10ec0295:
case 0x10ec0299:
+ alc_process_coef_fw(codec, alc225_pre_hsmode);
alc_process_coef_fw(codec, coef0225);
break;
case 0x10ec0255:
@@ -4177,6 +4197,8 @@ static void alc_headset_mode_default(struct hda_codec *codec)
/* Iphone type */
static void alc_headset_mode_ctia(struct hda_codec *codec)
{
+ int val;
+
static struct coef_fw coef0255[] = {
WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
WRITE_COEF(0x1b, 0x0c2b),
@@ -4219,11 +4241,14 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
WRITE_COEF(0xc3, 0x0000),
{}
};
- static struct coef_fw coef0225[] = {
+ static struct coef_fw coef0225_1[] = {
UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
- UPDATE_COEF(0x49, 1<<8, 1<<8),
- UPDATE_COEF(0x4a, 7<<6, 7<<6),
- UPDATE_COEF(0x4a, 3<<4, 3<<4),
+ UPDATE_COEF(0x63, 3<<14, 2<<14),
+ {}
+ };
+ static struct coef_fw coef0225_2[] = {
+ UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+ UPDATE_COEF(0x63, 3<<14, 1<<14),
{}
};
@@ -4244,8 +4269,17 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
alc_process_coef_fw(codec, coef0233);
break;
case 0x10ec0298:
- alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);/* Headset output enable */
- /* ALC298 jack type setting is the same with ALC286/ALC288 */
+ val = alc_read_coef_idx(codec, 0x50);
+ if (val & (1 << 12)) {
+ alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+ alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+ msleep(300);
+ } else {
+ alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+ alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+ msleep(300);
+ }
+ break;
case 0x10ec0286:
case 0x10ec0288:
alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
@@ -4264,7 +4298,11 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
case 0x10ec0225:
case 0x10ec0295:
case 0x10ec0299:
- alc_process_coef_fw(codec, coef0225);
+ val = alc_read_coef_idx(codec, 0x45);
+ if (val & (1 << 9))
+ alc_process_coef_fw(codec, coef0225_2);
+ else
+ alc_process_coef_fw(codec, coef0225_1);
break;
case 0x10ec0867:
alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
@@ -4320,9 +4358,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
};
static struct coef_fw coef0225[] = {
UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
- UPDATE_COEF(0x49, 1<<8, 1<<8),
- UPDATE_COEF(0x4a, 7<<6, 7<<6),
- UPDATE_COEF(0x4a, 3<<4, 3<<4),
+ UPDATE_COEF(0x63, 3<<14, 2<<14),
{}
};
@@ -4344,7 +4380,9 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
break;
case 0x10ec0298:
alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
- /* ALC298 jack type setting is the same with ALC286/ALC288 */
+ alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+ msleep(300);
+ break;
case 0x10ec0286:
case 0x10ec0288:
alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
@@ -4384,6 +4422,14 @@ static void alc_determine_headset_type(struct hda_codec *codec)
UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
{}
};
+ static struct coef_fw coef0298[] = {
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+ UPDATE_COEF(0x66, 0x0008, 0),
+ UPDATE_COEF(0x67, 0x2000, 0),
+ UPDATE_COEF(0x19, 0x1300, 0x1300),
+ {}
+ };
static struct coef_fw coef0293[] = {
UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
@@ -4396,11 +4442,6 @@ static void alc_determine_headset_type(struct hda_codec *codec)
WRITE_COEF(0xc3, 0x0c00),
{}
};
- static struct coef_fw coef0225[] = {
- UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
- UPDATE_COEF(0x49, 1<<8, 1<<8),
- {}
- };
static struct coef_fw coef0274[] = {
UPDATE_COEF(0x4a, 0x0010, 0),
UPDATE_COEF(0x4a, 0x8000, 0),
@@ -4433,8 +4474,34 @@ static void alc_determine_headset_type(struct hda_codec *codec)
is_ctia = (val & 0x0070) == 0x0070;
break;
case 0x10ec0298:
- alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020); /* Headset output enable */
- /* ALC298 check jack type is the same with ALC286/ALC288 */
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ msleep(100);
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ msleep(200);
+
+ val = alc_read_coef_idx(codec, 0x50);
+ if (val & (1 << 12)) {
+ alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+ alc_process_coef_fw(codec, coef0288);
+ msleep(350);
+ val = alc_read_coef_idx(codec, 0x50);
+ is_ctia = (val & 0x0070) == 0x0070;
+ } else {
+ alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+ alc_process_coef_fw(codec, coef0288);
+ msleep(350);
+ val = alc_read_coef_idx(codec, 0x50);
+ is_ctia = (val & 0x0070) == 0x0070;
+ }
+ alc_process_coef_fw(codec, coef0298);
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+ msleep(75);
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ break;
case 0x10ec0286:
case 0x10ec0288:
alc_process_coef_fw(codec, coef0288);
@@ -4463,10 +4530,25 @@ static void alc_determine_headset_type(struct hda_codec *codec)
case 0x10ec0225:
case 0x10ec0295:
case 0x10ec0299:
- alc_process_coef_fw(codec, coef0225);
- msleep(800);
- val = alc_read_coef_idx(codec, 0x46);
- is_ctia = (val & 0x00f0) == 0x00f0;
+ alc_process_coef_fw(codec, alc225_pre_hsmode);
+ alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
+ val = alc_read_coef_idx(codec, 0x45);
+ if (val & (1 << 9)) {
+ alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+ alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
+ msleep(800);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x00f0) == 0x00f0;
+ } else {
+ alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+ alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
+ msleep(800);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x00f0) == 0x00f0;
+ }
+ alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
+ alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
+ alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
break;
case 0x10ec0867:
is_ctia = true;
@@ -6565,7 +6647,6 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
SND_HDA_PIN_QUIRK(0x10ec0299, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
ALC225_STANDARD_PINS,
{0x12, 0xb7a60130},
- {0x13, 0xb8a61140},
{0x17, 0x90170110}),
{}
};
@@ -6724,6 +6805,7 @@ static int patch_alc269(struct hda_codec *codec)
case 0x10ec0225:
case 0x10ec0295:
spec->codec_variant = ALC269_TYPE_ALC225;
+ spec->gen.mixer_nid = 0; /* no loopback on ALC225 ALC295 */
break;
case 0x10ec0299:
spec->codec_variant = ALC269_TYPE_ALC225;
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index b7ef8c59b49a..0cd7caaed9c4 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -652,7 +652,6 @@ static int atmel_classd_probe(struct platform_device *pdev)
}
snd_soc_card_set_drvdata(card, dd);
- platform_set_drvdata(pdev, card);
ret = atmel_classd_asoc_card_init(dev, card);
if (ret) {
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
index c917df7715d1..8e3d34be9e69 100644
--- a/sound/soc/atmel/atmel-pdmic.c
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -694,7 +694,6 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
}
snd_soc_card_set_drvdata(card, dd);
- platform_set_drvdata(pdev, card);
ret = atmel_pdmic_asoc_card_init(dev, card);
if (ret) {
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 5c73061d912a..301e1fc9a377 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -99,7 +99,7 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream)
return 0;
}
-static struct snd_soc_ops db1200_i2s_wm8731_ops = {
+static const struct snd_soc_ops db1200_i2s_wm8731_ops = {
.startup = db1200_i2s_startup,
};
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index b5d1caa04d8e..6a035ca0f521 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -304,7 +304,7 @@ static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static struct snd_pcm_ops au1xpsc_pcm_ops = {
+static const struct snd_pcm_ops au1xpsc_pcm_ops = {
.open = au1xpsc_pcm_open,
.close = au1xpsc_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
index fcf5a9adde81..19457e2b351e 100644
--- a/sound/soc/au1x/dma.c
+++ b/sound/soc/au1x/dma.c
@@ -277,7 +277,7 @@ static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss)
return bytes_to_frames(ss->runtime, location);
}
-static struct snd_pcm_ops alchemy_pcm_ops = {
+static const struct snd_pcm_ops alchemy_pcm_ops = {
.open = alchemy_pcm_open,
.close = alchemy_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index bb53c7059005..a2050ae5a3fe 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -474,7 +474,7 @@ static int au1xpsc_ac97_drvresume(struct device *dev)
return 0;
}
-static struct dev_pm_ops au1xpscac97_pmops = {
+static const struct dev_pm_ops au1xpscac97_pmops = {
.suspend = au1xpsc_ac97_drvsuspend,
.resume = au1xpsc_ac97_drvresume,
};
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 0bf9d62b91a0..e6eec081eaae 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -392,7 +392,7 @@ static int au1xpsc_i2s_drvresume(struct device *dev)
return 0;
}
-static struct dev_pm_ops au1xpsci2s_pmops = {
+static const struct dev_pm_ops au1xpsci2s_pmops = {
.suspend = au1xpsc_i2s_drvsuspend,
.resume = au1xpsc_i2s_drvresume,
};
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index e710bb0c5637..15c438f0f22d 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -27,12 +27,6 @@
#define DEFAULT_VCO 1354750204
-#define CYGNUS_TDM_RATE \
- (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
- SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 | \
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
- SNDRV_PCM_RATE_48000)
-
#define CAPTURE_FCI_ID_BASE 0x180
#define CYGNUS_SSP_TRISTATE_MASK 0x001fff
#define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -234,152 +228,20 @@ static const struct pll_macro_entry pll_predef_mclk[] = {
{98304000, 2},
};
+#define CYGNUS_RATE_MIN 8000
+#define CYGNUS_RATE_MAX 384000
+
/* List of valid frame sizes for tdm mode */
static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512};
-/*
- * Use this relationship to derive the sampling rate (lrclk)
- * lrclk = (mclk) / ((2*mclk_to_sclk_ratio) * (32 * SCLK))).
- *
- * Use mclk and pll_ch from the table above
- *
- * Valid SCLK = 0/1/2/4/8/12
- *
- * mclk_to_sclk_ratio = number of MCLK per SCLK. Division is twice the
- * value programmed in this field.
- * Valid mclk_to_sclk_ratio = 1 through to 15
- *
- * eg: To set lrclk = 48khz, set mclk = 12288000, mclk_to_sclk_ratio = 2,
- * SCLK = 64
- */
-struct _ssp_clk_coeff {
- u32 mclk;
- u32 sclk_rate;
- u32 rate;
- u32 mclk_rate;
+static const unsigned int cygnus_rates[] = {
+ 8000, 11025, 16000, 22050, 32000, 44100, 48000,
+ 88200, 96000, 176400, 192000, 352800, 384000
};
-static const struct _ssp_clk_coeff ssp_clk_coeff[] = {
- { 4096000, 32, 16000, 4},
- { 4096000, 32, 32000, 2},
- { 4096000, 64, 8000, 4},
- { 4096000, 64, 16000, 2},
- { 4096000, 64, 32000, 1},
- { 4096000, 128, 8000, 2},
- { 4096000, 128, 16000, 1},
- { 4096000, 256, 8000, 1},
-
- { 6144000, 32, 16000, 6},
- { 6144000, 32, 32000, 3},
- { 6144000, 32, 48000, 2},
- { 6144000, 32, 96000, 1},
- { 6144000, 64, 8000, 6},
- { 6144000, 64, 16000, 3},
- { 6144000, 64, 48000, 1},
- { 6144000, 128, 8000, 3},
-
- { 8192000, 32, 32000, 4},
- { 8192000, 64, 16000, 4},
- { 8192000, 64, 32000, 2},
- { 8192000, 128, 8000, 4},
- { 8192000, 128, 16000, 2},
- { 8192000, 128, 32000, 1},
- { 8192000, 256, 8000, 2},
- { 8192000, 256, 16000, 1},
- { 8192000, 512, 8000, 1},
-
- {12288000, 32, 32000, 6},
- {12288000, 32, 48000, 4},
- {12288000, 32, 96000, 2},
- {12288000, 32, 192000, 1},
- {12288000, 64, 16000, 6},
- {12288000, 64, 32000, 3},
- {12288000, 64, 48000, 2},
- {12288000, 64, 96000, 1},
- {12288000, 128, 8000, 6},
- {12288000, 128, 16000, 3},
- {12288000, 128, 48000, 1},
- {12288000, 256, 8000, 3},
-
- {16384000, 64, 32000, 4},
- {16384000, 128, 16000, 4},
- {16384000, 128, 32000, 2},
- {16384000, 256, 8000, 4},
- {16384000, 256, 16000, 2},
- {16384000, 256, 32000, 1},
- {16384000, 512, 8000, 2},
- {16384000, 512, 16000, 1},
-
- {24576000, 32, 96000, 4},
- {24576000, 32, 192000, 2},
- {24576000, 64, 32000, 6},
- {24576000, 64, 48000, 4},
- {24576000, 64, 96000, 2},
- {24576000, 64, 192000, 1},
- {24576000, 128, 16000, 6},
- {24576000, 128, 32000, 3},
- {24576000, 128, 48000, 2},
- {24576000, 256, 8000, 6},
- {24576000, 256, 16000, 3},
- {24576000, 256, 48000, 1},
- {24576000, 512, 8000, 3},
-
- {49152000, 32, 192000, 4},
- {49152000, 64, 96000, 4},
- {49152000, 64, 192000, 2},
- {49152000, 128, 32000, 6},
- {49152000, 128, 48000, 4},
- {49152000, 128, 96000, 2},
- {49152000, 128, 192000, 1},
- {49152000, 256, 16000, 6},
- {49152000, 256, 32000, 3},
- {49152000, 256, 48000, 2},
- {49152000, 256, 96000, 1},
- {49152000, 512, 8000, 6},
- {49152000, 512, 16000, 3},
- {49152000, 512, 48000, 1},
-
- { 5644800, 32, 22050, 4},
- { 5644800, 32, 44100, 2},
- { 5644800, 32, 88200, 1},
- { 5644800, 64, 11025, 4},
- { 5644800, 64, 22050, 2},
- { 5644800, 64, 44100, 1},
-
- {11289600, 32, 44100, 4},
- {11289600, 32, 88200, 2},
- {11289600, 32, 176400, 1},
- {11289600, 64, 22050, 4},
- {11289600, 64, 44100, 2},
- {11289600, 64, 88200, 1},
- {11289600, 128, 11025, 4},
- {11289600, 128, 22050, 2},
- {11289600, 128, 44100, 1},
-
- {22579200, 32, 88200, 4},
- {22579200, 32, 176400, 2},
- {22579200, 64, 44100, 4},
- {22579200, 64, 88200, 2},
- {22579200, 64, 176400, 1},
- {22579200, 128, 22050, 4},
- {22579200, 128, 44100, 2},
- {22579200, 128, 88200, 1},
- {22579200, 256, 11025, 4},
- {22579200, 256, 22050, 2},
- {22579200, 256, 44100, 1},
-
- {45158400, 32, 176400, 4},
- {45158400, 64, 88200, 4},
- {45158400, 64, 176400, 2},
- {45158400, 128, 44100, 4},
- {45158400, 128, 88200, 2},
- {45158400, 128, 176400, 1},
- {45158400, 256, 22050, 4},
- {45158400, 256, 44100, 2},
- {45158400, 256, 88200, 1},
- {45158400, 512, 11025, 4},
- {45158400, 512, 22050, 2},
- {45158400, 512, 44100, 1},
+static const struct snd_pcm_hw_constraint_list cygnus_rate_constraint = {
+ .count = ARRAY_SIZE(cygnus_rates),
+ .list = cygnus_rates,
};
static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
@@ -679,40 +541,55 @@ static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
return p_entry->pll_ch_num;
}
-static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
- struct cygnus_audio *cygaud)
+static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
{
- u32 value, i = 0;
+ u32 value;
u32 mask = 0xf;
u32 sclk;
- bool found = false;
- const struct _ssp_clk_coeff *p_entry = NULL;
+ u32 mclk_rate;
+ unsigned int bit_rate;
+ unsigned int ratio;
- for (i = 0; i < ARRAY_SIZE(ssp_clk_coeff); i++) {
- p_entry = &ssp_clk_coeff[i];
- if ((p_entry->rate == aio->lrclk) &&
- (p_entry->sclk_rate == aio->bit_per_frame) &&
- (p_entry->mclk == aio->mclk)) {
- found = true;
- break;
- }
- }
- if (!found) {
+ bit_rate = aio->bit_per_frame * aio->lrclk;
+
+ /*
+ * Check if the bit clock can be generated from the given MCLK.
+ * MCLK must be a perfect multiple of bit clock and must be one of the
+ * following values... (2,4,6,8,10,12,14)
+ */
+ if ((aio->mclk % bit_rate) != 0)
+ return -EINVAL;
+
+ ratio = aio->mclk / bit_rate;
+ switch (ratio) {
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
+ case 14:
+ mclk_rate = ratio / 2;
+ break;
+
+ default:
dev_err(aio->cygaud->dev,
- "No valid match found in ssp_clk_coeff array\n");
+ "Invalid combination of MCLK and BCLK\n");
dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
aio->lrclk, aio->bit_per_frame, aio->mclk);
return -EINVAL;
}
- sclk = aio->bit_per_frame;
- if (sclk == 512)
- sclk = 0;
- /* sclks_per_1fs_div = sclk cycles/32 */
- sclk /= 32;
/* Set sclk rate */
switch (aio->port_type) {
case PORT_TDM:
+ sclk = aio->bit_per_frame;
+ if (sclk == 512)
+ sclk = 0;
+
+ /* sclks_per_1fs_div = sclk cycles/32 */
+ sclk /= 32;
+
/* Set number of bitclks per frame */
value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
@@ -731,7 +608,7 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
- value |= (p_entry->mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
+ value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
@@ -745,7 +622,6 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
- struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
int rate, bitres;
u32 value;
u32 mask = 0x1f;
@@ -841,7 +717,7 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
aio->lrclk = rate;
if (!aio->is_slave)
- ret = cygnus_ssp_set_clocks(aio, cygaud);
+ ret = cygnus_ssp_set_clocks(aio);
return ret;
}
@@ -888,6 +764,11 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
else
aio->clk_trace.cap_en = true;
+ substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
+ substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
+
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
return 0;
}
@@ -1261,9 +1142,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
.playback = { \
.channels_min = 1, \
.channels_max = 16, \
- .rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
- SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
- SNDRV_PCM_RATE_192000, \
+ .rates = SNDRV_PCM_RATE_KNOT, \
.formats = SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S32_LE, \
@@ -1271,9 +1150,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
.capture = { \
.channels_min = 2, \
.channels_max = 16, \
- .rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
- SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
- SNDRV_PCM_RATE_192000, \
+ .rates = SNDRV_PCM_RATE_KNOT, \
.formats = SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S32_LE, \
}, \
@@ -1288,14 +1165,12 @@ static const struct snd_soc_dai_driver cygnus_ssp_dai_info[] = {
INIT_CPU_DAI(2),
};
-static struct snd_soc_dai_driver cygnus_spdif_dai_info = {
+static const struct snd_soc_dai_driver cygnus_spdif_dai_info = {
.name = "cygnus-spdif",
.playback = {
.channels_min = 2,
.channels_max = 2,
- .rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 |
- SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
- SNDRV_PCM_RATE_192000,
+ .rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 913e29275f4e..8c1d1983b8f9 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -308,7 +308,7 @@ static int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream,
}
#endif
-static struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
+static const struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
.open = bf5xx_pcm_open,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = bf5xx_pcm_hw_params,
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 470d99abf6f6..51cae76f14e6 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -318,7 +318,7 @@ static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
+static const struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
.open = bf5xx_pcm_open,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = bf5xx_pcm_hw_params,
diff --git a/sound/soc/blackfin/bf6xx-i2s.c b/sound/soc/blackfin/bf6xx-i2s.c
index bd3b4d464145..819cff149a25 100644
--- a/sound/soc/blackfin/bf6xx-i2s.c
+++ b/sound/soc/blackfin/bf6xx-i2s.c
@@ -164,7 +164,7 @@ static int bfin_i2s_resume(struct snd_soc_dai *dai)
#define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops bfin_i2s_dai_ops = {
+static const struct snd_soc_dai_ops bfin_i2s_dai_ops = {
.hw_params = bfin_i2s_hw_params,
.set_fmt = bfin_i2s_set_dai_fmt,
};
diff --git a/sound/soc/blackfin/bf6xx-sport.c b/sound/soc/blackfin/bf6xx-sport.c
index dfb744381c42..d2caadfe7b6d 100644
--- a/sound/soc/blackfin/bf6xx-sport.c
+++ b/sound/soc/blackfin/bf6xx-sport.c
@@ -129,7 +129,7 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
for (i = 0; i < fragcount; ++i) {
desc[i].next_desc_addr = &(desc[i + 1]);
- desc[i].start_addr = (unsigned long)buf + i*fragsize;
+ desc[i].start_addr = (unsigned long)buf + i * fragsize;
desc[i].cfg = cfg;
desc[i].x_count = count;
desc[i].x_modify = wdsize;
@@ -138,7 +138,7 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
}
/* make circular */
- desc[fragcount-1].next_desc_addr = desc;
+ desc[fragcount - 1].next_desc_addr = desc;
}
int sport_config_tx_dma(struct sport_device *sport, void *buf,
@@ -148,7 +148,7 @@ int sport_config_tx_dma(struct sport_device *sport, void *buf,
unsigned int cfg;
dma_addr_t addr;
- count = fragsize/sport->wdsize;
+ count = fragsize / sport->wdsize;
if (sport->tx_desc)
dma_free_coherent(NULL, sport->tx_desc_size,
@@ -166,8 +166,7 @@ int sport_config_tx_dma(struct sport_device *sport, void *buf,
cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | NDSIZE_6;
setup_desc(sport->tx_desc, buf, fragcount, fragsize,
- cfg|DMAEN, count, sport->wdsize);
-
+ cfg | DMAEN, count, sport->wdsize);
return 0;
}
EXPORT_SYMBOL(sport_config_tx_dma);
@@ -179,7 +178,7 @@ int sport_config_rx_dma(struct sport_device *sport, void *buf,
unsigned int cfg;
dma_addr_t addr;
- count = fragsize/sport->wdsize;
+ count = fragsize / sport->wdsize;
if (sport->rx_desc)
dma_free_coherent(NULL, sport->rx_desc_size,
@@ -198,8 +197,7 @@ int sport_config_rx_dma(struct sport_device *sport, void *buf,
| WNR | NDSIZE_6;
setup_desc(sport->rx_desc, buf, fragcount, fragsize,
- cfg|DMAEN, count, sport->wdsize);
-
+ cfg | DMAEN, count, sport->wdsize);
return 0;
}
EXPORT_SYMBOL(sport_config_rx_dma);
@@ -226,7 +224,7 @@ static irqreturn_t sport_tx_irq(int irq, void *dev_id)
static unsigned long status;
status = get_dma_curr_irqstat(sport->tx_dma_chan);
- if (status & (DMA_DONE|DMA_ERR)) {
+ if (status & (DMA_DONE | DMA_ERR)) {
clear_dma_irqstat(sport->tx_dma_chan);
SSYNC();
}
@@ -241,7 +239,7 @@ static irqreturn_t sport_rx_irq(int irq, void *dev_id)
unsigned long status;
status = get_dma_curr_irqstat(sport->rx_dma_chan);
- if (status & (DMA_DONE|DMA_ERR)) {
+ if (status & (DMA_DONE | DMA_ERR)) {
clear_dma_irqstat(sport->rx_dma_chan);
SSYNC();
}
@@ -388,26 +386,24 @@ struct sport_device *sport_create(struct platform_device *pdev)
int ret;
sport = kzalloc(sizeof(*sport), GFP_KERNEL);
- if (!sport) {
- dev_err(dev, "Unable to allocate memory for sport device\n");
+ if (!sport)
return NULL;
- }
+
sport->pdev = pdev;
ret = sport_get_resource(sport);
- if (ret) {
- kfree(sport);
- return NULL;
- }
+ if (ret)
+ goto free_data;
ret = sport_request_resource(sport);
- if (ret) {
- kfree(sport);
- return NULL;
- }
+ if (ret)
+ goto free_data;
dev_dbg(dev, "SPORT create success\n");
return sport;
+free_data:
+ kfree(sport);
+ return NULL;
}
EXPORT_SYMBOL(sport_create);
diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
index 85962657aabe..c53bd6f2c2d7 100644
--- a/sound/soc/cirrus/edb93xx.c
+++ b/sound/soc/cirrus/edb93xx.c
@@ -56,7 +56,7 @@ static int edb93xx_hw_params(struct snd_pcm_substream *substream,
SND_SOC_CLOCK_OUT);
}
-static struct snd_soc_ops edb93xx_ops = {
+static const struct snd_soc_ops edb93xx_ops = {
.hw_params = edb93xx_hw_params,
};
diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
index 98089df08df6..2334ec19e7eb 100644
--- a/sound/soc/cirrus/snappercl15.c
+++ b/sound/soc/cirrus/snappercl15.c
@@ -45,7 +45,7 @@ static int snappercl15_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_soc_ops snappercl15_ops = {
+static const struct snd_soc_ops snappercl15_ops = {
.hw_params = snappercl15_hw_params,
};
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index b013a4c62b63..848c5fe49bc7 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -1355,7 +1355,7 @@ static struct regmap *pm860x_get_regmap(struct device *dev)
return pm860x->regmap;
}
-static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
+static const struct snd_soc_codec_driver soc_codec_dev_pm860x = {
.probe = pm860x_probe,
.remove = pm860x_remove,
.set_bias_level = pm860x_set_bias_level,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6c78b0b49b81..d81bc4195603 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -60,6 +60,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4271_I2C if I2C
select SND_SOC_CS4271_SPI if SPI_MASTER
select SND_SOC_CS42XX8_I2C if I2C
+ select SND_SOC_CS43130 if I2C
select SND_SOC_CS4349 if I2C
select SND_SOC_CS47L24 if MFD_CS47L24
select SND_SOC_CS53L30 if I2C
@@ -71,7 +72,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
select SND_SOC_DIO2125
- select SND_SOC_DMIC
+ select SND_SOC_DMIC if GPIOLIB
select SND_SOC_ES8316 if I2C
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
@@ -114,6 +115,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM5102A
select SND_SOC_PCM512x_I2C if I2C
select SND_SOC_PCM512x_SPI if SPI_MASTER
+ select SND_SOC_RT274 if I2C
select SND_SOC_RT286 if I2C
select SND_SOC_RT298 if I2C
select SND_SOC_RT5514 if I2C
@@ -486,6 +488,11 @@ config SND_SOC_CS42XX8_I2C
select SND_SOC_CS42XX8
select REGMAP_I2C
+# Cirrus Logic CS43130 HiFi DAC
+config SND_SOC_CS43130
+ tristate "Cirrus Logic CS43130 CODEC"
+ depends on I2C
+
# Cirrus Logic CS4349 HiFi DAC
config SND_SOC_CS4349
tristate "Cirrus Logic CS4349 CODEC"
@@ -716,11 +723,17 @@ config SND_SOC_RL6231
config SND_SOC_RL6347A
tristate
+ default y if SND_SOC_RT274=y
default y if SND_SOC_RT286=y
default y if SND_SOC_RT298=y
+ default m if SND_SOC_RT274=m
default m if SND_SOC_RT286=m
default m if SND_SOC_RT298=m
+config SND_SOC_RT274
+ tristate
+ depends on I2C
+
config SND_SOC_RT286
tristate
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 1755a54e3dc9..696e371f0e0c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -53,6 +53,7 @@ snd-soc-cs4271-i2c-objs := cs4271-i2c.o
snd-soc-cs4271-spi-objs := cs4271-spi.o
snd-soc-cs42xx8-objs := cs42xx8.o
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
+snd-soc-cs43130-objs := cs43130.o
snd-soc-cs4349-objs := cs4349.o
snd-soc-cs47l24-objs := cs47l24.o
snd-soc-cs53l30-objs := cs53l30.o
@@ -113,6 +114,7 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o
+snd-soc-rt274-objs := rt274.o
snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o
snd-soc-rt5514-objs := rt5514.o
@@ -290,6 +292,7 @@ obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o
obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
+obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o
obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o
obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o
obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o
@@ -320,6 +323,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o
+obj-$(CONFIG_SND_SOC_MAX98371) += snd-soc-max98371.o
obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o
obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o
@@ -349,6 +353,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
+obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o
@@ -372,6 +377,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
+obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o
obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 312b2a11abb6..006627b8c3a8 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -2523,7 +2523,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
return status;
}
-static struct snd_soc_codec_driver ab8500_codec_driver = {
+static const struct snd_soc_codec_driver ab8500_codec_driver = {
.probe = ab8500_codec_probe,
.component_driver = {
.controls = ab8500_ctrls,
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index f7f04c6be01e..440b4ce54376 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -112,7 +112,7 @@ static int ac97_soc_resume(struct snd_soc_codec *codec)
#define ac97_soc_resume NULL
#endif
-static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ac97 = {
.probe = ac97_soc_probe,
.suspend = ac97_soc_suspend,
.resume = ac97_soc_resume,
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index a478239aadac..d0361caad09e 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -321,7 +321,7 @@ static int ad1836_remove(struct snd_soc_codec *codec)
AD1836_ADC_SERFMT_MASK, 0);
}
-static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
.probe = ad1836_probe,
.remove = ad1836_remove,
.suspend = ad1836_suspend,
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index d643557d89a7..d10988eec0c1 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -408,7 +408,7 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
+static const struct snd_soc_codec_driver soc_codec_dev_ad193x = {
.probe = ad193x_codec_probe,
.component_driver = {
.controls = ad193x_snd_controls,
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index b7c1b9f4bf5f..ce89bfb42094 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -295,7 +295,7 @@ static int ad1980_soc_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
.probe = ad1980_soc_probe,
.remove = ad1980_soc_remove,
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index 3e358a49442d..d8d86a0fea60 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -54,7 +54,7 @@ static struct snd_soc_dai_driver ad73311_dai = {
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
};
-static struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
.component_driver = {
.dapm_widgets = ad73311_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets),
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 8fa9045571ff..a865945d776a 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1458,7 +1458,7 @@ static const struct regmap_config adau1373_regmap_config = {
.num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults),
};
-static struct snd_soc_codec_driver adau1373_codec_driver = {
+static const struct snd_soc_codec_driver adau1373_codec_driver = {
.probe = adau1373_probe,
.resume = adau1373_resume,
.set_bias_level = adau1373_set_bias_level,
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 3bad1bc8c00a..805afac8146b 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -757,7 +757,7 @@ static int adau1701_resume(struct snd_soc_codec *codec)
#define adau1701_suspend NULL
#endif /* CONFIG_PM */
-static struct snd_soc_codec_driver adau1701_codec_drv = {
+static const struct snd_soc_codec_driver adau1701_codec_drv = {
.probe = adau1701_probe,
.remove = adau1701_remove,
.resume = adau1701_resume,
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index b319db6a69f8..e384f212beb2 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -388,8 +388,7 @@ static int adau1977_power_disable(struct adau1977 *adau1977)
regcache_mark_dirty(adau1977->regmap);
- if (adau1977->reset_gpio)
- gpiod_set_value_cansleep(adau1977->reset_gpio, 0);
+ gpiod_set_value_cansleep(adau1977->reset_gpio, 0);
regcache_cache_only(adau1977->regmap, true);
@@ -420,8 +419,7 @@ static int adau1977_power_enable(struct adau1977 *adau1977)
goto err_disable_avdd;
}
- if (adau1977->reset_gpio)
- gpiod_set_value_cansleep(adau1977->reset_gpio, 1);
+ gpiod_set_value_cansleep(adau1977->reset_gpio, 1);
regcache_cache_only(adau1977->regmap, false);
@@ -867,7 +865,7 @@ static int adau1977_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver adau1977_codec_driver = {
+static const struct snd_soc_codec_driver adau1977_codec_driver = {
.probe = adau1977_codec_probe,
.set_bias_level = adau1977_set_bias_level,
.set_sysclk = adau1977_set_sysclk,
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 6e793ebb5883..da7ca81f47cf 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -825,7 +825,7 @@ static int adav80x_resume(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver adav80x_codec_driver = {
+static const struct snd_soc_codec_driver adav80x_codec_driver = {
.probe = adav80x_probe,
.resume = adav80x_resume,
.set_bias_level = adav80x_set_bias_level,
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index 90c756d183b4..b7f0057c0239 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -58,7 +58,7 @@ static struct snd_soc_dai_driver ads117x_dai = {
.formats = ADS117X_FORMATS,},
};
-static struct snd_soc_codec_driver soc_codec_dev_ads117x = {
+static const struct snd_soc_codec_driver soc_codec_dev_ads117x = {
.component_driver = {
.dapm_widgets = ads117x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets),
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 1a9d233c94d0..dbb184118f2e 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -242,7 +242,7 @@ static int ak4104_soc_resume(struct snd_soc_codec *codec)
#define ak4104_soc_resume NULL
#endif /* CONFIG_PM */
-static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
+static const struct snd_soc_codec_driver soc_codec_device_ak4104 = {
.probe = ak4104_probe,
.remove = ak4104_remove,
.suspend = ak4104_soc_suspend,
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 66cfffde9a12..e3c157dc88db 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -390,7 +390,7 @@ static const struct regmap_config ak4535_regmap = {
.num_reg_defaults = ARRAY_SIZE(ak4535_reg_defaults),
};
-static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
.resume = ak4535_resume,
.set_bias_level = ak4535_set_bias_level,
.suspend_bias_off = true,
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
index b92c548b9d29..0bb4fe5c122a 100644
--- a/sound/soc/codecs/ak4554.c
+++ b/sound/soc/codecs/ak4554.c
@@ -64,7 +64,7 @@ static struct snd_soc_dai_driver ak4554_dai = {
.symmetric_rates = 1,
};
-static struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
.component_driver = {
.dapm_widgets = ak4554_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets),
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 690edebf029e..b95bb8b52e51 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -522,7 +522,7 @@ static int ak4613_resume(struct snd_soc_codec *codec)
return regcache_sync(regmap);
}
-static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
.suspend = ak4613_suspend,
.resume = ak4613_resume,
.set_bias_level = ak4613_set_bias_level,
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index ebdaf56c1d61..60142ff32d4f 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -524,7 +524,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
.component_driver = {
.controls = ak4641_snd_controls,
.num_controls = ARRAY_SIZE(ak4641_snd_controls),
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 66de8a2013a6..29530c567bd9 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -550,7 +550,7 @@ static int ak4642_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
.probe = ak4642_probe,
.suspend = ak4642_suspend,
.resume = ak4642_resume,
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 6088afaabf62..dcfdff56fc5a 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -610,7 +610,7 @@ static struct snd_soc_dai_driver ak4671_dai = {
.ops = &ak4671_dai_ops,
};
-static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
.set_bias_level = ak4671_set_bias_level,
.component_driver = {
.controls = ak4671_snd_controls,
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
index 0ef2df223336..d0e16c03815c 100644
--- a/sound/soc/codecs/ak5386.c
+++ b/sound/soc/codecs/ak5386.c
@@ -69,7 +69,7 @@ static int ak5386_soc_resume(struct snd_soc_codec *codec)
#define ak5386_soc_resume NULL
#endif /* CONFIG_PM */
-static struct snd_soc_codec_driver soc_codec_ak5386 = {
+static const struct snd_soc_codec_driver soc_codec_ak5386 = {
.probe = ak5386_soc_probe,
.remove = ak5386_soc_remove,
.suspend = ak5386_soc_suspend,
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index d2e3a3ef7499..1db965a93632 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -951,7 +951,7 @@ static int alc5623_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_device_alc5623 = {
+static const struct snd_soc_codec_driver soc_codec_device_alc5623 = {
.probe = alc5623_probe,
.suspend = alc5623_suspend,
.resume = alc5623_resume,
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 0a734d910850..a1149f6a8450 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -710,7 +710,7 @@ const struct soc_enum arizona_anc_input_src[] = {
ARRAY_SIZE(arizona_anc_input_src_text),
arizona_anc_input_src_text),
SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
- ARIZONA_FCL_MIC_MODE_SEL,
+ ARIZONA_FCL_MIC_MODE_SEL_SHIFT,
ARRAY_SIZE(arizona_anc_channel_src_text),
arizona_anc_channel_src_text),
SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
@@ -718,7 +718,7 @@ const struct soc_enum arizona_anc_input_src[] = {
ARRAY_SIZE(arizona_anc_input_src_text),
arizona_anc_input_src_text),
SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
- ARIZONA_FCR_MIC_MODE_SEL,
+ ARIZONA_FCR_MIC_MODE_SEL_SHIFT,
ARRAY_SIZE(arizona_anc_channel_src_text),
arizona_anc_channel_src_text),
};
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index 8014e697d540..806191addb44 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -62,7 +62,7 @@ static struct snd_soc_dai_driver bt_sco_dai[] = {
}
};
-static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
+static const struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
.component_driver = {
.dapm_widgets = bt_sco_widgets,
.num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets),
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 7a2d9a2ee427..6ed2cc374768 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -128,7 +128,7 @@ static struct regmap *cq93vc_get_regmap(struct device *dev)
return davinci_vc->regmap;
}
-static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
+static const struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
.set_bias_level = cq93vc_set_bias_level,
.get_regmap = cq93vc_get_regmap,
.component_driver = {
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index 6df29fa30fb9..854cf8f27605 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -831,7 +831,7 @@ static int cs35l33_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_cs35l33 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs35l33 = {
.probe = cs35l33_probe,
.set_bias_level = cs35l33_set_bias_level,
@@ -869,8 +869,7 @@ static int __maybe_unused cs35l33_runtime_resume(struct device *dev)
dev_dbg(dev, "%s\n", __func__);
- if (cs35l33->reset_gpio)
- gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
ret = regulator_bulk_enable(cs35l33->num_core_supplies,
cs35l33->core_supplies);
@@ -881,8 +880,7 @@ static int __maybe_unused cs35l33_runtime_resume(struct device *dev)
regcache_cache_only(cs35l33->regmap, false);
- if (cs35l33->reset_gpio)
- gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
msleep(CS35L33_BOOT_DELAY);
@@ -1191,8 +1189,7 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client,
return ret;
}
- if (cs35l33->reset_gpio)
- gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
msleep(CS35L33_BOOT_DELAY);
regcache_cache_only(cs35l33->regmap, false);
@@ -1262,8 +1259,7 @@ static int cs35l33_i2c_remove(struct i2c_client *client)
snd_soc_unregister_codec(&client->dev);
- if (cs35l33->reset_gpio)
- gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
pm_runtime_disable(&client->dev);
regulator_bulk_disable(cs35l33->num_core_supplies,
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index 0a747c66cc6c..1e05026bedca 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -779,7 +779,7 @@ static int cs35l34_probe(struct snd_soc_codec *codec)
}
-static struct snd_soc_codec_driver soc_codec_dev_cs35l34 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs35l34 = {
.probe = cs35l34_probe,
.component_driver = {
@@ -1138,8 +1138,7 @@ static int cs35l34_i2c_remove(struct i2c_client *client)
snd_soc_unregister_codec(&client->dev);
- if (cs35l34->reset_gpio)
- gpiod_set_value_cansleep(cs35l34->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs35l34->reset_gpio, 0);
pm_runtime_disable(&client->dev);
regulator_bulk_disable(cs35l34->num_core_supplies,
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index f1ee184ecab2..129978d1243e 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -1079,7 +1079,7 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_cs35l35 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs35l35 = {
.probe = cs35l35_codec_probe,
.set_sysclk = cs35l35_codec_set_sysclk,
.component_driver = {
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index d8824773dc29..49a80627af12 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -639,7 +639,7 @@ static int cs4271_codec_remove(struct snd_soc_codec *codec)
return 0;
};
-static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
.probe = cs4271_codec_probe,
.remove = cs4271_codec_remove,
.suspend = cs4271_soc_suspend,
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 55e4520cdcaf..a2324a0e72ee 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -911,7 +911,7 @@ static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute)
SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops cs42l42_ops = {
+static const struct snd_soc_dai_ops cs42l42_ops = {
.hw_params = cs42l42_pcm_hw_params,
.set_fmt = cs42l42_set_dai_fmt,
.set_sysclk = cs42l42_set_sysclk,
@@ -1898,8 +1898,7 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
snd_soc_unregister_codec(&i2c_client->dev);
/* Hold down reset */
- if (cs42l42->reset_gpio)
- gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
return 0;
}
@@ -1913,8 +1912,7 @@ static int cs42l42_runtime_suspend(struct device *dev)
regcache_mark_dirty(cs42l42->regmap);
/* Hold down reset */
- if (cs42l42->reset_gpio)
- gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
/* remove power */
regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
@@ -1937,8 +1935,7 @@ static int cs42l42_runtime_resume(struct device *dev)
return ret;
}
- if (cs42l42->reset_gpio)
- gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
regcache_cache_only(cs42l42->regmap, false);
regcache_sync(cs42l42->regmap);
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 96cfe38943cd..f8072f1897d4 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -504,7 +504,7 @@ static int cs42l51_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
+static const struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
.probe = cs42l51_codec_probe,
.component_driver = {
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
new file mode 100644
index 000000000000..220e30199c5b
--- /dev/null
+++ b/sound/soc/codecs/cs43130.c
@@ -0,0 +1,2690 @@
+/*
+ * cs43130.c -- CS43130 ALSA Soc Audio driver
+ *
+ * Copyright 2017 Cirrus Logic, Inc.
+ *
+ * Authors: Li Xu <li.xu@cirrus.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/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_irq.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <sound/jack.h>
+
+#include "cs43130.h"
+
+static const struct reg_default cs43130_reg_defaults[] = {
+ {CS43130_SYS_CLK_CTL_1, 0x06},
+ {CS43130_SP_SRATE, 0x01},
+ {CS43130_SP_BITSIZE, 0x05},
+ {CS43130_PAD_INT_CFG, 0x03},
+ {CS43130_PWDN_CTL, 0xFE},
+ {CS43130_CRYSTAL_SET, 0x04},
+ {CS43130_PLL_SET_1, 0x00},
+ {CS43130_PLL_SET_2, 0x00},
+ {CS43130_PLL_SET_3, 0x00},
+ {CS43130_PLL_SET_4, 0x00},
+ {CS43130_PLL_SET_5, 0x40},
+ {CS43130_PLL_SET_6, 0x10},
+ {CS43130_PLL_SET_7, 0x80},
+ {CS43130_PLL_SET_8, 0x03},
+ {CS43130_PLL_SET_9, 0x02},
+ {CS43130_PLL_SET_10, 0x02},
+ {CS43130_CLKOUT_CTL, 0x00},
+ {CS43130_ASP_NUM_1, 0x01},
+ {CS43130_ASP_NUM_2, 0x00},
+ {CS43130_ASP_DEN_1, 0x08},
+ {CS43130_ASP_DEN_2, 0x00},
+ {CS43130_ASP_LRCK_HI_TIME_1, 0x1F},
+ {CS43130_ASP_LRCK_HI_TIME_2, 0x00},
+ {CS43130_ASP_LRCK_PERIOD_1, 0x3F},
+ {CS43130_ASP_LRCK_PERIOD_2, 0x00},
+ {CS43130_ASP_CLOCK_CONF, 0x0C},
+ {CS43130_ASP_FRAME_CONF, 0x0A},
+ {CS43130_XSP_NUM_1, 0x01},
+ {CS43130_XSP_NUM_2, 0x00},
+ {CS43130_XSP_DEN_1, 0x02},
+ {CS43130_XSP_DEN_2, 0x00},
+ {CS43130_XSP_LRCK_HI_TIME_1, 0x1F},
+ {CS43130_XSP_LRCK_HI_TIME_2, 0x00},
+ {CS43130_XSP_LRCK_PERIOD_1, 0x3F},
+ {CS43130_XSP_LRCK_PERIOD_2, 0x00},
+ {CS43130_XSP_CLOCK_CONF, 0x0C},
+ {CS43130_XSP_FRAME_CONF, 0x0A},
+ {CS43130_ASP_CH_1_LOC, 0x00},
+ {CS43130_ASP_CH_2_LOC, 0x00},
+ {CS43130_ASP_CH_1_SZ_EN, 0x06},
+ {CS43130_ASP_CH_2_SZ_EN, 0x0E},
+ {CS43130_XSP_CH_1_LOC, 0x00},
+ {CS43130_XSP_CH_2_LOC, 0x00},
+ {CS43130_XSP_CH_1_SZ_EN, 0x06},
+ {CS43130_XSP_CH_2_SZ_EN, 0x0E},
+ {CS43130_DSD_VOL_B, 0x78},
+ {CS43130_DSD_VOL_A, 0x78},
+ {CS43130_DSD_PATH_CTL_1, 0xA8},
+ {CS43130_DSD_INT_CFG, 0x00},
+ {CS43130_DSD_PATH_CTL_2, 0x02},
+ {CS43130_DSD_PCM_MIX_CTL, 0x00},
+ {CS43130_DSD_PATH_CTL_3, 0x40},
+ {CS43130_HP_OUT_CTL_1, 0x30},
+ {CS43130_PCM_FILT_OPT, 0x02},
+ {CS43130_PCM_VOL_B, 0x78},
+ {CS43130_PCM_VOL_A, 0x78},
+ {CS43130_PCM_PATH_CTL_1, 0xA8},
+ {CS43130_PCM_PATH_CTL_2, 0x00},
+ {CS43130_CLASS_H_CTL, 0x1E},
+ {CS43130_HP_DETECT, 0x04},
+ {CS43130_HP_LOAD_1, 0x00},
+ {CS43130_HP_MEAS_LOAD_1, 0x00},
+ {CS43130_HP_MEAS_LOAD_2, 0x00},
+ {CS43130_INT_MASK_1, 0xFF},
+ {CS43130_INT_MASK_2, 0xFF},
+ {CS43130_INT_MASK_3, 0xFF},
+ {CS43130_INT_MASK_4, 0xFF},
+ {CS43130_INT_MASK_5, 0xFF},
+};
+
+static bool cs43130_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
+ case CS43130_HP_DC_STAT_1 ... CS43130_HP_DC_STAT_2:
+ case CS43130_HP_AC_STAT_1 ... CS43130_HP_AC_STAT_2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs43130_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS43130_DEVID_AB ... CS43130_SYS_CLK_CTL_1:
+ case CS43130_SP_SRATE ... CS43130_PAD_INT_CFG:
+ case CS43130_PWDN_CTL:
+ case CS43130_CRYSTAL_SET:
+ case CS43130_PLL_SET_1 ... CS43130_PLL_SET_5:
+ case CS43130_PLL_SET_6:
+ case CS43130_PLL_SET_7:
+ case CS43130_PLL_SET_8:
+ case CS43130_PLL_SET_9:
+ case CS43130_PLL_SET_10:
+ case CS43130_CLKOUT_CTL:
+ case CS43130_ASP_NUM_1 ... CS43130_ASP_FRAME_CONF:
+ case CS43130_XSP_NUM_1 ... CS43130_XSP_FRAME_CONF:
+ case CS43130_ASP_CH_1_LOC:
+ case CS43130_ASP_CH_2_LOC:
+ case CS43130_ASP_CH_1_SZ_EN:
+ case CS43130_ASP_CH_2_SZ_EN:
+ case CS43130_XSP_CH_1_LOC:
+ case CS43130_XSP_CH_2_LOC:
+ case CS43130_XSP_CH_1_SZ_EN:
+ case CS43130_XSP_CH_2_SZ_EN:
+ case CS43130_DSD_VOL_B ... CS43130_DSD_PATH_CTL_3:
+ case CS43130_HP_OUT_CTL_1:
+ case CS43130_PCM_FILT_OPT ... CS43130_PCM_PATH_CTL_2:
+ case CS43130_CLASS_H_CTL:
+ case CS43130_HP_DETECT:
+ case CS43130_HP_STATUS:
+ case CS43130_HP_LOAD_1:
+ case CS43130_HP_MEAS_LOAD_1:
+ case CS43130_HP_MEAS_LOAD_2:
+ case CS43130_HP_DC_STAT_1:
+ case CS43130_HP_DC_STAT_2:
+ case CS43130_HP_AC_STAT_1:
+ case CS43130_HP_AC_STAT_2:
+ case CS43130_HP_LOAD_STAT:
+ case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
+ case CS43130_INT_MASK_1 ... CS43130_INT_MASK_5:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs43130_precious_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
+ return true;
+ default:
+ return false;
+ }
+}
+
+struct cs43130_pll_params {
+ unsigned int pll_in;
+ u8 sclk_prediv;
+ u8 pll_div_int;
+ u32 pll_div_frac;
+ u8 pll_mode;
+ u8 pll_divout;
+ unsigned int pll_out;
+ u8 pll_cal_ratio;
+};
+
+static const struct cs43130_pll_params pll_ratio_table[] = {
+ {9600000, 0x02, 0x49, 0x800000, 0x00, 0x08, 22579200, 151},
+ {9600000, 0x02, 0x50, 0x000000, 0x00, 0x08, 24576000, 164},
+
+ {11289600, 0x02, 0X40, 0, 0x01, 0x08, 22579200, 128},
+ {11289600, 0x02, 0x44, 0x06F700, 0x0, 0x08, 24576000, 139},
+
+ {12000000, 0x02, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120},
+ {12000000, 0x02, 0x40, 0x000000, 0x00, 0x08, 24576000, 131},
+
+ {12288000, 0x02, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118},
+ {12288000, 0x02, 0x40, 0x000000, 0x01, 0x08, 24576000, 128},
+
+ {13000000, 0x02, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111},
+ {13000000, 0x02, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121},
+
+ {19200000, 0x03, 0x49, 0x800000, 0x00, 0x08, 22579200, 151},
+ {19200000, 0x03, 0x50, 0x000000, 0x00, 0x08, 24576000, 164},
+
+ {22579200, 0, 0, 0, 0, 0, 22579200, 0},
+ {22579200, 0x03, 0x44, 0x06F700, 0x00, 0x08, 24576000, 139},
+
+ {24000000, 0x03, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120},
+ {24000000, 0x03, 0x40, 0x000000, 0x00, 0x08, 24576000, 131},
+
+ {24576000, 0x03, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118},
+ {24576000, 0, 0, 0, 0, 0, 24576000, 0},
+
+ {26000000, 0x03, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111},
+ {26000000, 0x03, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121},
+};
+
+static const struct cs43130_pll_params *cs43130_get_pll_table(
+ unsigned int freq_in, unsigned int freq_out)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+ if (pll_ratio_table[i].pll_in == freq_in &&
+ pll_ratio_table[i].pll_out == freq_out)
+ return &pll_ratio_table[i];
+ }
+
+ return NULL;
+}
+
+static int cs43130_pll_config(struct snd_soc_codec *codec)
+{
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+ const struct cs43130_pll_params *pll_entry;
+
+ dev_dbg(codec->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n",
+ cs43130->mclk, cs43130->mclk_int);
+
+ pll_entry = cs43130_get_pll_table(cs43130->mclk, cs43130->mclk_int);
+ if (!pll_entry)
+ return -EINVAL;
+
+ if (pll_entry->pll_cal_ratio == 0) {
+ regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1,
+ CS43130_PLL_START_MASK, 0);
+
+ cs43130->pll_bypass = true;
+ return 0;
+ }
+
+ cs43130->pll_bypass = false;
+
+ regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_2,
+ CS43130_PLL_DIV_DATA_MASK,
+ pll_entry->pll_div_frac >>
+ CS43130_PLL_DIV_FRAC_0_DATA_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_3,
+ CS43130_PLL_DIV_DATA_MASK,
+ pll_entry->pll_div_frac >>
+ CS43130_PLL_DIV_FRAC_1_DATA_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_4,
+ CS43130_PLL_DIV_DATA_MASK,
+ pll_entry->pll_div_frac >>
+ CS43130_PLL_DIV_FRAC_2_DATA_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_PLL_SET_5,
+ pll_entry->pll_div_int);
+ regmap_write(cs43130->regmap, CS43130_PLL_SET_6, pll_entry->pll_divout);
+ regmap_write(cs43130->regmap, CS43130_PLL_SET_7,
+ pll_entry->pll_cal_ratio);
+ regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_8,
+ CS43130_PLL_MODE_MASK,
+ pll_entry->pll_mode << CS43130_PLL_MODE_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_PLL_SET_9,
+ pll_entry->sclk_prediv);
+ regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1,
+ CS43130_PLL_START_MASK, 1);
+
+ return 0;
+}
+
+static int cs43130_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ int ret = 0;
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ switch (freq_in) {
+ case 9600000:
+ case 11289600:
+ case 12000000:
+ case 12288000:
+ case 13000000:
+ case 19200000:
+ case 22579200:
+ case 24000000:
+ case 24576000:
+ case 26000000:
+ cs43130->mclk = freq_in;
+ break;
+ default:
+ dev_err(codec->dev,
+ "unsupported pll input reference clock:%d\n", freq_in);
+ return -EINVAL;
+ }
+
+ switch (freq_out) {
+ case 22579200:
+ cs43130->mclk_int = freq_out;
+ break;
+ case 24576000:
+ cs43130->mclk_int = freq_out;
+ break;
+ default:
+ dev_err(codec->dev,
+ "unsupported pll output ref clock: %u\n", freq_out);
+ return -EINVAL;
+ }
+
+ ret = cs43130_pll_config(codec);
+ dev_dbg(codec->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass);
+ return ret;
+}
+
+static int cs43130_change_clksrc(struct snd_soc_codec *codec,
+ enum cs43130_mclk_src_sel src)
+{
+ int ret;
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+ int mclk_int_decoded;
+
+ if (src == cs43130->mclk_int_src) {
+ /* clk source has not changed */
+ return 0;
+ }
+
+ switch (cs43130->mclk_int) {
+ case CS43130_MCLK_22M:
+ mclk_int_decoded = CS43130_MCLK_22P5;
+ break;
+ case CS43130_MCLK_24M:
+ mclk_int_decoded = CS43130_MCLK_24P5;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int);
+ return -EINVAL;
+ }
+
+ switch (src) {
+ case CS43130_MCLK_SRC_EXT:
+ cs43130->pll_bypass = true;
+ cs43130->mclk_int_src = CS43130_MCLK_SRC_EXT;
+ if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) {
+ regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+ CS43130_PDN_XTAL_MASK,
+ 1 << CS43130_PDN_XTAL_SHIFT);
+ } else {
+ reinit_completion(&cs43130->xtal_rdy);
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_XTAL_RDY_INT_MASK, 0);
+ regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+ CS43130_PDN_XTAL_MASK, 0);
+ ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
+ msecs_to_jiffies(100));
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_XTAL_RDY_INT_MASK,
+ 1 << CS43130_XTAL_RDY_INT_SHIFT);
+ if (ret == 0) {
+ dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+ CS43130_MCLK_SRC_SEL_MASK,
+ src << CS43130_MCLK_SRC_SEL_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+ CS43130_MCLK_INT_MASK,
+ mclk_int_decoded << CS43130_MCLK_INT_SHIFT);
+ usleep_range(150, 200);
+
+ regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+ CS43130_PDN_PLL_MASK,
+ 1 << CS43130_PDN_PLL_SHIFT);
+ break;
+ case CS43130_MCLK_SRC_PLL:
+ cs43130->pll_bypass = false;
+ cs43130->mclk_int_src = CS43130_MCLK_SRC_PLL;
+ if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) {
+ regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+ CS43130_PDN_XTAL_MASK,
+ 1 << CS43130_PDN_XTAL_SHIFT);
+ } else {
+ reinit_completion(&cs43130->xtal_rdy);
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_XTAL_RDY_INT_MASK, 0);
+ regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+ CS43130_PDN_XTAL_MASK, 0);
+ ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
+ msecs_to_jiffies(100));
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_XTAL_RDY_INT_MASK,
+ 1 << CS43130_XTAL_RDY_INT_SHIFT);
+ if (ret == 0) {
+ dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ reinit_completion(&cs43130->pll_rdy);
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_PLL_RDY_INT_MASK, 0);
+ regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+ CS43130_PDN_PLL_MASK, 0);
+ ret = wait_for_completion_timeout(&cs43130->pll_rdy,
+ msecs_to_jiffies(100));
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_PLL_RDY_INT_MASK,
+ 1 << CS43130_PLL_RDY_INT_SHIFT);
+ if (ret == 0) {
+ dev_err(codec->dev, "Timeout waiting for PLL_READY interrupt\n");
+ return -ETIMEDOUT;
+ }
+
+ regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+ CS43130_MCLK_SRC_SEL_MASK,
+ src << CS43130_MCLK_SRC_SEL_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+ CS43130_MCLK_INT_MASK,
+ mclk_int_decoded << CS43130_MCLK_INT_SHIFT);
+ usleep_range(150, 200);
+ break;
+ case CS43130_MCLK_SRC_RCO:
+ cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
+
+ regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+ CS43130_MCLK_SRC_SEL_MASK,
+ src << CS43130_MCLK_SRC_SEL_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+ CS43130_MCLK_INT_MASK,
+ CS43130_MCLK_22P5 << CS43130_MCLK_INT_SHIFT);
+ usleep_range(150, 200);
+
+ regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+ CS43130_PDN_XTAL_MASK,
+ 1 << CS43130_PDN_XTAL_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+ CS43130_PDN_PLL_MASK,
+ 1 << CS43130_PDN_PLL_SHIFT);
+ break;
+ default:
+ dev_err(codec->dev, "Invalid MCLK source value\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct cs43130_bitwidth_map cs43130_bitwidth_table[] = {
+ {8, CS43130_SP_BIT_SIZE_8, CS43130_CH_BIT_SIZE_8},
+ {16, CS43130_SP_BIT_SIZE_16, CS43130_CH_BIT_SIZE_16},
+ {24, CS43130_SP_BIT_SIZE_24, CS43130_CH_BIT_SIZE_24},
+ {32, CS43130_SP_BIT_SIZE_32, CS43130_CH_BIT_SIZE_32},
+};
+
+static const struct cs43130_bitwidth_map *cs43130_get_bitwidth_table(
+ unsigned int bitwidth)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cs43130_bitwidth_table); i++) {
+ if (cs43130_bitwidth_table[i].bitwidth == bitwidth)
+ return &cs43130_bitwidth_table[i];
+ }
+
+ return NULL;
+}
+
+static int cs43130_set_bitwidth(int dai_id, unsigned int bitwidth_dai,
+ struct regmap *regmap)
+{
+ const struct cs43130_bitwidth_map *bw_map;
+
+ bw_map = cs43130_get_bitwidth_table(bitwidth_dai);
+ if (!bw_map)
+ return -EINVAL;
+
+ switch (dai_id) {
+ case CS43130_ASP_PCM_DAI:
+ case CS43130_ASP_DOP_DAI:
+ regmap_update_bits(regmap, CS43130_ASP_CH_1_SZ_EN,
+ CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+ regmap_update_bits(regmap, CS43130_ASP_CH_2_SZ_EN,
+ CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+ regmap_update_bits(regmap, CS43130_SP_BITSIZE,
+ CS43130_ASP_BITSIZE_MASK, bw_map->sp_bit);
+ break;
+ case CS43130_XSP_DOP_DAI:
+ regmap_update_bits(regmap, CS43130_XSP_CH_1_SZ_EN,
+ CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+ regmap_update_bits(regmap, CS43130_XSP_CH_2_SZ_EN,
+ CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+ regmap_update_bits(regmap, CS43130_SP_BITSIZE,
+ CS43130_XSP_BITSIZE_MASK, bw_map->sp_bit <<
+ CS43130_XSP_BITSIZE_SHIFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct cs43130_rate_map cs43130_rate_table[] = {
+ {32000, CS43130_ASP_SPRATE_32K},
+ {44100, CS43130_ASP_SPRATE_44_1K},
+ {48000, CS43130_ASP_SPRATE_48K},
+ {88200, CS43130_ASP_SPRATE_88_2K},
+ {96000, CS43130_ASP_SPRATE_96K},
+ {176400, CS43130_ASP_SPRATE_176_4K},
+ {192000, CS43130_ASP_SPRATE_192K},
+ {352800, CS43130_ASP_SPRATE_352_8K},
+ {384000, CS43130_ASP_SPRATE_384K},
+};
+
+static const struct cs43130_rate_map *cs43130_get_rate_table(int fs)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cs43130_rate_table); i++) {
+ if (cs43130_rate_table[i].fs == fs)
+ return &cs43130_rate_table[i];
+ }
+
+ return NULL;
+}
+
+static const struct cs43130_clk_gen *cs43130_get_clk_gen(int mclk_int, int fs,
+ const struct cs43130_clk_gen *clk_gen_table, int len_clk_gen_table)
+{
+ int i;
+
+ for (i = 0; i < len_clk_gen_table; i++) {
+ if (clk_gen_table[i].mclk_int == mclk_int &&
+ clk_gen_table[i].fs == fs)
+ return &clk_gen_table[i];
+ }
+
+ return NULL;
+}
+
+static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk,
+ struct snd_pcm_hw_params *params,
+ struct cs43130_private *cs43130)
+{
+ u16 frm_size;
+ u16 hi_size;
+ u8 frm_delay;
+ u8 frm_phase;
+ u8 frm_data;
+ u8 sclk_edge;
+ u8 lrck_edge;
+ u8 clk_data;
+ u8 loc_ch1;
+ u8 loc_ch2;
+ u8 dai_mode_val;
+ const struct cs43130_clk_gen *clk_gen;
+
+ switch (cs43130->dais[dai_id].dai_format) {
+ case SND_SOC_DAIFMT_I2S:
+ hi_size = bitwidth_sclk;
+ frm_delay = 2;
+ frm_phase = 0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ hi_size = bitwidth_sclk;
+ frm_delay = 2;
+ frm_phase = 1;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ hi_size = 1;
+ frm_delay = 2;
+ frm_phase = 1;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ hi_size = 1;
+ frm_delay = 0;
+ frm_phase = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (cs43130->dais[dai_id].dai_mode) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ dai_mode_val = 0;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ dai_mode_val = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ frm_size = bitwidth_sclk * params_channels(params);
+ sclk_edge = 1;
+ lrck_edge = 0;
+ loc_ch1 = 0;
+ loc_ch2 = bitwidth_sclk * (params_channels(params) - 1);
+
+ frm_data = frm_delay & CS43130_SP_FSD_MASK;
+ frm_data |= (frm_phase << CS43130_SP_STP_SHIFT) & CS43130_SP_STP_MASK;
+
+ clk_data = lrck_edge & CS43130_SP_LCPOL_IN_MASK;
+ clk_data |= (lrck_edge << CS43130_SP_LCPOL_OUT_SHIFT) &
+ CS43130_SP_LCPOL_OUT_MASK;
+ clk_data |= (sclk_edge << CS43130_SP_SCPOL_IN_SHIFT) &
+ CS43130_SP_SCPOL_IN_MASK;
+ clk_data |= (sclk_edge << CS43130_SP_SCPOL_OUT_SHIFT) &
+ CS43130_SP_SCPOL_OUT_MASK;
+ clk_data |= (dai_mode_val << CS43130_SP_MODE_SHIFT) &
+ CS43130_SP_MODE_MASK;
+
+ switch (dai_id) {
+ case CS43130_ASP_PCM_DAI:
+ case CS43130_ASP_DOP_DAI:
+ regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_1,
+ CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+ CS43130_SP_LCPR_LSB_DATA_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_2,
+ CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+ CS43130_SP_LCPR_MSB_DATA_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_1,
+ CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+ CS43130_SP_LCHI_LSB_DATA_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_2,
+ CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+ CS43130_SP_LCHI_MSB_DATA_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_ASP_FRAME_CONF, frm_data);
+ regmap_write(cs43130->regmap, CS43130_ASP_CH_1_LOC, loc_ch1);
+ regmap_write(cs43130->regmap, CS43130_ASP_CH_2_LOC, loc_ch2);
+ regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_1_SZ_EN,
+ CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_2_SZ_EN,
+ CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_ASP_CLOCK_CONF, clk_data);
+ break;
+ case CS43130_XSP_DOP_DAI:
+ regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_1,
+ CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+ CS43130_SP_LCPR_LSB_DATA_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_2,
+ CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+ CS43130_SP_LCPR_MSB_DATA_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_1,
+ CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+ CS43130_SP_LCHI_LSB_DATA_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_2,
+ CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+ CS43130_SP_LCHI_MSB_DATA_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_XSP_FRAME_CONF, frm_data);
+ regmap_write(cs43130->regmap, CS43130_XSP_CH_1_LOC, loc_ch1);
+ regmap_write(cs43130->regmap, CS43130_XSP_CH_2_LOC, loc_ch2);
+ regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_1_SZ_EN,
+ CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_2_SZ_EN,
+ CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_XSP_CLOCK_CONF, clk_data);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (frm_size) {
+ case 16:
+ clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+ params_rate(params),
+ cs43130_16_clk_gen,
+ ARRAY_SIZE(cs43130_16_clk_gen));
+ break;
+ case 32:
+ clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+ params_rate(params),
+ cs43130_32_clk_gen,
+ ARRAY_SIZE(cs43130_32_clk_gen));
+ break;
+ case 48:
+ clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+ params_rate(params),
+ cs43130_48_clk_gen,
+ ARRAY_SIZE(cs43130_48_clk_gen));
+ break;
+ case 64:
+ clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+ params_rate(params),
+ cs43130_64_clk_gen,
+ ARRAY_SIZE(cs43130_64_clk_gen));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!clk_gen)
+ return -EINVAL;
+
+ switch (dai_id) {
+ case CS43130_ASP_PCM_DAI:
+ case CS43130_ASP_DOP_DAI:
+ regmap_write(cs43130->regmap, CS43130_ASP_DEN_1,
+ (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >>
+ CS43130_SP_M_LSB_DATA_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_ASP_DEN_2,
+ (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >>
+ CS43130_SP_M_MSB_DATA_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_ASP_NUM_1,
+ (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >>
+ CS43130_SP_N_LSB_DATA_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_ASP_NUM_2,
+ (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >>
+ CS43130_SP_N_MSB_DATA_SHIFT);
+ break;
+ case CS43130_XSP_DOP_DAI:
+ regmap_write(cs43130->regmap, CS43130_XSP_DEN_1,
+ (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >>
+ CS43130_SP_M_LSB_DATA_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_XSP_DEN_2,
+ (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >>
+ CS43130_SP_M_MSB_DATA_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_XSP_NUM_1,
+ (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >>
+ CS43130_SP_N_LSB_DATA_SHIFT);
+ regmap_write(cs43130->regmap, CS43130_XSP_NUM_2,
+ (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >>
+ CS43130_SP_N_MSB_DATA_SHIFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs43130_pcm_dsd_mix(bool en, struct regmap *regmap)
+{
+ if (en) {
+ regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+ CS43130_MIX_PCM_PREP_MASK,
+ 1 << CS43130_MIX_PCM_PREP_SHIFT);
+ usleep_range(6000, 6050);
+ regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+ CS43130_MIX_PCM_DSD_MASK,
+ 1 << CS43130_MIX_PCM_DSD_SHIFT);
+ } else {
+ regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+ CS43130_MIX_PCM_DSD_MASK,
+ 0 << CS43130_MIX_PCM_DSD_SHIFT);
+ usleep_range(1600, 1650);
+ regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+ CS43130_MIX_PCM_PREP_MASK,
+ 0 << CS43130_MIX_PCM_PREP_SHIFT);
+ }
+
+ return 0;
+}
+
+static int cs43130_dsd_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 cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+ unsigned int required_clk;
+ u8 dsd_speed;
+
+ mutex_lock(&cs43130->clk_mutex);
+ if (!cs43130->clk_req) {
+ /* no DAI is currently using clk */
+ if (!(CS43130_MCLK_22M % params_rate(params)))
+ required_clk = CS43130_MCLK_22M;
+ else
+ required_clk = CS43130_MCLK_24M;
+
+ cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk);
+ if (cs43130->pll_bypass)
+ cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT);
+ else
+ cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
+ }
+
+ cs43130->clk_req++;
+ if (cs43130->clk_req == 2)
+ cs43130_pcm_dsd_mix(true, cs43130->regmap);
+ mutex_unlock(&cs43130->clk_mutex);
+
+ switch (params_rate(params)) {
+ case 176400:
+ dsd_speed = 0;
+ break;
+ case 352800:
+ dsd_speed = 1;
+ break;
+ default:
+ dev_err(codec->dev, "Rate(%u) not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ if (cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM)
+ regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG,
+ CS43130_DSD_MASTER, CS43130_DSD_MASTER);
+ else
+ regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG,
+ CS43130_DSD_MASTER, 0);
+
+ regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+ CS43130_DSD_SPEED_MASK,
+ dsd_speed << CS43130_DSD_SPEED_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+ CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_DSD <<
+ CS43130_DSD_SRC_SHIFT);
+
+ return 0;
+}
+
+static int cs43130_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 cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+ const struct cs43130_rate_map *rate_map;
+ unsigned int sclk = cs43130->dais[dai->id].sclk;
+ unsigned int bitwidth_sclk;
+ unsigned int bitwidth_dai = (unsigned int)(params_width(params));
+ unsigned int required_clk;
+ u8 dsd_speed;
+
+ mutex_lock(&cs43130->clk_mutex);
+ if (!cs43130->clk_req) {
+ /* no DAI is currently using clk */
+ if (!(CS43130_MCLK_22M % params_rate(params)))
+ required_clk = CS43130_MCLK_22M;
+ else
+ required_clk = CS43130_MCLK_24M;
+
+ cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk);
+ if (cs43130->pll_bypass)
+ cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT);
+ else
+ cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
+ }
+
+ cs43130->clk_req++;
+ if (cs43130->clk_req == 2)
+ cs43130_pcm_dsd_mix(true, cs43130->regmap);
+ mutex_unlock(&cs43130->clk_mutex);
+
+ switch (dai->id) {
+ case CS43130_ASP_DOP_DAI:
+ case CS43130_XSP_DOP_DAI:
+ /* DoP bitwidth is always 24-bit */
+ bitwidth_dai = 24;
+ sclk = params_rate(params) * bitwidth_dai *
+ params_channels(params);
+
+ switch (params_rate(params)) {
+ case 176400:
+ dsd_speed = 0;
+ break;
+ case 352800:
+ dsd_speed = 1;
+ break;
+ default:
+ dev_err(codec->dev, "Rate(%u) not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+ CS43130_DSD_SPEED_MASK,
+ dsd_speed << CS43130_DSD_SPEED_SHIFT);
+ break;
+ case CS43130_ASP_PCM_DAI:
+ rate_map = cs43130_get_rate_table(params_rate(params));
+ if (!rate_map)
+ return -EINVAL;
+
+ regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val);
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAI (%d)\n", dai->id);
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case CS43130_ASP_DOP_DAI:
+ regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+ CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_ASP <<
+ CS43130_DSD_SRC_SHIFT);
+ break;
+ case CS43130_XSP_DOP_DAI:
+ regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+ CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_XSP <<
+ CS43130_DSD_SRC_SHIFT);
+ }
+
+ if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM)
+ /* Calculate SCLK in master mode if unassigned */
+ sclk = params_rate(params) * bitwidth_dai *
+ params_channels(params);
+
+ if (!sclk) {
+ /* at this point, SCLK must be set */
+ dev_err(codec->dev, "SCLK freq is not set\n");
+ return -EINVAL;
+ }
+
+ bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params);
+ if (bitwidth_sclk < bitwidth_dai) {
+ dev_err(codec->dev, "Format not supported: SCLK freq is too low\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(codec->dev,
+ "sclk = %u, fs = %d, bitwidth_dai = %u\n",
+ sclk, params_rate(params), bitwidth_dai);
+
+ dev_dbg(codec->dev,
+ "bitwidth_sclk = %u, num_ch = %u\n",
+ bitwidth_sclk, params_channels(params));
+
+ cs43130_set_bitwidth(dai->id, bitwidth_dai, cs43130->regmap);
+ cs43130_set_sp_fmt(dai->id, bitwidth_sclk, params, cs43130);
+
+ return 0;
+}
+
+static int cs43130_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ mutex_lock(&cs43130->clk_mutex);
+ cs43130->clk_req--;
+ if (!cs43130->clk_req) {
+ /* no DAI is currently using clk */
+ cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO);
+ cs43130_pcm_dsd_mix(false, cs43130->regmap);
+ }
+ mutex_unlock(&cs43130->clk_mutex);
+
+ return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(pcm_vol_tlv, -12750, 50, 1);
+
+static const char * const pcm_ch_text[] = {
+ "Left-Right Ch",
+ "Left-Left Ch",
+ "Right-Left Ch",
+ "Right-Right Ch",
+};
+
+static const struct reg_sequence pcm_ch_en_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {0x180005, 0x8C},
+ {0x180007, 0xAB},
+ {0x180015, 0x31},
+ {0x180017, 0xB2},
+ {0x180025, 0x30},
+ {0x180027, 0x84},
+ {0x180035, 0x9C},
+ {0x180037, 0xAE},
+ {0x18000D, 0x24},
+ {0x18000F, 0xA3},
+ {0x18001D, 0x05},
+ {0x18001F, 0xD4},
+ {0x18002D, 0x0B},
+ {0x18002F, 0xC7},
+ {0x18003D, 0x71},
+ {0x18003F, 0xE7},
+ {CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence pcm_ch_dis_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {0x180005, 0x24},
+ {0x180007, 0xA3},
+ {0x180015, 0x05},
+ {0x180017, 0xD4},
+ {0x180025, 0x0B},
+ {0x180027, 0xC7},
+ {0x180035, 0x71},
+ {0x180037, 0xE7},
+ {0x18000D, 0x8C},
+ {0x18000F, 0xAB},
+ {0x18001D, 0x31},
+ {0x18001F, 0xB2},
+ {0x18002D, 0x30},
+ {0x18002F, 0x84},
+ {0x18003D, 0x9C},
+ {0x18003F, 0xAE},
+ {CS43130_DXD1, 0},
+};
+
+static int cs43130_pcm_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return snd_soc_get_enum_double(kcontrol, ucontrol);
+}
+
+static int cs43130_pcm_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+ switch (cs43130->dev_id) {
+ case CS43131_CHIP_ID:
+ case CS43198_CHIP_ID:
+ if (val >= 2)
+ regmap_multi_reg_write(cs43130->regmap, pcm_ch_en_seq,
+ ARRAY_SIZE(pcm_ch_en_seq));
+ else
+ regmap_multi_reg_write(cs43130->regmap, pcm_ch_dis_seq,
+ ARRAY_SIZE(pcm_ch_dis_seq));
+ }
+
+ return snd_soc_put_enum_double(kcontrol, ucontrol);
+}
+
+static SOC_ENUM_SINGLE_DECL(pcm_ch_enum, CS43130_PCM_PATH_CTL_2, 0,
+ pcm_ch_text);
+
+static const char * const pcm_spd_texts[] = {
+ "Fast",
+ "Slow",
+};
+
+static SOC_ENUM_SINGLE_DECL(pcm_spd_enum, CS43130_PCM_FILT_OPT, 7,
+ pcm_spd_texts);
+
+static const char * const dsd_texts[] = {
+ "Off",
+ "BCKA Mode",
+ "BCKD Mode",
+};
+
+static const unsigned int dsd_values[] = {
+ CS43130_DSD_SRC_DSD,
+ CS43130_DSD_SRC_ASP,
+ CS43130_DSD_SRC_XSP,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dsd_enum, CS43130_DSD_INT_CFG, 0, 0x03,
+ dsd_texts, dsd_values);
+
+static const struct snd_kcontrol_new cs43130_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("Master Playback Volume",
+ CS43130_PCM_VOL_A, CS43130_PCM_VOL_B, 0, 0xFF, 1,
+ pcm_vol_tlv),
+ SOC_DOUBLE_R_TLV("Master DSD Playback Volume",
+ CS43130_DSD_VOL_A, CS43130_DSD_VOL_B, 0, 0xFF, 1,
+ pcm_vol_tlv),
+ SOC_ENUM_EXT("PCM Ch Select", pcm_ch_enum, cs43130_pcm_ch_get,
+ cs43130_pcm_ch_put),
+ SOC_ENUM("PCM Filter Speed", pcm_spd_enum),
+ SOC_SINGLE("PCM Phase Compensation", CS43130_PCM_FILT_OPT, 6, 1, 0),
+ SOC_SINGLE("PCM Nonoversample Emulate", CS43130_PCM_FILT_OPT, 5, 1, 0),
+ SOC_SINGLE("PCM High-pass Filter", CS43130_PCM_FILT_OPT, 1, 1, 0),
+ SOC_SINGLE("PCM De-emphasis Filter", CS43130_PCM_FILT_OPT, 0, 1, 0),
+ SOC_ENUM("DSD Phase Modulation", dsd_enum),
+};
+
+static const struct reg_sequence pcm_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD7, 0x01},
+ {CS43130_DXD8, 0},
+ {CS43130_DXD9, 0x01},
+ {CS43130_DXD3, 0x12},
+ {CS43130_DXD4, 0},
+ {CS43130_DXD10, 0x28},
+ {CS43130_DXD11, 0x28},
+ {CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence dsd_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD7, 0x01},
+ {CS43130_DXD8, 0},
+ {CS43130_DXD9, 0x01},
+ {CS43130_DXD3, 0x12},
+ {CS43130_DXD4, 0},
+ {CS43130_DXD10, 0x1E},
+ {CS43130_DXD11, 0x20},
+ {CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence pop_free_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD12, 0x0A},
+ {CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence pop_free_seq2[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD13, 0x20},
+ {CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence mute_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD3, 0x12},
+ {CS43130_DXD5, 0x02},
+ {CS43130_DXD4, 0x12},
+ {CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence unmute_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD3, 0x10},
+ {CS43130_DXD5, 0},
+ {CS43130_DXD4, 0x16},
+ {CS43130_DXD1, 0},
+};
+
+static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, dsd_seq,
+ ARRAY_SIZE(dsd_seq));
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_1,
+ CS43130_MUTE_MASK, 0);
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, unmute_seq,
+ ARRAY_SIZE(unmute_seq));
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, mute_seq,
+ ARRAY_SIZE(mute_seq));
+ regmap_update_bits(cs43130->regmap,
+ CS43130_DSD_PATH_CTL_1,
+ CS43130_MUTE_MASK, CS43130_MUTE_EN);
+ /*
+ * DSD Power Down Sequence
+ * According to Design, 130ms is preferred.
+ */
+ msleep(130);
+ break;
+ case CS43131_CHIP_ID:
+ case CS43198_CHIP_ID:
+ regmap_update_bits(cs43130->regmap,
+ CS43130_DSD_PATH_CTL_1,
+ CS43130_MUTE_MASK, CS43130_MUTE_EN);
+ }
+ break;
+ default:
+ dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cs43130_pcm_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, pcm_seq,
+ ARRAY_SIZE(pcm_seq));
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(cs43130->regmap, CS43130_PCM_PATH_CTL_1,
+ CS43130_MUTE_MASK, 0);
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, unmute_seq,
+ ARRAY_SIZE(unmute_seq));
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, mute_seq,
+ ARRAY_SIZE(mute_seq));
+ regmap_update_bits(cs43130->regmap,
+ CS43130_PCM_PATH_CTL_1,
+ CS43130_MUTE_MASK, CS43130_MUTE_EN);
+ /*
+ * PCM Power Down Sequence
+ * According to Design, 130ms is preferred.
+ */
+ msleep(130);
+ break;
+ case CS43131_CHIP_ID:
+ case CS43198_CHIP_ID:
+ regmap_update_bits(cs43130->regmap,
+ CS43130_PCM_PATH_CTL_1,
+ CS43130_MUTE_MASK, CS43130_MUTE_EN);
+ }
+ break;
+ default:
+ dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct reg_sequence dac_postpmu_seq[] = {
+ {CS43130_DXD9, 0x0C},
+ {CS43130_DXD3, 0x10},
+ {CS43130_DXD4, 0x20},
+};
+
+static const struct reg_sequence dac_postpmd_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD6, 0x01},
+ {CS43130_DXD1, 0},
+};
+
+static int cs43130_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, pop_free_seq,
+ ARRAY_SIZE(pop_free_seq));
+ break;
+ case CS43131_CHIP_ID:
+ case CS43198_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, pop_free_seq2,
+ ARRAY_SIZE(pop_free_seq2));
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(10000, 10050);
+
+ regmap_write(cs43130->regmap, CS43130_DXD1, 0x99);
+
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, dac_postpmu_seq,
+ ARRAY_SIZE(dac_postpmu_seq));
+ /*
+ * Per datasheet, Sec. PCM Power-Up Sequence.
+ * According to Design, CS43130_DXD12 must be 0 to meet
+ * THDN and Dynamic Range spec.
+ */
+ msleep(1000);
+ regmap_write(cs43130->regmap, CS43130_DXD12, 0);
+ break;
+ case CS43131_CHIP_ID:
+ case CS43198_CHIP_ID:
+ usleep_range(12000, 12010);
+ regmap_write(cs43130->regmap, CS43130_DXD13, 0);
+ }
+
+ regmap_write(cs43130->regmap, CS43130_DXD1, 0);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ regmap_multi_reg_write(cs43130->regmap, dac_postpmd_seq,
+ ARRAY_SIZE(dac_postpmd_seq));
+ }
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAC event = 0x%x\n", event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct reg_sequence hpin_prepmd_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD15, 0x64},
+ {CS43130_DXD14, 0},
+ {CS43130_DXD2, 0},
+ {CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence hpin_postpmu_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD2, 1},
+ {CS43130_DXD14, 0xDC},
+ {CS43130_DXD15, 0xE4},
+ {CS43130_DXD1, 0},
+};
+
+static int cs43130_hpin_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_multi_reg_write(cs43130->regmap, hpin_prepmd_seq,
+ ARRAY_SIZE(hpin_prepmd_seq));
+ break;
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_multi_reg_write(cs43130->regmap, hpin_postpmu_seq,
+ ARRAY_SIZE(hpin_postpmu_seq));
+ break;
+ default:
+ dev_err(codec->dev, "Invalid HPIN event = 0x%x\n", event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget digital_hp_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("HPOUTA"),
+ SND_SOC_DAPM_OUTPUT("HPOUTB"),
+
+ SND_SOC_DAPM_AIF_IN_E("ASPIN PCM", NULL, 0, CS43130_PWDN_CTL,
+ CS43130_PDN_ASP_SHIFT, 1, cs43130_pcm_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD)),
+
+ SND_SOC_DAPM_AIF_IN_E("ASPIN DoP", NULL, 0, CS43130_PWDN_CTL,
+ CS43130_PDN_ASP_SHIFT, 1, cs43130_dsd_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD)),
+
+ SND_SOC_DAPM_AIF_IN_E("XSPIN DoP", NULL, 0, CS43130_PWDN_CTL,
+ CS43130_PDN_XSP_SHIFT, 1, cs43130_dsd_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD)),
+
+ SND_SOC_DAPM_AIF_IN_E("XSPIN DSD", NULL, 0, CS43130_PWDN_CTL,
+ CS43130_PDN_DSDIF_SHIFT, 1, cs43130_dsd_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD)),
+
+ SND_SOC_DAPM_DAC("DSD", NULL, CS43130_DSD_PATH_CTL_2,
+ CS43130_DSD_EN_SHIFT, 0),
+
+ SND_SOC_DAPM_DAC_E("HiFi DAC", NULL, CS43130_PWDN_CTL,
+ CS43130_PDN_HP_SHIFT, 1, cs43130_dac_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD)),
+};
+
+static const struct snd_soc_dapm_widget analog_hp_widgets[] = {
+ SND_SOC_DAPM_DAC_E("Analog Playback", NULL, CS43130_HP_OUT_CTL_1,
+ CS43130_HP_IN_EN_SHIFT, 0, cs43130_hpin_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)),
+};
+
+static struct snd_soc_dapm_widget all_hp_widgets[
+ ARRAY_SIZE(digital_hp_widgets) +
+ ARRAY_SIZE(analog_hp_widgets)];
+
+static const struct snd_soc_dapm_route digital_hp_routes[] = {
+ {"ASPIN PCM", NULL, "ASP PCM Playback"},
+ {"ASPIN DoP", NULL, "ASP DoP Playback"},
+ {"XSPIN DoP", NULL, "XSP DoP Playback"},
+ {"XSPIN DSD", NULL, "XSP DSD Playback"},
+ {"DSD", NULL, "ASPIN DoP"},
+ {"DSD", NULL, "XSPIN DoP"},
+ {"DSD", NULL, "XSPIN DSD"},
+ {"HiFi DAC", NULL, "ASPIN PCM"},
+ {"HiFi DAC", NULL, "DSD"},
+ {"HPOUTA", NULL, "HiFi DAC"},
+ {"HPOUTB", NULL, "HiFi DAC"},
+};
+
+static const struct snd_soc_dapm_route analog_hp_routes[] = {
+ {"HPOUTA", NULL, "Analog Playback"},
+ {"HPOUTB", NULL, "Analog Playback"},
+};
+
+static struct snd_soc_dapm_route all_hp_routes[
+ ARRAY_SIZE(digital_hp_routes) +
+ ARRAY_SIZE(analog_hp_routes)];
+
+static const unsigned int cs43130_asp_src_rates[] = {
+ 32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
+};
+
+static const struct snd_pcm_hw_constraint_list cs43130_asp_constraints = {
+ .count = ARRAY_SIZE(cs43130_asp_src_rates),
+ .list = cs43130_asp_src_rates,
+};
+
+static int cs43130_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &cs43130_asp_constraints);
+}
+
+static const unsigned int cs43130_dop_src_rates[] = {
+ 176400, 352800,
+};
+
+static const struct snd_pcm_hw_constraint_list cs43130_dop_constraints = {
+ .count = ARRAY_SIZE(cs43130_dop_src_rates),
+ .list = cs43130_dop_src_rates,
+};
+
+static int cs43130_dop_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &cs43130_dop_constraints);
+}
+
+static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported mode\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_B;
+ break;
+ default:
+ dev_err(codec->dev,
+ "unsupported audio format\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(codec->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n",
+ codec_dai->id,
+ cs43130->dais[codec_dai->id].dai_mode,
+ cs43130->dais[codec_dai->id].dai_format);
+
+ return 0;
+}
+
+static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported DAI format.\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(codec->dev, "dai_mode = 0x%x\n",
+ cs43130->dais[codec_dai->id].dai_mode);
+
+ return 0;
+}
+
+static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ cs43130->dais[codec_dai->id].sclk = freq;
+ dev_dbg(codec->dev, "dai_id = %d, sclk = %u\n", codec_dai->id,
+ cs43130->dais[codec_dai->id].sclk);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops cs43130_pcm_ops = {
+ .startup = cs43130_pcm_startup,
+ .hw_params = cs43130_hw_params,
+ .hw_free = cs43130_hw_free,
+ .set_sysclk = cs43130_set_sysclk,
+ .set_fmt = cs43130_pcm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops cs43130_dop_ops = {
+ .startup = cs43130_dop_startup,
+ .hw_params = cs43130_hw_params,
+ .hw_free = cs43130_hw_free,
+ .set_sysclk = cs43130_set_sysclk,
+ .set_fmt = cs43130_pcm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops cs43130_dsd_ops = {
+ .startup = cs43130_dop_startup,
+ .hw_params = cs43130_dsd_hw_params,
+ .hw_free = cs43130_hw_free,
+ .set_fmt = cs43130_dsd_set_fmt,
+};
+
+static struct snd_soc_dai_driver cs43130_dai[] = {
+ {
+ .name = "cs43130-asp-pcm",
+ .id = CS43130_ASP_PCM_DAI,
+ .playback = {
+ .stream_name = "ASP PCM Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS43130_PCM_FORMATS,
+ },
+ .ops = &cs43130_pcm_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "cs43130-asp-dop",
+ .id = CS43130_ASP_DOP_DAI,
+ .playback = {
+ .stream_name = "ASP DoP Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS43130_DOP_FORMATS,
+ },
+ .ops = &cs43130_dop_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "cs43130-xsp-dop",
+ .id = CS43130_XSP_DOP_DAI,
+ .playback = {
+ .stream_name = "XSP DoP Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS43130_DOP_FORMATS,
+ },
+ .ops = &cs43130_dop_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "cs43130-xsp-dsd",
+ .id = CS43130_XSP_DSD_DAI,
+ .playback = {
+ .stream_name = "XSP DSD Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS43130_DOP_FORMATS,
+ },
+ .ops = &cs43130_dsd_ops,
+ },
+
+};
+
+static int cs43130_codec_set_sysclk(struct snd_soc_codec *codec,
+ int clk_id, int source, unsigned int freq,
+ int dir)
+{
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n",
+ clk_id, source, freq, dir);
+
+ switch (freq) {
+ case CS43130_MCLK_22M:
+ case CS43130_MCLK_24M:
+ cs43130->mclk = freq;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", freq);
+ return -EINVAL;
+ }
+
+ if (source == CS43130_MCLK_SRC_EXT) {
+ cs43130->pll_bypass = true;
+ } else {
+ dev_err(codec->dev, "Invalid MCLK source\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline u16 cs43130_get_ac_reg_val(u16 ac_freq)
+{
+ /* AC freq is counted in 5.94Hz step. */
+ return ac_freq / 6;
+}
+
+static int cs43130_show_dc(struct device *dev, char *buf, u8 ch)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cs43130_private *cs43130 = i2c_get_clientdata(client);
+
+ if (!cs43130->hpload_done)
+ return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n");
+ else
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ cs43130->hpload_dc[ch]);
+}
+
+static ssize_t cs43130_show_dc_l(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return cs43130_show_dc(dev, buf, HP_LEFT);
+}
+
+static ssize_t cs43130_show_dc_r(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return cs43130_show_dc(dev, buf, HP_RIGHT);
+}
+
+static u16 const cs43130_ac_freq[CS43130_AC_FREQ] = {
+ 24,
+ 43,
+ 93,
+ 200,
+ 431,
+ 928,
+ 2000,
+ 4309,
+ 9283,
+ 20000,
+};
+
+static int cs43130_show_ac(struct device *dev, char *buf, u8 ch)
+{
+ int i, j = 0, tmp;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cs43130_private *cs43130 = i2c_get_clientdata(client);
+
+ if (cs43130->hpload_done && cs43130->ac_meas) {
+ for (i = 0; i < ARRAY_SIZE(cs43130_ac_freq); i++) {
+ tmp = scnprintf(buf + j, PAGE_SIZE - j, "%u\n",
+ cs43130->hpload_ac[i][ch]);
+ if (!tmp)
+ break;
+
+ j += tmp;
+ }
+
+ return j;
+ } else {
+ return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n");
+ }
+}
+
+static ssize_t cs43130_show_ac_l(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return cs43130_show_ac(dev, buf, HP_LEFT);
+}
+
+static ssize_t cs43130_show_ac_r(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return cs43130_show_ac(dev, buf, HP_RIGHT);
+}
+
+static DEVICE_ATTR(hpload_dc_l, S_IRUGO, cs43130_show_dc_l, NULL);
+static DEVICE_ATTR(hpload_dc_r, S_IRUGO, cs43130_show_dc_r, NULL);
+static DEVICE_ATTR(hpload_ac_l, S_IRUGO, cs43130_show_ac_l, NULL);
+static DEVICE_ATTR(hpload_ac_r, S_IRUGO, cs43130_show_ac_r, NULL);
+
+static struct reg_sequence hp_en_cal_seq[] = {
+ {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
+ {CS43130_HP_MEAS_LOAD_1, 0},
+ {CS43130_HP_MEAS_LOAD_2, 0},
+ {CS43130_INT_MASK_4, 0},
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD16, 0xBB},
+ {CS43130_DXD12, 0x01},
+ {CS43130_DXD19, 0xCB},
+ {CS43130_DXD17, 0x95},
+ {CS43130_DXD18, 0x0B},
+ {CS43130_DXD1, 0},
+ {CS43130_HP_LOAD_1, 0x80},
+};
+
+static struct reg_sequence hp_en_cal_seq2[] = {
+ {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
+ {CS43130_HP_MEAS_LOAD_1, 0},
+ {CS43130_HP_MEAS_LOAD_2, 0},
+ {CS43130_INT_MASK_4, 0},
+ {CS43130_HP_LOAD_1, 0x80},
+};
+
+static struct reg_sequence hp_dis_cal_seq[] = {
+ {CS43130_HP_LOAD_1, 0x80},
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD12, 0},
+ {CS43130_DXD1, 0},
+ {CS43130_HP_LOAD_1, 0},
+};
+
+static struct reg_sequence hp_dis_cal_seq2[] = {
+ {CS43130_HP_LOAD_1, 0x80},
+ {CS43130_HP_LOAD_1, 0},
+};
+
+static struct reg_sequence hp_dc_ch_l_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD19, 0x0A},
+ {CS43130_DXD17, 0x93},
+ {CS43130_DXD18, 0x0A},
+ {CS43130_DXD1, 0},
+ {CS43130_HP_LOAD_1, 0x80},
+ {CS43130_HP_LOAD_1, 0x81},
+};
+
+static struct reg_sequence hp_dc_ch_l_seq2[] = {
+ {CS43130_HP_LOAD_1, 0x80},
+ {CS43130_HP_LOAD_1, 0x81},
+};
+
+static struct reg_sequence hp_dc_ch_r_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD19, 0x8A},
+ {CS43130_DXD17, 0x15},
+ {CS43130_DXD18, 0x06},
+ {CS43130_DXD1, 0},
+ {CS43130_HP_LOAD_1, 0x90},
+ {CS43130_HP_LOAD_1, 0x91},
+};
+
+static struct reg_sequence hp_dc_ch_r_seq2[] = {
+ {CS43130_HP_LOAD_1, 0x90},
+ {CS43130_HP_LOAD_1, 0x91},
+};
+
+static struct reg_sequence hp_ac_ch_l_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD19, 0x0A},
+ {CS43130_DXD17, 0x93},
+ {CS43130_DXD18, 0x0A},
+ {CS43130_DXD1, 0},
+ {CS43130_HP_LOAD_1, 0x80},
+ {CS43130_HP_LOAD_1, 0x82},
+};
+
+static struct reg_sequence hp_ac_ch_l_seq2[] = {
+ {CS43130_HP_LOAD_1, 0x80},
+ {CS43130_HP_LOAD_1, 0x82},
+};
+
+static struct reg_sequence hp_ac_ch_r_seq[] = {
+ {CS43130_DXD1, 0x99},
+ {CS43130_DXD19, 0x8A},
+ {CS43130_DXD17, 0x15},
+ {CS43130_DXD18, 0x06},
+ {CS43130_DXD1, 0},
+ {CS43130_HP_LOAD_1, 0x90},
+ {CS43130_HP_LOAD_1, 0x92},
+};
+
+static struct reg_sequence hp_ac_ch_r_seq2[] = {
+ {CS43130_HP_LOAD_1, 0x90},
+ {CS43130_HP_LOAD_1, 0x92},
+};
+
+static struct reg_sequence hp_cln_seq[] = {
+ {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
+ {CS43130_HP_MEAS_LOAD_1, 0},
+ {CS43130_HP_MEAS_LOAD_2, 0},
+};
+
+struct reg_sequences {
+ struct reg_sequence *seq;
+ int size;
+ unsigned int msk;
+};
+
+static struct reg_sequences hpload_seq1[] = {
+ {
+ .seq = hp_en_cal_seq,
+ .size = ARRAY_SIZE(hp_en_cal_seq),
+ .msk = CS43130_HPLOAD_ON_INT,
+ },
+ {
+ .seq = hp_dc_ch_l_seq,
+ .size = ARRAY_SIZE(hp_dc_ch_l_seq),
+ .msk = CS43130_HPLOAD_DC_INT,
+ },
+ {
+ .seq = hp_ac_ch_l_seq,
+ .size = ARRAY_SIZE(hp_ac_ch_l_seq),
+ .msk = CS43130_HPLOAD_AC_INT,
+ },
+ {
+ .seq = hp_dis_cal_seq,
+ .size = ARRAY_SIZE(hp_dis_cal_seq),
+ .msk = CS43130_HPLOAD_OFF_INT,
+ },
+ {
+ .seq = hp_en_cal_seq,
+ .size = ARRAY_SIZE(hp_en_cal_seq),
+ .msk = CS43130_HPLOAD_ON_INT,
+ },
+ {
+ .seq = hp_dc_ch_r_seq,
+ .size = ARRAY_SIZE(hp_dc_ch_r_seq),
+ .msk = CS43130_HPLOAD_DC_INT,
+ },
+ {
+ .seq = hp_ac_ch_r_seq,
+ .size = ARRAY_SIZE(hp_ac_ch_r_seq),
+ .msk = CS43130_HPLOAD_AC_INT,
+ },
+};
+
+static struct reg_sequences hpload_seq2[] = {
+ {
+ .seq = hp_en_cal_seq2,
+ .size = ARRAY_SIZE(hp_en_cal_seq2),
+ .msk = CS43130_HPLOAD_ON_INT,
+ },
+ {
+ .seq = hp_dc_ch_l_seq2,
+ .size = ARRAY_SIZE(hp_dc_ch_l_seq2),
+ .msk = CS43130_HPLOAD_DC_INT,
+ },
+ {
+ .seq = hp_ac_ch_l_seq2,
+ .size = ARRAY_SIZE(hp_ac_ch_l_seq2),
+ .msk = CS43130_HPLOAD_AC_INT,
+ },
+ {
+ .seq = hp_dis_cal_seq2,
+ .size = ARRAY_SIZE(hp_dis_cal_seq2),
+ .msk = CS43130_HPLOAD_OFF_INT,
+ },
+ {
+ .seq = hp_en_cal_seq2,
+ .size = ARRAY_SIZE(hp_en_cal_seq2),
+ .msk = CS43130_HPLOAD_ON_INT,
+ },
+ {
+ .seq = hp_dc_ch_r_seq2,
+ .size = ARRAY_SIZE(hp_dc_ch_r_seq2),
+ .msk = CS43130_HPLOAD_DC_INT,
+ },
+ {
+ .seq = hp_ac_ch_r_seq2,
+ .size = ARRAY_SIZE(hp_ac_ch_r_seq2),
+ .msk = CS43130_HPLOAD_AC_INT,
+ },
+};
+
+static int cs43130_update_hpload(unsigned int msk, int ac_idx,
+ struct cs43130_private *cs43130)
+{
+ bool left_ch = true;
+ unsigned int reg;
+ u32 addr;
+ u16 impedance;
+ struct snd_soc_codec *codec = cs43130->codec;
+
+ switch (msk) {
+ case CS43130_HPLOAD_DC_INT:
+ case CS43130_HPLOAD_AC_INT:
+ break;
+ default:
+ return 0;
+ }
+
+ regmap_read(cs43130->regmap, CS43130_HP_LOAD_1, &reg);
+ if (reg & CS43130_HPLOAD_CHN_SEL)
+ left_ch = false;
+
+ if (msk == CS43130_HPLOAD_DC_INT)
+ addr = CS43130_HP_DC_STAT_1;
+ else
+ addr = CS43130_HP_AC_STAT_1;
+
+ regmap_read(cs43130->regmap, addr, &reg);
+ impedance = reg >> 3;
+ regmap_read(cs43130->regmap, addr + 1, &reg);
+ impedance |= reg << 5;
+
+ if (msk == CS43130_HPLOAD_DC_INT) {
+ if (left_ch)
+ cs43130->hpload_dc[HP_LEFT] = impedance;
+ else
+ cs43130->hpload_dc[HP_RIGHT] = impedance;
+
+ dev_dbg(codec->dev, "HP DC impedance (Ch %u): %u\n", !left_ch,
+ impedance);
+ } else {
+ if (left_ch)
+ cs43130->hpload_ac[ac_idx][HP_LEFT] = impedance;
+ else
+ cs43130->hpload_ac[ac_idx][HP_RIGHT] = impedance;
+
+ dev_dbg(codec->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n",
+ cs43130->ac_freq[ac_idx], !left_ch, impedance);
+ }
+
+ return 0;
+}
+
+static int cs43130_hpload_proc(struct cs43130_private *cs43130,
+ struct reg_sequence *seq, int seq_size,
+ unsigned int rslt_msk, int ac_idx)
+{
+ int ret;
+ unsigned int msk;
+ u16 ac_reg_val;
+ struct snd_soc_codec *codec = cs43130->codec;
+
+ reinit_completion(&cs43130->hpload_evt);
+
+ if (rslt_msk == CS43130_HPLOAD_AC_INT) {
+ ac_reg_val = cs43130_get_ac_reg_val(cs43130->ac_freq[ac_idx]);
+ regmap_update_bits(cs43130->regmap, CS43130_HP_LOAD_1,
+ CS43130_HPLOAD_AC_START, 0);
+ regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_1,
+ CS43130_HP_MEAS_LOAD_MASK,
+ ac_reg_val >> CS43130_HP_MEAS_LOAD_1_SHIFT);
+ regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_2,
+ CS43130_HP_MEAS_LOAD_MASK,
+ ac_reg_val >> CS43130_HP_MEAS_LOAD_2_SHIFT);
+ }
+
+ regmap_multi_reg_write(cs43130->regmap, seq,
+ seq_size);
+
+ ret = wait_for_completion_timeout(&cs43130->hpload_evt,
+ msecs_to_jiffies(1000));
+ regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk);
+ if (!ret) {
+ dev_err(codec->dev, "Timeout waiting for HPLOAD interrupt\n");
+ return -1;
+ }
+
+ dev_dbg(codec->dev, "HP load stat: %x, INT_MASK_4: %x\n",
+ cs43130->hpload_stat, msk);
+ if ((cs43130->hpload_stat & (CS43130_HPLOAD_NO_DC_INT |
+ CS43130_HPLOAD_UNPLUG_INT |
+ CS43130_HPLOAD_OOR_INT)) ||
+ !(cs43130->hpload_stat & rslt_msk)) {
+ dev_dbg(codec->dev, "HP load measure failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static const struct reg_sequence hv_seq[][2] = {
+ {
+ {CS43130_CLASS_H_CTL, 0x1C},
+ {CS43130_HP_OUT_CTL_1, 0x10},
+ },
+ {
+ {CS43130_CLASS_H_CTL, 0x1E},
+ {CS43130_HP_OUT_CTL_1, 0x20},
+ },
+ {
+ {CS43130_CLASS_H_CTL, 0x1E},
+ {CS43130_HP_OUT_CTL_1, 0x30},
+ },
+};
+
+static int cs43130_set_hv(struct regmap *regmap, u16 hpload_dc,
+ const u16 *dc_threshold)
+{
+ int i;
+
+ for (i = 0; i < CS43130_DC_THRESHOLD; i++) {
+ if (hpload_dc <= dc_threshold[i])
+ break;
+ }
+
+ regmap_multi_reg_write(regmap, hv_seq[i], ARRAY_SIZE(hv_seq[i]));
+
+ return 0;
+}
+
+static void cs43130_imp_meas(struct work_struct *wk)
+{
+ unsigned int reg, seq_size;
+ int i, ret, ac_idx;
+ struct cs43130_private *cs43130;
+ struct snd_soc_codec *codec;
+ struct reg_sequences *hpload_seq;
+
+ cs43130 = container_of(wk, struct cs43130_private, work);
+ codec = cs43130->codec;
+
+ if (!cs43130->mclk)
+ return;
+
+ cs43130->hpload_done = false;
+
+ mutex_lock(&cs43130->clk_mutex);
+ if (!cs43130->clk_req) {
+ /* clk not in use */
+ cs43130_set_pll(codec, 0, 0, cs43130->mclk, CS43130_MCLK_22M);
+ if (cs43130->pll_bypass)
+ cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT);
+ else
+ cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
+ }
+
+ cs43130->clk_req++;
+ mutex_unlock(&cs43130->clk_mutex);
+
+ regmap_read(cs43130->regmap, CS43130_INT_STATUS_4, &reg);
+
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ hpload_seq = hpload_seq1;
+ seq_size = ARRAY_SIZE(hpload_seq1);
+ break;
+ case CS43131_CHIP_ID:
+ hpload_seq = hpload_seq2;
+ seq_size = ARRAY_SIZE(hpload_seq2);
+ }
+
+ i = 0;
+ ac_idx = 0;
+ while (i < seq_size) {
+ ret = cs43130_hpload_proc(cs43130, hpload_seq[i].seq,
+ hpload_seq[i].size,
+ hpload_seq[i].msk, ac_idx);
+ if (ret < 0)
+ goto exit;
+
+ cs43130_update_hpload(hpload_seq[i].msk, ac_idx, cs43130);
+
+ if (cs43130->ac_meas &&
+ hpload_seq[i].msk == CS43130_HPLOAD_AC_INT &&
+ ac_idx < CS43130_AC_FREQ - 1) {
+ ac_idx++;
+ } else {
+ ac_idx = 0;
+ i++;
+ }
+ }
+ cs43130->hpload_done = true;
+
+ if (cs43130->hpload_dc[HP_LEFT] >= CS43130_LINEOUT_LOAD)
+ snd_soc_jack_report(&cs43130->jack, CS43130_JACK_LINEOUT,
+ CS43130_JACK_MASK);
+ else
+ snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE,
+ CS43130_JACK_MASK);
+
+ dev_dbg(codec->dev, "Set HP output control. DC threshold\n");
+ for (i = 0; i < CS43130_DC_THRESHOLD; i++)
+ dev_dbg(codec->dev, "DC threshold[%d]: %u.\n", i,
+ cs43130->dc_threshold[i]);
+
+ cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT],
+ cs43130->dc_threshold);
+
+exit:
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ cs43130_hpload_proc(cs43130, hp_dis_cal_seq,
+ ARRAY_SIZE(hp_dis_cal_seq),
+ CS43130_HPLOAD_OFF_INT, ac_idx);
+ break;
+ case CS43131_CHIP_ID:
+ cs43130_hpload_proc(cs43130, hp_dis_cal_seq2,
+ ARRAY_SIZE(hp_dis_cal_seq2),
+ CS43130_HPLOAD_OFF_INT, ac_idx);
+ }
+
+ regmap_multi_reg_write(cs43130->regmap, hp_cln_seq,
+ ARRAY_SIZE(hp_cln_seq));
+
+ mutex_lock(&cs43130->clk_mutex);
+ cs43130->clk_req--;
+ /* clk not in use */
+ if (!cs43130->clk_req)
+ cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO);
+ mutex_unlock(&cs43130->clk_mutex);
+}
+
+static irqreturn_t cs43130_irq_thread(int irq, void *data)
+{
+ struct cs43130_private *cs43130 = (struct cs43130_private *)data;
+ struct snd_soc_codec *codec = cs43130->codec;
+ unsigned int stickies[CS43130_NUM_INT];
+ unsigned int irq_occurrance = 0;
+ unsigned int masks[CS43130_NUM_INT];
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+ regmap_read(cs43130->regmap, CS43130_INT_STATUS_1 + i,
+ &stickies[i]);
+ regmap_read(cs43130->regmap, CS43130_INT_MASK_1 + i,
+ &masks[i]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+ stickies[i] = stickies[i] & (~masks[i]);
+ for (j = 0; j < 8; j++)
+ irq_occurrance += (stickies[i] >> j) & 1;
+ }
+ dev_dbg(codec->dev, "number of interrupts occurred (%u)\n",
+ irq_occurrance);
+
+ if (!irq_occurrance)
+ return IRQ_NONE;
+
+ if (stickies[0] & CS43130_XTAL_RDY_INT) {
+ complete(&cs43130->xtal_rdy);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[0] & CS43130_PLL_RDY_INT) {
+ complete(&cs43130->pll_rdy);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) {
+ cs43130->hpload_stat = stickies[3];
+ dev_err(codec->dev,
+ "DC load has not completed before AC load (%x)\n",
+ cs43130->hpload_stat);
+ complete(&cs43130->hpload_evt);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) {
+ cs43130->hpload_stat = stickies[3];
+ dev_err(codec->dev, "HP unplugged during measurement (%x)\n",
+ cs43130->hpload_stat);
+ complete(&cs43130->hpload_evt);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[3] & CS43130_HPLOAD_OOR_INT) {
+ cs43130->hpload_stat = stickies[3];
+ dev_err(codec->dev, "HP load out of range (%x)\n",
+ cs43130->hpload_stat);
+ complete(&cs43130->hpload_evt);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[3] & CS43130_HPLOAD_AC_INT) {
+ cs43130->hpload_stat = stickies[3];
+ dev_dbg(codec->dev, "HP AC load measurement done (%x)\n",
+ cs43130->hpload_stat);
+ complete(&cs43130->hpload_evt);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[3] & CS43130_HPLOAD_DC_INT) {
+ cs43130->hpload_stat = stickies[3];
+ dev_dbg(codec->dev, "HP DC load measurement done (%x)\n",
+ cs43130->hpload_stat);
+ complete(&cs43130->hpload_evt);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[3] & CS43130_HPLOAD_ON_INT) {
+ cs43130->hpload_stat = stickies[3];
+ dev_dbg(codec->dev, "HP load state machine on done (%x)\n",
+ cs43130->hpload_stat);
+ complete(&cs43130->hpload_evt);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[3] & CS43130_HPLOAD_OFF_INT) {
+ cs43130->hpload_stat = stickies[3];
+ dev_dbg(codec->dev, "HP load state machine off done (%x)\n",
+ cs43130->hpload_stat);
+ complete(&cs43130->hpload_evt);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[0] & CS43130_XTAL_ERR_INT) {
+ dev_err(codec->dev, "Crystal err: clock is not running\n");
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[0] & CS43130_HP_UNPLUG_INT) {
+ dev_dbg(codec->dev, "HP unplugged\n");
+ cs43130->hpload_done = false;
+ snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK);
+ return IRQ_HANDLED;
+ }
+
+ if (stickies[0] & CS43130_HP_PLUG_INT) {
+ if (cs43130->dc_meas && !cs43130->hpload_done &&
+ !work_busy(&cs43130->work)) {
+ dev_dbg(codec->dev, "HP load queue work\n");
+ queue_work(cs43130->wq, &cs43130->work);
+ }
+
+ snd_soc_jack_report(&cs43130->jack, SND_JACK_MECHANICAL,
+ CS43130_JACK_MASK);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int cs43130_probe(struct snd_soc_codec *codec)
+{
+ int ret;
+ struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_card *card = codec->component.card;
+ unsigned int reg;
+
+ cs43130->codec = codec;
+
+ if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) {
+ regmap_update_bits(cs43130->regmap, CS43130_CRYSTAL_SET,
+ CS43130_XTAL_IBIAS_MASK,
+ cs43130->xtal_ibias);
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_XTAL_ERR_INT, 0);
+ }
+
+ ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK,
+ &cs43130->jack, NULL, 0);
+ if (ret < 0) {
+ dev_err(codec->dev, "Cannot create jack\n");
+ return ret;
+ }
+
+ cs43130->hpload_done = false;
+ if (cs43130->dc_meas) {
+ ret = device_create_file(codec->dev, &dev_attr_hpload_dc_l);
+ if (ret < 0)
+ return ret;
+
+ ret = device_create_file(codec->dev, &dev_attr_hpload_dc_r);
+ if (ret < 0)
+ return ret;
+
+ ret = device_create_file(codec->dev, &dev_attr_hpload_ac_l);
+ if (ret < 0)
+ return ret;
+
+ ret = device_create_file(codec->dev, &dev_attr_hpload_ac_r);
+ if (ret < 0)
+ return ret;
+
+ cs43130->wq = create_singlethread_workqueue("cs43130_hp");
+ INIT_WORK(&cs43130->work, cs43130_imp_meas);
+ }
+
+ regmap_read(cs43130->regmap, CS43130_INT_STATUS_1, &reg);
+ regmap_read(cs43130->regmap, CS43130_HP_STATUS, &reg);
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT, 0);
+ regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT,
+ CS43130_HP_DETECT_CTRL_MASK, 0);
+ regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT,
+ CS43130_HP_DETECT_CTRL_MASK,
+ CS43130_HP_DETECT_CTRL_MASK);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs43130 = {
+ .probe = cs43130_probe,
+ .component_driver = {
+ .controls = cs43130_snd_controls,
+ .num_controls = ARRAY_SIZE(cs43130_snd_controls),
+ },
+ .set_sysclk = cs43130_codec_set_sysclk,
+ .set_pll = cs43130_set_pll,
+};
+
+static const struct regmap_config cs43130_regmap = {
+ .reg_bits = 24,
+ .pad_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CS43130_LASTREG,
+ .reg_defaults = cs43130_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs43130_reg_defaults),
+ .readable_reg = cs43130_readable_register,
+ .precious_reg = cs43130_precious_register,
+ .volatile_reg = cs43130_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_rw = true, /* needed for regcache_sync */
+};
+
+static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = {
+ 50,
+ 120,
+};
+
+static int cs43130_handle_device_data(struct i2c_client *i2c_client,
+ struct cs43130_private *cs43130)
+{
+ struct device_node *np = i2c_client->dev.of_node;
+ unsigned int val;
+ int i;
+
+ if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) {
+ /* Crystal is unused. System clock is used for external MCLK */
+ cs43130->xtal_ibias = CS43130_XTAL_UNUSED;
+ return 0;
+ }
+
+ switch (val) {
+ case 1:
+ cs43130->xtal_ibias = CS43130_XTAL_IBIAS_7_5UA;
+ break;
+ case 2:
+ cs43130->xtal_ibias = CS43130_XTAL_IBIAS_12_5UA;
+ break;
+ case 3:
+ cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA;
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "Invalid cirrus,xtal-ibias value: %d\n", val);
+ return -EINVAL;
+ }
+
+ cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure");
+ cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure");
+
+ if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq,
+ CS43130_AC_FREQ) < 0) {
+ for (i = 0; i < CS43130_AC_FREQ; i++)
+ cs43130->ac_freq[i] = cs43130_ac_freq[i];
+ }
+
+ if (of_property_read_u16_array(np, "cirrus,dc-threshold",
+ cs43130->dc_threshold,
+ CS43130_DC_THRESHOLD) < 0) {
+ for (i = 0; i < CS43130_DC_THRESHOLD; i++)
+ cs43130->dc_threshold[i] = cs43130_dc_threshold[i];
+ }
+
+ return 0;
+}
+
+static int cs43130_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cs43130_private *cs43130;
+ int ret;
+ unsigned int devid = 0;
+ unsigned int reg;
+ int i;
+
+ cs43130 = devm_kzalloc(&client->dev, sizeof(*cs43130), GFP_KERNEL);
+ if (!cs43130)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, cs43130);
+
+ cs43130->regmap = devm_regmap_init_i2c(client, &cs43130_regmap);
+ if (IS_ERR(cs43130->regmap)) {
+ ret = PTR_ERR(cs43130->regmap);
+ return ret;
+ }
+
+ if (client->dev.of_node) {
+ ret = cs43130_handle_device_data(client, cs43130);
+ if (ret != 0)
+ return ret;
+ }
+ for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++)
+ cs43130->supplies[i].supply = cs43130_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(cs43130->supplies),
+ cs43130->supplies);
+ if (ret != 0) {
+ dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs43130->supplies),
+ cs43130->supplies);
+ if (ret != 0) {
+ dev_err(&client->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(cs43130->reset_gpio))
+ return PTR_ERR(cs43130->reset_gpio);
+
+ gpiod_set_value_cansleep(cs43130->reset_gpio, 1);
+
+ usleep_range(2000, 2050);
+
+ ret = regmap_read(cs43130->regmap, CS43130_DEVID_AB, &reg);
+
+ devid = (reg & 0xFF) << 12;
+ ret = regmap_read(cs43130->regmap, CS43130_DEVID_CD, &reg);
+ devid |= (reg & 0xFF) << 4;
+ ret = regmap_read(cs43130->regmap, CS43130_DEVID_E, &reg);
+ devid |= (reg & 0xF0) >> 4;
+
+ switch (devid) {
+ case CS43130_CHIP_ID:
+ case CS4399_CHIP_ID:
+ case CS43131_CHIP_ID:
+ case CS43198_CHIP_ID:
+ break;
+ default:
+ dev_err(&client->dev,
+ "CS43130 Device ID %X. Expected ID %X, %X, %X or %X\n",
+ devid, CS43130_CHIP_ID, CS4399_CHIP_ID,
+ CS43131_CHIP_ID, CS43198_CHIP_ID);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ cs43130->dev_id = devid;
+ ret = regmap_read(cs43130->regmap, CS43130_REV_ID, &reg);
+ if (ret < 0) {
+ dev_err(&client->dev, "Get Revision ID failed\n");
+ goto err;
+ }
+
+ dev_info(&client->dev,
+ "Cirrus Logic CS43130 (%x), Revision: %02X\n", devid,
+ reg & 0xFF);
+
+ mutex_init(&cs43130->clk_mutex);
+
+ init_completion(&cs43130->xtal_rdy);
+ init_completion(&cs43130->pll_rdy);
+ init_completion(&cs43130->hpload_evt);
+
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, cs43130_irq_thread,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ "cs43130", cs43130);
+ if (ret != 0) {
+ dev_err(&client->dev, "Failed to request IRQ: %d\n", ret);
+ return ret;
+ }
+
+ cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
+
+ pm_runtime_set_autosuspend_delay(&client->dev, 100);
+ pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+
+ switch (cs43130->dev_id) {
+ case CS43130_CHIP_ID:
+ case CS43131_CHIP_ID:
+ memcpy(all_hp_widgets, digital_hp_widgets,
+ sizeof(digital_hp_widgets));
+ memcpy(all_hp_widgets + ARRAY_SIZE(digital_hp_widgets),
+ analog_hp_widgets, sizeof(analog_hp_widgets));
+ memcpy(all_hp_routes, digital_hp_routes,
+ sizeof(digital_hp_routes));
+ memcpy(all_hp_routes + ARRAY_SIZE(digital_hp_routes),
+ analog_hp_routes, sizeof(analog_hp_routes));
+
+ soc_codec_dev_cs43130.component_driver.dapm_widgets =
+ all_hp_widgets;
+ soc_codec_dev_cs43130.component_driver.num_dapm_widgets =
+ ARRAY_SIZE(all_hp_widgets);
+ soc_codec_dev_cs43130.component_driver.dapm_routes =
+ all_hp_routes;
+ soc_codec_dev_cs43130.component_driver.num_dapm_routes =
+ ARRAY_SIZE(all_hp_routes);
+ break;
+ case CS43198_CHIP_ID:
+ case CS4399_CHIP_ID:
+ soc_codec_dev_cs43130.component_driver.dapm_widgets =
+ digital_hp_widgets;
+ soc_codec_dev_cs43130.component_driver.num_dapm_widgets =
+ ARRAY_SIZE(digital_hp_widgets);
+ soc_codec_dev_cs43130.component_driver.dapm_routes =
+ digital_hp_routes;
+ soc_codec_dev_cs43130.component_driver.num_dapm_routes =
+ ARRAY_SIZE(digital_hp_routes);
+ }
+
+ ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_cs43130,
+ cs43130_dai, ARRAY_SIZE(cs43130_dai));
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "snd_soc_register_codec failed with ret = %d\n", ret);
+ goto err;
+ }
+
+ regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
+ CS43130_ASP_3ST_MASK, 0);
+ regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
+ CS43130_XSP_3ST_MASK, 0);
+
+ return 0;
+err:
+ return ret;
+}
+
+static int cs43130_i2c_remove(struct i2c_client *client)
+{
+ struct cs43130_private *cs43130 = i2c_get_clientdata(client);
+
+ if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED)
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_XTAL_ERR_INT,
+ 1 << CS43130_XTAL_ERR_INT_SHIFT);
+
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT,
+ CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT);
+
+ if (cs43130->dc_meas) {
+ cancel_work_sync(&cs43130->work);
+ flush_workqueue(cs43130->wq);
+
+ device_remove_file(&client->dev, &dev_attr_hpload_dc_l);
+ device_remove_file(&client->dev, &dev_attr_hpload_dc_r);
+ device_remove_file(&client->dev, &dev_attr_hpload_ac_l);
+ device_remove_file(&client->dev, &dev_attr_hpload_ac_r);
+ }
+
+ if (cs43130->reset_gpio)
+ gpiod_set_value_cansleep(cs43130->reset_gpio, 0);
+
+ pm_runtime_disable(&client->dev);
+ regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+
+ snd_soc_unregister_codec(&client->dev);
+
+ return 0;
+}
+
+static int cs43130_runtime_suspend(struct device *dev)
+{
+ struct cs43130_private *cs43130 = dev_get_drvdata(dev);
+
+ if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED)
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_XTAL_ERR_INT,
+ 1 << CS43130_XTAL_ERR_INT_SHIFT);
+
+ regcache_cache_only(cs43130->regmap, true);
+ regcache_mark_dirty(cs43130->regmap);
+
+ gpiod_set_value_cansleep(cs43130->reset_gpio, 0);
+
+ regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+
+ return 0;
+}
+
+static int cs43130_runtime_resume(struct device *dev)
+{
+ struct cs43130_private *cs43130 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_bulk_enable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ regcache_cache_only(cs43130->regmap, false);
+
+ gpiod_set_value_cansleep(cs43130->reset_gpio, 1);
+
+ usleep_range(2000, 2050);
+
+ ret = regcache_sync(cs43130->regmap);
+ if (ret != 0) {
+ dev_err(dev, "Failed to restore register cache\n");
+ goto err;
+ }
+
+ if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED)
+ regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+ CS43130_XTAL_ERR_INT, 0);
+
+ return 0;
+err:
+ regcache_cache_only(cs43130->regmap, true);
+ regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+
+ return ret;
+}
+
+static const struct dev_pm_ops cs43130_runtime_pm = {
+ SET_RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id cs43130_of_match[] = {
+ {.compatible = "cirrus,cs43130",},
+ {.compatible = "cirrus,cs4399",},
+ {.compatible = "cirrus,cs43131",},
+ {.compatible = "cirrus,cs43198",},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, cs43130_of_match);
+
+static const struct i2c_device_id cs43130_i2c_id[] = {
+ {"cs43130", 0},
+ {"cs4399", 0},
+ {"cs43131", 0},
+ {"cs43198", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs43130_i2c_id);
+
+static struct i2c_driver cs43130_i2c_driver = {
+ .driver = {
+ .name = "cs43130",
+ .of_match_table = cs43130_of_match,
+ .pm = &cs43130_runtime_pm,
+ },
+ .id_table = cs43130_i2c_id,
+ .probe = cs43130_i2c_probe,
+ .remove = cs43130_i2c_remove,
+};
+
+module_i2c_driver(cs43130_i2c_driver);
+
+MODULE_AUTHOR("Li Xu <li.xu@cirrus.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS43130 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h
new file mode 100644
index 000000000000..781258418d89
--- /dev/null
+++ b/sound/soc/codecs/cs43130.h
@@ -0,0 +1,546 @@
+/*
+ * ALSA SoC CS43130 codec driver
+ *
+ * Copyright 2017 Cirrus Logic, Inc.
+ *
+ * Author: Li Xu <li.xu@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#ifndef __CS43130_H__
+#define __CS43130_H__
+
+/* CS43130 registers addresses */
+/* all reg address is shifted by a byte for control byte to be LSB */
+#define CS43130_FIRSTREG 0x010000
+#define CS43130_LASTREG 0x190000
+#define CS43130_CHIP_ID 0x00043130
+#define CS4399_CHIP_ID 0x00043990
+#define CS43131_CHIP_ID 0x00043131
+#define CS43198_CHIP_ID 0x00043198
+#define CS43130_DEVID_AB 0x010000 /* Device ID A & B [RO] */
+#define CS43130_DEVID_CD 0x010001 /* Device ID C & D [RO] */
+#define CS43130_DEVID_E 0x010002 /* Device ID E [RO] */
+#define CS43130_FAB_ID 0x010003 /* Fab ID [RO] */
+#define CS43130_REV_ID 0x010004 /* Revision ID [RO] */
+#define CS43130_SUBREV_ID 0x010005 /* Subrevision ID */
+#define CS43130_SYS_CLK_CTL_1 0x010006 /* System Clocking Ctl 1 */
+#define CS43130_SP_SRATE 0x01000B /* Serial Port Sample Rate */
+#define CS43130_SP_BITSIZE 0x01000C /* Serial Port Bit Size */
+#define CS43130_PAD_INT_CFG 0x01000D /* Pad Interface Config */
+#define CS43130_DXD1 0x010010 /* DXD1 */
+#define CS43130_DXD7 0x010025 /* DXD7 */
+#define CS43130_DXD19 0x010026 /* DXD19 */
+#define CS43130_DXD17 0x010027 /* DXD17 */
+#define CS43130_DXD18 0x010028 /* DXD18 */
+#define CS43130_DXD12 0x01002C /* DXD12 */
+#define CS43130_DXD8 0x01002E /* DXD8 */
+#define CS43130_PWDN_CTL 0x020000 /* Power Down Ctl */
+#define CS43130_DXD2 0x020019 /* DXD2 */
+#define CS43130_CRYSTAL_SET 0x020052 /* Crystal Setting */
+#define CS43130_PLL_SET_1 0x030001 /* PLL Setting 1 */
+#define CS43130_PLL_SET_2 0x030002 /* PLL Setting 2 */
+#define CS43130_PLL_SET_3 0x030003 /* PLL Setting 3 */
+#define CS43130_PLL_SET_4 0x030004 /* PLL Setting 4 */
+#define CS43130_PLL_SET_5 0x030005 /* PLL Setting 5 */
+#define CS43130_PLL_SET_6 0x030008 /* PLL Setting 6 */
+#define CS43130_PLL_SET_7 0x03000A /* PLL Setting 7 */
+#define CS43130_PLL_SET_8 0x03001B /* PLL Setting 8 */
+#define CS43130_PLL_SET_9 0x040002 /* PLL Setting 9 */
+#define CS43130_PLL_SET_10 0x040003 /* PLL Setting 10 */
+#define CS43130_CLKOUT_CTL 0x040004 /* CLKOUT Ctl */
+#define CS43130_ASP_NUM_1 0x040010 /* ASP Numerator 1 */
+#define CS43130_ASP_NUM_2 0x040011 /* ASP Numerator 2 */
+#define CS43130_ASP_DEN_1 0x040012 /* ASP Denominator 1 */
+#define CS43130_ASP_DEN_2 0x040013 /* ASP Denominator 2 */
+#define CS43130_ASP_LRCK_HI_TIME_1 0x040014 /* ASP LRCK High Time 1 */
+#define CS43130_ASP_LRCK_HI_TIME_2 0x040015 /* ASP LRCK High Time 2 */
+#define CS43130_ASP_LRCK_PERIOD_1 0x040016 /* ASP LRCK Period 1 */
+#define CS43130_ASP_LRCK_PERIOD_2 0x040017 /* ASP LRCK Period 2 */
+#define CS43130_ASP_CLOCK_CONF 0x040018 /* ASP Clock Config */
+#define CS43130_ASP_FRAME_CONF 0x040019 /* ASP Frame Config */
+#define CS43130_XSP_NUM_1 0x040020 /* XSP Numerator 1 */
+#define CS43130_XSP_NUM_2 0x040021 /* XSP Numerator 2 */
+#define CS43130_XSP_DEN_1 0x040022 /* XSP Denominator 1 */
+#define CS43130_XSP_DEN_2 0x040023 /* XSP Denominator 2 */
+#define CS43130_XSP_LRCK_HI_TIME_1 0x040024 /* XSP LRCK High Time 1 */
+#define CS43130_XSP_LRCK_HI_TIME_2 0x040025 /* XSP LRCK High Time 2 */
+#define CS43130_XSP_LRCK_PERIOD_1 0x040026 /* XSP LRCK Period 1 */
+#define CS43130_XSP_LRCK_PERIOD_2 0x040027 /* XSP LRCK Period 2 */
+#define CS43130_XSP_CLOCK_CONF 0x040028 /* XSP Clock Config */
+#define CS43130_XSP_FRAME_CONF 0x040029 /* XSP Frame Config */
+#define CS43130_ASP_CH_1_LOC 0x050000 /* ASP Chan 1 Location */
+#define CS43130_ASP_CH_2_LOC 0x050001 /* ASP Chan 2 Location */
+#define CS43130_ASP_CH_1_SZ_EN 0x05000A /* ASP Chan 1 Size, Enable */
+#define CS43130_ASP_CH_2_SZ_EN 0x05000B /* ASP Chan 2 Size, Enable */
+#define CS43130_XSP_CH_1_LOC 0x060000 /* XSP Chan 1 Location */
+#define CS43130_XSP_CH_2_LOC 0x060001 /* XSP Chan 2 Location */
+#define CS43130_XSP_CH_1_SZ_EN 0x06000A /* XSP Chan 1 Size, Enable */
+#define CS43130_XSP_CH_2_SZ_EN 0x06000B /* XSP Chan 2 Size, Enable */
+#define CS43130_DSD_VOL_B 0x070000 /* DSD Volume B */
+#define CS43130_DSD_VOL_A 0x070001 /* DSD Volume A */
+#define CS43130_DSD_PATH_CTL_1 0x070002 /* DSD Proc Path Sig Ctl 1 */
+#define CS43130_DSD_INT_CFG 0x070003 /* DSD Interface Config */
+#define CS43130_DSD_PATH_CTL_2 0x070004 /* DSD Proc Path Sig Ctl 2 */
+#define CS43130_DSD_PCM_MIX_CTL 0x070005 /* DSD and PCM Mixing Ctl */
+#define CS43130_DSD_PATH_CTL_3 0x070006 /* DSD Proc Path Sig Ctl 3 */
+#define CS43130_HP_OUT_CTL_1 0x080000 /* HP Output Ctl 1 */
+#define CS43130_DXD16 0x080024 /* DXD16 */
+#define CS43130_DXD13 0x080032 /* DXD13 */
+#define CS43130_PCM_FILT_OPT 0x090000 /* PCM Filter Option */
+#define CS43130_PCM_VOL_B 0x090001 /* PCM Volume B */
+#define CS43130_PCM_VOL_A 0x090002 /* PCM Volume A */
+#define CS43130_PCM_PATH_CTL_1 0x090003 /* PCM Path Signal Ctl 1 */
+#define CS43130_PCM_PATH_CTL_2 0x090004 /* PCM Path Signal Ctl 2 */
+#define CS43130_DXD6 0x090097 /* DXD6 */
+#define CS43130_CLASS_H_CTL 0x0B0000 /* Class H Ctl */
+#define CS43130_DXD15 0x0B0005 /* DXD15 */
+#define CS43130_DXD14 0x0B0006 /* DXD14 */
+#define CS43130_DXD3 0x0C0002 /* DXD3 */
+#define CS43130_DXD10 0x0C0003 /* DXD10 */
+#define CS43130_DXD11 0x0C0005 /* DXD11 */
+#define CS43130_DXD9 0x0C0006 /* DXD9 */
+#define CS43130_DXD4 0x0C0009 /* DXD4 */
+#define CS43130_DXD5 0x0C000E /* DXD5 */
+#define CS43130_HP_DETECT 0x0D0000 /* HP Detect */
+#define CS43130_HP_STATUS 0x0D0001 /* HP Status [RO] */
+#define CS43130_HP_LOAD_1 0x0E0000 /* HP Load 1 */
+#define CS43130_HP_MEAS_LOAD_1 0x0E0003 /* HP Load Measurement 1 */
+#define CS43130_HP_MEAS_LOAD_2 0x0E0004 /* HP Load Measurement 2 */
+#define CS43130_HP_DC_STAT_1 0x0E000D /* HP DC Load Status 0 [RO] */
+#define CS43130_HP_DC_STAT_2 0x0E000E /* HP DC Load Status 1 [RO] */
+#define CS43130_HP_AC_STAT_1 0x0E0010 /* HP AC Load Status 0 [RO] */
+#define CS43130_HP_AC_STAT_2 0x0E0011 /* HP AC Load Status 1 [RO] */
+#define CS43130_HP_LOAD_STAT 0x0E001A /* HP Load Status [RO] */
+#define CS43130_INT_STATUS_1 0x0F0000 /* Interrupt Status 1 */
+#define CS43130_INT_STATUS_2 0x0F0001 /* Interrupt Status 2 */
+#define CS43130_INT_STATUS_3 0x0F0002 /* Interrupt Status 3 */
+#define CS43130_INT_STATUS_4 0x0F0003 /* Interrupt Status 4 */
+#define CS43130_INT_STATUS_5 0x0F0004 /* Interrupt Status 5 */
+#define CS43130_INT_MASK_1 0x0F0010 /* Interrupt Mask 1 */
+#define CS43130_INT_MASK_2 0x0F0011 /* Interrupt Mask 2 */
+#define CS43130_INT_MASK_3 0x0F0012 /* Interrupt Mask 3 */
+#define CS43130_INT_MASK_4 0x0F0013 /* Interrupt Mask 4 */
+#define CS43130_INT_MASK_5 0x0F0014 /* Interrupt Mask 5 */
+
+#define CS43130_MCLK_SRC_SEL_MASK 0x03
+#define CS43130_MCLK_SRC_SEL_SHIFT 0
+#define CS43130_MCLK_INT_MASK 0x04
+#define CS43130_MCLK_INT_SHIFT 2
+#define CS43130_CH_BITSIZE_MASK 0x03
+#define CS43130_CH_EN_MASK 0x04
+#define CS43130_CH_EN_SHIFT 2
+#define CS43130_ASP_BITSIZE_MASK 0x03
+#define CS43130_XSP_BITSIZE_MASK 0x0C
+#define CS43130_XSP_BITSIZE_SHIFT 2
+#define CS43130_SP_BITSIZE_ASP_SHIFT 0
+#define CS43130_HP_DETECT_CTRL_SHIFT 6
+#define CS43130_HP_DETECT_CTRL_MASK (0x03 << CS43130_HP_DETECT_CTRL_SHIFT)
+#define CS43130_HP_DETECT_INV_SHIFT 5
+#define CS43130_HP_DETECT_INV_MASK (1 << CS43130_HP_DETECT_INV_SHIFT)
+
+/* CS43130_INT_MASK_1 */
+#define CS43130_HP_PLUG_INT_SHIFT 6
+#define CS43130_HP_PLUG_INT (1 << CS43130_HP_PLUG_INT_SHIFT)
+#define CS43130_HP_UNPLUG_INT_SHIFT 5
+#define CS43130_HP_UNPLUG_INT (1 << CS43130_HP_UNPLUG_INT_SHIFT)
+#define CS43130_XTAL_RDY_INT_SHIFT 4
+#define CS43130_XTAL_RDY_INT_MASK 0x10
+#define CS43130_XTAL_RDY_INT (1 << CS43130_XTAL_RDY_INT_SHIFT)
+#define CS43130_XTAL_ERR_INT_SHIFT 3
+#define CS43130_XTAL_ERR_INT (1 << CS43130_XTAL_ERR_INT_SHIFT)
+#define CS43130_PLL_RDY_INT_MASK 0x04
+#define CS43130_PLL_RDY_INT_SHIFT 2
+#define CS43130_PLL_RDY_INT (1 << CS43130_PLL_RDY_INT_SHIFT)
+
+/* CS43130_INT_MASK_4 */
+#define CS43130_INT_MASK_ALL 0xFF
+#define CS43130_HPLOAD_NO_DC_INT_SHIFT 7
+#define CS43130_HPLOAD_NO_DC_INT (1 << CS43130_HPLOAD_NO_DC_INT_SHIFT)
+#define CS43130_HPLOAD_UNPLUG_INT_SHIFT 6
+#define CS43130_HPLOAD_UNPLUG_INT (1 << CS43130_HPLOAD_UNPLUG_INT_SHIFT)
+#define CS43130_HPLOAD_OOR_INT_SHIFT 4
+#define CS43130_HPLOAD_OOR_INT (1 << CS43130_HPLOAD_OOR_INT_SHIFT)
+#define CS43130_HPLOAD_AC_INT_SHIFT 3
+#define CS43130_HPLOAD_AC_INT (1 << CS43130_HPLOAD_AC_INT_SHIFT)
+#define CS43130_HPLOAD_DC_INT_SHIFT 2
+#define CS43130_HPLOAD_DC_INT (1 << CS43130_HPLOAD_DC_INT_SHIFT)
+#define CS43130_HPLOAD_OFF_INT_SHIFT 1
+#define CS43130_HPLOAD_OFF_INT (1 << CS43130_HPLOAD_OFF_INT_SHIFT)
+#define CS43130_HPLOAD_ON_INT 1
+
+/* CS43130_HP_LOAD_1 */
+#define CS43130_HPLOAD_EN_SHIFT 7
+#define CS43130_HPLOAD_EN (1 << CS43130_HPLOAD_EN_SHIFT)
+#define CS43130_HPLOAD_CHN_SEL_SHIFT 4
+#define CS43130_HPLOAD_CHN_SEL (1 << CS43130_HPLOAD_CHN_SEL_SHIFT)
+#define CS43130_HPLOAD_AC_START_SHIFT 1
+#define CS43130_HPLOAD_AC_START (1 << CS43130_HPLOAD_AC_START_SHIFT)
+#define CS43130_HPLOAD_DC_START 1
+
+/* Reg CS43130_SP_BITSIZE */
+#define CS43130_SP_BIT_SIZE_8 0x03
+#define CS43130_SP_BIT_SIZE_16 0x02
+#define CS43130_SP_BIT_SIZE_24 0x01
+#define CS43130_SP_BIT_SIZE_32 0x00
+
+/* Reg CS43130_SP_CH_SZ_EN */
+#define CS43130_CH_BIT_SIZE_8 0x00
+#define CS43130_CH_BIT_SIZE_16 0x01
+#define CS43130_CH_BIT_SIZE_24 0x02
+#define CS43130_CH_BIT_SIZE_32 0x03
+
+/* PLL */
+#define CS43130_PLL_START_MASK 0x01
+#define CS43130_PLL_MODE_MASK 0x02
+#define CS43130_PLL_MODE_SHIFT 1
+
+#define CS43130_PLL_REF_PREDIV_MASK 0x3
+
+#define CS43130_SP_STP_MASK 0x10
+#define CS43130_SP_STP_SHIFT 4
+#define CS43130_SP_5050_MASK 0x08
+#define CS43130_SP_5050_SHIFT 3
+#define CS43130_SP_FSD_MASK 0x07
+
+#define CS43130_SP_MODE_MASK 0x10
+#define CS43130_SP_MODE_SHIFT 4
+#define CS43130_SP_SCPOL_OUT_MASK 0x08
+#define CS43130_SP_SCPOL_OUT_SHIFT 3
+#define CS43130_SP_SCPOL_IN_MASK 0x04
+#define CS43130_SP_SCPOL_IN_SHIFT 2
+#define CS43130_SP_LCPOL_OUT_MASK 0x02
+#define CS43130_SP_LCPOL_OUT_SHIFT 1
+#define CS43130_SP_LCPOL_IN_MASK 0x01
+#define CS43130_SP_LCPOL_IN_SHIFT 0
+
+/* Reg CS43130_PWDN_CTL */
+#define CS43130_PDN_XSP_MASK 0x80
+#define CS43130_PDN_XSP_SHIFT 7
+#define CS43130_PDN_ASP_MASK 0x40
+#define CS43130_PDN_ASP_SHIFT 6
+#define CS43130_PDN_DSPIF_MASK 0x20
+#define CS43130_PDN_DSDIF_SHIFT 5
+#define CS43130_PDN_HP_MASK 0x10
+#define CS43130_PDN_HP_SHIFT 4
+#define CS43130_PDN_XTAL_MASK 0x08
+#define CS43130_PDN_XTAL_SHIFT 3
+#define CS43130_PDN_PLL_MASK 0x04
+#define CS43130_PDN_PLL_SHIFT 2
+#define CS43130_PDN_CLKOUT_MASK 0x02
+#define CS43130_PDN_CLKOUT_SHIFT 1
+
+/* Reg CS43130_HP_OUT_CTL_1 */
+#define CS43130_HP_IN_EN_SHIFT 3
+#define CS43130_HP_IN_EN_MASK 0x08
+
+/* Reg CS43130_PAD_INT_CFG */
+#define CS43130_ASP_3ST_MASK 0x01
+#define CS43130_XSP_3ST_MASK 0x02
+
+/* Reg CS43130_PLL_SET_2 */
+#define CS43130_PLL_DIV_DATA_MASK 0x000000FF
+#define CS43130_PLL_DIV_FRAC_0_DATA_SHIFT 0
+
+/* Reg CS43130_PLL_SET_3 */
+#define CS43130_PLL_DIV_FRAC_1_DATA_SHIFT 8
+
+/* Reg CS43130_PLL_SET_4 */
+#define CS43130_PLL_DIV_FRAC_2_DATA_SHIFT 16
+
+/* Reg CS43130_SP_DEN_1 */
+#define CS43130_SP_M_LSB_DATA_MASK 0x00FF
+#define CS43130_SP_M_LSB_DATA_SHIFT 0
+
+/* Reg CS43130_SP_DEN_2 */
+#define CS43130_SP_M_MSB_DATA_MASK 0xFF00
+#define CS43130_SP_M_MSB_DATA_SHIFT 8
+
+/* Reg CS43130_SP_NUM_1 */
+#define CS43130_SP_N_LSB_DATA_MASK 0x00FF
+#define CS43130_SP_N_LSB_DATA_SHIFT 0
+
+/* Reg CS43130_SP_NUM_2 */
+#define CS43130_SP_N_MSB_DATA_MASK 0xFF00
+#define CS43130_SP_N_MSB_DATA_SHIFT 8
+
+/* Reg CS43130_SP_LRCK_HI_TIME_1 */
+#define CS43130_SP_LCHI_DATA_MASK 0x00FF
+#define CS43130_SP_LCHI_LSB_DATA_SHIFT 0
+
+/* Reg CS43130_SP_LRCK_HI_TIME_2 */
+#define CS43130_SP_LCHI_MSB_DATA_SHIFT 8
+
+/* Reg CS43130_SP_LRCK_PERIOD_1 */
+#define CS43130_SP_LCPR_DATA_MASK 0x00FF
+#define CS43130_SP_LCPR_LSB_DATA_SHIFT 0
+
+/* Reg CS43130_SP_LRCK_PERIOD_2 */
+#define CS43130_SP_LCPR_MSB_DATA_SHIFT 8
+
+#define CS43130_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define CS43130_DOP_FORMATS (SNDRV_PCM_FMTBIT_DSD_U16_LE | \
+ SNDRV_PCM_FMTBIT_DSD_U16_BE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+/* Reg CS43130_CRYSTAL_SET */
+#define CS43130_XTAL_IBIAS_MASK 0x07
+
+/* Reg CS43130_PATH_CTL_1 */
+#define CS43130_MUTE_MASK 0x03
+#define CS43130_MUTE_EN 0x03
+
+/* Reg CS43130_DSD_INT_CFG */
+#define CS43130_DSD_MASTER 0x04
+
+/* Reg CS43130_DSD_PATH_CTL_2 */
+#define CS43130_DSD_SRC_MASK 0x60
+#define CS43130_DSD_SRC_SHIFT 5
+#define CS43130_DSD_EN_SHIFT 4
+#define CS43130_DSD_SPEED_MASK 0x04
+#define CS43130_DSD_SPEED_SHIFT 2
+
+/* Reg CS43130_DSD_PCM_MIX_CTL */
+#define CS43130_MIX_PCM_PREP_SHIFT 1
+#define CS43130_MIX_PCM_PREP_MASK 0x02
+
+#define CS43130_MIX_PCM_DSD_SHIFT 0
+#define CS43130_MIX_PCM_DSD_MASK 0x01
+
+/* Reg CS43130_HP_MEAS_LOAD */
+#define CS43130_HP_MEAS_LOAD_MASK 0x000000FF
+#define CS43130_HP_MEAS_LOAD_1_SHIFT 0
+#define CS43130_HP_MEAS_LOAD_2_SHIFT 8
+
+#define CS43130_MCLK_22M 22579200
+#define CS43130_MCLK_24M 24576000
+
+#define CS43130_LINEOUT_LOAD 5000
+#define CS43130_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT)
+#define CS43130_JACK_HEADPHONE (SND_JACK_MECHANICAL | \
+ SND_JACK_HEADPHONE)
+#define CS43130_JACK_MASK (SND_JACK_MECHANICAL | \
+ SND_JACK_LINEOUT | \
+ SND_JACK_HEADPHONE)
+
+enum cs43130_dsd_src {
+ CS43130_DSD_SRC_DSD = 0,
+ CS43130_DSD_SRC_ASP = 2,
+ CS43130_DSD_SRC_XSP = 3,
+};
+
+enum cs43130_asp_rate {
+ CS43130_ASP_SPRATE_32K = 0,
+ CS43130_ASP_SPRATE_44_1K,
+ CS43130_ASP_SPRATE_48K,
+ CS43130_ASP_SPRATE_88_2K,
+ CS43130_ASP_SPRATE_96K,
+ CS43130_ASP_SPRATE_176_4K,
+ CS43130_ASP_SPRATE_192K,
+ CS43130_ASP_SPRATE_352_8K,
+ CS43130_ASP_SPRATE_384K,
+};
+
+enum cs43130_mclk_src_sel {
+ CS43130_MCLK_SRC_EXT = 0,
+ CS43130_MCLK_SRC_PLL,
+ CS43130_MCLK_SRC_RCO
+};
+
+enum cs43130_mclk_int_freq {
+ CS43130_MCLK_24P5 = 0,
+ CS43130_MCLK_22P5,
+};
+
+enum cs43130_xtal_ibias {
+ CS43130_XTAL_UNUSED = -1,
+ CS43130_XTAL_IBIAS_15UA = 2,
+ CS43130_XTAL_IBIAS_12_5UA = 4,
+ CS43130_XTAL_IBIAS_7_5UA = 6,
+};
+
+enum cs43130_dai_id {
+ CS43130_ASP_PCM_DAI = 0,
+ CS43130_ASP_DOP_DAI,
+ CS43130_XSP_DOP_DAI,
+ CS43130_XSP_DSD_DAI,
+ CS43130_DAI_ID_MAX,
+};
+
+struct cs43130_clk_gen {
+ unsigned int mclk_int;
+ int fs;
+ u16 den;
+ u16 num;
+};
+
+/* frm_size = 16 */
+static const struct cs43130_clk_gen cs43130_16_clk_gen[] = {
+ {22579200, 32000, 441, 10,},
+ {22579200, 44100, 32, 1,},
+ {22579200, 48000, 147, 5,},
+ {22579200, 88200, 16, 1,},
+ {22579200, 96000, 147, 10,},
+ {22579200, 176400, 8, 1,},
+ {22579200, 192000, 147, 20,},
+ {22579200, 352800, 4, 1,},
+ {22579200, 384000, 147, 40,},
+ {24576000, 32000, 48, 1,},
+ {24576000, 44100, 5120, 147,},
+ {24576000, 48000, 32, 1,},
+ {24576000, 88200, 2560, 147,},
+ {24576000, 96000, 16, 1,},
+ {24576000, 176400, 1280, 147,},
+ {24576000, 192000, 8, 1,},
+ {24576000, 352800, 640, 147,},
+ {24576000, 384000, 4, 1,},
+};
+
+/* frm_size = 32 */
+static const struct cs43130_clk_gen cs43130_32_clk_gen[] = {
+ {22579200, 32000, 441, 20,},
+ {22579200, 44100, 16, 1,},
+ {22579200, 48000, 147, 10,},
+ {22579200, 88200, 8, 1,},
+ {22579200, 96000, 147, 20,},
+ {22579200, 176400, 4, 1,},
+ {22579200, 192000, 147, 40,},
+ {22579200, 352800, 2, 1,},
+ {22579200, 384000, 147, 80,},
+ {24576000, 32000, 24, 1,},
+ {24576000, 44100, 2560, 147,},
+ {24576000, 48000, 16, 1,},
+ {24576000, 88200, 1280, 147,},
+ {24576000, 96000, 8, 1,},
+ {24576000, 176400, 640, 147,},
+ {24576000, 192000, 4, 1,},
+ {24576000, 352800, 320, 147,},
+ {24576000, 384000, 2, 1,},
+};
+
+/* frm_size = 48 */
+static const struct cs43130_clk_gen cs43130_48_clk_gen[] = {
+ {22579200, 32000, 147, 100,},
+ {22579200, 44100, 32, 3,},
+ {22579200, 48000, 49, 5,},
+ {22579200, 88200, 16, 3,},
+ {22579200, 96000, 49, 10,},
+ {22579200, 176400, 8, 3,},
+ {22579200, 192000, 49, 20,},
+ {22579200, 352800, 4, 3,},
+ {22579200, 384000, 49, 40,},
+ {24576000, 32000, 16, 1,},
+ {24576000, 44100, 5120, 441,},
+ {24576000, 48000, 32, 3,},
+ {24576000, 88200, 2560, 441,},
+ {24576000, 96000, 16, 3,},
+ {24576000, 176400, 1280, 441,},
+ {24576000, 192000, 8, 3,},
+ {24576000, 352800, 640, 441,},
+ {24576000, 384000, 4, 3,},
+};
+
+/* frm_size = 64 */
+static const struct cs43130_clk_gen cs43130_64_clk_gen[] = {
+ {22579200, 32000, 441, 40,},
+ {22579200, 44100, 8, 1,},
+ {22579200, 48000, 147, 20,},
+ {22579200, 88200, 4, 1,},
+ {22579200, 96000, 147, 40,},
+ {22579200, 176400, 2, 1,},
+ {22579200, 192000, 147, 80,},
+ {22579200, 352800, 1, 1,},
+ {24576000, 32000, 12, 1,},
+ {24576000, 44100, 1280, 147,},
+ {24576000, 48000, 8, 1,},
+ {24576000, 88200, 640, 147,},
+ {24576000, 96000, 4, 1,},
+ {24576000, 176400, 320, 147,},
+ {24576000, 192000, 2, 1,},
+ {24576000, 352800, 160, 147,},
+ {24576000, 384000, 1, 1,},
+};
+
+struct cs43130_bitwidth_map {
+ unsigned int bitwidth;
+ u8 sp_bit;
+ u8 ch_bit;
+};
+
+struct cs43130_rate_map {
+ int fs;
+ int val;
+};
+
+#define HP_LEFT 0
+#define HP_RIGHT 1
+#define CS43130_AC_FREQ 10
+#define CS43130_DC_THRESHOLD 2
+
+#define CS43130_NUM_SUPPLIES 5
+static const char *const cs43130_supply_names[CS43130_NUM_SUPPLIES] = {
+ "VA",
+ "VP",
+ "VCP",
+ "VD",
+ "VL",
+};
+
+#define CS43130_NUM_INT 5 /* number of interrupt status reg */
+
+struct cs43130_dai {
+ unsigned int sclk;
+ unsigned int dai_format;
+ unsigned int dai_mode;
+};
+
+struct cs43130_private {
+ struct snd_soc_codec *codec;
+ struct regmap *regmap;
+ struct regulator_bulk_data supplies[CS43130_NUM_SUPPLIES];
+ struct gpio_desc *reset_gpio;
+ unsigned int dev_id; /* codec device ID */
+ int xtal_ibias;
+
+ /* shared by both DAIs */
+ struct mutex clk_mutex;
+ int clk_req;
+ bool pll_bypass;
+ struct completion xtal_rdy;
+ struct completion pll_rdy;
+ unsigned int mclk;
+ unsigned int mclk_int;
+ int mclk_int_src;
+
+ /* DAI specific */
+ struct cs43130_dai dais[CS43130_DAI_ID_MAX];
+
+ /* HP load specific */
+ bool dc_meas;
+ bool ac_meas;
+ bool hpload_done;
+ struct completion hpload_evt;
+ unsigned int hpload_stat;
+ u16 hpload_dc[2];
+ u16 dc_threshold[CS43130_DC_THRESHOLD];
+ u16 ac_freq[CS43130_AC_FREQ];
+ u16 hpload_ac[CS43130_AC_FREQ][2];
+ struct workqueue_struct *wq;
+ struct work_struct work;
+ struct snd_soc_jack jack;
+};
+
+#endif /* __CS43130_H__ */
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 231ca935cdf3..0a749c79ef57 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -255,7 +255,7 @@ static struct snd_soc_dai_driver cs4349_dai = {
.symmetric_rates = 1,
};
-static struct snd_soc_codec_driver soc_codec_dev_cs4349 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs4349 = {
.component_driver = {
.controls = cs4349_snd_controls,
.num_controls = ARRAY_SIZE(cs4349_snd_controls),
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index 47e6fddef92b..e09fc8f037f1 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -1183,7 +1183,7 @@ static struct regmap *cs47l24_get_regmap(struct device *dev)
return priv->core.arizona->regmap;
}
-static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
.probe = cs47l24_codec_probe,
.remove = cs47l24_codec_remove,
.get_regmap = cs47l24_get_regmap,
@@ -1203,7 +1203,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
},
};
-static struct snd_compr_ops cs47l24_compr_ops = {
+static const struct snd_compr_ops cs47l24_compr_ops = {
.open = cs47l24_open,
.free = wm_adsp_compr_free,
.set_params = wm_adsp_compr_set_params,
@@ -1213,7 +1213,7 @@ static struct snd_compr_ops cs47l24_compr_ops = {
.copy = wm_adsp_compr_copy,
};
-static struct snd_soc_platform_driver cs47l24_compr_platform = {
+static const struct snd_soc_platform_driver cs47l24_compr_platform = {
.compr_ops = &cs47l24_compr_ops,
};
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index 06933a5d0a75..c7edf2df5e36 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -842,8 +842,7 @@ static int cs53l30_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
{
struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec);
- if (priv->mute_gpio)
- gpiod_set_value_cansleep(priv->mute_gpio, mute);
+ gpiod_set_value_cansleep(priv->mute_gpio, mute);
return 0;
}
@@ -892,7 +891,7 @@ static int cs53l30_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver cs53l30_driver = {
+static const struct snd_soc_codec_driver cs53l30_driver = {
.probe = cs53l30_codec_probe,
.set_bias_level = cs53l30_set_bias_level,
.idle_bias_off = true,
@@ -960,8 +959,7 @@ static int cs53l30_i2c_probe(struct i2c_client *client,
goto error;
}
- if (cs53l30->reset_gpio)
- gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
i2c_set_clientdata(client, cs53l30);
@@ -1056,8 +1054,7 @@ static int cs53l30_i2c_remove(struct i2c_client *client)
snd_soc_unregister_codec(&client->dev);
/* Hold down reset */
- if (cs53l30->reset_gpio)
- gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies),
cs53l30->supplies);
@@ -1073,8 +1070,7 @@ static int cs53l30_runtime_suspend(struct device *dev)
regcache_cache_only(cs53l30->regmap, true);
/* Hold down reset */
- if (cs53l30->reset_gpio)
- gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies),
cs53l30->supplies);
@@ -1094,8 +1090,7 @@ static int cs53l30_runtime_resume(struct device *dev)
return ret;
}
- if (cs53l30->reset_gpio)
- gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
regcache_cache_only(cs53l30->regmap, false);
ret = regcache_sync(cs53l30->regmap);
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 2c12471e42a6..46b1fbb66eba 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -398,7 +398,7 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec)
static const u8 cx20442_reg;
-static struct snd_soc_codec_driver cx20442_codec_dev = {
+static const struct snd_soc_codec_driver cx20442_codec_dev = {
.probe = cx20442_codec_probe,
.remove = cx20442_codec_remove,
.set_bias_level = cx20442_set_bias_level,
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 17053dfc94cf..1af443ccbc51 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -1164,7 +1164,7 @@ static int da7210_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da7210 = {
.probe = da7210_probe,
.component_driver = {
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index c3e11897f8ae..cc0b2d2eaf15 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1787,7 +1787,7 @@ static int da7213_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_da7213 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da7213 = {
.probe = da7213_probe,
.set_bias_level = da7213_set_bias_level,
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 6e1940eb0653..b2d42ec1dcd9 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -3035,7 +3035,7 @@ static int da7218_resume(struct snd_soc_codec *codec)
#define da7218_resume NULL
#endif
-static struct snd_soc_codec_driver soc_codec_dev_da7218 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da7218 = {
.probe = da7218_probe,
.remove = da7218_remove,
.suspend = da7218_suspend,
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index f71d72c22bfc..6f088536df32 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -1891,7 +1891,7 @@ static int da7219_resume(struct snd_soc_codec *codec)
#define da7219_resume NULL
#endif
-static struct snd_soc_codec_driver soc_codec_dev_da7219 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da7219 = {
.probe = da7219_probe,
.remove = da7219_remove,
.suspend = da7219_suspend,
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index c1cc1c1c28f2..83db4d23c90b 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -1499,7 +1499,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_da732x = {
+static const struct snd_soc_codec_driver soc_codec_dev_da732x = {
.set_bias_level = da732x_set_bias_level,
.component_driver = {
.controls = da732x_snd_controls,
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 4efb5f897a0c..bd7faaee5802 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1451,7 +1451,7 @@ static int da9055_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_da9055 = {
+static const struct snd_soc_codec_driver soc_codec_dev_da9055 = {
.probe = da9055_probe,
.set_bias_level = da9055_set_bias_level,
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index c82b9dc41e9a..b88a1ee66f80 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -19,6 +19,8 @@
*
*/
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -27,6 +29,34 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+static int dmic_daiops_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct gpio_desc *dmic_en = snd_soc_dai_get_drvdata(dai);
+
+ if (!dmic_en)
+ return 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ gpiod_set_value(dmic_en, 1);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ gpiod_set_value(dmic_en, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+ .trigger = dmic_daiops_trigger,
+};
+
static struct snd_soc_dai_driver dmic_dai = {
.name = "dmic-hifi",
.capture = {
@@ -38,8 +68,23 @@ static struct snd_soc_dai_driver dmic_dai = {
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S16_LE,
},
+ .ops = &dmic_dai_ops,
};
+static int dmic_codec_probe(struct snd_soc_codec *codec)
+{
+ struct gpio_desc *dmic_en;
+
+ dmic_en = devm_gpiod_get_optional(codec->dev,
+ "dmicen", GPIOD_OUT_LOW);
+ if (IS_ERR(dmic_en))
+ return PTR_ERR(dmic_en);
+
+ snd_soc_codec_set_drvdata(codec, dmic_en);
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0,
SND_SOC_NOPM, 0, 0),
@@ -50,7 +95,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"DMIC AIF", NULL, "DMic"},
};
-static struct snd_soc_codec_driver soc_dmic = {
+static const struct snd_soc_codec_driver soc_dmic = {
+ .probe = dmic_codec_probe,
.component_driver = {
.dapm_widgets = dmic_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets),
@@ -73,9 +119,15 @@ static int dmic_dev_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:dmic-codec");
+static const struct of_device_id dmic_dev_match[] = {
+ {.compatible = "dmic-codec"},
+ {}
+};
+
static struct platform_driver dmic_driver = {
.driver = {
.name = "dmic-codec",
+ .of_match_table = dmic_dev_match,
},
.probe = dmic_dev_probe,
.remove = dmic_dev_remove,
diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c
index 25ede825d349..3869025754d8 100644
--- a/sound/soc/codecs/es7134.c
+++ b/sound/soc/codecs/es7134.c
@@ -69,7 +69,7 @@ static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
{ "AOUTR", NULL, "DAC" },
};
-static struct snd_soc_codec_driver es7134_codec_driver = {
+static const struct snd_soc_codec_driver es7134_codec_driver = {
.component_driver = {
.dapm_widgets = es7134_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(es7134_dapm_widgets),
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index ecc02449c569..da2d353af5ba 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -502,7 +502,7 @@ static int es8316_mute(struct snd_soc_dai *dai, int mute)
#define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE)
-static struct snd_soc_dai_ops es8316_ops = {
+static const struct snd_soc_dai_ops es8316_ops = {
.startup = es8316_pcm_startup,
.hw_params = es8316_pcm_hw_params,
.set_fmt = es8316_set_dai_fmt,
@@ -554,7 +554,7 @@ static int es8316_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_es8316 = {
+static const struct snd_soc_codec_driver soc_codec_dev_es8316 = {
.probe = es8316_probe,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index ed7cc42d1ee2..bcdb8914ec16 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -830,7 +830,7 @@ const struct regmap_config es8328_regmap_config = {
};
EXPORT_SYMBOL_GPL(es8328_regmap_config);
-static struct snd_soc_codec_driver es8328_codec_driver = {
+static const struct snd_soc_codec_driver es8328_codec_driver = {
.probe = es8328_codec_probe,
.suspend = es8328_suspend,
.resume = es8328_resume,
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index bc2e74ff3b2d..e824d47cc22b 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -121,6 +121,10 @@ struct hdac_hdmi_dai_port_map {
struct hdac_hdmi_cvt *cvt;
};
+struct hdac_hdmi_drv_data {
+ unsigned int vendor_nid;
+};
+
struct hdac_hdmi_priv {
struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
struct list_head pin_list;
@@ -131,6 +135,7 @@ struct hdac_hdmi_priv {
int num_ports;
struct mutex pin_mutex;
struct hdac_chmap chmap;
+ struct hdac_hdmi_drv_data *drv_data;
};
static struct hdac_hdmi_pcm *
@@ -1321,6 +1326,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
}
#define INTEL_VENDOR_NID 0x08
+#define INTEL_GLK_VENDOR_NID 0x0b
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
@@ -1329,14 +1335,17 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
{
unsigned int vendor_param;
+ struct hdac_ext_device *edev = to_ehdac_device(hdac);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
- vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+ vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
return;
vendor_param |= INTEL_EN_ALL_PIN_CVTS;
- vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+ vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1)
return;
@@ -1345,22 +1354,25 @@ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
{
unsigned int vendor_param;
+ struct hdac_ext_device *edev = to_ehdac_device(hdac);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
- vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+ vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
return;
/* enable DP1.2 mode */
vendor_param |= INTEL_EN_DP12;
- vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+ vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1)
return;
}
-static struct snd_soc_dai_ops hdmi_dai_ops = {
+static const struct snd_soc_dai_ops hdmi_dai_ops = {
.startup = hdac_hdmi_pcm_open,
.shutdown = hdac_hdmi_pcm_close,
.hw_params = hdac_hdmi_set_hw_params,
@@ -1858,7 +1870,7 @@ static void hdmi_codec_complete(struct device *dev)
#define hdmi_codec_complete NULL
#endif
-static struct snd_soc_codec_driver hdmi_hda_codec = {
+static const struct snd_soc_codec_driver hdmi_hda_codec = {
.probe = hdmi_codec_probe,
.remove = hdmi_codec_remove,
.idle_bias_off = true,
@@ -1927,6 +1939,14 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
return port->eld.info.spk_alloc;
}
+static struct hdac_hdmi_drv_data intel_glk_drv_data = {
+ .vendor_nid = INTEL_GLK_VENDOR_NID,
+};
+
+static struct hdac_hdmi_drv_data intel_drv_data = {
+ .vendor_nid = INTEL_VENDOR_NID,
+};
+
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
{
struct hdac_device *codec = &edev->hdac;
@@ -1935,6 +1955,8 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
struct hdac_ext_link *hlink = NULL;
int num_dais = 0;
int ret = 0;
+ struct hdac_driver *hdrv = drv_to_hdac_driver(codec->dev.driver);
+ const struct hda_device_id *hdac_id = hdac_get_device_id(codec, hdrv);
/* hold the ref while we probe */
hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
@@ -1956,6 +1978,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
+ if (hdac_id->driver_data)
+ hdmi_priv->drv_data =
+ (struct hdac_hdmi_drv_data *)hdac_id->driver_data;
+ else
+ hdmi_priv->drv_data = &intel_drv_data;
+
dev_set_drvdata(&codec->dev, edev);
INIT_LIST_HEAD(&hdmi_priv->pin_list);
@@ -2127,7 +2155,8 @@ static const struct hda_device_id hdmi_list[] = {
HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
- HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", 0),
+ HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
+ &intel_glk_drv_data),
{}
};
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 22ed0dc88f0a..3abf82563408 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -67,14 +67,14 @@ struct hdmi_codec_cea_spk_alloc {
};
/* Channel maps stereo HDMI */
-const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = {
+static const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = {
{ .channels = 2,
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
{ }
};
/* Channel maps for multi-channel playbacks, up to 8 n_ch */
-const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
+static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
{ .channels = 2, /* CA_ID 0x00 */
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
{ .channels = 4, /* CA_ID 0x01 */
@@ -326,7 +326,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc)
{
int i;
- const unsigned long hdmi_codec_eld_spk_alloc_bits[] = {
+ static const unsigned long hdmi_codec_eld_spk_alloc_bits[] = {
[0] = FL | FR, [1] = LFE, [2] = FC, [3] = RL | RR,
[4] = RC, [5] = FLC | FRC, [6] = RLC | RRC,
};
@@ -340,7 +340,7 @@ static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc)
return spk_mask;
}
-void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp)
+static void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp)
{
u8 spk_alloc;
unsigned long spk_mask;
@@ -399,18 +399,6 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
return 0;
}
-
-static const struct snd_kcontrol_new hdmi_controls[] = {
- {
- .access = SNDRV_CTL_ELEM_ACCESS_READ |
- SNDRV_CTL_ELEM_ACCESS_VOLATILE,
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .name = "ELD",
- .info = hdmi_eld_ctl_info,
- .get = hdmi_eld_ctl_get,
- },
-};
-
static int hdmi_codec_new_stream(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -668,6 +656,16 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
{
struct snd_soc_dai_driver *drv = dai->driver;
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_new hdmi_eld_ctl = {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "ELD",
+ .info = hdmi_eld_ctl_info,
+ .get = hdmi_eld_ctl_get,
+ .device = rtd->pcm->device,
+ };
int ret;
dev_dbg(dai->dev, "%s()\n", __func__);
@@ -686,14 +684,19 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
- return 0;
+ /* add ELD ctl with the device number corresponding to the PCM stream */
+ kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component);
+ if (!kctl)
+ return -ENOMEM;
+
+ return snd_ctl_add(rtd->card->snd_card, kctl);
}
-static struct snd_soc_dai_driver hdmi_i2s_dai = {
+static const struct snd_soc_dai_driver hdmi_i2s_dai = {
.name = "i2s-hifi",
.id = DAI_ID_I2S,
.playback = {
- .stream_name = "Playback",
+ .stream_name = "I2S Playback",
.channels_min = 2,
.channels_max = 8,
.rates = HDMI_RATES,
@@ -708,7 +711,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.name = "spdif-hifi",
.id = DAI_ID_SPDIF,
.playback = {
- .stream_name = "Playback",
+ .stream_name = "SPDIF Playback",
.channels_min = 2,
.channels_max = 2,
.rates = HDMI_RATES,
@@ -730,10 +733,8 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
return ret;
}
-static struct snd_soc_codec_driver hdmi_codec = {
+static const struct snd_soc_codec_driver hdmi_codec = {
.component_driver = {
- .controls = hdmi_controls,
- .num_controls = ARRAY_SIZE(hdmi_controls),
.dapm_widgets = hdmi_widgets,
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
.dapm_routes = hdmi_routes,
diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c
index dd850b93938d..651206273f36 100644
--- a/sound/soc/codecs/ics43432.c
+++ b/sound/soc/codecs/ics43432.c
@@ -37,7 +37,7 @@ static struct snd_soc_dai_driver ics43432_dai = {
},
};
-static struct snd_soc_codec_driver ics43432_codec_driver = {
+static const struct snd_soc_codec_driver ics43432_codec_driver = {
};
static int ics43432_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
index b918ba5c8ce5..6b59b6f08298 100644
--- a/sound/soc/codecs/inno_rk3036.c
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -310,7 +310,7 @@ static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops rk3036_codec_dai_ops = {
+static const struct snd_soc_dai_ops rk3036_codec_dai_ops = {
.set_fmt = rk3036_codec_dai_set_fmt,
.hw_params = rk3036_codec_dai_hw_params,
};
@@ -376,7 +376,7 @@ static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static struct snd_soc_codec_driver rk3036_codec_driver = {
+static const struct snd_soc_codec_driver rk3036_codec_driver = {
.probe = rk3036_codec_probe,
.remove = rk3036_codec_remove,
.set_bias_level = rk3036_codec_set_bias_level,
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index a4b0eded984a..5ca99280ae00 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -1087,7 +1087,7 @@ static struct snd_soc_dai_driver isabelle_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_isabelle = {
+static const struct snd_soc_codec_driver soc_codec_dev_isabelle = {
.set_bias_level = isabelle_set_bias_level,
.component_driver = {
.controls = isabelle_snd_controls,
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 0290fab383da..6324ccdc8a5c 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -293,7 +293,7 @@ static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
+static const struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
.probe = jz4740_codec_dev_probe,
.set_bias_level = jz4740_codec_set_bias_level,
.suspend_bias_off = true,
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index 558de1053f73..1e964079642a 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -100,7 +100,7 @@ static const struct snd_soc_dapm_route lm4857_routes[] = {
{ "EP", "Earpiece", "Mode" },
};
-static struct snd_soc_component_driver lm4857_component_driver = {
+static const struct snd_soc_component_driver lm4857_component_driver = {
.controls = lm4857_controls,
.num_controls = ARRAY_SIZE(lm4857_controls),
.dapm_widgets = lm4857_dapm_widgets,
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 8d413c2677cc..41e09d1287b8 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1389,7 +1389,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
+static const struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
.set_bias_level = lm49453_set_bias_level,
.component_driver = {
.controls = lm49453_snd_controls,
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
index 5b82e26cd5d1..7017c0389e73 100644
--- a/sound/soc/codecs/max9768.c
+++ b/sound/soc/codecs/max9768.c
@@ -151,7 +151,7 @@ static int max9768_probe(struct snd_soc_component *component)
return 0;
}
-static struct snd_soc_component_driver max9768_component_driver = {
+static const struct snd_soc_component_driver max9768_component_driver = {
.probe = max9768_probe,
.controls = max9768_volume,
.num_controls = ARRAY_SIZE(max9768_volume),
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 72f77455582e..f0bb830874e5 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1698,7 +1698,7 @@ static int max98088_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max98088 = {
.probe = max98088_probe,
.remove = max98088_remove,
.set_bias_level = max98088_set_bias_level,
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 66828480d484..13bcfb1ef9b4 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2499,7 +2499,7 @@ static void max98090_seq_notifier(struct snd_soc_dapm_context *dapm,
}
}
-static struct snd_soc_codec_driver soc_codec_dev_max98090 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max98090 = {
.probe = max98090_probe,
.remove = max98090_remove,
.seq_notifier = max98090_seq_notifier,
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 6f8a757876ed..5ead87d2ab1d 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2102,7 +2102,7 @@ static int max98095_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_max98095 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max98095 = {
.probe = max98095_probe,
.remove = max98095_remove,
.suspend = max98095_suspend,
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index 6a6b68a4cb52..426ed2dae6ca 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -72,7 +72,7 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver max98357a_codec_driver = {
+static const struct snd_soc_codec_driver max98357a_codec_driver = {
.probe = max98357a_codec_probe,
.component_driver = {
.dapm_widgets = max98357a_dapm_widgets,
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
index 781be9ba8dba..7bc2a17c1e94 100644
--- a/sound/soc/codecs/max98371.c
+++ b/sound/soc/codecs/max98371.c
@@ -349,12 +349,14 @@ static struct snd_soc_dai_driver max98371_dai[] = {
};
static const struct snd_soc_codec_driver max98371_codec = {
- .controls = max98371_snd_controls,
- .num_controls = ARRAY_SIZE(max98371_snd_controls),
- .dapm_routes = max98371_audio_map,
- .num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
- .dapm_widgets = max98371_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
+ .component_driver = {
+ .controls = max98371_snd_controls,
+ .num_controls = ARRAY_SIZE(max98371_snd_controls),
+ .dapm_routes = max98371_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
+ .dapm_widgets = max98371_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
+ },
};
static const struct regmap_config max98371_regmap = {
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index 0610840733d1..a3dfc918c278 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -301,7 +301,7 @@ static int max9850_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max9850 = {
.probe = max9850_probe,
.set_bias_level = max9850_set_bias_level,
.suspend_bias_off = true,
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 499bdbfd0a2d..a2dc6a47f466 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -534,7 +534,7 @@ static int max9860_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static struct snd_soc_codec_driver max9860_codec_driver = {
+static const struct snd_soc_codec_driver max9860_codec_driver = {
.set_bias_level = max9860_set_bias_level,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 2a40a69a7513..2f60924fe919 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -350,7 +350,7 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
-static struct snd_soc_dai_ops max9867_dai_ops = {
+static const struct snd_soc_dai_ops max9867_dai_ops = {
.set_fmt = max9867_dai_set_fmt,
.set_sysclk = max9867_set_dai_sysclk,
.prepare = max9867_prepare,
@@ -413,7 +413,7 @@ static int max9867_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver max9867_codec = {
+static const struct snd_soc_codec_driver max9867_codec = {
.probe = max9867_probe,
.component_driver = {
.controls = max9867_snd_controls,
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index 1eff7e0b092e..03d07bf4d942 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -213,8 +213,8 @@ static bool max98926_readable_register(struct device *dev, unsigned int reg)
}
};
-DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0);
-DECLARE_TLV_DB_RANGE(max98926_current_tlv,
+static DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0);
+static DECLARE_TLV_DB_RANGE(max98926_current_tlv,
0, 11, TLV_DB_SCALE_ITEM(20, 20, 0),
12, 15, TLV_DB_SCALE_ITEM(320, 40, 0),
);
@@ -459,7 +459,7 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream,
#define MAX98926_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops max98926_dai_ops = {
+static const struct snd_soc_dai_ops max98926_dai_ops = {
.set_fmt = max98926_dai_set_fmt,
.hw_params = max98926_dai_hw_params,
};
@@ -496,7 +496,7 @@ static int max98926_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_max98926 = {
+static const struct snd_soc_codec_driver soc_codec_dev_max98926 = {
.probe = max98926_probe,
.component_driver = {
.controls = max98926_snd_controls,
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index b5ee29499e16..d9dbbe72f8ad 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -44,9 +44,9 @@ static struct reg_default max98927_reg[] = {
{MAX98927_R0011_CLK_MON, 0x00},
{MAX98927_R0012_WDOG_CTRL, 0x00},
{MAX98927_R0013_WDOG_RST, 0x00},
- {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH, 0x00},
- {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH, 0x00},
- {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS, 0x00},
+ {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH, 0x75},
+ {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH, 0x8c},
+ {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS, 0x08},
{MAX98927_R0017_PIN_CFG, 0x55},
{MAX98927_R0018_PCM_RX_EN_A, 0x00},
{MAX98927_R0019_PCM_RX_EN_B, 0x00},
@@ -82,14 +82,14 @@ static struct reg_default max98927_reg[] = {
{MAX98927_R003A_AMP_EN, 0x00},
{MAX98927_R003B_SPK_SRC_SEL, 0x00},
{MAX98927_R003C_SPK_GAIN, 0x00},
- {MAX98927_R003D_SSM_CFG, 0x01},
+ {MAX98927_R003D_SSM_CFG, 0x04},
{MAX98927_R003E_MEAS_EN, 0x00},
{MAX98927_R003F_MEAS_DSP_CFG, 0x04},
{MAX98927_R0040_BOOST_CTRL0, 0x00},
{MAX98927_R0041_BOOST_CTRL3, 0x00},
{MAX98927_R0042_BOOST_CTRL1, 0x00},
{MAX98927_R0043_MEAS_ADC_CFG, 0x00},
- {MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00},
+ {MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x01},
{MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x00},
{MAX98927_R0046_ADC_CH0_DIVIDE, 0x00},
{MAX98927_R0047_ADC_CH1_DIVIDE, 0x00},
@@ -159,7 +159,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
mode = MAX98927_PCM_MASTER_MODE_MASTER;
break;
default:
- dev_err(codec->dev, "DAI clock mode unsupported");
+ dev_err(codec->dev, "DAI clock mode unsupported\n");
return -EINVAL;
}
@@ -175,7 +175,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE;
break;
default:
- dev_err(codec->dev, "DAI invert mode unsupported");
+ dev_err(codec->dev, "DAI invert mode unsupported\n");
return -EINVAL;
}
@@ -311,7 +311,7 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
break;
default:
- dev_err(codec->dev, "format unsupported %d",
+ dev_err(codec->dev, "format unsupported %d\n",
params_format(params));
goto err;
}
@@ -418,11 +418,6 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
regmap_update_bits(max98927->regmap,
MAX98927_R003A_AMP_EN,
MAX98927_AMP_EN_MASK, 1);
- /* enable VMON and IMON */
- regmap_update_bits(max98927->regmap,
- MAX98927_R003E_MEAS_EN,
- MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN,
- MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN);
regmap_update_bits(max98927->regmap,
MAX98927_R00FF_GLOBAL_SHDN,
MAX98927_GLOBAL_EN_MASK, 1);
@@ -434,10 +429,6 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
regmap_update_bits(max98927->regmap,
MAX98927_R003A_AMP_EN,
MAX98927_AMP_EN_MASK, 0);
- /* disable VMON and IMON */
- regmap_update_bits(max98927->regmap,
- MAX98927_R003E_MEAS_EN,
- MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 0);
break;
default:
return 0;
@@ -456,14 +447,24 @@ static const struct soc_enum dai_sel_enum =
static const struct snd_kcontrol_new max98927_dai_controls =
SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
+static const struct snd_kcontrol_new max98927_vi_control =
+ SOC_DAPM_SINGLE("Switch", MAX98927_R003F_MEAS_DSP_CFG, 2, 1, 0);
+
static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
- SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
0, 0, max98927_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
&max98927_dai_controls),
SND_SOC_DAPM_OUTPUT("BE_OUT"),
+ SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
+ MAX98927_R003E_MEAS_EN, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
+ MAX98927_R003E_MEAS_EN, 1, 0),
+ SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
+ &max98927_vi_control),
+ SND_SOC_DAPM_SIGGEN("VMON"),
+ SND_SOC_DAPM_SIGGEN("IMON"),
};
static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0);
@@ -495,6 +496,13 @@ static bool max98927_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX98927_R0001_INT_RAW1 ... MAX98927_R0009_INT_FLAG3:
+ case MAX98927_R004C_MEAS_ADC_CH0_READ:
+ case MAX98927_R004D_MEAS_ADC_CH1_READ:
+ case MAX98927_R004E_MEAS_ADC_CH2_READ:
+ case MAX98927_R0051_BROWNOUT_STATUS:
+ case MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ:
+ case MAX98927_R01FF_REV_ID:
+ case MAX98927_R0100_SOFT_RESET:
return true;
default:
return false;
@@ -543,11 +551,16 @@ static const struct snd_kcontrol_new max98927_snd_controls[] = {
};
static const struct snd_soc_dapm_route max98927_audio_map[] = {
- {"Amp Enable", NULL, "DAI_OUT"},
+ /* Plabyack */
{"DAI Sel Mux", "Left", "Amp Enable"},
{"DAI Sel Mux", "Right", "Amp Enable"},
{"DAI Sel Mux", "LeftRight", "Amp Enable"},
{"BE_OUT", NULL, "DAI Sel Mux"},
+ /* Capture */
+ { "VI Sense", "Switch", "VMON" },
+ { "VI Sense", "Switch", "IMON" },
+ { "Voltage Sense", NULL, "VI Sense" },
+ { "Current Sense", NULL, "VI Sense" },
};
static struct snd_soc_dai_driver max98927_dai[] = {
@@ -577,7 +590,6 @@ static int max98927_probe(struct snd_soc_codec *codec)
max98927->codec = codec;
codec->control_data = max98927->regmap;
- codec->cache_bypass = 1;
/* Software Reset */
regmap_write(max98927->regmap,
@@ -694,6 +706,31 @@ static int max98927_probe(struct snd_soc_codec *codec)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int max98927_suspend(struct device *dev)
+{
+ struct max98927_priv *max98927 = dev_get_drvdata(dev);
+
+ regcache_cache_only(max98927->regmap, true);
+ regcache_mark_dirty(max98927->regmap);
+ return 0;
+}
+static int max98927_resume(struct device *dev)
+{
+ struct max98927_priv *max98927 = dev_get_drvdata(dev);
+
+ regmap_write(max98927->regmap,
+ MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+ regcache_cache_only(max98927->regmap, false);
+ regcache_sync(max98927->regmap);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops max98927_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(max98927_suspend, max98927_resume)
+};
+
static const struct snd_soc_codec_driver soc_codec_dev_max98927 = {
.probe = max98927_probe,
.component_driver = {
@@ -721,14 +758,14 @@ static void max98927_slot_config(struct i2c_client *i2c,
struct max98927_priv *max98927)
{
int value;
+ struct device *dev = &i2c->dev;
- if (!of_property_read_u32(i2c->dev.of_node,
- "vmon-slot-no", &value))
+ if (!device_property_read_u32(dev, "vmon-slot-no", &value))
max98927->v_l_slot = value & 0xF;
else
max98927->v_l_slot = 0;
- if (!of_property_read_u32(i2c->dev.of_node,
- "imon-slot-no", &value))
+
+ if (!device_property_read_u32(dev, "imon-slot-no", &value))
max98927->i_l_slot = value & 0xF;
else
max98927->i_l_slot = 1;
@@ -827,7 +864,7 @@ static struct i2c_driver max98927_i2c_driver = {
.name = "max98927",
.of_match_table = of_match_ptr(max98927_of_match),
.acpi_match_table = ACPI_PTR(max98927_acpi_match),
- .pm = NULL,
+ .pm = &max98927_pm,
},
.probe = max98927_i2c_probe,
.remove = max98927_i2c_remove,
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 90562703dcfd..4fd8d1dc4eef 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -733,7 +733,7 @@ static struct regmap *mc13783_get_regmap(struct device *dev)
return dev_get_regmap(dev->parent, NULL);
}
-static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
+static const struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
.probe = mc13783_probe,
.remove = mc13783_remove,
.get_regmap = mc13783_get_regmap,
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 69e5e18880c5..5cc960d8211e 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -537,7 +537,7 @@ static int ml26124_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
.probe = ml26124_probe,
.set_bias_level = ml26124_set_bias_level,
.suspend_bias_off = true,
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index a78802920c3c..549c269acc7d 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -12,9 +12,16 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
+#include <sound/jack.h>
#define CDC_D_REVISION1 (0xf000)
#define CDC_D_PERPH_SUBTYPE (0xf005)
+#define CDC_D_INT_EN_SET (0x015)
+#define CDC_D_INT_EN_CLR (0x016)
+#define MBHC_SWITCH_INT BIT(7)
+#define MBHC_MIC_ELECTRICAL_INS_REM_DET BIT(6)
+#define MBHC_BUTTON_PRESS_DET BIT(5)
+#define MBHC_BUTTON_RELEASE_DET BIT(4)
#define CDC_D_CDC_RST_CTL (0xf046)
#define RST_CTL_DIG_SW_RST_N_MASK BIT(7)
#define RST_CTL_DIG_SW_RST_N_RESET 0
@@ -36,7 +43,9 @@
#define CDC_D_CDC_DIG_CLK_CTL (0xf04A)
#define DIG_CLK_CTL_RXD1_CLK_EN BIT(0)
#define DIG_CLK_CTL_RXD2_CLK_EN BIT(1)
-#define DIG_CLK_CTL_RXD3_CLK_EN BIT(3)
+#define DIG_CLK_CTL_RXD3_CLK_EN BIT(2)
+#define DIG_CLK_CTL_D_MBHC_CLK_EN_MASK BIT(3)
+#define DIG_CLK_CTL_D_MBHC_CLK_EN BIT(3)
#define DIG_CLK_CTL_TXD_CLK_EN BIT(4)
#define DIG_CLK_CTL_NCP_CLK_EN_MASK BIT(6)
#define DIG_CLK_CTL_NCP_CLK_EN BIT(6)
@@ -93,8 +102,12 @@
#define MICB_1_EN_TX3_GND_SEL_TX_GND 0
#define CDC_A_MICB_1_VAL (0xf141)
+#define MICB_MIN_VAL 1600
+#define MICB_STEP_SIZE 50
+#define MICB_VOLTAGE_REGVAL(v) ((v - MICB_MIN_VAL)/MICB_STEP_SIZE)
#define MICB_1_VAL_MICB_OUT_VAL_MASK GENMASK(7, 3)
#define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16) << 3)
+#define MICB_1_VAL_MICB_OUT_VAL_V1P80V ((0x4) << 3)
#define CDC_A_MICB_1_CTL (0xf142)
#define MICB_1_CTL_CFILT_REF_SEL_MASK BIT(1)
@@ -128,8 +141,51 @@
#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND 0
#define CDC_A_MICB_2_EN (0xf144)
+#define CDC_A_MICB_2_EN_ENABLE BIT(7)
+#define CDC_A_MICB_2_PULL_DOWN_EN_MASK BIT(5)
+#define CDC_A_MICB_2_PULL_DOWN_EN BIT(5)
#define CDC_A_TX_1_2_ATEST_CTL_2 (0xf145)
#define CDC_A_MASTER_BIAS_CTL (0xf146)
+#define CDC_A_MBHC_DET_CTL_1 (0xf147)
+#define CDC_A_MBHC_DET_CTL_L_DET_EN BIT(7)
+#define CDC_A_MBHC_DET_CTL_GND_DET_EN BIT(6)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION BIT(5)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_REMOVAL (0)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK BIT(5)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT (5)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO BIT(4)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MANUAL BIT(3)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MASK GENMASK(4, 3)
+#define CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN BIT(2)
+#define CDC_A_MBHC_DET_CTL_2 (0xf150)
+#define CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 (BIT(7) | BIT(6))
+#define CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD BIT(5)
+#define CDC_A_PLUG_TYPE_MASK GENMASK(4, 3)
+#define CDC_A_HPHL_PLUG_TYPE_NO BIT(4)
+#define CDC_A_GND_PLUG_TYPE_NO BIT(3)
+#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN_MASK BIT(0)
+#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN BIT(0)
+#define CDC_A_MBHC_FSM_CTL (0xf151)
+#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN BIT(7)
+#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK BIT(7)
+#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA (0x3 << 4)
+#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK GENMASK(6, 4)
+#define CDC_A_MBHC_DBNC_TIMER (0xf152)
+#define CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS BIT(3)
+#define CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS (0x9 << 4)
+#define CDC_A_MBHC_BTN0_ZDET_CTL_0 (0xf153)
+#define CDC_A_MBHC_BTN1_ZDET_CTL_1 (0xf154)
+#define CDC_A_MBHC_BTN2_ZDET_CTL_2 (0xf155)
+#define CDC_A_MBHC_BTN3_CTL (0xf156)
+#define CDC_A_MBHC_BTN4_CTL (0xf157)
+#define CDC_A_MBHC_BTN_VREF_FINE_SHIFT (2)
+#define CDC_A_MBHC_BTN_VREF_FINE_MASK GENMASK(4, 2)
+#define CDC_A_MBHC_BTN_VREF_COARSE_MASK GENMASK(7, 5)
+#define CDC_A_MBHC_BTN_VREF_COARSE_SHIFT (5)
+#define CDC_A_MBHC_BTN_VREF_MASK (CDC_A_MBHC_BTN_VREF_COARSE_MASK | \
+ CDC_A_MBHC_BTN_VREF_FINE_MASK)
+#define CDC_A_MBHC_RESULT_1 (0xf158)
+#define CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK GENMASK(4, 0)
#define CDC_A_TX_1_EN (0xf160)
#define CDC_A_TX_2_EN (0xf161)
#define CDC_A_TX_1_2_TEST_CTL_1 (0xf162)
@@ -213,18 +269,37 @@
#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4;
+static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET;
+
static const char * const supply_names[] = {
"vdd-cdc-io",
"vdd-cdc-tx-rx-cx",
};
+#define MBHC_MAX_BUTTONS (5)
+
struct pm8916_wcd_analog_priv {
u16 pmic_rev;
u16 codec_version;
+ bool mbhc_btn_enabled;
+ /* special event to detect accessory type */
+ bool mbhc_btn0_pressed;
+ bool detect_accessory_type;
struct clk *mclk;
+ struct snd_soc_codec *codec;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+ struct snd_soc_jack *jack;
+ bool hphl_jack_type_normally_open;
+ bool gnd_jack_type_normally_open;
+ /* Voltage threshold when internal current source of 100uA is used */
+ u32 vref_btn_cs[MBHC_MAX_BUTTONS];
+ /* Voltage threshold when microphone bias is ON */
+ u32 vref_btn_micb[MBHC_MAX_BUTTONS];
unsigned int micbias1_cap_mode;
unsigned int micbias2_cap_mode;
+ unsigned int micbias_mv;
};
static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
@@ -265,18 +340,25 @@ static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = {
static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
{
+ struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
MICB_1_CTL_EXT_PRECHARG_EN_MASK |
MICB_1_CTL_INT_PRECHARG_BYP_MASK,
MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL
| MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
- snd_soc_write(codec, CDC_A_MICB_1_VAL, MICB_1_VAL_MICB_OUT_VAL_V2P70V);
- /*
- * Special headset needs MICBIAS as 2.7V so wait for
- * 50 msec for the MICBIAS to reach 2.7 volts.
- */
- msleep(50);
+ if (wcd->micbias_mv) {
+ snd_soc_write(codec, CDC_A_MICB_1_VAL,
+ MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
+ /*
+ * Special headset needs MICBIAS as 2.7V so wait for
+ * 50 msec for the MICBIAS to reach 2.7 volts.
+ */
+ if (wcd->micbias_mv >= 2700)
+ msleep(50);
+ }
+
snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
MICB_1_CTL_EXT_PRECHARG_EN_MASK |
MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0);
@@ -361,6 +443,97 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct
wcd->micbias1_cap_mode);
}
+static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
+{
+ struct snd_soc_codec *codec = wcd->codec;
+ u32 plug_type = 0;
+ u32 int_en_mask;
+
+ snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
+ CDC_A_MBHC_DET_CTL_L_DET_EN |
+ CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
+ CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
+ CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);
+
+ if (wcd->hphl_jack_type_normally_open)
+ plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;
+
+ if (wcd->gnd_jack_type_normally_open)
+ plug_type |= CDC_A_GND_PLUG_TYPE_NO;
+
+ snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
+ CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
+ CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
+ plug_type |
+ CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);
+
+
+ snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
+ CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
+ CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);
+
+ /* enable MBHC clock */
+ snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+ DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
+ DIG_CLK_CTL_D_MBHC_CLK_EN);
+
+ int_en_mask = MBHC_SWITCH_INT;
+ if (wcd->mbhc_btn_enabled)
+ int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;
+
+ snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
+ snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
+ wcd->mbhc_btn0_pressed = false;
+ wcd->detect_accessory_type = true;
+}
+
+static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
+ bool micbias2_enabled)
+{
+ struct snd_soc_codec *codec = priv->codec;
+ u32 coarse, fine, reg_val, reg_addr;
+ int *vrefs, i;
+
+ if (!micbias2_enabled) { /* use internal 100uA Current source */
+ /* Enable internal 2.2k Internal Rbias Resistor */
+ snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+ MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
+ MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
+ /* Remove pull down on MIC BIAS2 */
+ snd_soc_update_bits(codec, CDC_A_MICB_2_EN,
+ CDC_A_MICB_2_PULL_DOWN_EN_MASK,
+ 0);
+ /* enable 100uA internal current source */
+ snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
+ CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK,
+ CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA);
+ }
+ snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
+ CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK,
+ CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN);
+
+ if (micbias2_enabled)
+ vrefs = &priv->vref_btn_micb[0];
+ else
+ vrefs = &priv->vref_btn_cs[0];
+
+ /* program vref ranges for all the buttons */
+ reg_addr = CDC_A_MBHC_BTN0_ZDET_CTL_0;
+ for (i = 0; i < MBHC_MAX_BUTTONS; i++) {
+ /* split mv in to coarse parts of 100mv & fine parts of 12mv */
+ coarse = (vrefs[i] / 100);
+ fine = ((vrefs[i] % 100) / 12);
+ reg_val = (coarse << CDC_A_MBHC_BTN_VREF_COARSE_SHIFT) |
+ (fine << CDC_A_MBHC_BTN_VREF_FINE_SHIFT);
+ snd_soc_update_bits(codec, reg_addr,
+ CDC_A_MBHC_BTN_VREF_MASK,
+ reg_val);
+ reg_addr++;
+ }
+
+ return 0;
+}
+
static int pm8916_wcd_analog_enable_micbias_int2(struct
snd_soc_dapm_widget
*w, struct snd_kcontrol
@@ -369,6 +542,15 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ pm8916_mbhc_configure_bias(wcd, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ pm8916_mbhc_configure_bias(wcd, false);
+ break;
+ }
+
return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg,
wcd->micbias2_cap_mode);
}
@@ -536,6 +718,14 @@ static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg,
wcd_reg_defaults_2_0[reg].def);
+ priv->codec = codec;
+
+ snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
+ RST_CTL_DIG_SW_RST_N_MASK,
+ RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
+
+ pm8916_wcd_setup_mbhc(priv);
+
return 0;
}
@@ -543,6 +733,9 @@ static int pm8916_wcd_analog_remove(struct snd_soc_codec *codec)
{
struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev);
+ snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
+ RST_CTL_DIG_SW_RST_N_MASK, 0);
+
return regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
priv->supplies);
}
@@ -731,32 +924,128 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0),
};
+static int pm8916_wcd_analog_set_jack(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack,
+ void *data)
+{
+ struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+ wcd->jack = jack;
+
+ return 0;
+}
+
static struct regmap *pm8916_get_regmap(struct device *dev)
{
return dev_get_regmap(dev->parent, NULL);
}
-static int pm8916_wcd_analog_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
{
- snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
- RST_CTL_DIG_SW_RST_N_MASK,
- RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
+ struct pm8916_wcd_analog_priv *priv = arg;
- return 0;
+ if (priv->detect_accessory_type) {
+ struct snd_soc_codec *codec = priv->codec;
+ u32 val = snd_soc_read(codec, CDC_A_MBHC_RESULT_1);
+
+ /* check if its BTN0 thats released */
+ if ((val != -1) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK))
+ priv->mbhc_btn0_pressed = false;
+
+ } else {
+ snd_soc_jack_report(priv->jack, 0, btn_mask);
+ }
+
+ return IRQ_HANDLED;
}
-static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
{
- snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
- RST_CTL_DIG_SW_RST_N_MASK, 0);
+ struct pm8916_wcd_analog_priv *priv = arg;
+ struct snd_soc_codec *codec = priv->codec;
+ u32 btn_result;
+
+ btn_result = snd_soc_read(codec, CDC_A_MBHC_RESULT_1) &
+ CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK;
+
+ switch (btn_result) {
+ case 0xf:
+ snd_soc_jack_report(priv->jack, SND_JACK_BTN_4, btn_mask);
+ break;
+ case 0x7:
+ snd_soc_jack_report(priv->jack, SND_JACK_BTN_3, btn_mask);
+ break;
+ case 0x3:
+ snd_soc_jack_report(priv->jack, SND_JACK_BTN_2, btn_mask);
+ break;
+ case 0x1:
+ snd_soc_jack_report(priv->jack, SND_JACK_BTN_1, btn_mask);
+ break;
+ case 0x0:
+ /* handle BTN_0 specially for type detection */
+ if (priv->detect_accessory_type)
+ priv->mbhc_btn0_pressed = true;
+ else
+ snd_soc_jack_report(priv->jack,
+ SND_JACK_BTN_0, btn_mask);
+ break;
+ default:
+ dev_err(codec->dev,
+ "Unexpected button press result (%x)", btn_result);
+ break;
+ }
+
+ return IRQ_HANDLED;
}
-static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = {
- .startup = pm8916_wcd_analog_startup,
- .shutdown = pm8916_wcd_analog_shutdown,
-};
+static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
+{
+ struct pm8916_wcd_analog_priv *priv = arg;
+ struct snd_soc_codec *codec = priv->codec;
+ bool ins = false;
+
+ if (snd_soc_read(codec, CDC_A_MBHC_DET_CTL_1) &
+ CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK)
+ ins = true;
+
+ /* Set the detection type appropriately */
+ snd_soc_update_bits(codec, CDC_A_MBHC_DET_CTL_1,
+ CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK,
+ (!ins << CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT));
+
+
+ if (ins) { /* hs insertion */
+ bool micbias_enabled = false;
+
+ if (snd_soc_read(codec, CDC_A_MICB_2_EN) &
+ CDC_A_MICB_2_EN_ENABLE)
+ micbias_enabled = true;
+
+ pm8916_mbhc_configure_bias(priv, micbias_enabled);
+
+ /*
+ * if only a btn0 press event is receive just before
+ * insert event then its a 3 pole headphone else if
+ * both press and release event received then its
+ * a headset.
+ */
+ if (priv->mbhc_btn0_pressed)
+ snd_soc_jack_report(priv->jack,
+ SND_JACK_HEADPHONE, hs_jack_mask);
+ else
+ snd_soc_jack_report(priv->jack,
+ SND_JACK_HEADSET, hs_jack_mask);
+
+ priv->detect_accessory_type = false;
+
+ } else { /* removal */
+ snd_soc_jack_report(priv->jack, 0, hs_jack_mask);
+ priv->detect_accessory_type = true;
+ priv->mbhc_btn0_pressed = false;
+ }
+
+ return IRQ_HANDLED;
+}
static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
[0] = {
@@ -769,7 +1058,6 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
.channels_min = 1,
.channels_max = 3,
},
- .ops = &pm8916_wcd_analog_dai_ops,
},
[1] = {
.name = "pm8916_wcd_analog_pdm_tx",
@@ -781,13 +1069,13 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
.channels_min = 1,
.channels_max = 4,
},
- .ops = &pm8916_wcd_analog_dai_ops,
},
};
-static struct snd_soc_codec_driver pm8916_wcd_analog = {
+static const struct snd_soc_codec_driver pm8916_wcd_analog = {
.probe = pm8916_wcd_analog_probe,
.remove = pm8916_wcd_analog_remove,
+ .set_jack = pm8916_wcd_analog_set_jack,
.get_regmap = pm8916_get_regmap,
.component_driver = {
.controls = pm8916_wcd_analog_snd_controls,
@@ -802,6 +1090,7 @@ static struct snd_soc_codec_driver pm8916_wcd_analog = {
static int pm8916_wcd_analog_parse_dt(struct device *dev,
struct pm8916_wcd_analog_priv *priv)
{
+ int rval;
if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap"))
priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP;
@@ -813,6 +1102,42 @@ static int pm8916_wcd_analog_parse_dt(struct device *dev,
else
priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
+ of_property_read_u32(dev->of_node, "qcom,micbias-lvl",
+ &priv->micbias_mv);
+
+ if (of_property_read_bool(dev->of_node,
+ "qcom,hphl-jack-type-normally-open"))
+ priv->hphl_jack_type_normally_open = true;
+ else
+ priv->hphl_jack_type_normally_open = false;
+
+ if (of_property_read_bool(dev->of_node,
+ "qcom,gnd-jack-type-normally-open"))
+ priv->gnd_jack_type_normally_open = true;
+ else
+ priv->gnd_jack_type_normally_open = false;
+
+ priv->mbhc_btn_enabled = true;
+ rval = of_property_read_u32_array(dev->of_node,
+ "qcom,mbhc-vthreshold-low",
+ &priv->vref_btn_cs[0],
+ MBHC_MAX_BUTTONS);
+ if (rval < 0) {
+ priv->mbhc_btn_enabled = false;
+ } else {
+ rval = of_property_read_u32_array(dev->of_node,
+ "qcom,mbhc-vthreshold-high",
+ &priv->vref_btn_micb[0],
+ MBHC_MAX_BUTTONS);
+ if (rval < 0)
+ priv->mbhc_btn_enabled = false;
+ }
+
+ if (!priv->mbhc_btn_enabled)
+ dev_err(dev,
+ "DT property missing, MBHC btn detection disabled\n");
+
+
return 0;
}
@@ -820,7 +1145,7 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
{
struct pm8916_wcd_analog_priv *priv;
struct device *dev = &pdev->dev;
- int ret, i;
+ int ret, i, irq;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -852,6 +1177,48 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
return ret;
}
+ irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
+ if (irq < 0) {
+ dev_err(dev, "failed to get mbhc switch irq\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, pm8916_mbhc_switch_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "mbhc switch irq", priv);
+ if (ret)
+ dev_err(dev, "cannot request mbhc switch irq\n");
+
+ if (priv->mbhc_btn_enabled) {
+ irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
+ if (irq < 0) {
+ dev_err(dev, "failed to get button press irq\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, mbhc_btn_press_irq_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "mbhc btn press irq", priv);
+ if (ret)
+ dev_err(dev, "cannot request mbhc button press irq\n");
+
+ irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
+ if (irq < 0) {
+ dev_err(dev, "failed to get button release irq\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, mbhc_btn_release_irq_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "mbhc btn release irq", priv);
+ if (ret)
+ dev_err(dev, "cannot request mbhc button release irq\n");
+
+ }
+
dev_set_drvdata(dev, priv);
return snd_soc_register_codec(dev, &pm8916_wcd_analog,
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
index f690442af8c9..66df8f810f0d 100644
--- a/sound/soc/codecs/msm8916-wcd-digital.c
+++ b/sound/soc/codecs/msm8916-wcd-digital.c
@@ -218,6 +218,8 @@ static const char *const rx_mix1_text[] = {
static const char *const dec_mux_text[] = {
"ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
};
+
+static const char *const cic_mux_text[] = { "AMIC", "DMIC" };
static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" };
static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
@@ -256,11 +258,21 @@ static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE(
static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE(
LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text);
+/* CIC */
+static const struct soc_enum cic1_mux_enum = SOC_ENUM_SINGLE(
+ LPASS_CDC_TX1_MUX_CTL, 0, 2, cic_mux_text);
+static const struct soc_enum cic2_mux_enum = SOC_ENUM_SINGLE(
+ LPASS_CDC_TX2_MUX_CTL, 0, 2, cic_mux_text);
+
/* RDAC2 MUX */
static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM(
"DEC1 MUX Mux", dec1_mux_enum);
static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM(
"DEC2 MUX Mux", dec2_mux_enum);
+static const struct snd_kcontrol_new cic1_mux = SOC_DAPM_ENUM(
+ "CIC1 MUX Mux", cic1_mux_enum);
+static const struct snd_kcontrol_new cic2_mux = SOC_DAPM_ENUM(
+ "CIC2 MUX Mux", cic2_mux_enum);
static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM(
"RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]);
static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM(
@@ -500,6 +512,8 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = {
SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
&rx3_mix1_inp3_mux),
+ SND_SOC_DAPM_MUX("CIC1 MUX", SND_SOC_NOPM, 0, 0, &cic1_mux),
+ SND_SOC_DAPM_MUX("CIC2 MUX", SND_SOC_NOPM, 0, 0, &cic2_mux),
/* TX */
SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -536,6 +550,8 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = {
/* Connectivity Clock */
SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0,
NULL, 0),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
};
@@ -568,6 +584,15 @@ static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec)
return 0;
}
+static int msm8916_wcd_digital_codec_set_sysclk(struct snd_soc_codec *codec,
+ int clk_id, int source,
+ unsigned int freq, int dir)
+{
+ struct msm8916_wcd_digital_priv *p = dev_get_drvdata(codec->dev);
+
+ return clk_set_rate(p->mclk, freq);
+}
+
static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -646,6 +671,11 @@ static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = {
{"AIF1 Capture", NULL, "I2S TX2"},
{"AIF1 Capture", NULL, "I2S TX3"},
+ {"CIC1 MUX", "DMIC", "DEC1 MUX"},
+ {"CIC1 MUX", "AMIC", "DEC1 MUX"},
+ {"CIC2 MUX", "DMIC", "DEC2 MUX"},
+ {"CIC2 MUX", "AMIC", "DEC2 MUX"},
+
/* Decimator Inputs */
{"DEC1 MUX", "DMIC1", "DMIC1"},
{"DEC1 MUX", "DMIC2", "DMIC2"},
@@ -664,8 +694,8 @@ static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = {
{"DMIC1", NULL, "DMIC_CLK"},
{"DMIC2", NULL, "DMIC_CLK"},
- {"I2S TX1", NULL, "DEC1 MUX"},
- {"I2S TX2", NULL, "DEC2 MUX"},
+ {"I2S TX1", NULL, "CIC1 MUX"},
+ {"I2S TX2", NULL, "CIC2 MUX"},
{"I2S TX1", NULL, "TX_I2S_CLK"},
{"I2S TX2", NULL, "TX_I2S_CLK"},
@@ -788,7 +818,7 @@ static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream,
LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0);
}
-static struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = {
+static const struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = {
.startup = msm8916_wcd_digital_startup,
.shutdown = msm8916_wcd_digital_shutdown,
.hw_params = msm8916_wcd_digital_hw_params,
@@ -821,8 +851,9 @@ static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = {
},
};
-static struct snd_soc_codec_driver msm8916_wcd_digital = {
+static const struct snd_soc_codec_driver msm8916_wcd_digital = {
.probe = msm8916_wcd_digital_codec_probe,
+ .set_sysclk = msm8916_wcd_digital_codec_set_sysclk,
.component_driver = {
.controls = msm8916_wcd_digital_snd_controls,
.num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls),
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index c8bcb1db966d..f9c9933acffb 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -735,7 +735,7 @@ static int __maybe_unused nau8540_resume(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver nau8540_codec_driver = {
+static const struct snd_soc_codec_driver nau8540_codec_driver = {
.set_sysclk = nau8540_set_sysclk,
.set_pll = nau8540_set_pll,
.suspend = nau8540_suspend,
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index e45518629968..c8e2451ae0a3 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -808,7 +808,7 @@ static const struct regmap_config nau8810_regmap_config = {
.num_reg_defaults = ARRAY_SIZE(nau8810_reg_defaults),
};
-static struct snd_soc_codec_driver nau8810_codec_driver = {
+static const struct snd_soc_codec_driver nau8810_codec_driver = {
.set_bias_level = nau8810_set_bias_level,
.suspend_bias_off = true,
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 3a309b18035e..0240759f951c 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -1469,7 +1469,7 @@ static int __maybe_unused nau8824_resume(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver nau8824_codec_driver = {
+static const struct snd_soc_codec_driver nau8824_codec_driver = {
.probe = nau8824_codec_probe,
.set_sysclk = nau8824_set_sysclk,
.set_pll = nau8824_set_pll,
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 46a30eaa7ace..714ce17da717 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -260,11 +260,11 @@ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
if (timeout) {
ret = down_timeout(&nau8825->xtalk_sem, timeout);
if (ret < 0)
- dev_warn(nau8825->dev, "Acquire semaphone timeout\n");
+ dev_warn(nau8825->dev, "Acquire semaphore timeout\n");
} else {
ret = down_interruptible(&nau8825->xtalk_sem);
if (ret < 0)
- dev_warn(nau8825->dev, "Acquire semaphone fail\n");
+ dev_warn(nau8825->dev, "Acquire semaphore fail\n");
}
return ret;
@@ -1299,7 +1299,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1,
NAU8825_I2S_DL_MASK, val_len);
- /* Release the semaphone. */
+ /* Release the semaphore. */
nau8825_sema_release(nau8825);
return 0;
@@ -1361,7 +1361,7 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
NAU8825_I2S_MS_MASK, ctrl2_val);
- /* Release the semaphone. */
+ /* Release the semaphore. */
nau8825_sema_release(nau8825);
return 0;
@@ -2140,7 +2140,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
break;
case NAU8825_CLK_MCLK:
- /* Acquire the semaphone to synchronize the playback and
+ /* Acquire the semaphore to synchronize the playback and
* interrupt handler. In order to avoid the playback inter-
* fered by cross talk process, the driver make the playback
* preparation halted until cross talk process finish.
@@ -2150,7 +2150,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
/* MCLK not changed by clock tree */
regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
NAU8825_CLK_MCLK_SRC_MASK, 0);
- /* Release the semaphone. */
+ /* Release the semaphore. */
nau8825_sema_release(nau8825);
ret = nau8825_mclk_prepare(nau8825, freq);
@@ -2188,7 +2188,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
break;
case NAU8825_CLK_FLL_MCLK:
- /* Acquire the semaphone to synchronize the playback and
+ /* Acquire the semaphore to synchronize the playback and
* interrupt handler. In order to avoid the playback inter-
* fered by cross talk process, the driver make the playback
* preparation halted until cross talk process finish.
@@ -2201,7 +2201,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
regmap_update_bits(regmap, NAU8825_REG_FLL3,
NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
NAU8825_FLL_CLK_SRC_MCLK | 0);
- /* Release the semaphone. */
+ /* Release the semaphore. */
nau8825_sema_release(nau8825);
ret = nau8825_mclk_prepare(nau8825, freq);
@@ -2210,7 +2210,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
break;
case NAU8825_CLK_FLL_BLK:
- /* Acquire the semaphone to synchronize the playback and
+ /* Acquire the semaphore to synchronize the playback and
* interrupt handler. In order to avoid the playback inter-
* fered by cross talk process, the driver make the playback
* preparation halted until cross talk process finish.
@@ -2226,7 +2226,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
NAU8825_FLL_CLK_SRC_BLK |
(0xf << NAU8825_GAIN_ERR_SFT));
- /* Release the semaphone. */
+ /* Release the semaphore. */
nau8825_sema_release(nau8825);
if (nau8825->mclk_freq) {
@@ -2236,7 +2236,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
break;
case NAU8825_CLK_FLL_FS:
- /* Acquire the semaphone to synchronize the playback and
+ /* Acquire the semaphore to synchronize the playback and
* interrupt handler. In order to avoid the playback inter-
* fered by cross talk process, the driver make the playback
* preparation halted until cross talk process finish.
@@ -2252,7 +2252,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
NAU8825_FLL_CLK_SRC_FS |
(0xf << NAU8825_GAIN_ERR_SFT));
- /* Release the semaphone. */
+ /* Release the semaphore. */
nau8825_sema_release(nau8825);
if (nau8825->mclk_freq) {
@@ -2388,7 +2388,7 @@ static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver nau8825_codec_driver = {
+static const struct snd_soc_codec_driver nau8825_codec_driver = {
.probe = nau8825_codec_probe,
.remove = nau8825_codec_remove,
.set_sysclk = nau8825_set_sysclk,
@@ -2563,7 +2563,7 @@ static int nau8825_i2c_probe(struct i2c_client *i2c,
return PTR_ERR(nau8825->regmap);
nau8825->dev = dev;
nau8825->irq = i2c->irq;
- /* Initiate parameters, semaphone and work queue which are needed in
+ /* Initiate parameters, semaphore and work queue which are needed in
* cross talk suppression measurment function.
*/
nau8825->xtalk_state = NAU8825_XTALK_DONE;
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index 0b14efab6280..c7e28dd2e815 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -288,7 +288,7 @@ static const struct regmap_config pcm1681_regmap = {
.readable_reg = pcm1681_accessible_reg,
};
-static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
+static const struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
.component_driver = {
.controls = pcm1681_controls,
.num_controls = ARRAY_SIZE(pcm1681_controls),
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
index b813a154ddd9..82a3d9db32cb 100644
--- a/sound/soc/codecs/pcm179x.c
+++ b/sound/soc/codecs/pcm179x.c
@@ -205,7 +205,7 @@ const struct regmap_config pcm179x_regmap_config = {
};
EXPORT_SYMBOL_GPL(pcm179x_regmap_config);
-static struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
+static const struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
.component_driver = {
.controls = pcm179x_controls,
.num_controls = ARRAY_SIZE(pcm179x_controls),
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index 708af05486f6..e59d8ffb93bd 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -98,7 +98,7 @@ static struct snd_soc_dai_driver pcm3008_dai = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
+static const struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
.component_driver = {
.dapm_widgets = pcm3008_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets),
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 72b19e62f626..f1005a31c709 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1344,7 +1344,7 @@ static struct snd_soc_dai_driver pcm512x_dai = {
.ops = &pcm512x_dai_ops,
};
-static struct snd_soc_codec_driver pcm512x_codec_driver = {
+static const struct snd_soc_codec_driver pcm512x_codec_driver = {
.set_bias_level = pcm512x_set_bias_level,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
new file mode 100644
index 000000000000..8f92e5c4dd9d
--- /dev/null
+++ b/sound/soc/codecs/rt274.c
@@ -0,0 +1,1229 @@
+/*
+ * rt274.c -- RT274 ALSA SoC audio codec driver
+ *
+ * Copyright 2017 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <linux/workqueue.h>
+
+#include "rl6347a.h"
+#include "rt274.h"
+
+#define RT274_VENDOR_ID 0x10ec0274
+
+struct rt274_priv {
+ struct reg_default *index_cache;
+ int index_cache_size;
+ struct regmap *regmap;
+ struct snd_soc_codec *codec;
+ struct i2c_client *i2c;
+ struct snd_soc_jack *jack;
+ struct delayed_work jack_detect_work;
+ int sys_clk;
+ int clk_id;
+ int fs;
+ bool master;
+};
+
+static const struct reg_default rt274_index_def[] = {
+ { 0x00, 0x1004 },
+ { 0x01, 0xaaaa },
+ { 0x02, 0x88aa },
+ { 0x03, 0x0002 },
+ { 0x04, 0xaa09 },
+ { 0x05, 0x0700 },
+ { 0x06, 0x6110 },
+ { 0x07, 0x0200 },
+ { 0x08, 0xa807 },
+ { 0x09, 0x0021 },
+ { 0x0a, 0x7770 },
+ { 0x0b, 0x7770 },
+ { 0x0c, 0x002b },
+ { 0x0d, 0x2420 },
+ { 0x0e, 0x65c0 },
+ { 0x0f, 0x7770 },
+ { 0x10, 0x0420 },
+ { 0x11, 0x7418 },
+ { 0x12, 0x6bd0 },
+ { 0x13, 0x645f },
+ { 0x14, 0x0400 },
+ { 0x15, 0x8ccc },
+ { 0x16, 0x4c50 },
+ { 0x17, 0xff00 },
+ { 0x18, 0x0003 },
+ { 0x19, 0x2c11 },
+ { 0x1a, 0x830b },
+ { 0x1b, 0x4e4b },
+ { 0x1c, 0x0000 },
+ { 0x1d, 0x0000 },
+ { 0x1e, 0x0000 },
+ { 0x1f, 0x0000 },
+ { 0x20, 0x51ff },
+ { 0x21, 0x8000 },
+ { 0x22, 0x8f00 },
+ { 0x23, 0x88f4 },
+ { 0x24, 0x0000 },
+ { 0x25, 0x0000 },
+ { 0x26, 0x0000 },
+ { 0x27, 0x0000 },
+ { 0x28, 0x0000 },
+ { 0x29, 0x3000 },
+ { 0x2a, 0x0000 },
+ { 0x2b, 0x0000 },
+ { 0x2c, 0x0f00 },
+ { 0x2d, 0x100f },
+ { 0x2e, 0x2902 },
+ { 0x2f, 0xe280 },
+ { 0x30, 0x1000 },
+ { 0x31, 0x8400 },
+ { 0x32, 0x5aaa },
+ { 0x33, 0x8420 },
+ { 0x34, 0xa20c },
+ { 0x35, 0x096a },
+ { 0x36, 0x5757 },
+ { 0x37, 0xfe05 },
+ { 0x38, 0x4901 },
+ { 0x39, 0x110a },
+ { 0x3a, 0x0010 },
+ { 0x3b, 0x60d9 },
+ { 0x3c, 0xf214 },
+ { 0x3d, 0xc2ba },
+ { 0x3e, 0xa928 },
+ { 0x3f, 0x0000 },
+ { 0x40, 0x9800 },
+ { 0x41, 0x0000 },
+ { 0x42, 0x2000 },
+ { 0x43, 0x3d90 },
+ { 0x44, 0x4900 },
+ { 0x45, 0x5289 },
+ { 0x46, 0x0004 },
+ { 0x47, 0xa47a },
+ { 0x48, 0xd049 },
+ { 0x49, 0x0049 },
+ { 0x4a, 0xa83b },
+ { 0x4b, 0x0777 },
+ { 0x4c, 0x065c },
+ { 0x4d, 0x7fff },
+ { 0x4e, 0x7fff },
+ { 0x4f, 0x0000 },
+ { 0x50, 0x0000 },
+ { 0x51, 0x0000 },
+ { 0x52, 0xbf5f },
+ { 0x53, 0x3320 },
+ { 0x54, 0xcc00 },
+ { 0x55, 0x0000 },
+ { 0x56, 0x3f00 },
+ { 0x57, 0x0000 },
+ { 0x58, 0x0000 },
+ { 0x59, 0x0000 },
+ { 0x5a, 0x1300 },
+ { 0x5b, 0x005f },
+ { 0x5c, 0x0000 },
+ { 0x5d, 0x1001 },
+ { 0x5e, 0x1000 },
+ { 0x5f, 0x0000 },
+ { 0x60, 0x5554 },
+ { 0x61, 0xffc0 },
+ { 0x62, 0xa000 },
+ { 0x63, 0xd010 },
+ { 0x64, 0x0000 },
+ { 0x65, 0x3fb1 },
+ { 0x66, 0x1881 },
+ { 0x67, 0xc810 },
+ { 0x68, 0x2000 },
+ { 0x69, 0xfff0 },
+ { 0x6a, 0x0300 },
+ { 0x6b, 0x5060 },
+ { 0x6c, 0x0000 },
+ { 0x6d, 0x0000 },
+ { 0x6e, 0x0c25 },
+ { 0x6f, 0x0c0b },
+ { 0x70, 0x8000 },
+ { 0x71, 0x4008 },
+ { 0x72, 0x0000 },
+ { 0x73, 0x0800 },
+ { 0x74, 0xa28f },
+ { 0x75, 0xa050 },
+ { 0x76, 0x7fe8 },
+ { 0x77, 0xdb8c },
+ { 0x78, 0x0000 },
+ { 0x79, 0x0000 },
+ { 0x7a, 0x2a96 },
+ { 0x7b, 0x800f },
+ { 0x7c, 0x0200 },
+ { 0x7d, 0x1600 },
+ { 0x7e, 0x0000 },
+ { 0x7f, 0x0000 },
+};
+#define INDEX_CACHE_SIZE ARRAY_SIZE(rt274_index_def)
+
+static const struct reg_default rt274_reg[] = {
+ { 0x00170500, 0x00000400 },
+ { 0x00220000, 0x00000031 },
+ { 0x00239000, 0x00000057 },
+ { 0x0023a000, 0x00000057 },
+ { 0x00270500, 0x00000400 },
+ { 0x00370500, 0x00000400 },
+ { 0x00870500, 0x00000400 },
+ { 0x00920000, 0x00000031 },
+ { 0x00935000, 0x00000097 },
+ { 0x00936000, 0x00000097 },
+ { 0x00970500, 0x00000400 },
+ { 0x00b37000, 0x00000400 },
+ { 0x00b37200, 0x00000400 },
+ { 0x00b37300, 0x00000400 },
+ { 0x00c37000, 0x00000400 },
+ { 0x00c37100, 0x00000400 },
+ { 0x01270500, 0x00000400 },
+ { 0x01370500, 0x00000400 },
+ { 0x01371f00, 0x411111f0 },
+ { 0x01937000, 0x00000000 },
+ { 0x01970500, 0x00000400 },
+ { 0x02050000, 0x0000001b },
+ { 0x02139000, 0x00000080 },
+ { 0x0213a000, 0x00000080 },
+ { 0x02170100, 0x00000001 },
+ { 0x02170500, 0x00000400 },
+ { 0x02170700, 0x00000000 },
+ { 0x02270100, 0x00000000 },
+ { 0x02370100, 0x00000000 },
+ { 0x01970700, 0x00000020 },
+ { 0x00830000, 0x00000097 },
+ { 0x00930000, 0x00000097 },
+ { 0x01270700, 0x00000000 },
+};
+
+static bool rt274_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0 ... 0xff:
+ case RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+ case RT274_GET_HP_SENSE:
+ case RT274_GET_MIC_SENSE:
+ case RT274_PROC_COEF:
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_MIC, 0):
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT0, 0):
+ case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT1, 0):
+ case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN1, 0):
+ case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN2, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC1, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC2, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_MIC, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE1, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE2, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN1, 0):
+ case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN2, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC2, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_MIC, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE1, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE2, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_MIC, 0):
+ case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_INLINE_CMD, 0):
+ return true;
+ default:
+ return false;
+ }
+
+
+}
+
+static bool rt274_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0 ... 0xff:
+ case RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+ case RT274_GET_HP_SENSE:
+ case RT274_GET_MIC_SENSE:
+ case RT274_SET_AUDIO_POWER:
+ case RT274_SET_HPO_POWER:
+ case RT274_SET_DMIC1_POWER:
+ case RT274_LOUT_MUX:
+ case RT274_HPO_MUX:
+ case RT274_ADC0_MUX:
+ case RT274_ADC1_MUX:
+ case RT274_SET_MIC:
+ case RT274_SET_PIN_HPO:
+ case RT274_SET_PIN_LOUT3:
+ case RT274_SET_PIN_DMIC1:
+ case RT274_SET_AMP_GAIN_HPO:
+ case RT274_SET_DMIC2_DEFAULT:
+ case RT274_DAC0L_GAIN:
+ case RT274_DAC0R_GAIN:
+ case RT274_DAC1L_GAIN:
+ case RT274_DAC1R_GAIN:
+ case RT274_ADCL_GAIN:
+ case RT274_ADCR_GAIN:
+ case RT274_MIC_GAIN:
+ case RT274_HPOL_GAIN:
+ case RT274_HPOR_GAIN:
+ case RT274_LOUTL_GAIN:
+ case RT274_LOUTR_GAIN:
+ case RT274_DAC_FORMAT:
+ case RT274_ADC_FORMAT:
+ case RT274_COEF_INDEX:
+ case RT274_PROC_COEF:
+ case RT274_SET_AMP_GAIN_ADC_IN1:
+ case RT274_SET_AMP_GAIN_ADC_IN2:
+ case RT274_SET_POWER(RT274_DAC_OUT0):
+ case RT274_SET_POWER(RT274_DAC_OUT1):
+ case RT274_SET_POWER(RT274_ADC_IN1):
+ case RT274_SET_POWER(RT274_ADC_IN2):
+ case RT274_SET_POWER(RT274_DMIC2):
+ case RT274_SET_POWER(RT274_MIC):
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_MIC, 0):
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT0, 0):
+ case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT1, 0):
+ case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN1, 0):
+ case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN2, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC1, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC2, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_MIC, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE1, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE2, 0):
+ case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN1, 0):
+ case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN2, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC2, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_MIC, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE1, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE2, 0):
+ case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_HP_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_MIC, 0):
+ case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_INLINE_CMD, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifdef CONFIG_PM
+static void rt274_index_sync(struct snd_soc_codec *codec)
+{
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ for (i = 0; i < INDEX_CACHE_SIZE; i++) {
+ snd_soc_write(codec, rt274->index_cache[i].reg,
+ rt274->index_cache[i].def);
+ }
+}
+#endif
+
+static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic)
+{
+ unsigned int buf;
+
+ *hp = false;
+ *mic = false;
+
+ if (!rt274->codec)
+ return -EINVAL;
+
+ regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf);
+ *hp = buf & 0x80000000;
+ regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf);
+ *mic = buf & 0x80000000;
+
+ pr_debug("*hp = %d *mic = %d\n", *hp, *mic);
+
+ return 0;
+}
+
+static void rt274_jack_detect_work(struct work_struct *work)
+{
+ struct rt274_priv *rt274 =
+ container_of(work, struct rt274_priv, jack_detect_work.work);
+ int status = 0;
+ bool hp = false;
+ bool mic = false;
+
+ if (rt274_jack_detect(rt274, &hp, &mic) < 0)
+ return;
+
+ if (hp == true)
+ status |= SND_JACK_HEADPHONE;
+
+ if (mic == true)
+ status |= SND_JACK_MICROPHONE;
+
+ snd_soc_jack_report(rt274->jack, status,
+ SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+}
+
+static irqreturn_t rt274_irq(int irq, void *data);
+
+static int rt274_mic_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, void *data)
+{
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+ if (jack == NULL) {
+ /* Disable jack detection */
+ regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+ RT274_IRQ_EN, RT274_IRQ_DIS);
+
+ return 0;
+ }
+ rt274->jack = jack;
+
+ regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+ RT274_IRQ_EN, RT274_IRQ_EN);
+
+ /* Send an initial report */
+ rt274_irq(0, rt274);
+
+ return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt274_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT274_DAC0L_GAIN,
+ RT274_DAC0R_GAIN, 0, 0x7f, 0, out_vol_tlv),
+ SOC_DOUBLE_R_TLV("DAC1 Playback Volume", RT274_DAC1L_GAIN,
+ RT274_DAC1R_GAIN, 0, 0x7f, 0, out_vol_tlv),
+ SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT274_ADCL_GAIN,
+ RT274_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+ SOC_DOUBLE_R("ADC0 Capture Switch", RT274_ADCL_GAIN,
+ RT274_ADCR_GAIN, RT274_MUTE_SFT, 1, 1),
+ SOC_SINGLE_TLV("AMIC Volume", RT274_MIC_GAIN,
+ 0, 0x3, 0, mic_vol_tlv),
+};
+
+static const struct snd_kcontrol_new hpol_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_HPOL_GAIN,
+ RT274_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpor_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_HPOR_GAIN,
+ RT274_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new loutl_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_LOUTL_GAIN,
+ RT274_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new loutr_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_LOUTR_GAIN,
+ RT274_MUTE_SFT, 1, 1);
+
+/* ADC0 source */
+static const char * const rt274_adc_src[] = {
+ "Mic", "Line1", "Line2", "Dmic"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt274_adc0_enum, RT274_ADC0_MUX, RT274_ADC_SEL_SFT,
+ rt274_adc_src);
+
+static const struct snd_kcontrol_new rt274_adc0_mux =
+ SOC_DAPM_ENUM("ADC 0 source", rt274_adc0_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt274_adc1_enum, RT274_ADC1_MUX, RT274_ADC_SEL_SFT,
+ rt274_adc_src);
+
+static const struct snd_kcontrol_new rt274_adc1_mux =
+ SOC_DAPM_ENUM("ADC 1 source", rt274_adc1_enum);
+
+static const char * const rt274_dac_src[] = {
+ "DAC OUT0", "DAC OUT1"
+};
+/* HP-OUT source */
+static SOC_ENUM_SINGLE_DECL(rt274_hpo_enum, RT274_HPO_MUX,
+ 0, rt274_dac_src);
+
+static const struct snd_kcontrol_new rt274_hpo_mux =
+SOC_DAPM_ENUM("HPO source", rt274_hpo_enum);
+
+/* Line out source */
+static SOC_ENUM_SINGLE_DECL(rt274_lout_enum, RT274_LOUT_MUX,
+ 0, rt274_dac_src);
+
+static const struct snd_kcontrol_new rt274_lout_mux =
+SOC_DAPM_ENUM("LOUT source", rt274_lout_enum);
+
+static const struct snd_soc_dapm_widget rt274_dapm_widgets[] = {
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("DMIC1 Pin"),
+ SND_SOC_DAPM_INPUT("DMIC2 Pin"),
+ SND_SOC_DAPM_INPUT("MIC"),
+ SND_SOC_DAPM_INPUT("LINE1"),
+ SND_SOC_DAPM_INPUT("LINE2"),
+
+ /* DMIC */
+ SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* ADCs */
+ SND_SOC_DAPM_ADC("ADC 0", NULL, RT274_SET_STREAMID_ADC1, 4, 0),
+ SND_SOC_DAPM_ADC("ADC 1", NULL, RT274_SET_STREAMID_ADC2, 4, 0),
+
+ /* ADC Mux */
+ SND_SOC_DAPM_MUX("ADC 0 Mux", SND_SOC_NOPM, 0, 0,
+ &rt274_adc0_mux),
+ SND_SOC_DAPM_MUX("ADC 1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt274_adc1_mux),
+
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RXL", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF1RXR", "AIF1 Playback", 1, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TXL", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TXR", "AIF1 Capture", 1, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF2RXL", "AIF1 Playback", 2, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF2RXR", "AIF1 Playback", 3, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF2TXL", "AIF1 Capture", 2, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF2TXR", "AIF1 Capture", 3, SND_SOC_NOPM, 0, 0),
+
+ /* Output Side */
+ /* DACs */
+ SND_SOC_DAPM_DAC("DAC 0", NULL, RT274_SET_STREAMID_DAC0, 4, 0),
+ SND_SOC_DAPM_DAC("DAC 1", NULL, RT274_SET_STREAMID_DAC1, 4, 0),
+
+ /* Output Mux */
+ SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt274_hpo_mux),
+ SND_SOC_DAPM_MUX("LOUT Mux", SND_SOC_NOPM, 0, 0, &rt274_lout_mux),
+
+ SND_SOC_DAPM_SUPPLY("HP Power", RT274_SET_PIN_HPO,
+ RT274_SET_PIN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("LOUT Power", RT274_SET_PIN_LOUT3,
+ RT274_SET_PIN_SFT, 0, NULL, 0),
+
+ /* Output Mixer */
+ SND_SOC_DAPM_PGA("DAC OUT0", SND_SOC_NOPM, 0, 0,
+ NULL, 0),
+ SND_SOC_DAPM_PGA("DAC OUT1", SND_SOC_NOPM, 0, 0,
+ NULL, 0),
+
+ /* Output Pga */
+ SND_SOC_DAPM_SWITCH("LOUT L", SND_SOC_NOPM, 0, 0,
+ &loutl_enable_control),
+ SND_SOC_DAPM_SWITCH("LOUT R", SND_SOC_NOPM, 0, 0,
+ &loutr_enable_control),
+ SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0,
+ &hpol_enable_control),
+ SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0,
+ &hpor_enable_control),
+
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("HPO Pin"),
+ SND_SOC_DAPM_OUTPUT("SPDIF"),
+ SND_SOC_DAPM_OUTPUT("LINE3"),
+};
+
+static const struct snd_soc_dapm_route rt274_dapm_routes[] = {
+ {"DMIC1", NULL, "DMIC1 Pin"},
+ {"DMIC2", NULL, "DMIC2 Pin"},
+
+ {"ADC 0 Mux", "Mic", "MIC"},
+ {"ADC 0 Mux", "Dmic", "DMIC1"},
+ {"ADC 0 Mux", "Line1", "LINE1"},
+ {"ADC 0 Mux", "Line2", "LINE2"},
+ {"ADC 1 Mux", "Mic", "MIC"},
+ {"ADC 1 Mux", "Dmic", "DMIC2"},
+ {"ADC 1 Mux", "Line1", "LINE1"},
+ {"ADC 1 Mux", "Line2", "LINE2"},
+
+ {"ADC 0", NULL, "ADC 0 Mux"},
+ {"ADC 1", NULL, "ADC 1 Mux"},
+
+ {"AIF1TXL", NULL, "ADC 0"},
+ {"AIF1TXR", NULL, "ADC 0"},
+ {"AIF2TXL", NULL, "ADC 1"},
+ {"AIF2TXR", NULL, "ADC 1"},
+
+ {"DAC 0", NULL, "AIF1RXL"},
+ {"DAC 0", NULL, "AIF1RXR"},
+ {"DAC 1", NULL, "AIF2RXL"},
+ {"DAC 1", NULL, "AIF2RXR"},
+
+ {"DAC OUT0", NULL, "DAC 0"},
+
+ {"DAC OUT1", NULL, "DAC 1"},
+
+ {"LOUT Mux", "DAC OUT0", "DAC OUT0"},
+ {"LOUT Mux", "DAC OUT1", "DAC OUT1"},
+
+ {"LOUT L", "Switch", "LOUT Mux"},
+ {"LOUT R", "Switch", "LOUT Mux"},
+ {"LOUT L", NULL, "LOUT Power"},
+ {"LOUT R", NULL, "LOUT Power"},
+
+ {"LINE3", NULL, "LOUT L"},
+ {"LINE3", NULL, "LOUT R"},
+
+ {"HPO Mux", "DAC OUT0", "DAC OUT0"},
+ {"HPO Mux", "DAC OUT1", "DAC OUT1"},
+
+ {"HPO L", "Switch", "HPO Mux"},
+ {"HPO R", "Switch", "HPO Mux"},
+ {"HPO L", NULL, "HP Power"},
+ {"HPO R", NULL, "HP Power"},
+
+ {"HPO Pin", NULL, "HPO L"},
+ {"HPO Pin", NULL, "HPO R"},
+};
+
+static int rt274_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 rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val = 0;
+ int d_len_code = 0, c_len_code = 0;
+
+ switch (params_rate(params)) {
+ /* bit 14 0:48K 1:44.1K */
+ case 44100:
+ case 48000:
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported sample rate %d\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+ switch (rt274->sys_clk) {
+ case 12288000:
+ case 24576000:
+ if (params_rate(params) != 48000) {
+ dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+ params_rate(params), rt274->sys_clk);
+ return -EINVAL;
+ }
+ break;
+ case 11289600:
+ case 22579200:
+ if (params_rate(params) != 44100) {
+ dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+ params_rate(params), rt274->sys_clk);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ if (params_channels(params) <= 16) {
+ /* bit 3:0 Number of Channel */
+ val |= (params_channels(params) - 1);
+ } else {
+ dev_err(codec->dev, "Unsupported channels %d\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ switch (params_width(params)) {
+ /* bit 6:4 Bits per Sample */
+ case 16:
+ d_len_code = 0;
+ c_len_code = 0;
+ val |= (0x1 << 4);
+ break;
+ case 32:
+ d_len_code = 2;
+ c_len_code = 3;
+ val |= (0x4 << 4);
+ break;
+ case 20:
+ d_len_code = 1;
+ c_len_code = 1;
+ val |= (0x2 << 4);
+ break;
+ case 24:
+ d_len_code = 2;
+ c_len_code = 2;
+ val |= (0x3 << 4);
+ break;
+ case 8:
+ d_len_code = 3;
+ c_len_code = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (rt274->master)
+ c_len_code = 0x3;
+
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL1, 0xc018, d_len_code << 3 | c_len_code << 14);
+ dev_dbg(codec->dev, "format val = 0x%x\n", val);
+
+ snd_soc_update_bits(codec, RT274_DAC_FORMAT, 0x407f, val);
+ snd_soc_update_bits(codec, RT274_ADC_FORMAT, 0x407f, val);
+
+ return 0;
+}
+
+static int rt274_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_M);
+ rt274->master = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_S);
+ rt274->master = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+ RT274_I2S_FMT_MASK, RT274_I2S_FMT_I2S);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+ RT274_I2S_FMT_MASK, RT274_I2S_FMT_LJ);
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+ RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMA);
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+ RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMB);
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* bit 15 Stream Type 0:PCM 1:Non-PCM */
+ snd_soc_update_bits(codec, RT274_DAC_FORMAT, 0x8000, 0);
+ snd_soc_update_bits(codec, RT274_ADC_FORMAT, 0x8000, 0);
+
+ return 0;
+}
+
+static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+ switch (source) {
+ case RT274_PLL2_S_MCLK:
+ snd_soc_update_bits(codec, RT274_PLL2_CTRL,
+ RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_MCLK);
+ break;
+ default:
+ dev_warn(codec->dev, "invalid pll source, use BCLK\n");
+ case RT274_PLL2_S_BCLK:
+ snd_soc_update_bits(codec, RT274_PLL2_CTRL,
+ RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK);
+ break;
+ }
+
+ if (source == RT274_PLL2_S_BCLK) {
+ snd_soc_update_bits(codec, RT274_MCLK_CTRL,
+ (0x3 << 12), (0x3 << 12));
+ switch (rt274->fs) {
+ case 50:
+ snd_soc_write(codec, 0x7a, 0xaab6);
+ snd_soc_write(codec, 0x7b, 0x0301);
+ snd_soc_write(codec, 0x7c, 0x04fe);
+ break;
+ case 64:
+ snd_soc_write(codec, 0x7a, 0xaa96);
+ snd_soc_write(codec, 0x7b, 0x8003);
+ snd_soc_write(codec, 0x7c, 0x081e);
+ break;
+ case 128:
+ snd_soc_write(codec, 0x7a, 0xaa96);
+ snd_soc_write(codec, 0x7b, 0x8003);
+ snd_soc_write(codec, 0x7c, 0x080e);
+ break;
+ default:
+ dev_warn(codec->dev, "invalid freq_in, assume 4.8M\n");
+ case 100:
+ snd_soc_write(codec, 0x7a, 0xaab6);
+ snd_soc_write(codec, 0x7b, 0x0301);
+ snd_soc_write(codec, 0x7c, 0x047e);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int rt274_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+ unsigned int clk_src, mclk_en;
+
+ dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq);
+
+ switch (clk_id) {
+ case RT274_SCLK_S_MCLK:
+ mclk_en = RT274_MCLK_MODE_EN;
+ clk_src = RT274_CLK_SRC_MCLK;
+ break;
+ case RT274_SCLK_S_PLL1:
+ mclk_en = RT274_MCLK_MODE_DIS;
+ clk_src = RT274_CLK_SRC_MCLK;
+ break;
+ case RT274_SCLK_S_PLL2:
+ mclk_en = RT274_MCLK_MODE_EN;
+ clk_src = RT274_CLK_SRC_PLL2;
+ break;
+ default:
+ mclk_en = RT274_MCLK_MODE_DIS;
+ clk_src = RT274_CLK_SRC_MCLK;
+ dev_warn(codec->dev, "invalid sysclk source, use PLL1\n");
+ break;
+ }
+ snd_soc_update_bits(codec, RT274_MCLK_CTRL,
+ RT274_MCLK_MODE_MASK, mclk_en);
+ snd_soc_update_bits(codec, RT274_CLK_CTRL,
+ RT274_CLK_SRC_MASK, clk_src);
+
+ switch (freq) {
+ case 19200000:
+ if (clk_id == RT274_SCLK_S_MCLK) {
+ dev_err(codec->dev, "Should not use MCLK\n");
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL2, 0x40, 0x40);
+ break;
+ case 24000000:
+ if (clk_id == RT274_SCLK_S_MCLK) {
+ dev_err(codec->dev, "Should not use MCLK\n");
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL2, 0x40, 0x0);
+ break;
+ case 12288000:
+ case 11289600:
+ snd_soc_update_bits(codec,
+ RT274_MCLK_CTRL, 0x1fcf, 0x0008);
+ break;
+ case 24576000:
+ case 22579200:
+ snd_soc_update_bits(codec,
+ RT274_MCLK_CTRL, 0x1fcf, 0x1543);
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported system clock\n");
+ return -EINVAL;
+ }
+
+ rt274->sys_clk = freq;
+ rt274->clk_id = clk_id;
+
+ return 0;
+}
+
+static int rt274_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+ rt274->fs = ratio;
+ if ((ratio / 50) == 0)
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL1, 0x1000, 0x1000);
+ else
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL1, 0x1000, 0x0);
+
+
+ return 0;
+}
+
+static int rt274_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ if (rx_mask || tx_mask) {
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_EN);
+ } else {
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_DIS);
+ return 0;
+ }
+
+ switch (slots) {
+ case 4:
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_4CH);
+ break;
+ case 2:
+ snd_soc_update_bits(codec,
+ RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_2CH);
+ break;
+ default:
+ dev_err(codec->dev,
+ "Support 2 or 4 slots TDM only\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt274_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_PREPARE:
+ if (SND_SOC_BIAS_STANDBY ==
+ snd_soc_codec_get_bias_level(codec)) {
+ snd_soc_write(codec,
+ RT274_SET_AUDIO_POWER, AC_PWRST_D0);
+ }
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_write(codec,
+ RT274_SET_AUDIO_POWER, AC_PWRST_D3);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static irqreturn_t rt274_irq(int irq, void *data)
+{
+ struct rt274_priv *rt274 = data;
+ bool hp = false;
+ bool mic = false;
+ int ret, status = 0;
+
+ /* Clear IRQ */
+ regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+ RT274_IRQ_CLR, RT274_IRQ_CLR);
+
+ ret = rt274_jack_detect(rt274, &hp, &mic);
+
+ if (ret == 0) {
+ if (hp == true)
+ status |= SND_JACK_HEADPHONE;
+
+ if (mic == true)
+ status |= SND_JACK_MICROPHONE;
+
+ snd_soc_jack_report(rt274->jack, status,
+ SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+
+ pm_wakeup_event(&rt274->i2c->dev, 300);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int rt274_probe(struct snd_soc_codec *codec)
+{
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+ rt274->codec = codec;
+
+ if (rt274->i2c->irq) {
+ INIT_DELAYED_WORK(&rt274->jack_detect_work,
+ rt274_jack_detect_work);
+ schedule_delayed_work(&rt274->jack_detect_work,
+ msecs_to_jiffies(1250));
+ }
+
+ return 0;
+}
+
+static int rt274_remove(struct snd_soc_codec *codec)
+{
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+ cancel_delayed_work_sync(&rt274->jack_detect_work);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt274_suspend(struct snd_soc_codec *codec)
+{
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt274->regmap, true);
+ regcache_mark_dirty(rt274->regmap);
+
+ return 0;
+}
+
+static int rt274_resume(struct snd_soc_codec *codec)
+{
+ struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt274->regmap, false);
+ rt274_index_sync(codec);
+ regcache_sync(rt274->regmap);
+
+ return 0;
+}
+#else
+#define rt274_suspend NULL
+#define rt274_resume NULL
+#endif
+
+#define RT274_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define RT274_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt274_aif_dai_ops = {
+ .hw_params = rt274_hw_params,
+ .set_fmt = rt274_set_dai_fmt,
+ .set_sysclk = rt274_set_dai_sysclk,
+ .set_pll = rt274_set_dai_pll,
+ .set_bclk_ratio = rt274_set_bclk_ratio,
+ .set_tdm_slot = rt274_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver rt274_dai[] = {
+ {
+ .name = "rt274-aif1",
+ .id = RT274_AIF1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT274_STEREO_RATES,
+ .formats = RT274_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT274_STEREO_RATES,
+ .formats = RT274_FORMATS,
+ },
+ .ops = &rt274_aif_dai_ops,
+ .symmetric_rates = 1,
+ },
+};
+
+static const struct snd_soc_codec_driver soc_codec_dev_rt274 = {
+ .probe = rt274_probe,
+ .remove = rt274_remove,
+ .suspend = rt274_suspend,
+ .resume = rt274_resume,
+ .set_bias_level = rt274_set_bias_level,
+ .idle_bias_off = true,
+ .component_driver = {
+ .controls = rt274_snd_controls,
+ .num_controls = ARRAY_SIZE(rt274_snd_controls),
+ .dapm_widgets = rt274_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt274_dapm_widgets),
+ .dapm_routes = rt274_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt274_dapm_routes),
+ },
+ .set_jack = rt274_mic_detect,
+};
+
+static const struct regmap_config rt274_regmap = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .max_register = 0x05bfffff,
+ .volatile_reg = rt274_volatile_register,
+ .readable_reg = rt274_readable_register,
+ .reg_write = rl6347a_hw_write,
+ .reg_read = rl6347a_hw_read,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt274_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt274_reg),
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt274_of_match[] = {
+ {.compatible = "realtek,rt274"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt274_of_match);
+#endif
+
+static const struct i2c_device_id rt274_i2c_id[] = {
+ {"rt274", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, rt274_i2c_id);
+
+static const struct acpi_device_id rt274_acpi_match[] = {
+ { "10EC0274", 0 },
+ { "INT34C2", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, rt274_acpi_match);
+
+static int rt274_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt274_priv *rt274;
+
+ int ret;
+ unsigned int val;
+
+ rt274 = devm_kzalloc(&i2c->dev, sizeof(*rt274),
+ GFP_KERNEL);
+ if (rt274 == NULL)
+ return -ENOMEM;
+
+ rt274->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt274_regmap);
+ if (IS_ERR(rt274->regmap)) {
+ ret = PTR_ERR(rt274->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt274->regmap,
+ RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val);
+ if (val != RT274_VENDOR_ID) {
+ dev_err(&i2c->dev,
+ "Device with ID register %#x is not rt274\n", val);
+ return -ENODEV;
+ }
+
+ rt274->index_cache = devm_kmemdup(&i2c->dev, rt274_index_def,
+ sizeof(rt274_index_def), GFP_KERNEL);
+ if (!rt274->index_cache)
+ return -ENOMEM;
+
+ rt274->index_cache_size = INDEX_CACHE_SIZE;
+ rt274->i2c = i2c;
+ i2c_set_clientdata(i2c, rt274);
+
+ /* reset codec */
+ regmap_write(rt274->regmap, RT274_RESET, 0);
+ regmap_update_bits(rt274->regmap, 0x1a, 0x4000, 0x4000);
+
+ /* Set Pad PDB is floating */
+ regmap_update_bits(rt274->regmap, RT274_PAD_CTRL12, 0x3, 0x0);
+ regmap_write(rt274->regmap, RT274_COEF5b_INDEX, 0x01);
+ regmap_write(rt274->regmap, RT274_COEF5b_COEF, 0x8540);
+ regmap_update_bits(rt274->regmap, 0x6f, 0x0100, 0x0100);
+ /* Combo jack auto detect */
+ regmap_write(rt274->regmap, 0x4a, 0x201b);
+ /* Aux mode off */
+ regmap_update_bits(rt274->regmap, 0x6f, 0x3000, 0x2000);
+ /* HP DC Calibration */
+ regmap_update_bits(rt274->regmap, 0x6f, 0xf, 0x0);
+ /* Set NID=58h.Index 00h [15]= 1b; */
+ regmap_write(rt274->regmap, RT274_COEF58_INDEX, 0x00);
+ regmap_write(rt274->regmap, RT274_COEF58_COEF, 0xb888);
+ msleep(500);
+ regmap_update_bits(rt274->regmap, 0x6f, 0xf, 0xb);
+ regmap_write(rt274->regmap, RT274_COEF58_INDEX, 0x00);
+ regmap_write(rt274->regmap, RT274_COEF58_COEF, 0x3888);
+ /* Set pin widget */
+ regmap_write(rt274->regmap, RT274_SET_PIN_HPO, 0x40);
+ regmap_write(rt274->regmap, RT274_SET_PIN_LOUT3, 0x40);
+ regmap_write(rt274->regmap, RT274_SET_MIC, 0x20);
+ regmap_write(rt274->regmap, RT274_SET_PIN_DMIC1, 0x20);
+
+ regmap_update_bits(rt274->regmap, RT274_I2S_CTRL2, 0xc004, 0x4004);
+ regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+ RT274_GPI2_SEL_MASK, RT274_GPI2_SEL_DMIC_CLK);
+
+ /* jack detection */
+ regmap_write(rt274->regmap, RT274_UNSOLICITED_HP_OUT, 0x81);
+ regmap_write(rt274->regmap, RT274_UNSOLICITED_MIC, 0x82);
+
+ if (rt274->i2c->irq) {
+ ret = request_threaded_irq(rt274->i2c->irq, NULL, rt274_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt274", rt274);
+ if (ret != 0) {
+ dev_err(&i2c->dev,
+ "Failed to reguest IRQ: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt274,
+ rt274_dai, ARRAY_SIZE(rt274_dai));
+
+ return ret;
+}
+
+static int rt274_i2c_remove(struct i2c_client *i2c)
+{
+ struct rt274_priv *rt274 = i2c_get_clientdata(i2c);
+
+ if (i2c->irq)
+ free_irq(i2c->irq, rt274);
+ snd_soc_unregister_codec(&i2c->dev);
+
+ return 0;
+}
+
+
+static struct i2c_driver rt274_i2c_driver = {
+ .driver = {
+ .name = "rt274",
+ .acpi_match_table = ACPI_PTR(rt274_acpi_match),
+#ifdef CONFIG_OF
+ .of_match_table = of_match_ptr(rt274_of_match),
+#endif
+ },
+ .probe = rt274_i2c_probe,
+ .remove = rt274_i2c_remove,
+ .id_table = rt274_i2c_id,
+};
+
+module_i2c_driver(rt274_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT274 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt274.h b/sound/soc/codecs/rt274.h
new file mode 100644
index 000000000000..4fd1bcb73dba
--- /dev/null
+++ b/sound/soc/codecs/rt274.h
@@ -0,0 +1,217 @@
+/*
+ * rt274.h -- RT274 ALSA SoC audio driver
+ *
+ * Copyright 2016 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.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.
+ */
+
+#ifndef __RT274_H__
+#define __RT274_H__
+
+#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
+
+#define RT274_AUDIO_FUNCTION_GROUP 0x01
+#define RT274_DAC_OUT0 0x02
+#define RT274_DAC_OUT1 0x03
+#define RT274_ADC_IN2 0x08
+#define RT274_ADC_IN1 0x09
+#define RT274_DIG_CVT 0x0a
+#define RT274_DMIC1 0x12
+#define RT274_DMIC2 0x13
+#define RT274_MIC 0x19
+#define RT274_LINE1 0x1a
+#define RT274_LINE2 0x1b
+#define RT274_LINE3 0x16
+#define RT274_SPDIF 0x1e
+#define RT274_VENDOR_REGISTERS 0x20
+#define RT274_HP_OUT 0x21
+#define RT274_MIXER_IN1 0x22
+#define RT274_MIXER_IN2 0x23
+#define RT274_INLINE_CMD 0x55
+
+#define RT274_SET_PIN_SFT 6
+#define RT274_SET_PIN_ENABLE 0x40
+#define RT274_SET_PIN_DISABLE 0
+#define RT274_SET_EAPD_HIGH 0x2
+#define RT274_SET_EAPD_LOW 0
+
+#define RT274_MUTE_SFT 7
+
+/* Verb commands */
+#define RT274_RESET\
+ VERB_CMD(AC_VERB_SET_CODEC_RESET, RT274_AUDIO_FUNCTION_GROUP, 0)
+#define RT274_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM)
+#define RT274_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0)
+#define RT274_SET_AUDIO_POWER RT274_SET_POWER(RT274_AUDIO_FUNCTION_GROUP)
+#define RT274_SET_HPO_POWER RT274_SET_POWER(RT274_HP_OUT)
+#define RT274_SET_DMIC1_POWER RT274_SET_POWER(RT274_DMIC1)
+#define RT274_LOUT_MUX\
+ VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_LINE3, 0)
+#define RT274_HPO_MUX\
+ VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_HP_OUT, 0)
+#define RT274_ADC0_MUX\
+ VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_MIXER_IN1, 0)
+#define RT274_ADC1_MUX\
+ VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_MIXER_IN2, 0)
+#define RT274_SET_MIC\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_MIC, 0)
+#define RT274_SET_PIN_LOUT3\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_LINE3, 0)
+#define RT274_SET_PIN_HPO\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0)
+#define RT274_SET_PIN_DMIC1\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0)
+#define RT274_SET_PIN_SPDIF\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_SPDIF, 0)
+#define RT274_SET_PIN_DIG_CVT\
+ VERB_CMD(AC_VERB_SET_DIGI_CONVERT_1, RT274_DIG_CVT, 0)
+#define RT274_SET_AMP_GAIN_HPO\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0)
+#define RT274_SET_AMP_GAIN_ADC_IN1\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0)
+#define RT274_SET_AMP_GAIN_ADC_IN2\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0)
+#define RT274_GET_HP_SENSE\
+ VERB_CMD(AC_VERB_GET_PIN_SENSE, RT274_HP_OUT, 0)
+#define RT274_GET_MIC_SENSE\
+ VERB_CMD(AC_VERB_GET_PIN_SENSE, RT274_MIC, 0)
+#define RT274_SET_DMIC2_DEFAULT\
+ VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT274_DMIC2, 0)
+#define RT274_SET_SPDIF_DEFAULT\
+ VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT274_SPDIF, 0)
+#define RT274_DAC0L_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0xa000)
+#define RT274_DAC0R_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0x9000)
+#define RT274_DAC1L_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0xa000)
+#define RT274_DAC1R_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0x9000)
+#define RT274_ADCL_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0x6000)
+#define RT274_ADCR_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0x5000)
+#define RT274_MIC_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_MIC, 0x7000)
+#define RT274_LOUTL_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_LINE3, 0xa000)
+#define RT274_LOUTR_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_LINE3, 0x9000)
+#define RT274_HPOL_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0xa000)
+#define RT274_HPOR_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0x9000)
+#define RT274_DAC_FORMAT\
+ VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT274_DAC_OUT0, 0)
+#define RT274_ADC_FORMAT\
+ VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT274_ADC_IN1, 0)
+#define RT274_COEF_INDEX\
+ VERB_CMD(AC_VERB_SET_COEF_INDEX, RT274_VENDOR_REGISTERS, 0)
+#define RT274_PROC_COEF\
+ VERB_CMD(AC_VERB_SET_PROC_COEF, RT274_VENDOR_REGISTERS, 0)
+#define RT274_UNSOLICITED_INLINE_CMD\
+ VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_INLINE_CMD, 0)
+#define RT274_UNSOLICITED_HP_OUT\
+ VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_HP_OUT, 0)
+#define RT274_UNSOLICITED_MIC\
+ VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_MIC, 0)
+#define RT274_COEF58_INDEX\
+ VERB_CMD(AC_VERB_SET_COEF_INDEX, 0x58, 0)
+#define RT274_COEF58_COEF\
+ VERB_CMD(AC_VERB_SET_PROC_COEF, 0x58, 0)
+#define RT274_COEF5b_INDEX\
+ VERB_CMD(AC_VERB_SET_COEF_INDEX, 0x5b, 0)
+#define RT274_COEF5b_COEF\
+ VERB_CMD(AC_VERB_SET_PROC_COEF, 0x5b, 0)
+#define RT274_SET_STREAMID_DAC0\
+ VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_DAC_OUT0, 0)
+#define RT274_SET_STREAMID_DAC1\
+ VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_DAC_OUT1, 0)
+#define RT274_SET_STREAMID_ADC1\
+ VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_ADC_IN1, 0)
+#define RT274_SET_STREAMID_ADC2\
+ VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_ADC_IN2, 0)
+
+/* Index registers */
+#define RT274_EAPD_GPIO_IRQ_CTRL 0x10
+#define RT274_PAD_CTRL12 0x35
+#define RT274_I2S_CTRL1 0x63
+#define RT274_I2S_CTRL2 0x64
+#define RT274_MCLK_CTRL 0x71
+#define RT274_CLK_CTRL 0x72
+#define RT274_PLL2_CTRL 0x7b
+
+
+/* EAPD GPIO IRQ control (Index 0x10) */
+#define RT274_IRQ_DIS (0x0 << 13)
+#define RT274_IRQ_EN (0x1 << 13)
+#define RT274_IRQ_CLR (0x1 << 12)
+#define RT274_GPI2_SEL_MASK (0x3 << 7)
+#define RT274_GPI2_SEL_GPIO2 (0x0 << 7)
+#define RT274_GPI2_SEL_I2S (0x1 << 7)
+#define RT274_GPI2_SEL_DMIC_CLK (0x2 << 7)
+#define RT274_GPI2_SEL_CBJ (0x3 << 7)
+
+/* Front I2S_Interface control 1 (Index 0x63) */
+#define RT274_I2S_MODE_MASK (0x1 << 11)
+#define RT274_I2S_MODE_S (0x0 << 11)
+#define RT274_I2S_MODE_M (0x1 << 11)
+#define RT274_TDM_DIS (0x0 << 10)
+#define RT274_TDM_EN (0x1 << 10)
+#define RT274_TDM_CH_NUM (0x1 << 7)
+#define RT274_TDM_2CH (0x0 << 7)
+#define RT274_TDM_4CH (0x1 << 7)
+#define RT274_I2S_FMT_MASK (0x3 << 8)
+#define RT274_I2S_FMT_I2S (0x0 << 8)
+#define RT274_I2S_FMT_LJ (0x1 << 8)
+#define RT274_I2S_FMT_PCMA (0x2 << 8)
+#define RT274_I2S_FMT_PCMB (0x3 << 8)
+
+/* MCLK clock domain control (Index 0x71) */
+#define RT274_MCLK_MODE_MASK (0x1 << 14)
+#define RT274_MCLK_MODE_DIS (0x0 << 14)
+#define RT274_MCLK_MODE_EN (0x1 << 14)
+
+/* Clock control (Index 0x72) */
+#define RT274_CLK_SRC_MASK (0x7 << 3)
+#define RT274_CLK_SRC_MCLK (0x0 << 3)
+#define RT274_CLK_SRC_PLL2 (0x3 << 3)
+
+/* PLL2 control (Index 0x7b) */
+#define RT274_PLL2_SRC_MASK (0x1 << 13)
+#define RT274_PLL2_SRC_MCLK (0x0 << 13)
+#define RT274_PLL2_SRC_BCLK (0x1 << 13)
+
+/* HP-OUT (0x21) */
+#define RT274_M_HP_MUX_SFT 14
+#define RT274_HP_SEL_MASK 0x1
+#define RT274_HP_SEL_SFT 0
+#define RT274_HP_SEL_F 0
+#define RT274_HP_SEL_S 1
+
+/* ADC (0x22) (0x23) */
+#define RT274_ADC_SEL_MASK 0x7
+#define RT274_ADC_SEL_SFT 0
+#define RT274_ADC_SEL_MIC 0
+#define RT274_ADC_SEL_LINE1 1
+#define RT274_ADC_SEL_LINE2 2
+#define RT274_ADC_SEL_DMIC 3
+
+#define RT274_SCLK_S_MCLK 0
+#define RT274_SCLK_S_PLL1 1
+#define RT274_SCLK_S_PLL2 2
+
+#define RT274_PLL2_S_MCLK 0
+#define RT274_PLL2_S_BCLK 1
+
+enum {
+ RT274_AIF1,
+ RT274_AIFS,
+};
+
+#endif /* __RT274_H__ */
+
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 7899a2cdeb42..af6325c78292 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1046,7 +1046,7 @@ static struct snd_soc_dai_driver rt286_dai[] = {
};
-static struct snd_soc_codec_driver soc_codec_dev_rt286 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt286 = {
.probe = rt286_probe,
.remove = rt286_remove,
.suspend = rt286_suspend,
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index d9e96e65e1c4..ce963768449f 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1113,7 +1113,7 @@ static struct snd_soc_dai_driver rt298_dai[] = {
};
-static struct snd_soc_codec_driver soc_codec_dev_rt298 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt298 = {
.probe = rt298_probe,
.remove = rt298_remove,
.suspend = rt298_suspend,
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 7ed62e8c80b4..ed6e5373916c 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -43,9 +43,7 @@ struct rt5514_dsp {
struct mutex dma_lock;
struct snd_pcm_substream *substream;
unsigned int buf_base, buf_limit, buf_rp;
- size_t buf_size;
- size_t dma_offset;
- size_t dsp_offset;
+ size_t buf_size, get_size, dma_offset;
};
static const struct snd_pcm_hardware rt5514_spi_pcm_hardware = {
@@ -80,6 +78,8 @@ static void rt5514_spi_copy_work(struct work_struct *work)
container_of(work, struct rt5514_dsp, copy_work.work);
struct snd_pcm_runtime *runtime;
size_t period_bytes, truncated_bytes = 0;
+ unsigned int cur_wp, remain_data;
+ u8 buf[8];
mutex_lock(&rt5514_dsp->dma_lock);
if (!rt5514_dsp->substream) {
@@ -90,8 +90,24 @@ static void rt5514_spi_copy_work(struct work_struct *work)
runtime = rt5514_dsp->substream->runtime;
period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream);
- if (rt5514_dsp->buf_size - rt5514_dsp->dsp_offset < period_bytes)
- period_bytes = rt5514_dsp->buf_size - rt5514_dsp->dsp_offset;
+ if (rt5514_dsp->get_size >= rt5514_dsp->buf_size) {
+ rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf,
+ sizeof(buf));
+ cur_wp = buf[0] | buf[1] << 8 | buf[2] << 16 |
+ buf[3] << 24;
+
+ if (cur_wp >= rt5514_dsp->buf_rp)
+ remain_data = (cur_wp - rt5514_dsp->buf_rp);
+ else
+ remain_data =
+ (rt5514_dsp->buf_limit - rt5514_dsp->buf_rp) +
+ (cur_wp - rt5514_dsp->buf_base);
+
+ if (remain_data < period_bytes) {
+ schedule_delayed_work(&rt5514_dsp->copy_work, 5);
+ goto done;
+ }
+ }
if (rt5514_dsp->buf_rp + period_bytes <= rt5514_dsp->buf_limit) {
rt5514_spi_burst_read(rt5514_dsp->buf_rp,
@@ -112,24 +128,62 @@ static void rt5514_spi_copy_work(struct work_struct *work)
runtime->dma_area + rt5514_dsp->dma_offset +
truncated_bytes, period_bytes - truncated_bytes);
- rt5514_dsp->buf_rp = rt5514_dsp->buf_base +
- period_bytes - truncated_bytes;
+ rt5514_dsp->buf_rp = rt5514_dsp->buf_base + period_bytes -
+ truncated_bytes;
}
+ rt5514_dsp->get_size += period_bytes;
rt5514_dsp->dma_offset += period_bytes;
if (rt5514_dsp->dma_offset >= runtime->dma_bytes)
rt5514_dsp->dma_offset = 0;
- rt5514_dsp->dsp_offset += period_bytes;
-
snd_pcm_period_elapsed(rt5514_dsp->substream);
- if (rt5514_dsp->dsp_offset < rt5514_dsp->buf_size)
- schedule_delayed_work(&rt5514_dsp->copy_work, 5);
+ schedule_delayed_work(&rt5514_dsp->copy_work, 5);
+
done:
mutex_unlock(&rt5514_dsp->dma_lock);
}
+static irqreturn_t rt5514_spi_irq(int irq, void *data)
+{
+ struct rt5514_dsp *rt5514_dsp = data;
+ u8 buf[8];
+
+ rt5514_dsp->get_size = 0;
+
+ /**
+ * The address area x1800XXXX is the register address, and it cannot
+ * support spi burst read perfectly. So we use the spi burst read
+ * individually to make sure the data correctly.
+ */
+ rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE, (u8 *)&buf,
+ sizeof(buf));
+ rt5514_dsp->buf_base = buf[0] | buf[1] << 8 | buf[2] << 16 |
+ buf[3] << 24;
+
+ rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT, (u8 *)&buf,
+ sizeof(buf));
+ rt5514_dsp->buf_limit = buf[0] | buf[1] << 8 | buf[2] << 16 |
+ buf[3] << 24;
+
+ rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf,
+ sizeof(buf));
+ rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 |
+ buf[3] << 24;
+
+ if (rt5514_dsp->buf_rp % 8)
+ rt5514_dsp->buf_rp = (rt5514_dsp->buf_rp / 8) * 8;
+
+ rt5514_dsp->buf_size = rt5514_dsp->buf_limit - rt5514_dsp->buf_base;
+
+ if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit &&
+ rt5514_dsp->buf_rp && rt5514_dsp->buf_size)
+ schedule_delayed_work(&rt5514_dsp->copy_work, 0);
+
+ return IRQ_HANDLED;
+}
+
/* PCM for streaming audio from the DSP buffer */
static int rt5514_spi_pcm_open(struct snd_pcm_substream *substream)
{
@@ -150,6 +204,7 @@ static int rt5514_spi_hw_params(struct snd_pcm_substream *substream,
ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
rt5514_dsp->substream = substream;
+ rt5514_dsp->dma_offset = 0;
mutex_unlock(&rt5514_dsp->dma_lock);
return ret;
@@ -170,59 +225,6 @@ static int rt5514_spi_hw_free(struct snd_pcm_substream *substream)
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
-static int rt5514_spi_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct rt5514_dsp *rt5514_dsp =
- snd_soc_platform_get_drvdata(rtd->platform);
- u8 buf[8];
-
- rt5514_dsp->dma_offset = 0;
- rt5514_dsp->dsp_offset = 0;
-
- /**
- * The address area x1800XXXX is the register address, and it cannot
- * support spi burst read perfectly. So we use the spi burst read
- * individually to make sure the data correctly.
- */
- rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE, (u8 *)&buf,
- sizeof(buf));
- rt5514_dsp->buf_base = buf[0] | buf[1] << 8 | buf[2] << 16 |
- buf[3] << 24;
-
- rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT, (u8 *)&buf,
- sizeof(buf));
- rt5514_dsp->buf_limit = buf[0] | buf[1] << 8 | buf[2] << 16 |
- buf[3] << 24;
-
- rt5514_spi_burst_read(RT5514_BUFFER_VOICE_RP, (u8 *)&buf,
- sizeof(buf));
- rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 |
- buf[3] << 24;
-
- rt5514_spi_burst_read(RT5514_BUFFER_VOICE_SIZE, (u8 *)&buf,
- sizeof(buf));
- rt5514_dsp->buf_size = buf[0] | buf[1] << 8 | buf[2] << 16 |
- buf[3] << 24;
-
- return 0;
-}
-
-static int rt5514_spi_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct rt5514_dsp *rt5514_dsp =
- snd_soc_platform_get_drvdata(rtd->platform);
-
- if (cmd == SNDRV_PCM_TRIGGER_START) {
- if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit &&
- rt5514_dsp->buf_rp && rt5514_dsp->buf_size)
- schedule_delayed_work(&rt5514_dsp->copy_work, 0);
- }
-
- return 0;
-}
-
static snd_pcm_uframes_t rt5514_spi_pcm_pointer(
struct snd_pcm_substream *substream)
{
@@ -238,8 +240,6 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
.open = rt5514_spi_pcm_open,
.hw_params = rt5514_spi_hw_params,
.hw_free = rt5514_spi_hw_free,
- .trigger = rt5514_spi_trigger,
- .prepare = rt5514_spi_prepare,
.pointer = rt5514_spi_pcm_pointer,
.mmap = snd_pcm_lib_mmap_vmalloc,
.page = snd_pcm_lib_get_vmalloc_page,
@@ -248,6 +248,7 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform)
{
struct rt5514_dsp *rt5514_dsp;
+ int ret;
rt5514_dsp = devm_kzalloc(platform->dev, sizeof(*rt5514_dsp),
GFP_KERNEL);
@@ -257,10 +258,21 @@ static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform)
INIT_DELAYED_WORK(&rt5514_dsp->copy_work, rt5514_spi_copy_work);
snd_soc_platform_set_drvdata(platform, rt5514_dsp);
+ if (rt5514_spi->irq) {
+ ret = devm_request_threaded_irq(&rt5514_spi->dev,
+ rt5514_spi->irq, NULL, rt5514_spi_irq,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5514-spi",
+ rt5514_dsp);
+ if (ret)
+ dev_err(&rt5514_spi->dev,
+ "%s Failed to reguest IRQ: %d\n", __func__,
+ ret);
+ }
+
return 0;
}
-static struct snd_soc_platform_driver rt5514_spi_platform = {
+static const struct snd_soc_platform_driver rt5514_spi_platform = {
.probe = rt5514_spi_pcm_probe,
.ops = &rt5514_spi_pcm_ops,
};
diff --git a/sound/soc/codecs/rt5514-spi.h b/sound/soc/codecs/rt5514-spi.h
index f69b1cdf2f9b..a6434ee6ff03 100644
--- a/sound/soc/codecs/rt5514-spi.h
+++ b/sound/soc/codecs/rt5514-spi.h
@@ -17,10 +17,9 @@
*/
#define RT5514_SPI_BUF_LEN 240
-#define RT5514_BUFFER_VOICE_BASE 0x18001034
-#define RT5514_BUFFER_VOICE_LIMIT 0x18001038
-#define RT5514_BUFFER_VOICE_RP 0x1800103c
-#define RT5514_BUFFER_VOICE_SIZE 0x18001040
+#define RT5514_BUFFER_VOICE_BASE 0x18000200
+#define RT5514_BUFFER_VOICE_LIMIT 0x18000204
+#define RT5514_BUFFER_VOICE_WP 0x1800020c
/* SPI Command */
enum {
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 1b6796c4c471..0945d212b8dc 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -31,7 +31,7 @@
#include "rl6231.h"
#include "rt5514.h"
-#if defined(CONFIG_SND_SOC_RT5514_SPI)
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
#include "rt5514-spi.h"
#endif
@@ -63,6 +63,9 @@ static const struct reg_sequence rt5514_patch[] = {
{RT5514_SRC_CTRL, 0x44000eee},
{RT5514_ANA_CTRL_LDO10, 0x00028604},
{RT5514_ANA_CTRL_ADCFED, 0x00000800},
+ {RT5514_ASRC_IN_CTRL1, 0x00000003},
+ {RT5514_DOWNFILTER0_CTRL3, 0x10000362},
+ {RT5514_DOWNFILTER1_CTRL3, 0x10000362},
};
static const struct reg_default rt5514_reg[] = {
@@ -88,10 +91,10 @@ static const struct reg_default rt5514_reg[] = {
{RT5514_DELAY_BUF_CTRL3, 0x00000000},
{RT5514_DOWNFILTER0_CTRL1, 0x00020c2f},
{RT5514_DOWNFILTER0_CTRL2, 0x00020c2f},
- {RT5514_DOWNFILTER0_CTRL3, 0x00000362},
+ {RT5514_DOWNFILTER0_CTRL3, 0x10000362},
{RT5514_DOWNFILTER1_CTRL1, 0x00020c2f},
{RT5514_DOWNFILTER1_CTRL2, 0x00020c2f},
- {RT5514_DOWNFILTER1_CTRL3, 0x00000362},
+ {RT5514_DOWNFILTER1_CTRL3, 0x10000362},
{RT5514_ANA_CTRL_LDO10, 0x00028604},
{RT5514_ANA_CTRL_LDO18_16, 0x02000345},
{RT5514_ANA_CTRL_ADC12, 0x0000a2a8},
@@ -311,7 +314,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
request_firmware(&fw, RT5514_FIRMWARE1, codec->dev);
if (fw) {
-#if defined(CONFIG_SND_SOC_RT5514_SPI)
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
rt5514_spi_burst_write(0x4ff60000, fw->data,
((fw->size/8)+1)*8);
#else
@@ -324,7 +327,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
request_firmware(&fw, RT5514_FIRMWARE2, codec->dev);
if (fw) {
-#if defined(CONFIG_SND_SOC_RT5514_SPI)
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
rt5514_spi_burst_write(0x4ffc0000, fw->data,
((fw->size/8)+1)*8);
#else
@@ -335,6 +338,39 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
fw = NULL;
}
+ if (rt5514->model_buf && rt5514->model_len) {
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
+ int ret;
+
+ ret = rt5514_spi_burst_write(0x4ff80000,
+ rt5514->model_buf,
+ ((rt5514->model_len / 8) + 1) * 8);
+ if (ret) {
+ dev_err(codec->dev,
+ "Model load failed %d\n", ret);
+ return ret;
+ }
+#else
+ dev_err(codec->dev,
+ "No SPI driver for loading firmware\n");
+#endif
+ } else {
+ request_firmware(&fw, RT5514_FIRMWARE3,
+ codec->dev);
+ if (fw) {
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
+ rt5514_spi_burst_write(0x4ff80000,
+ fw->data,
+ ((fw->size/8)+1)*8);
+#else
+ dev_err(codec->dev,
+ "No SPI driver to load fw\n");
+#endif
+ release_firmware(fw);
+ fw = NULL;
+ }
+ }
+
/* DSP run */
regmap_write(rt5514->i2c_regmap, 0x18002f00,
0x00055148);
@@ -349,6 +385,34 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static int rt5514_hotword_model_put(struct snd_kcontrol *kcontrol,
+ const unsigned int __user *bytes, unsigned int size)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_codec *codec = rt5514->codec;
+ int ret = 0;
+
+ if (rt5514->model_buf || rt5514->model_len < size) {
+ if (rt5514->model_buf)
+ devm_kfree(codec->dev, rt5514->model_buf);
+ rt5514->model_buf = devm_kmalloc(codec->dev, size, GFP_KERNEL);
+ if (!rt5514->model_buf) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ /* Skips the TLV header. */
+ bytes += 2;
+
+ if (copy_from_user(rt5514->model_buf, bytes, size))
+ ret = -EFAULT;
+done:
+ rt5514->model_len = (ret ? 0 : size);
+ return ret;
+}
+
static const struct snd_kcontrol_new rt5514_snd_controls[] = {
SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST,
RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv),
@@ -360,6 +424,8 @@ static const struct snd_kcontrol_new rt5514_snd_controls[] = {
adc_vol_tlv),
SOC_SINGLE_EXT("DSP Voice Wake Up", SND_SOC_NOPM, 0, 1, 0,
rt5514_dsp_voice_wake_up_get, rt5514_dsp_voice_wake_up_put),
+ SND_SOC_BYTES_TLV("Hotword Model", 0x8504,
+ NULL, rt5514_hotword_model_put),
};
/* ADC Mixer*/
@@ -471,33 +537,13 @@ static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
return 0;
}
-static int rt5514_pre_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static int rt5514_i2s_use_asrc(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- /**
- * If the DSP is enabled in start of recording, the DSP
- * should be disabled, and sync back to normal recording
- * settings to make sure recording properly.
- */
- if (rt5514->dsp_enabled) {
- rt5514->dsp_enabled = 0;
- regmap_multi_reg_write(rt5514->i2c_regmap,
- rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch));
- regcache_mark_dirty(rt5514->regmap);
- regcache_sync(rt5514->regmap);
- }
- break;
-
- default:
- return 0;
- }
-
- return 0;
+ return (rt5514->sysclk > rt5514->lrck * 384);
}
static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
@@ -570,6 +616,10 @@ static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
RT5514_POW_PLL1_LDO_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("PLL1", RT5514_PWR_ANA2, RT5514_POW_PLL1_BIT, 0,
NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ASRC AD1", 1, RT5514_CLK_CTRL2,
+ RT5514_CLK_AD0_ASRC_EN_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ASRC AD2", 1, RT5514_CLK_CTRL2,
+ RT5514_CLK_AD1_ASRC_EN_BIT, 0, NULL, 0),
/* ADC Mux */
SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
@@ -607,8 +657,6 @@ static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
/* Audio Interface */
SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
-
- SND_SOC_DAPM_PRE("DAPM Pre", rt5514_pre_event),
};
static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
@@ -669,6 +717,7 @@ static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" },
{ "Stereo1 ADC MIX", NULL, "adc stereo1 filter" },
{ "adc stereo1 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll },
+ { "adc stereo1 filter", NULL, "ASRC AD1", rt5514_i2s_use_asrc },
{ "Stereo2 DMIC Mux", "DMIC1", "DMIC1" },
{ "Stereo2 DMIC Mux", "DMIC2", "DMIC2" },
@@ -685,6 +734,7 @@ static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
{ "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR" },
{ "Stereo2 ADC MIX", NULL, "adc stereo2 filter" },
{ "adc stereo2 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll },
+ { "adc stereo2 filter", NULL, "ASRC AD2", rt5514_i2s_use_asrc },
{ "AIF1TX", NULL, "Stereo1 ADC MIX"},
{ "AIF1TX", NULL, "Stereo2 ADC MIX"},
@@ -737,6 +787,9 @@ static int rt5514_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_I2S_DL_MASK,
val_len);
+ regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL1,
+ RT5514_CLK_AD_ANA1_SEL_MASK,
+ (pre_div + 1) << RT5514_CLK_AD_ANA1_SEL_SFT);
regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2,
RT5514_CLK_SYS_DIV_OUT_MASK | RT5514_SEL_ADC_OSR_MASK,
pre_div << RT5514_CLK_SYS_DIV_OUT_SFT |
@@ -902,11 +955,38 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
{
struct snd_soc_codec *codec = dai->codec;
struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
- unsigned int val = 0;
+ unsigned int val = 0, val2 = 0;
if (rx_mask || tx_mask)
val |= RT5514_TDM_MODE;
+ switch (tx_mask) {
+ case 0x3:
+ val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH2 |
+ RT5514_TDM_DOCKING_START_SLOT0;
+ break;
+
+ case 0x30:
+ val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH2 |
+ RT5514_TDM_DOCKING_START_SLOT4;
+ break;
+
+ case 0xf:
+ val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH4 |
+ RT5514_TDM_DOCKING_START_SLOT0;
+ break;
+
+ case 0xf0:
+ val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH4 |
+ RT5514_TDM_DOCKING_START_SLOT4;
+ break;
+
+ default:
+ break;
+ }
+
+
+
switch (slots) {
case 4:
val |= RT5514_TDMSLOT_SEL_RX_4CH | RT5514_TDMSLOT_SEL_TX_4CH;
@@ -952,6 +1032,10 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK |
RT5514_TDM_MODE2, val);
+ regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL2,
+ RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH_MASK |
+ RT5514_TDM_DOCKING_START_MASK, val2);
+
return 0;
}
@@ -975,6 +1059,24 @@ static int rt5514_set_bias_level(struct snd_soc_codec *codec,
}
break;
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+ /*
+ * If the DSP is enabled in start of recording, the DSP
+ * should be disabled, and sync back to normal recording
+ * settings to make sure recording properly.
+ */
+ if (rt5514->dsp_enabled) {
+ rt5514->dsp_enabled = 0;
+ regmap_multi_reg_write(rt5514->i2c_regmap,
+ rt5514_i2c_patch,
+ ARRAY_SIZE(rt5514_i2c_patch));
+ regcache_mark_dirty(rt5514->regmap);
+ regcache_sync(rt5514->regmap);
+ }
+ }
+ break;
+
default:
break;
}
@@ -1019,7 +1121,7 @@ static int rt5514_i2c_write(void *context, unsigned int reg, unsigned int val)
#define RT5514_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-struct snd_soc_dai_ops rt5514_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt5514_aif_dai_ops = {
.hw_params = rt5514_hw_params,
.set_fmt = rt5514_set_dai_fmt,
.set_sysclk = rt5514_set_dai_sysclk,
@@ -1027,7 +1129,7 @@ struct snd_soc_dai_ops rt5514_aif_dai_ops = {
.set_tdm_slot = rt5514_set_tdm_slot,
};
-struct snd_soc_dai_driver rt5514_dai[] = {
+static struct snd_soc_dai_driver rt5514_dai[] = {
{
.name = "rt5514-aif1",
.id = 0,
@@ -1042,7 +1144,7 @@ struct snd_soc_dai_driver rt5514_dai[] = {
}
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5514 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5514 = {
.probe = rt5514_probe,
.idle_bias_off = true,
.set_bias_level = rt5514_set_bias_level,
@@ -1097,7 +1199,7 @@ MODULE_DEVICE_TABLE(of, rt5514_of_match);
#endif
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt5514_acpi_match[] = {
+static const struct acpi_device_id rt5514_acpi_match[] = {
{ "10EC5514", 0},
{},
};
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h
index 02bc212a86d9..803311cb7e2a 100644
--- a/sound/soc/codecs/rt5514.h
+++ b/sound/soc/codecs/rt5514.h
@@ -37,6 +37,7 @@
#define RT5514_PLL3_CALIB_CTRL5 0x2124
#define RT5514_DELAY_BUF_CTRL1 0x2140
#define RT5514_DELAY_BUF_CTRL3 0x2148
+#define RT5514_ASRC_IN_CTRL1 0x2180
#define RT5514_DOWNFILTER0_CTRL1 0x2190
#define RT5514_DOWNFILTER0_CTRL2 0x2194
#define RT5514_DOWNFILTER0_CTRL3 0x2198
@@ -164,6 +165,18 @@
#define RT5514_I2S_DL_24 (0x2 << 0)
#define RT5514_I2S_DL_8 (0x3 << 0)
+/* RT5514_I2S_CTRL2 (0x2014) */
+#define RT5514_TDM_DOCKING_MODE (0x1 << 31)
+#define RT5514_TDM_DOCKING_MODE_SFT 31
+#define RT5514_TDM_DOCKING_VALID_CH_MASK (0x1 << 29)
+#define RT5514_TDM_DOCKING_VALID_CH_SFT 29
+#define RT5514_TDM_DOCKING_VALID_CH2 (0x0 << 29)
+#define RT5514_TDM_DOCKING_VALID_CH4 (0x1 << 29)
+#define RT5514_TDM_DOCKING_START_MASK (0x1 << 28)
+#define RT5514_TDM_DOCKING_START_SFT 28
+#define RT5514_TDM_DOCKING_START_SLOT0 (0x0 << 28)
+#define RT5514_TDM_DOCKING_START_SLOT4 (0x1 << 28)
+
/* RT5514_DIG_SOURCE_CTRL (0x20a4) */
#define RT5514_AD1_DMIC_INPUT_SEL (0x1 << 1)
#define RT5514_AD1_DMIC_INPUT_SEL_SFT 1
@@ -185,8 +198,14 @@
#define RT5514_CLK_AD0_EN_BIT 23
#define RT5514_CLK_DMIC_OUT_SEL_MASK (0x7 << 8)
#define RT5514_CLK_DMIC_OUT_SEL_SFT 8
+#define RT5514_CLK_AD_ANA1_SEL_MASK (0xf << 0)
+#define RT5514_CLK_AD_ANA1_SEL_SFT 0
/* RT5514_CLK_CTRL2 (0x2108) */
+#define RT5514_CLK_AD1_ASRC_EN (0x1 << 17)
+#define RT5514_CLK_AD1_ASRC_EN_BIT 17
+#define RT5514_CLK_AD0_ASRC_EN (0x1 << 16)
+#define RT5514_CLK_AD0_ASRC_EN_BIT 16
#define RT5514_CLK_SYS_DIV_OUT_MASK (0x7 << 8)
#define RT5514_CLK_SYS_DIV_OUT_SFT 8
#define RT5514_SEL_ADC_OSR_MASK (0x7 << 4)
@@ -236,6 +255,7 @@
#define RT5514_FIRMWARE1 "rt5514_dsp_fw1.bin"
#define RT5514_FIRMWARE2 "rt5514_dsp_fw2.bin"
+#define RT5514_FIRMWARE3 "rt5514_dsp_fw3.bin"
/* System Clock Source */
enum {
@@ -262,6 +282,8 @@ struct rt5514_priv {
int pll_in;
int pll_out;
int dsp_enabled;
+ u8 *model_buf;
+ unsigned int model_len;
};
#endif /* __RT5514_H__ */
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
index 7d6e0823f98f..c94e94fe8297 100644
--- a/sound/soc/codecs/rt5616.c
+++ b/sound/soc/codecs/rt5616.c
@@ -1265,7 +1265,7 @@ static int rt5616_resume(struct snd_soc_codec *codec)
#define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt5616_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt5616_aif_dai_ops = {
.hw_params = rt5616_hw_params,
.set_fmt = rt5616_set_dai_fmt,
.set_sysclk = rt5616_set_dai_sysclk,
@@ -1294,7 +1294,7 @@ static struct snd_soc_dai_driver rt5616_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5616 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5616 = {
.probe = rt5616_probe,
.suspend = rt5616_suspend,
.resume = rt5616_resume,
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 0e418089c053..55b04c55fb4b 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -1653,7 +1653,7 @@ static struct snd_soc_dai_driver rt5631_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
.probe = rt5631_probe,
.set_bias_level = rt5631_set_bias_level,
.suspend_bias_off = true,
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 1584ccc3a87b..438fe52a12df 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -2259,7 +2259,7 @@ static struct snd_soc_dai_driver rt5640_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
.probe = rt5640_probe,
.remove = rt5640_remove,
.suspend = rt5640_suspend,
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 9ec58166f7c4..6a7778a44853 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3473,7 +3473,7 @@ static struct snd_soc_dai_driver rt5645_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5645 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5645 = {
.probe = rt5645_probe,
.remove = rt5645_remove,
.suspend = rt5645_suspend,
@@ -3559,7 +3559,7 @@ static const struct acpi_device_id rt5645_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
#endif
-static struct rt5645_platform_data general_platform_data = {
+static const struct rt5645_platform_data general_platform_data = {
.dmic1_data_pin = RT5645_DMIC1_DISABLE,
.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
.jd_mode = 3,
@@ -3593,7 +3593,7 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
{ }
};
-static struct rt5645_platform_data buddy_platform_data = {
+static const struct rt5645_platform_data buddy_platform_data = {
.dmic1_data_pin = RT5645_DMIC_DATA_GPIO5,
.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
.jd_mode = 3,
@@ -3610,7 +3610,7 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = {
{ }
};
-static struct rt5645_platform_data gpd_win_platform_data = {
+static const struct rt5645_platform_data gpd_win_platform_data = {
.jd_mode = 3,
.inv_jd1_1 = true,
};
@@ -3637,6 +3637,39 @@ static const struct dmi_system_id dmi_platform_gpd_win[] = {
{}
};
+static struct rt5645_platform_data general_platform_data2 = {
+ .dmic1_data_pin = RT5645_DMIC_DATA_IN2N,
+ .dmic2_data_pin = RT5645_DMIC2_DISABLE,
+ .jd_mode = 3,
+ .inv_jd1_1 = true,
+};
+
+static struct dmi_system_id dmi_platform_asus_t100ha[] = {
+ {
+ .ident = "ASUS T100HAN",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
+ },
+ },
+ { }
+};
+
+static struct rt5645_platform_data minix_z83_4_platform_data = {
+ .jd_mode = 3,
+};
+
+static struct dmi_system_id dmi_platform_minix_z83_4[] = {
+ {
+ .ident = "MINIX Z83-4",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MINIX"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
+ },
+ },
+ { }
+};
+
static bool rt5645_check_dp(struct device *dev)
{
if (device_property_present(dev, "realtek,in2-differential") ||
@@ -3689,6 +3722,10 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
rt5645->pdata = general_platform_data;
else if (dmi_check_system(dmi_platform_gpd_win))
rt5645->pdata = gpd_win_platform_data;
+ else if (dmi_check_system(dmi_platform_asus_t100ha))
+ rt5645->pdata = general_platform_data2;
+ else if (dmi_check_system(dmi_platform_minix_z83_4))
+ rt5645->pdata = minix_z83_4_platform_data;
if (quirk != -1) {
rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk);
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index db05b60d5002..da60b28ba3df 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -1664,7 +1664,7 @@ static struct snd_soc_dai_driver rt5651_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
.probe = rt5651_probe,
.suspend = rt5651_suspend,
.resume = rt5651_resume,
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 1b7060850340..71216db15eab 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -3730,7 +3730,7 @@ static struct snd_soc_dai_driver rt5659_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
.probe = rt5659_probe,
.remove = rt5659_remove,
.suspend = rt5659_suspend,
@@ -4222,7 +4222,7 @@ MODULE_DEVICE_TABLE(of, rt5659_of_match);
#endif
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt5659_acpi_match[] = {
+static const struct acpi_device_id rt5659_acpi_match[] = {
{ "10EC5658", 0, },
{ "10EC5659", 0, },
{ },
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index c93490d77f2a..d22ef00e0d96 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -1197,7 +1197,7 @@ static struct snd_soc_dai_driver rt5660_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5660 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5660 = {
.probe = rt5660_probe,
.remove = rt5660_remove,
.suspend = rt5660_suspend,
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index a33202affeb1..ab9e0ebff5a7 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -40,6 +40,7 @@ enum {
struct rt5663_priv {
struct snd_soc_codec *codec;
+ struct rt5663_platform_data pdata;
struct regmap *regmap;
struct delayed_work jack_detect_work;
struct snd_soc_jack *hs_jack;
@@ -57,6 +58,11 @@ struct rt5663_priv {
int jack_type;
};
+static const struct reg_sequence rt5663_patch_list[] = {
+ { 0x002a, 0x8020 },
+ { 0x0086, 0x0028 },
+};
+
static const struct reg_default rt5663_v2_reg[] = {
{ 0x0000, 0x0000 },
{ 0x0001, 0xc8c8 },
@@ -466,7 +472,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0006, 0x1000 },
{ 0x000a, 0x0000 },
{ 0x0010, 0x000f },
- { 0x0015, 0x42c1 },
+ { 0x0015, 0x42f1 },
{ 0x0016, 0x0000 },
{ 0x0018, 0x000b },
{ 0x0019, 0xafaf },
@@ -476,7 +482,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0023, 0x0039 },
{ 0x0026, 0xc0c0 },
{ 0x0029, 0x8080 },
- { 0x002a, 0xa0a0 },
+ { 0x002a, 0x8020 },
{ 0x002c, 0x000c },
{ 0x002d, 0x0000 },
{ 0x0040, 0x0808 },
@@ -504,12 +510,12 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0082, 0x0000 },
{ 0x0083, 0x0000 },
{ 0x0084, 0x0000 },
- { 0x0086, 0x0008 },
+ { 0x0086, 0x0028 },
{ 0x0087, 0x0000 },
{ 0x008a, 0x0000 },
{ 0x008b, 0x0000 },
{ 0x008c, 0x0003 },
- { 0x008e, 0x0004 },
+ { 0x008e, 0x0008 },
{ 0x008f, 0x1000 },
{ 0x0090, 0x0646 },
{ 0x0091, 0x0e3e },
@@ -520,7 +526,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0098, 0x0000 },
{ 0x009a, 0x0000 },
{ 0x009f, 0x0000 },
- { 0x00ae, 0x2000 },
+ { 0x00ae, 0x6000 },
{ 0x00af, 0x0000 },
{ 0x00b6, 0x0000 },
{ 0x00b7, 0x0000 },
@@ -538,7 +544,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x00d9, 0x08f9 },
{ 0x00db, 0x0008 },
{ 0x00dc, 0x00c0 },
- { 0x00dd, 0x6724 },
+ { 0x00dd, 0x6729 },
{ 0x00de, 0x3131 },
{ 0x00df, 0x0008 },
{ 0x00e0, 0x4000 },
@@ -578,7 +584,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0116, 0x0000 },
{ 0x0117, 0x0f00 },
{ 0x0118, 0x0006 },
- { 0x0125, 0x2224 },
+ { 0x0125, 0x2424 },
{ 0x0126, 0x5550 },
{ 0x0127, 0x0400 },
{ 0x0128, 0x7711 },
@@ -596,8 +602,8 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0145, 0x0002 },
{ 0x0146, 0x0000 },
{ 0x0160, 0x0e80 },
- { 0x0161, 0x0020 },
- { 0x0162, 0x0080 },
+ { 0x0161, 0x0080 },
+ { 0x0162, 0x0200 },
{ 0x0163, 0x0800 },
{ 0x0164, 0x0000 },
{ 0x0165, 0x0000 },
@@ -676,8 +682,8 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0251, 0x0000 },
{ 0x0252, 0x028a },
{ 0x02fa, 0x0000 },
- { 0x02fb, 0x0000 },
- { 0x02fc, 0x0000 },
+ { 0x02fb, 0x00a4 },
+ { 0x02fc, 0x0300 },
{ 0x0300, 0x0000 },
{ 0x03d0, 0x0000 },
{ 0x03d1, 0x0000 },
@@ -1508,7 +1514,7 @@ static int rt5663_v2_jack_detect(struct snd_soc_codec *codec, int jack_insert)
static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
{
struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
- int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+ int val, i = 0;
dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert);
@@ -1543,25 +1549,68 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN);
snd_soc_update_bits(codec, RT5663_IRQ_1,
RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN);
- while (i < 5) {
- msleep(sleep_time[i]);
- val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) &
- 0x0003;
- dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n",
- __func__, val, sleep_time[i]);
- i++;
- if (val == 0x1 || val == 0x2 || val == 0x3)
+
+ while (true) {
+ regmap_read(rt5663->regmap, RT5663_INT_ST_2, &val);
+ if (!(val & 0x80))
+ usleep_range(10000, 10005);
+ else
break;
+
+ if (i > 200)
+ break;
+ i++;
}
+
+ val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & 0x0003;
dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
+
+ snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+ RT5663_OSW_HP_L_MASK | RT5663_OSW_HP_R_MASK,
+ RT5663_OSW_HP_L_EN | RT5663_OSW_HP_R_EN);
+
switch (val) {
case 1:
case 2:
rt5663->jack_type = SND_JACK_HEADSET;
rt5663_enable_push_button_irq(codec, true);
+
+ if (rt5663->pdata.dc_offset_l_manual_mic) {
+ regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
+ rt5663->pdata.dc_offset_l_manual_mic >>
+ 16);
+ regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3,
+ rt5663->pdata.dc_offset_l_manual_mic &
+ 0xffff);
+ }
+
+ if (rt5663->pdata.dc_offset_r_manual_mic) {
+ regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5,
+ rt5663->pdata.dc_offset_r_manual_mic >>
+ 16);
+ regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6,
+ rt5663->pdata.dc_offset_r_manual_mic &
+ 0xffff);
+ }
break;
default:
rt5663->jack_type = SND_JACK_HEADPHONE;
+
+ if (rt5663->pdata.dc_offset_l_manual) {
+ regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
+ rt5663->pdata.dc_offset_l_manual >> 16);
+ regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3,
+ rt5663->pdata.dc_offset_l_manual &
+ 0xffff);
+ }
+
+ if (rt5663->pdata.dc_offset_r_manual) {
+ regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5,
+ rt5663->pdata.dc_offset_r_manual >> 16);
+ regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6,
+ rt5663->pdata.dc_offset_r_manual &
+ 0xffff);
+ }
break;
}
} else {
@@ -1656,6 +1705,9 @@ static void rt5663_jack_detect_work(struct work_struct *work)
default:
dev_err(codec->dev, "Unknown CODEC Version\n");
}
+
+ /* Delay the jack insert report to avoid pop noise */
+ msleep(30);
} else {
/* jack is already in, report button event */
report = SND_JACK_HEADSET;
@@ -1953,13 +2005,9 @@ static const struct snd_kcontrol_new rt5663_adda_r_mix[] = {
static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = {
SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER,
RT5663_M_DAC_L1_STO_L_SHIFT, 1, 1),
- SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER,
- RT5663_M_DAC_R1_STO_L_SHIFT, 1, 1),
};
static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = {
- SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER,
- RT5663_M_DAC_L1_STO_R_SHIFT, 1, 1),
SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER,
RT5663_M_DAC_R1_STO_R_SHIFT, 1, 1),
};
@@ -2024,10 +2072,6 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
RT5663_HP_SIG_SRC1_SILENCE);
} else {
snd_soc_write(codec, RT5663_DEPOP_2, 0x3003);
- snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b,
- 0x000b);
- snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030,
- 0x0030);
snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS);
snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371);
@@ -2036,6 +2080,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7766);
snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa);
snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777);
+ snd_soc_update_bits(codec, RT5663_STO_DRE_1, 0x8000,
+ 0x8000);
snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000,
0x3000);
}
@@ -2050,9 +2096,36 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0);
snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN);
- snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0);
- snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b,
- 0x000b);
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5663_charge_pump_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (rt5663->codec_ver == CODEC_VER_0) {
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030,
+ 0x0030);
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003,
+ 0x0003);
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ if (rt5663->codec_ver == CODEC_VER_0) {
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0);
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0);
}
break;
@@ -2182,6 +2255,9 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0),
/* Headphone*/
+ SND_SOC_DAPM_SUPPLY("HP Charge Pump", SND_SOC_NOPM, 0, 0,
+ rt5663_charge_pump_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5663_hp_event,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
@@ -2330,14 +2406,13 @@ static const struct snd_soc_dapm_route rt5663_dapm_routes[] = {
{ "DAC R1", NULL, "ADDA MIXR" },
{ "STO1 DAC MIXL", "DAC L Switch", "DAC L1" },
- { "STO1 DAC MIXL", "DAC R Switch", "DAC R1" },
{ "STO1 DAC MIXL", NULL, "STO1 DAC L Power" },
{ "STO1 DAC MIXL", NULL, "STO1 DAC Filter" },
{ "STO1 DAC MIXR", "DAC R Switch", "DAC R1" },
- { "STO1 DAC MIXR", "DAC L Switch", "DAC L1" },
{ "STO1 DAC MIXR", NULL, "STO1 DAC R Power" },
{ "STO1 DAC MIXR", NULL, "STO1 DAC Filter" },
+ { "HP Amp", NULL, "HP Charge Pump" },
{ "HP Amp", NULL, "DAC L" },
{ "HP Amp", NULL, "DAC R" },
};
@@ -2860,7 +2935,7 @@ static int rt5663_resume(struct snd_soc_codec *codec)
#define RT5663_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt5663_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt5663_aif_dai_ops = {
.hw_params = rt5663_hw_params,
.set_fmt = rt5663_set_dai_fmt,
.set_sysclk = rt5663_set_dai_sysclk,
@@ -2891,7 +2966,7 @@ static struct snd_soc_dai_driver rt5663_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5663 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5663 = {
.probe = rt5663_probe,
.remove = rt5663_remove,
.suspend = rt5663_suspend,
@@ -2956,7 +3031,7 @@ MODULE_DEVICE_TABLE(of, rt5663_of_match);
#endif
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt5663_acpi_match[] = {
+static const struct acpi_device_id rt5663_acpi_match[] = {
{ "10EC5663", 0},
{},
};
@@ -2986,47 +3061,76 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
{
int value, count;
- regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0280);
+ regmap_write(rt5663->regmap, RT5663_RESET, 0x0000);
+ msleep(20);
+ regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_4, 0x00a1);
+ regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0380);
regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000);
- regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001);
+ regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1000);
regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032);
- regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be);
- msleep(20);
- regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be);
- regmap_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400);
- regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000);
- regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b);
- regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8);
- regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0003);
- regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c);
- regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1111);
+ regmap_write(rt5663->regmap, RT5663_HP_IMP_SEN_19, 0x000c);
+ regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x0324);
+ regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001);
+ regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa23b);
+ msleep(30);
+ regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23b);
+ regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x8000);
+ regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x0008);
regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_1, 0xffff);
regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_2, 0xffff);
+ regmap_write(rt5663->regmap, RT5663_CBJ_1, 0x8c10);
+ regmap_write(rt5663->regmap, RT5663_IL_CMD_2, 0x00c1);
+ regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_1, 0xb880);
+ regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_2, 0x4110);
+ regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_2, 0x4118);
+
+ count = 0;
+ while (true) {
+ regmap_read(rt5663->regmap, RT5663_INT_ST_2, &value);
+ if (!(value & 0x80))
+ usleep_range(10000, 10005);
+ else
+ break;
+
+ if (++count > 200)
+ break;
+ }
+
+ regmap_write(rt5663->regmap, RT5663_HP_IMP_SEN_19, 0x0000);
regmap_write(rt5663->regmap, RT5663_DEPOP_2, 0x3003);
+ regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x0038);
regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b);
+ regmap_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400);
+ regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8);
+ regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x8003);
+ regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c);
regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32);
- regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371);
regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b);
- regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x2080);
+ msleep(40);
+ regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x0000);
regmap_write(rt5663->regmap, RT5663_BYPASS_STO_DAC, 0x000c);
- regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xabba);
+ regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xafaa);
regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_1, 0x2224);
regmap_write(rt5663->regmap, RT5663_HP_OUT_EN, 0x8088);
regmap_write(rt5663->regmap, RT5663_STO_DRE_9, 0x0017);
regmap_write(rt5663->regmap, RT5663_STO_DRE_10, 0x0017);
regmap_write(rt5663->regmap, RT5663_STO1_ADC_MIXER, 0x4040);
+ regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000);
regmap_write(rt5663->regmap, RT5663_RECMIX, 0x0005);
regmap_write(rt5663->regmap, RT5663_ADDA_RST, 0xc000);
regmap_write(rt5663->regmap, RT5663_STO1_HPF_ADJ1, 0x3320);
regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x00c9);
regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x004c);
- regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766);
- regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4702);
- msleep(200);
+ regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x1111);
+ regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4402);
+ regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_2, 0x3311);
regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0x0069);
- regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06c2);
- regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x7b00);
- regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xfb00);
+ regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06ce);
+ regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x6800);
+ regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_2, 0x1100);
+ regmap_write(rt5663->regmap, RT5663_HP_CALIB_7, 0x0057);
+ regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xe800);
+
count = 0;
while (true) {
regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value);
@@ -3039,11 +3143,56 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
return;
count++;
}
+
+ regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x6200);
+ regmap_write(rt5663->regmap, RT5663_HP_CALIB_7, 0x0059);
+ regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xe200);
+
+ count = 0;
+ while (true) {
+ regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value);
+ if (value & 0x8000)
+ usleep_range(10000, 10005);
+ else
+ break;
+
+ if (count > 200)
+ return;
+ count++;
+ }
+
+ regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_1, 0xb8e0);
+ usleep_range(10000, 10005);
+ regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0x003b);
+ usleep_range(10000, 10005);
+ regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x0000);
+ usleep_range(10000, 10005);
+ regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x000b);
+ usleep_range(10000, 10005);
+ regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x0008);
+ usleep_range(10000, 10005);
+ regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0000);
+ usleep_range(10000, 10005);
+}
+
+static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev)
+{
+ device_property_read_u32(dev, "realtek,dc_offset_l_manual",
+ &rt5663->pdata.dc_offset_l_manual);
+ device_property_read_u32(dev, "realtek,dc_offset_r_manual",
+ &rt5663->pdata.dc_offset_r_manual);
+ device_property_read_u32(dev, "realtek,dc_offset_l_manual_mic",
+ &rt5663->pdata.dc_offset_l_manual_mic);
+ device_property_read_u32(dev, "realtek,dc_offset_r_manual_mic",
+ &rt5663->pdata.dc_offset_r_manual_mic);
+
+ return 0;
}
static int rt5663_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
+ struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5663_priv *rt5663;
int ret;
unsigned int val;
@@ -3057,6 +3206,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, rt5663);
+ if (pdata)
+ rt5663->pdata = *pdata;
+ else
+ rt5663_parse_dp(rt5663, &i2c->dev);
+
regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
@@ -3105,6 +3259,20 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
regmap_write(rt5663->regmap, RT5663_RESET, 0);
dev_dbg(&i2c->dev, "calibrate done\n");
+ switch (rt5663->codec_ver) {
+ case CODEC_VER_1:
+ break;
+ case CODEC_VER_0:
+ ret = regmap_register_patch(rt5663->regmap, rt5663_patch_list,
+ ARRAY_SIZE(rt5663_patch_list));
+ if (ret != 0)
+ dev_warn(&i2c->dev,
+ "Failed to apply regmap patch: %d\n", ret);
+ break;
+ default:
+ dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__);
+ }
+
/* GPIO1 as IRQ */
regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5663_GP1_PIN_MASK,
RT5663_GP1_PIN_IRQ);
diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h
index 4621812c94d8..c5a9b69579ad 100644
--- a/sound/soc/codecs/rt5663.h
+++ b/sound/soc/codecs/rt5663.h
@@ -12,6 +12,8 @@
#ifndef __RT5663_H__
#define __RT5663_H__
+#include <sound/rt5663.h>
+
/* Info */
#define RT5663_RESET 0x0000
#define RT5663_VENDOR_ID 0x00fd
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 370ed54d1e15..f05d362c4e23 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -1381,6 +1381,16 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
mutex_unlock(&rt5665->calibrate_mutex);
}
+static const char * const rt5665_clk_sync[] = {
+ "I2S1_1", "I2S1_2", "I2S2", "I2S3", "IF2 Slave", "IF3 Slave"
+};
+
+static const struct soc_enum rt5665_enum[] = {
+ SOC_ENUM_SINGLE(RT5665_I2S1_SDP, 11, 5, rt5665_clk_sync),
+ SOC_ENUM_SINGLE(RT5665_I2S2_SDP, 11, 5, rt5665_clk_sync),
+ SOC_ENUM_SINGLE(RT5665_I2S3_SDP, 11, 5, rt5665_clk_sync),
+};
+
static const struct snd_kcontrol_new rt5665_snd_controls[] = {
/* Headphone Output Volume */
SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5665_HPL_GAIN,
@@ -1392,6 +1402,9 @@ static const struct snd_kcontrol_new rt5665_snd_controls[] = {
RT5665_L_VOL_SFT, 15, 1, snd_soc_get_volsw,
rt5665_mono_vol_put, mono_vol_tlv),
+ SOC_SINGLE_TLV("MONOVOL Playback Volume", RT5665_MONO_OUT,
+ RT5665_L_VOL_SFT, 39, 1, out_vol_tlv),
+
/* Output Volume */
SOC_DOUBLE_TLV("OUT Playback Volume", RT5665_LOUT, RT5665_L_VOL_SFT,
RT5665_R_VOL_SFT, 39, 1, out_vol_tlv),
@@ -1446,6 +1459,11 @@ static const struct snd_kcontrol_new rt5665_snd_controls[] = {
SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5665_STO2_ADC_BOOST,
RT5665_STO2_ADC_L_BST_SFT, RT5665_STO2_ADC_R_BST_SFT,
3, 0, adc_bst_tlv),
+
+ /* I2S3 CLK Source */
+ SOC_ENUM("I2S1 Master Clk Sel", rt5665_enum[0]),
+ SOC_ENUM("I2S2 Master Clk Sel", rt5665_enum[1]),
+ SOC_ENUM("I2S3 Master Clk Sel", rt5665_enum[2]),
};
/**
@@ -4098,9 +4116,12 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
rt5665->lrck[dai->id] = params_rate(params);
pre_div = rl6231_get_clk_info(rt5665->sysclk, rt5665->lrck[dai->id]);
if (pre_div < 0) {
- dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
- rt5665->lrck[dai->id], dai->id);
- return -EINVAL;
+ dev_warn(codec->dev, "Force using PLL");
+ snd_soc_codec_set_pll(codec, 0, RT5665_PLL1_S_MCLK,
+ rt5665->sysclk, rt5665->lrck[dai->id] * 512);
+ snd_soc_codec_set_sysclk(codec, RT5665_SCLK_S_PLL1, 0,
+ rt5665->lrck[dai->id] * 512, 0);
+ pre_div = 1;
}
frame_size = snd_soc_params_to_frame_size(params);
if (frame_size < 0) {
@@ -4183,6 +4204,15 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
break;
}
+ if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) {
+ snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+ RT5665_I2S2_M_PD_MASK, pre_div << RT5665_I2S2_M_PD_SFT);
+ }
+ if (rt5665->master[RT5665_AIF3]) {
+ snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+ RT5665_I2S3_M_PD_MASK, pre_div << RT5665_I2S3_M_PD_SFT);
+ }
+
return 0;
}
@@ -4259,7 +4289,7 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir)
{
struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
- unsigned int reg_val = 0;
+ unsigned int reg_val = 0, src = 0;
if (freq == rt5665->sysclk && clk_id == rt5665->sysclk_src)
return 0;
@@ -4267,12 +4297,15 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
switch (clk_id) {
case RT5665_SCLK_S_MCLK:
reg_val |= RT5665_SCLK_SRC_MCLK;
+ src = RT5665_CLK_SRC_MCLK;
break;
case RT5665_SCLK_S_PLL1:
reg_val |= RT5665_SCLK_SRC_PLL1;
+ src = RT5665_CLK_SRC_PLL1;
break;
case RT5665_SCLK_S_RCCLK:
reg_val |= RT5665_SCLK_SRC_RCCLK;
+ src = RT5665_CLK_SRC_RCCLK;
break;
default:
dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
@@ -4280,6 +4313,16 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
}
snd_soc_update_bits(codec, RT5665_GLB_CLK,
RT5665_SCLK_SRC_MASK, reg_val);
+
+ if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) {
+ snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+ RT5665_I2S2_SRC_MASK, src << RT5665_I2S2_SRC_SFT);
+ }
+ if (rt5665->master[RT5665_AIF3]) {
+ snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+ RT5665_I2S3_SRC_MASK, src << RT5665_I2S3_SRC_SFT);
+ }
+
rt5665->sysclk = freq;
rt5665->sysclk_src = clk_id;
@@ -4368,12 +4411,12 @@ static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
switch (dai->id) {
case RT5665_AIF2_1:
case RT5665_AIF2_2:
- snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+ snd_soc_update_bits(codec, RT5665_ADDA_CLK_2,
RT5665_I2S_BCLK_MS2_MASK,
RT5665_I2S_BCLK_MS2_64);
break;
case RT5665_AIF3:
- snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+ snd_soc_update_bits(codec, RT5665_ADDA_CLK_2,
RT5665_I2S_BCLK_MS3_MASK,
RT5665_I2S_BCLK_MS3_64);
break;
@@ -4562,7 +4605,7 @@ static struct snd_soc_dai_driver rt5665_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5665 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5665 = {
.probe = rt5665_probe,
.remove = rt5665_remove,
.suspend = rt5665_suspend,
@@ -4927,7 +4970,7 @@ MODULE_DEVICE_TABLE(of, rt5665_of_match);
#endif
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt5665_acpi_match[] = {
+static const struct acpi_device_id rt5665_acpi_match[] = {
{"10EC5665", 0,},
{"10EC5666", 0,},
{"10EC5668", 0,},
diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h
index 1db5c6a62a8e..5ddebd6a4a1b 100644
--- a/sound/soc/codecs/rt5665.h
+++ b/sound/soc/codecs/rt5665.h
@@ -1628,6 +1628,27 @@
#define RT5665_PWR_CLK1M_PD (0x0 << 8)
#define RT5665_PWR_CLK1M_PU (0x1 << 8)
+/* I2S Master Mode Clock Control 1 (0x00a0) */
+#define RT5665_CLK_SRC_MCLK (0x0)
+#define RT5665_CLK_SRC_PLL1 (0x1)
+#define RT5665_CLK_SRC_RCCLK (0x2)
+#define RT5665_I2S_PD_1 (0x0)
+#define RT5665_I2S_PD_2 (0x1)
+#define RT5665_I2S_PD_3 (0x2)
+#define RT5665_I2S_PD_4 (0x3)
+#define RT5665_I2S_PD_6 (0x4)
+#define RT5665_I2S_PD_8 (0x5)
+#define RT5665_I2S_PD_12 (0x6)
+#define RT5665_I2S_PD_16 (0x7)
+#define RT5665_I2S2_SRC_MASK (0x3 << 12)
+#define RT5665_I2S2_SRC_SFT 12
+#define RT5665_I2S2_M_PD_MASK (0x7 << 8)
+#define RT5665_I2S2_M_PD_SFT 8
+#define RT5665_I2S3_SRC_MASK (0x3 << 4)
+#define RT5665_I2S3_SRC_SFT 4
+#define RT5665_I2S3_M_PD_MASK (0x7 << 0)
+#define RT5665_I2S3_M_PD_SFT 0
+
/* EQ Control 1 (0x00b0) */
#define RT5665_EQ_SRC_DAC (0x0 << 15)
@@ -1692,8 +1713,8 @@
#define RT5665_GP6_PIN_MASK (0x3 << 5)
#define RT5665_GP6_PIN_SFT 5
#define RT5665_GP6_PIN_GPIO6 (0x0 << 5)
-#define RT5665_GP6_PIN_BCLK3 (0x0 << 5)
-#define RT5665_GP6_PIN_PDM_SCL (0x1 << 5)
+#define RT5665_GP6_PIN_BCLK3 (0x1 << 5)
+#define RT5665_GP6_PIN_PDM_SCL (0x2 << 5)
#define RT5665_GP7_PIN_MASK (0x3 << 3)
#define RT5665_GP7_PIN_SFT 3
#define RT5665_GP7_PIN_GPIO7 (0x0 << 3)
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 0ec7985ed306..9545764ef3eb 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -567,7 +567,7 @@ int rt5670_set_jack_detect(struct snd_soc_codec *codec,
rt5670->jack = jack;
rt5670->hp_gpio.gpiod_dev = codec->dev;
- rt5670->hp_gpio.name = "headphone detect";
+ rt5670->hp_gpio.name = "headset";
rt5670->hp_gpio.report = SND_JACK_HEADSET |
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2;
rt5670->hp_gpio.debounce_time = 150;
@@ -1151,20 +1151,15 @@ static const char * const rt5670_stereo_adc1_src[] = {
static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc1_enum, RT5670_STO1_ADC_MIXER,
RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src);
-static const struct snd_kcontrol_new rt5670_sto_adc_l1_mux =
- SOC_DAPM_ENUM("Stereo1 ADC L1 source", rt5670_stereo1_adc1_enum);
-
-static const struct snd_kcontrol_new rt5670_sto_adc_r1_mux =
- SOC_DAPM_ENUM("Stereo1 ADC R1 source", rt5670_stereo1_adc1_enum);
+static const struct snd_kcontrol_new rt5670_sto_adc_1_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC 1 Mux", rt5670_stereo1_adc1_enum);
static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc1_enum, RT5670_STO2_ADC_MIXER,
RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src);
-static const struct snd_kcontrol_new rt5670_sto2_adc_l1_mux =
- SOC_DAPM_ENUM("Stereo2 ADC L1 source", rt5670_stereo2_adc1_enum);
+static const struct snd_kcontrol_new rt5670_sto2_adc_1_mux =
+ SOC_DAPM_ENUM("Stereo2 ADC 1 Mux", rt5670_stereo2_adc1_enum);
-static const struct snd_kcontrol_new rt5670_sto2_adc_r1_mux =
- SOC_DAPM_ENUM("Stereo2 ADC R1 source", rt5670_stereo2_adc1_enum);
/* MX-27 MX-26 [11] */
static const char * const rt5670_stereo_adc2_src[] = {
@@ -1174,20 +1169,15 @@ static const char * const rt5670_stereo_adc2_src[] = {
static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc2_enum, RT5670_STO1_ADC_MIXER,
RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src);
-static const struct snd_kcontrol_new rt5670_sto_adc_l2_mux =
- SOC_DAPM_ENUM("Stereo1 ADC L2 source", rt5670_stereo1_adc2_enum);
-
-static const struct snd_kcontrol_new rt5670_sto_adc_r2_mux =
- SOC_DAPM_ENUM("Stereo1 ADC R2 source", rt5670_stereo1_adc2_enum);
+static const struct snd_kcontrol_new rt5670_sto_adc_2_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC 2 Mux", rt5670_stereo1_adc2_enum);
static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc2_enum, RT5670_STO2_ADC_MIXER,
RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src);
-static const struct snd_kcontrol_new rt5670_sto2_adc_l2_mux =
- SOC_DAPM_ENUM("Stereo2 ADC L2 source", rt5670_stereo2_adc2_enum);
+static const struct snd_kcontrol_new rt5670_sto2_adc_2_mux =
+ SOC_DAPM_ENUM("Stereo2 ADC 2 Mux", rt5670_stereo2_adc2_enum);
-static const struct snd_kcontrol_new rt5670_sto2_adc_r2_mux =
- SOC_DAPM_ENUM("Stereo2 ADC R2 source", rt5670_stereo2_adc2_enum);
/* MX-27 MX26 [10] */
static const char * const rt5670_stereo_adc_src[] = {
@@ -1642,23 +1632,23 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
&rt5670_sto1_dmic_mux),
SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
- &rt5670_sto_adc_l2_mux),
+ &rt5670_sto_adc_2_mux),
SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
- &rt5670_sto_adc_r2_mux),
+ &rt5670_sto_adc_2_mux),
SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
- &rt5670_sto_adc_l1_mux),
+ &rt5670_sto_adc_1_mux),
SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
- &rt5670_sto_adc_r1_mux),
+ &rt5670_sto_adc_1_mux),
SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0,
&rt5670_sto2_dmic_mux),
SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
- &rt5670_sto2_adc_l2_mux),
+ &rt5670_sto2_adc_2_mux),
SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
- &rt5670_sto2_adc_r2_mux),
+ &rt5670_sto2_adc_2_mux),
SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
- &rt5670_sto2_adc_l1_mux),
+ &rt5670_sto2_adc_1_mux),
SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
- &rt5670_sto2_adc_r1_mux),
+ &rt5670_sto2_adc_1_mux),
SND_SOC_DAPM_MUX("Stereo2 ADC LR Mux", SND_SOC_NOPM, 0, 0,
&rt5670_sto2_adc_lr_mux),
SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
@@ -2743,6 +2733,7 @@ static struct snd_soc_dai_driver rt5670_dai[] = {
.formats = RT5670_FORMATS,
},
.ops = &rt5670_aif_dai_ops,
+ .symmetric_rates = 1,
},
{
.name = "rt5670-aif2",
@@ -2762,10 +2753,11 @@ static struct snd_soc_dai_driver rt5670_dai[] = {
.formats = RT5670_FORMATS,
},
.ops = &rt5670_aif_dai_ops,
+ .symmetric_rates = 1,
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5670 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5670 = {
.probe = rt5670_probe,
.remove = rt5670_remove,
.suspend = rt5670_suspend,
@@ -2859,6 +2851,17 @@ static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode2[] = {
{}
};
+static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode3[] = {
+ {
+ .ident = "Dell Venue 8 Pro 5855",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5855"),
+ },
+ },
+ {}
+};
+
static int rt5670_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -2888,6 +2891,11 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
rt5670->pdata.dev_gpio = true;
rt5670->pdata.jd_mode = 2;
+ } else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode3)) {
+ rt5670->pdata.dmic_en = true;
+ rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+ rt5670->pdata.dev_gpio = true;
+ rt5670->pdata.jd_mode = 3;
}
rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 36e530a36c82..0791fec398fb 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/firmware.h>
+#include <linux/of_device.h>
#include <linux/property.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -779,9 +780,7 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
return 0;
}
-static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
-static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
@@ -4624,35 +4623,27 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
struct regmap_irq_chip_data *data = rt5677->irq_data;
int irq;
- if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) {
- if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
- (rt5677->pdata.jd1_gpio == 2 &&
- offset == RT5677_GPIO2) ||
- (rt5677->pdata.jd1_gpio == 3 &&
- offset == RT5677_GPIO3)) {
- irq = RT5677_IRQ_JD1;
- } else {
- return -ENXIO;
- }
- }
-
- if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) {
- if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
- (rt5677->pdata.jd2_gpio == 2 &&
- offset == RT5677_GPIO5) ||
- (rt5677->pdata.jd2_gpio == 3 &&
- offset == RT5677_GPIO6)) {
- irq = RT5677_IRQ_JD2;
- } else if ((rt5677->pdata.jd3_gpio == 1 &&
- offset == RT5677_GPIO4) ||
- (rt5677->pdata.jd3_gpio == 2 &&
- offset == RT5677_GPIO5) ||
- (rt5677->pdata.jd3_gpio == 3 &&
- offset == RT5677_GPIO6)) {
- irq = RT5677_IRQ_JD3;
- } else {
- return -ENXIO;
- }
+ if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
+ (rt5677->pdata.jd1_gpio == 2 &&
+ offset == RT5677_GPIO2) ||
+ (rt5677->pdata.jd1_gpio == 3 &&
+ offset == RT5677_GPIO3)) {
+ irq = RT5677_IRQ_JD1;
+ } else if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
+ (rt5677->pdata.jd2_gpio == 2 &&
+ offset == RT5677_GPIO5) ||
+ (rt5677->pdata.jd2_gpio == 3 &&
+ offset == RT5677_GPIO6)) {
+ irq = RT5677_IRQ_JD2;
+ } else if ((rt5677->pdata.jd3_gpio == 1 &&
+ offset == RT5677_GPIO4) ||
+ (rt5677->pdata.jd3_gpio == 2 &&
+ offset == RT5677_GPIO5) ||
+ (rt5677->pdata.jd3_gpio == 3 &&
+ offset == RT5677_GPIO6)) {
+ irq = RT5677_IRQ_JD3;
+ } else {
+ return -ENXIO;
}
return regmap_irq_get_virq(data, irq);
@@ -4968,7 +4959,7 @@ static struct snd_soc_dai_driver rt5677_dai[] = {
},
};
-static struct snd_soc_codec_driver soc_codec_dev_rt5677 = {
+static const struct snd_soc_codec_driver soc_codec_dev_rt5677 = {
.probe = rt5677_probe,
.remove = rt5677_remove,
.suspend = rt5677_suspend,
@@ -5026,18 +5017,16 @@ static const struct i2c_device_id rt5677_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
static const struct of_device_id rt5677_of_match[] = {
- { .compatible = "realtek,rt5677", },
+ { .compatible = "realtek,rt5677", RT5677 },
{ }
};
MODULE_DEVICE_TABLE(of, rt5677_of_match);
-#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5677_acpi_match[] = {
{ "RT5677CE", RT5677 },
{ }
};
MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match);
-#endif
static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677,
struct device *dev)
@@ -5147,7 +5136,6 @@ static void rt5677_free_irq(struct i2c_client *i2c)
static int rt5677_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct rt5677_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5677_priv *rt5677;
int ret;
unsigned int val;
@@ -5159,16 +5147,25 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, rt5677);
- rt5677->type = id->driver_data;
+ if (i2c->dev.of_node) {
+ const struct of_device_id *match_id;
+
+ match_id = of_match_device(rt5677_of_match, &i2c->dev);
+ if (match_id)
+ rt5677->type = (enum rt5677_type)match_id->data;
- if (pdata)
- rt5677->pdata = *pdata;
- else if (i2c->dev.of_node)
rt5677_read_device_properties(rt5677, &i2c->dev);
- else if (ACPI_HANDLE(&i2c->dev))
+ } else if (ACPI_HANDLE(&i2c->dev)) {
+ const struct acpi_device_id *acpi_id;
+
+ acpi_id = acpi_match_device(rt5677_acpi_match, &i2c->dev);
+ if (acpi_id)
+ rt5677->type = (enum rt5677_type)acpi_id->driver_data;
+
rt5677_read_acpi_properties(rt5677, &i2c->dev);
- else
+ } else {
return -EINVAL;
+ }
/* pow-ldo2 and reset are optional. The codec pins may be statically
* connected on the board without gpios. If the gpio device property
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index d46855a42c40..97239973edc4 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -12,7 +12,6 @@
#ifndef __RT5677_H__
#define __RT5677_H__
-#include <sound/rt5677.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
@@ -1761,6 +1760,35 @@ enum {
RT5677_I2S4_SOURCE = (0x1 << 18),
};
+enum rt5677_dmic2_clk {
+ RT5677_DMIC_CLK1 = 0,
+ RT5677_DMIC_CLK2 = 1,
+};
+
+struct rt5677_platform_data {
+ /* IN1/IN2/LOUT1/LOUT2/LOUT3 can optionally be differential */
+ bool in1_diff;
+ bool in2_diff;
+ bool lout1_diff;
+ bool lout2_diff;
+ bool lout3_diff;
+ /* DMIC2 clock source selection */
+ enum rt5677_dmic2_clk dmic2_clk_pin;
+
+ /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */
+ u8 gpio_config[6];
+
+ /* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */
+ unsigned int jd1_gpio;
+ /* jd2 and jd3 can select 0 ~ 3 as
+ OFF, GPIO4, GPIO5 and GPIO6 respectively */
+ unsigned int jd2_gpio;
+ unsigned int jd3_gpio;
+
+ /* Set MICBIAS1 VDD 1v8 or 3v3 */
+ bool micbias1_vdd_3v3;
+};
+
struct rt5677_priv {
struct snd_soc_codec *codec;
struct rt5677_platform_data pdata;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 8f6814c1eb6b..f2bb4feba3b6 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -409,7 +409,7 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
static int avc_get_threshold(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
int db, i;
u16 reg = snd_soc_read(codec, SGTL5000_DAP_AVC_THRESHOLD);
@@ -442,7 +442,7 @@ static int avc_get_threshold(struct snd_kcontrol *kcontrol,
static int avc_put_threshold(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
int db;
u16 reg;
@@ -1248,7 +1248,7 @@ static int sgtl5000_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver sgtl5000_driver = {
+static const struct snd_soc_codec_driver sgtl5000_driver = {
.probe = sgtl5000_probe,
.remove = sgtl5000_remove,
.set_bias_level = sgtl5000_set_bias_level,
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 5344f4aa8fde..354dc0d64f11 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -236,7 +236,7 @@ static struct regmap *si476x_get_regmap(struct device *dev)
return dev_get_regmap(dev->parent, NULL);
}
-static struct snd_soc_codec_driver soc_codec_dev_si476x = {
+static const struct snd_soc_codec_driver soc_codec_dev_si476x = {
.get_regmap = si476x_get_regmap,
.component_driver = {
.dapm_widgets = si476x_dapm_widgets,
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
index 6bfd25c289d1..7ae8c181d1a4 100644
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -429,13 +429,15 @@ static int sirf_audio_codec_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = {
+static const struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = {
.probe = sirf_audio_codec_probe,
.remove = sirf_audio_codec_remove,
- .dapm_widgets = sirf_audio_codec_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
- .dapm_routes = sirf_audio_codec_map,
- .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
+ .component_driver = {
+ .dapm_widgets = sirf_audio_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
+ .dapm_routes = sirf_audio_codec_map,
+ .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
+ },
.idle_bias_off = true,
};
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index eae54c37cff9..887923e68849 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -883,7 +883,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver sn95031_codec = {
+static const struct snd_soc_codec_driver sn95031_codec = {
.probe = sn95031_codec_probe,
.set_bias_level = sn95031_set_vaud_bias,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
index 234f87b54838..7acd05140a81 100644
--- a/sound/soc/codecs/spdif_receiver.c
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -37,7 +37,7 @@ static const struct snd_soc_dapm_route dir_routes[] = {
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
-static struct snd_soc_codec_driver soc_codec_spdif_dir = {
+static const struct snd_soc_codec_driver soc_codec_spdif_dir = {
.component_driver = {
.dapm_widgets = dir_widgets,
.num_dapm_widgets = ARRAY_SIZE(dir_widgets),
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
index ee367536a498..063a64ff82d3 100644
--- a/sound/soc/codecs/spdif_transmitter.c
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -37,7 +37,7 @@ static const struct snd_soc_dapm_route dit_routes[] = {
{ "spdif-out", NULL, "Playback" },
};
-static struct snd_soc_codec_driver soc_codec_spdif_dit = {
+static const struct snd_soc_codec_driver soc_codec_spdif_dit = {
.component_driver = {
.dapm_widgets = dit_widgets,
.num_dapm_widgets = ARRAY_SIZE(dit_widgets),
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 38a85f3adc80..15486fd16269 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -710,7 +710,7 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
SSM2518_POWER1_NO_BCLK, val);
}
-static struct snd_soc_codec_driver ssm2518_codec_driver = {
+static const struct snd_soc_codec_driver ssm2518_codec_driver = {
.set_bias_level = ssm2518_set_bias_level,
.set_sysclk = ssm2518_set_sysclk,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 993bde29ca1b..9b341c23f62b 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -591,7 +591,7 @@ static int ssm260x_codec_probe(struct snd_soc_codec *codec)
return ret;
}
-static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
+static const struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
.probe = ssm260x_codec_probe,
.resume = ssm2602_resume,
.set_bias_level = ssm2602_set_bias_level,
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index a622623e8558..4afeddef7728 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -417,7 +417,7 @@ static struct snd_soc_dai_driver ssm4567_dai = {
.ops = &ssm4567_dai_ops,
};
-static struct snd_soc_codec_driver ssm4567_codec_driver = {
+static const struct snd_soc_codec_driver ssm4567_codec_driver = {
.set_bias_level = ssm4567_set_bias_level,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 0790ae8530d9..5b888476d9ff 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -847,8 +847,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
msleep(300);
sta32x_watchdog_stop(sta32x);
- if (sta32x->gpiod_nreset)
- gpiod_set_value(sta32x->gpiod_nreset, 0);
+ gpiod_set_value(sta32x->gpiod_nreset, 0);
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
sta32x->supplies);
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 9de7fe8af255..c66363a2cac7 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -307,7 +307,7 @@ static int stac9766_codec_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
+static const struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
.component_driver = {
.controls = stac9766_snd_ac97_controls,
.num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls),
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 8840f72f3c4a..87307dd0f12e 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -192,7 +192,7 @@ static int tas2552_setup_pll(struct snd_soc_codec *codec,
* pll_clk = (.5 * pll_clkin * J.D) / 2^p
* Need to fill in J and D here based on incoming freq
*/
- unsigned int d;
+ unsigned int d, q, t;
u8 j;
u8 pll_sel = (tas2552->pll_clk_id << 3) & TAS2552_PLL_SRC_MASK;
u8 p = snd_soc_read(codec, TAS2552_PLL_CTRL_1);
@@ -200,9 +200,12 @@ static int tas2552_setup_pll(struct snd_soc_codec *codec,
p = (p >> 7);
recalc:
- j = (pll_clk * 2 * (1 << p)) / pll_clkin;
- d = (pll_clk * 2 * (1 << p)) % pll_clkin;
- d /= (pll_clkin / 10000);
+ t = (pll_clk * 2) << p;
+ j = t / pll_clkin;
+ d = t % pll_clkin;
+ t = pll_clkin / 10000;
+ q = d / (t + 1);
+ d = q + ((9999 - pll_clkin % 10000) * (d / t - q)) / 10000;
if (d && (pll_clkin < 512000 || pll_clkin > 9200000)) {
if (tas2552->pll_clk_id == TAS2552_PLL_CLKIN_BCLK) {
@@ -660,7 +663,7 @@ static int tas2552_resume(struct snd_soc_codec *codec)
#define tas2552_resume NULL
#endif
-static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
.probe = tas2552_codec_probe,
.remove = tas2552_codec_remove,
.suspend = tas2552_suspend,
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index b7de857abb16..199272d5cb6a 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -885,7 +885,7 @@ static int tas5086_remove(struct snd_soc_codec *codec)
return 0;
};
-static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
.probe = tas5086_probe,
.remove = tas5086_remove,
.suspend = tas5086_soc_suspend,
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index c65b917598d2..a736a2a6976c 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -483,7 +483,7 @@ static const struct snd_soc_dapm_route tas5720_audio_map[] = {
{ "OUT", NULL, "DAC" },
};
-static struct snd_soc_codec_driver soc_codec_dev_tas5720 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tas5720 = {
.probe = tas5720_codec_probe,
.remove = tas5720_codec_remove,
.suspend = tas5720_suspend,
@@ -507,7 +507,7 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5720 = {
#define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
-static struct snd_soc_dai_ops tas5720_speaker_dai_ops = {
+static const struct snd_soc_dai_ops tas5720_speaker_dai_ops = {
.hw_params = tas5720_hw_params,
.set_fmt = tas5720_set_dai_fmt,
.set_tdm_slot = tas5720_set_dai_tdm_slot,
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 628a8eeaab68..3d42138a7974 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -576,7 +576,7 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
.probe = tlv320aic23_codec_probe,
.resume = tlv320aic23_resume,
.set_bias_level = tlv320aic23_set_bias_level,
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 14aa96d41719..89421caaeb70 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -319,7 +319,7 @@ static int aic26_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver aic26_soc_codec_dev = {
+static const struct snd_soc_codec_driver aic26_soc_codec_dev = {
.probe = aic26_probe,
.component_driver = {
.controls = aic26_snd_controls,
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index d7d03c92cb8a..54a87a905eb6 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1185,7 +1185,7 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
+static const struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
.probe = aic31xx_codec_probe,
.remove = aic31xx_codec_remove,
.set_bias_level = aic31xx_set_bias_level,
diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c
index 59606cf3008f..385fa2e9525a 100644
--- a/sound/soc/codecs/tlv320aic32x4-i2c.c
+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
@@ -47,12 +47,14 @@ static int aic32x4_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id aic32x4_i2c_id[] = {
{ "tlv320aic32x4", 0 },
+ { "tlv320aic32x6", 1 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id);
static const struct of_device_id aic32x4_of_id[] = {
{ .compatible = "ti,tlv320aic32x4", },
+ { .compatible = "ti,tlv320aic32x6", },
{ /* senitel */ }
};
MODULE_DEVICE_TABLE(of, aic32x4_of_id);
diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c
index 724fcdd491b2..07d78ae51e05 100644
--- a/sound/soc/codecs/tlv320aic32x4-spi.c
+++ b/sound/soc/codecs/tlv320aic32x4-spi.c
@@ -48,12 +48,14 @@ static int aic32x4_spi_remove(struct spi_device *spi)
static const struct spi_device_id aic32x4_spi_id[] = {
{ "tlv320aic32x4", 0 },
+ { "tlv320aic32x6", 1 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, aic32x4_spi_id);
static const struct of_device_id aic32x4_of_id[] = {
{ .compatible = "ti,tlv320aic32x4", },
+ { .compatible = "ti,tlv320aic32x6", },
{ /* senitel */ }
};
MODULE_DEVICE_TABLE(of, aic32x4_of_id);
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 28fdfc5ec544..e694f5f04eb9 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -74,6 +74,152 @@ struct aic32x4_priv {
struct regulator *supply_iov;
struct regulator *supply_dv;
struct regulator *supply_av;
+
+ struct aic32x4_setup_data *setup;
+ struct device *dev;
+};
+
+static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u8 val;
+
+ val = snd_soc_read(codec, AIC32X4_DINCTL);
+
+ ucontrol->value.integer.value[0] = (val & 0x01);
+
+ return 0;
+};
+
+static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u8 val;
+ u8 gpio_check;
+
+ val = snd_soc_read(codec, AIC32X4_DOUTCTL);
+ gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
+ if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
+ printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP2_GPIO_OUT_HIGH))
+ return 0;
+
+ if (ucontrol->value.integer.value[0])
+ val |= ucontrol->value.integer.value[0];
+ else
+ val &= ~AIC32X4_MFP2_GPIO_OUT_HIGH;
+
+ snd_soc_write(codec, AIC32X4_DOUTCTL, val);
+
+ return 0;
+};
+
+static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u8 val;
+
+ val = snd_soc_read(codec, AIC32X4_SCLKCTL);
+
+ ucontrol->value.integer.value[0] = (val & 0x01);
+
+ return 0;
+};
+
+static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u8 val;
+ u8 gpio_check;
+
+ val = snd_soc_read(codec, AIC32X4_MISOCTL);
+ gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
+ if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
+ printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP5_GPIO_OUT_HIGH))
+ return 0;
+
+ if (ucontrol->value.integer.value[0])
+ val |= ucontrol->value.integer.value[0];
+ else
+ val &= ~AIC32X4_MFP5_GPIO_OUT_HIGH;
+
+ snd_soc_write(codec, AIC32X4_MISOCTL, val);
+
+ return 0;
+};
+
+static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u8 val;
+
+ val = snd_soc_read(codec, AIC32X4_GPIOCTL);
+ ucontrol->value.integer.value[0] = ((val & 0x2) >> 1);
+
+ return 0;
+};
+
+static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u8 val;
+ u8 gpio_check;
+
+ val = snd_soc_read(codec, AIC32X4_GPIOCTL);
+ gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT);
+ if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) {
+ printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (ucontrol->value.integer.value[0] == (val & 0x1))
+ return 0;
+
+ if (ucontrol->value.integer.value[0])
+ val |= ucontrol->value.integer.value[0];
+ else
+ val &= 0xfe;
+
+ snd_soc_write(codec, AIC32X4_GPIOCTL, val);
+
+ return 0;
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp1[] = {
+ SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL),
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp2[] = {
+ SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio),
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp3[] = {
+ SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL),
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp4[] = {
+ SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio),
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp5[] = {
+ SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio,
+ aic32x4_set_mfp5_gpio),
};
/* 0dB min, 0.5dB steps */
@@ -734,6 +880,52 @@ static struct snd_soc_dai_driver aic32x4_dai = {
.symmetric_rates = 1,
};
+static void aic32x4_setup_gpios(struct snd_soc_codec *codec)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+
+ /* setup GPIO functions */
+ /* MFP1 */
+ if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_write(codec, AIC32X4_DINCTL,
+ aic32x4->setup->gpio_func[0]);
+ snd_soc_add_codec_controls(codec, aic32x4_mfp1,
+ ARRAY_SIZE(aic32x4_mfp1));
+ }
+
+ /* MFP2 */
+ if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_write(codec, AIC32X4_DOUTCTL,
+ aic32x4->setup->gpio_func[1]);
+ snd_soc_add_codec_controls(codec, aic32x4_mfp2,
+ ARRAY_SIZE(aic32x4_mfp2));
+ }
+
+ /* MFP3 */
+ if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_write(codec, AIC32X4_SCLKCTL,
+ aic32x4->setup->gpio_func[2]);
+ snd_soc_add_codec_controls(codec, aic32x4_mfp3,
+ ARRAY_SIZE(aic32x4_mfp3));
+ }
+
+ /* MFP4 */
+ if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_write(codec, AIC32X4_MISOCTL,
+ aic32x4->setup->gpio_func[3]);
+ snd_soc_add_codec_controls(codec, aic32x4_mfp4,
+ ARRAY_SIZE(aic32x4_mfp4));
+ }
+
+ /* MFP5 */
+ if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_write(codec, AIC32X4_GPIOCTL,
+ aic32x4->setup->gpio_func[4]);
+ snd_soc_add_codec_controls(codec, aic32x4_mfp5,
+ ARRAY_SIZE(aic32x4_mfp5));
+ }
+}
+
static int aic32x4_codec_probe(struct snd_soc_codec *codec)
{
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
@@ -746,6 +938,9 @@ static int aic32x4_codec_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, AIC32X4_RESET, 0x01);
+ if (aic32x4->setup)
+ aic32x4_setup_gpios(codec);
+
/* Power platform configuration */
if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
snd_soc_write(codec, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN |
@@ -792,7 +987,7 @@ static int aic32x4_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
+static const struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
.probe = aic32x4_codec_probe,
.set_bias_level = aic32x4_set_bias_level,
.suspend_bias_off = true,
@@ -810,10 +1005,20 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
struct device_node *np)
{
+ struct aic32x4_setup_data *aic32x4_setup;
+
+ aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
+ GFP_KERNEL);
+ if (!aic32x4_setup)
+ return -ENOMEM;
+
aic32x4->swapdacs = false;
aic32x4->micpga_routing = 0;
aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+ if (of_property_read_u32_array(np, "aic32x4-gpio-func",
+ aic32x4_setup->gpio_func, 5) >= 0)
+ aic32x4->setup = aic32x4_setup;
return 0;
}
@@ -932,6 +1137,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
if (aic32x4 == NULL)
return -ENOMEM;
+ aic32x4->dev = dev;
dev_set_drvdata(dev, aic32x4);
if (pdata) {
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index a197dd51addc..da7cec482bcb 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -44,8 +44,11 @@ int aic32x4_remove(struct device *dev);
#define AIC32X4_IFACE4 31
#define AIC32X4_IFACE5 32
#define AIC32X4_IFACE6 33
+#define AIC32X4_GPIOCTL 52
#define AIC32X4_DOUTCTL 53
#define AIC32X4_DINCTL 54
+#define AIC32X4_MISOCTL 55
+#define AIC32X4_SCLKCTL 56
#define AIC32X4_DACSPB 60
#define AIC32X4_ADCSPB 61
#define AIC32X4_DACSETUP 63
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 29bf8c81ae02..06f92571eba4 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -93,6 +93,8 @@ struct aic3x_priv {
/* Selects the micbias voltage */
enum aic3x_micbias_voltage micbias_vg;
+ /* Output Common-Mode Voltage */
+ u8 ocmv;
};
static const struct reg_default aic3x_reg[] = {
@@ -1572,6 +1574,10 @@ static int aic3x_init(struct snd_soc_codec *codec)
break;
}
+ /* Output common-mode voltage = 1.5 V */
+ snd_soc_update_bits(codec, HPOUT_SC, HPOUT_SC_OCMV_MASK,
+ aic3x->ocmv << HPOUT_SC_OCMV_SHIFT);
+
return 0;
}
@@ -1684,7 +1690,7 @@ static int aic3x_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
+static const struct snd_soc_codec_driver soc_codec_dev_aic3x = {
.set_bias_level = aic3x_set_bias_level,
.idle_bias_off = true,
.probe = aic3x_probe,
@@ -1699,6 +1705,43 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
},
};
+static void aic3x_configure_ocmv(struct i2c_client *client)
+{
+ struct device_node *np = client->dev.of_node;
+ struct aic3x_priv *aic3x = i2c_get_clientdata(client);
+ u32 value;
+ int dvdd, avdd;
+
+ if (np && !of_property_read_u32(np, "ai3x-ocmv", &value)) {
+ /* OCMV setting is forced by DT */
+ if (value <= 3) {
+ aic3x->ocmv = value;
+ return;
+ }
+ }
+
+ dvdd = regulator_get_voltage(aic3x->supplies[1].consumer);
+ avdd = regulator_get_voltage(aic3x->supplies[2].consumer);
+
+ if (avdd > 3600000 || dvdd > 1950000) {
+ dev_warn(&client->dev,
+ "Too high supply voltage(s) AVDD: %d, DVDD: %d\n",
+ avdd, dvdd);
+ } else if (avdd == 3600000 && dvdd == 1950000) {
+ aic3x->ocmv = HPOUT_SC_OCMV_1_8V;
+ } else if (avdd > 3300000 && dvdd > 1800000) {
+ aic3x->ocmv = HPOUT_SC_OCMV_1_65V;
+ } else if (avdd > 3000000 && dvdd > 1650000) {
+ aic3x->ocmv = HPOUT_SC_OCMV_1_5V;
+ } else if (avdd >= 2700000 && dvdd >= 1525000) {
+ aic3x->ocmv = HPOUT_SC_OCMV_1_35V;
+ } else {
+ dev_warn(&client->dev,
+ "Invalid supply voltage(s) AVDD: %d, DVDD: %d\n",
+ avdd, dvdd);
+ }
+}
+
/*
* AIC3X 2 wire address can be up to 4 devices with device addresses
* 0x18, 0x19, 0x1A, 0x1B
@@ -1816,6 +1859,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
goto err_gpio;
}
+ aic3x_configure_ocmv(i2c);
+
if (aic3x->model == AIC3X_MODEL_3007) {
ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
ARRAY_SIZE(aic3007_class_d));
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 89fa692df206..34c35196aa0d 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -243,6 +243,14 @@
#define MICBIAS_LEVEL_SHIFT (6)
#define MICBIAS_LEVEL_MASK (3 << 6)
+/* HPOUT_SC */
+#define HPOUT_SC_OCMV_MASK (3 << 6)
+#define HPOUT_SC_OCMV_SHIFT (6)
+#define HPOUT_SC_OCMV_1_35V 0
+#define HPOUT_SC_OCMV_1_5V 1
+#define HPOUT_SC_OCMV_1_65V 2
+#define HPOUT_SC_OCMV_1_8V 3
+
/* headset detection / button API */
/* The AIC3x supports detection of stereo headsets (GND + left + right signal)
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 7bcf01efdf9a..5b94a151539c 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1433,7 +1433,7 @@ static int dac33_soc_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
+static const struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
.read = dac33_read_reg_cache,
.write = dac33_write_locked,
.set_bias_level = dac33_set_bias_level,
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index a2104d68169d..d439c4c6fe50 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -2191,7 +2191,7 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
+static const struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
.probe = twl4030_soc_probe,
.remove = twl4030_soc_remove,
.read = twl4030_read,
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 2b6ad09e0886..1773ff84ee3b 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1123,8 +1123,8 @@ static int twl6040_probe(struct snd_soc_codec *codec)
priv->plug_irq = platform_get_irq(pdev, 0);
if (priv->plug_irq < 0) {
- dev_err(codec->dev, "invalid irq\n");
- return -EINVAL;
+ dev_err(codec->dev, "invalid irq: %d\n", priv->plug_irq);
+ return priv->plug_irq;
}
INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
@@ -1155,7 +1155,7 @@ static int twl6040_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
+static const struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
.probe = twl6040_probe,
.remove = twl6040_remove,
.read = twl6040_read,
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 5fdee874406d..77c9cc4467b8 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -518,7 +518,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
+static const struct snd_soc_codec_driver soc_codec_dev_uda134x = {
.probe = uda134x_soc_probe,
.set_bias_level = uda134x_set_bias_level,
.suspend_bias_off = true,
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 61cdc79840e7..926c81ae8185 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -720,7 +720,7 @@ static int uda1380_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
+static const struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
.probe = uda1380_probe,
.read = uda1380_read_reg_cache,
.write = uda1380_write,
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index fcffb6e707d9..942f1644973e 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -480,7 +480,7 @@ static int wl1273_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
.probe = wl1273_probe,
.remove = wl1273_remove,
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 1fe358e6be61..72486bf072f2 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -2017,7 +2017,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
},
};
-static struct snd_compr_ops wm5102_compr_ops = {
+static const struct snd_compr_ops wm5102_compr_ops = {
.open = wm5102_open,
.free = wm_adsp_compr_free,
.set_params = wm_adsp_compr_set_params,
@@ -2027,7 +2027,7 @@ static struct snd_compr_ops wm5102_compr_ops = {
.copy = wm_adsp_compr_copy,
};
-static struct snd_soc_platform_driver wm5102_compr_platform = {
+static const struct snd_soc_platform_driver wm5102_compr_platform = {
.compr_ops = &wm5102_compr_ops,
};
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 1bc942152eff..858a24fc28e8 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -2372,7 +2372,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
},
};
-static struct snd_compr_ops wm5110_compr_ops = {
+static const struct snd_compr_ops wm5110_compr_ops = {
.open = wm5110_open,
.free = wm_adsp_compr_free,
.set_params = wm_adsp_compr_set_params,
@@ -2382,7 +2382,7 @@ static struct snd_compr_ops wm5110_compr_ops = {
.copy = wm_adsp_compr_copy,
};
-static struct snd_soc_platform_driver wm5110_compr_platform = {
+static const struct snd_soc_platform_driver wm5110_compr_platform = {
.compr_ops = &wm5110_compr_ops,
};
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
index 032fb7cf6cbd..51fad48892d3 100644
--- a/sound/soc/codecs/zx_aud96p22.c
+++ b/sound/soc/codecs/zx_aud96p22.c
@@ -261,7 +261,7 @@ static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = {
{ "LINEOUTMN", NULL, "LD2" },
};
-static struct snd_soc_codec_driver aud96p22_driver = {
+static const struct snd_soc_codec_driver aud96p22_driver = {
.component_driver = {
.controls = aud96p22_snd_controls,
.num_controls = ARRAY_SIZE(aud96p22_snd_controls),
@@ -312,7 +312,7 @@ static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static struct snd_soc_dai_ops aud96p22_dai_ops = {
+static const struct snd_soc_dai_ops aud96p22_dai_ops = {
.set_fmt = aud96p22_set_fmt,
};
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 56ec1d301ac2..f395bbc7c354 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -1602,8 +1602,6 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
GFP_KERNEL);
if (!pdata) {
- dev_err(&pdev->dev,
- "Failed to allocate memory for pdata\n");
ret = -ENOMEM;
return pdata;
}
@@ -1853,6 +1851,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev,
sizeof(u32) * mcasp->num_serializer,
GFP_KERNEL);
+ if (!mcasp->context.xrsr_regs) {
+ ret = -ENOMEM;
+ goto err;
+ }
#endif
mcasp->serial_dir = pdata->serial_dir;
mcasp->version = pdata->version;
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index c77d9218795a..5415b72393fa 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -210,11 +210,8 @@ static int davinci_vcif_probe(struct platform_device *pdev)
davinci_vcif_dev = devm_kzalloc(&pdev->dev,
sizeof(struct davinci_vcif_dev),
GFP_KERNEL);
- if (!davinci_vcif_dev) {
- dev_dbg(&pdev->dev,
- "could not allocate memory for private data\n");
+ if (!davinci_vcif_dev)
return -ENOMEM;
- }
/* DMA tx params */
davinci_vcif_dev->davinci_vc = davinci_vc;
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 916067638180..e27e21f8569a 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -381,7 +381,7 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
return ret;
}
-static struct snd_soc_dai_ops dw_i2s_dai_ops = {
+static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
.startup = dw_i2s_startup,
.shutdown = dw_i2s_shutdown,
.hw_params = dw_i2s_hw_params,
@@ -617,10 +617,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
const char *clk_id;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- dev_warn(&pdev->dev, "kzalloc fail\n");
+ if (!dev)
return -ENOMEM;
- }
dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
if (!dw_i2s_dai)
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 9998aea23597..2db4d0c80d33 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -683,7 +683,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&priv->card, priv);
ret = devm_snd_soc_register_card(&pdev->dev, &priv->card);
- if (ret)
+ if (ret && ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
asrc_fail:
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 8cfffa70c144..806d39927318 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -542,7 +542,7 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static struct snd_soc_dai_ops fsl_asrc_dai_ops = {
+static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
.hw_params = fsl_asrc_dai_hw_params,
.hw_free = fsl_asrc_dai_hw_free,
.trigger = fsl_asrc_dai_trigger,
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index 282d841840b1..e1b97e59275a 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -20,7 +20,7 @@
#define FSL_ASRC_DMABUF_SIZE (256 * 1024)
-static struct snd_pcm_hardware snd_imx_hardware = {
+static const struct snd_pcm_hardware snd_imx_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
@@ -279,10 +279,8 @@ static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream)
struct fsl_asrc_pair *pair;
pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
- if (!pair) {
- dev_err(dev, "failed to allocate pair\n");
+ if (!pair)
return -ENOMEM;
- }
pair->asrc_priv = asrc_priv;
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index ccadefceeff2..0c11f434a374 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -63,7 +63,6 @@ struct dma_object {
struct ccsr_dma_channel __iomem *channel;
unsigned int irq;
bool assigned;
- char path[1];
};
/*
@@ -870,7 +869,7 @@ static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
return NULL;
}
-static struct snd_pcm_ops fsl_dma_ops = {
+static const struct snd_pcm_ops fsl_dma_ops = {
.open = fsl_dma_open,
.close = fsl_dma_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -897,20 +896,18 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
ret = of_address_to_resource(ssi_np, 0, &res);
if (ret) {
- dev_err(&pdev->dev, "could not determine resources for %s\n",
- ssi_np->full_name);
+ dev_err(&pdev->dev, "could not determine resources for %pOF\n",
+ ssi_np);
of_node_put(ssi_np);
return ret;
}
- dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL);
+ dma = kzalloc(sizeof(*dma), GFP_KERNEL);
if (!dma) {
- dev_err(&pdev->dev, "could not allocate dma object\n");
of_node_put(ssi_np);
return -ENOMEM;
}
- strcpy(dma->path, np->full_name);
dma->dai.ops = &fsl_dma_ops;
dma->dai.pcm_new = fsl_dma_new;
dma->dai.pcm_free = fsl_dma_free_dma_buffers;
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 809a069d490b..cef79a1a620b 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -620,7 +620,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static struct snd_soc_dai_ops fsl_esai_dai_ops = {
+static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
.startup = fsl_esai_startup,
.shutdown = fsl_esai_shutdown,
.trigger = fsl_esai_trigger,
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 1ff467c9598a..7e6cc4da0088 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -626,7 +626,7 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_soc_dai_ops fsl_spdif_dai_ops = {
+static const struct snd_soc_dai_ops fsl_spdif_dai_ops = {
.startup = fsl_spdif_startup,
.hw_params = fsl_spdif_hw_params,
.trigger = fsl_spdif_trigger,
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 173cb8496641..64598d1183f8 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1432,10 +1432,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private),
GFP_KERNEL);
- if (!ssi_private) {
- dev_err(&pdev->dev, "could not allocate DAI object\n");
+ if (!ssi_private)
return -ENOMEM;
- }
ssi_private->soc = of_id->data;
ssi_private->dev = &pdev->dev;
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index fc57da341d61..392d5eef356d 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -268,13 +268,13 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
ret = of_property_read_u32(child, "fsl,audmux-port", &port);
if (ret) {
- dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%s\"\n",
- child->full_name);
+ dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%pOF\"\n",
+ child);
continue;
}
if (!of_property_read_bool(child, "fsl,port-config")) {
- dev_warn(&pdev->dev, "child node \"%s\" does not have property fsl,port-config\n",
- child->full_name);
+ dev_warn(&pdev->dev, "child node \"%pOF\" does not have property fsl,port-config\n",
+ child);
continue;
}
@@ -292,15 +292,15 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
}
if (ret != -EOVERFLOW) {
- dev_err(&pdev->dev, "Failed to read u32 at index %d of child %s\n",
- i, child->full_name);
+ dev_err(&pdev->dev, "Failed to read u32 at index %d of child %pOF\n",
+ i, child);
continue;
}
if (audmux_type == IMX31_AUDMUX) {
if (i % 2) {
- dev_err(&pdev->dev, "One pdcr value is missing in child node %s\n",
- child->full_name);
+ dev_err(&pdev->dev, "One pdcr value is missing in child node %pOF\n",
+ child);
continue;
}
imx_audmux_v2_configure_port(port, ptcr, pdcr);
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
index 20e7400e2611..9953438086e4 100644
--- a/sound/soc/fsl/imx-es8328.c
+++ b/sound/soc/fsl/imx-es8328.c
@@ -203,9 +203,6 @@ static int imx_es8328_remove(struct platform_device *pdev)
{
struct imx_es8328_data *data = platform_get_drvdata(pdev);
- snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios),
- headset_jack_gpios);
-
snd_soc_unregister_card(&data->card);
return 0;
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 92410f7ca1fa..4e5fefee111e 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -154,7 +154,7 @@ static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream
return bytes_to_frames(substream->runtime, iprtd->offset);
}
-static struct snd_pcm_hardware snd_imx_hardware = {
+static const struct snd_pcm_hardware snd_imx_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
@@ -227,7 +227,7 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_pcm_ops imx_pcm_ops = {
+static const struct snd_pcm_ops imx_pcm_ops = {
.open = snd_imx_open,
.close = snd_imx_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -341,7 +341,7 @@ static void imx_pcm_fiq_free(struct snd_pcm *pcm)
imx_pcm_free(pcm);
}
-static struct snd_soc_platform_driver imx_soc_platform_fiq = {
+static const struct snd_soc_platform_driver imx_soc_platform_fiq = {
.ops = &imx_pcm_ops,
.pcm_new = imx_pcm_fiq_new,
.pcm_free = imx_pcm_fiq_free,
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index b95132e2f9dc..06790615e04e 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -527,6 +527,10 @@ static int imx_ssi_probe(struct platform_device *pdev)
}
ssi->irq = platform_get_irq(pdev, 0);
+ if (ssi->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get IRQ: %d\n", ssi->irq);
+ return ssi->irq;
+ }
ssi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ssi->clk)) {
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 1f7e70bfbd55..e63029f1aabc 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -287,7 +287,7 @@ psc_dma_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_pcm_ops psc_dma_ops = {
+static const struct snd_pcm_ops psc_dma_ops = {
.open = psc_dma_open,
.close = psc_dma_close,
.hw_free = psc_dma_hw_free,
@@ -356,7 +356,7 @@ static void psc_dma_free(struct snd_pcm *pcm)
}
}
-static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
+static const struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
.ops = &psc_dma_ops,
.pcm_new = &psc_dma_new,
.pcm_free = &psc_dma_free,
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 105ec3a6e30d..488c52f9405f 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -95,7 +95,7 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
asoc_simple_card_clk_disable(&dai_props->codec_dai);
}
-static struct snd_soc_ops asoc_graph_card_ops = {
+static const struct snd_soc_ops asoc_graph_card_ops = {
.startup = asoc_graph_card_startup,
.shutdown = asoc_graph_card_shutdown,
};
@@ -224,9 +224,11 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
ret = asoc_graph_card_dai_link_of(it.node, priv, idx++);
- of_node_put(it.node);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(it.node);
+
return ret;
+ }
}
return asoc_simple_card_parse_card_name(card, NULL);
@@ -239,10 +241,8 @@ static int asoc_graph_get_dais_count(struct device *dev)
int count = 0;
int rc;
- of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
+ of_for_each_phandle(&it, rc, node, "dais", NULL, 0)
count++;
- of_node_put(it.node);
- }
return count;
}
@@ -325,6 +325,7 @@ MODULE_DEVICE_TABLE(of, asoc_graph_of_match);
static struct platform_driver asoc_graph_card = {
.driver = {
.name = "asoc-audio-graph-card",
+ .pm = &snd_soc_pm_ops,
.of_match_table = asoc_graph_of_match,
},
.probe = asoc_graph_card_probe,
diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c
index dcd2df37bc3b..a967aa143d51 100644
--- a/sound/soc/generic/audio-graph-scu-card.c
+++ b/sound/soc/generic/audio-graph-scu-card.c
@@ -56,7 +56,7 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
asoc_simple_card_clk_disable(dai_props);
}
-static struct snd_soc_ops asoc_graph_card_ops = {
+static const struct snd_soc_ops asoc_graph_card_ops = {
.startup = asoc_graph_card_startup,
.shutdown = asoc_graph_card_shutdown,
};
@@ -215,7 +215,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
- of_node_put(cpu_port);
of_node_put(cpu_ep);
of_node_put(codec_ep);
of_node_put(rcpu_ep);
@@ -232,8 +231,10 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &daifmt);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(cpu_port);
goto parse_of_err;
+ }
}
dai_idx = 0;
@@ -250,7 +251,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
codec_port = of_graph_get_port_parent(codec_ep);
- of_node_put(cpu_port);
of_node_put(cpu_ep);
of_node_put(codec_ep);
of_node_put(codec_port);
@@ -266,13 +266,17 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
/* Back-End (= Codec) */
ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(cpu_port);
goto parse_of_err;
+ }
} else {
/* Front-End (= CPU) */
ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(cpu_port);
goto parse_of_err;
+ }
}
}
}
@@ -306,7 +310,6 @@ static int asoc_graph_get_dais_count(struct device *dev)
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
codec_port = of_graph_get_port_parent(codec_ep);
- of_node_put(cpu_port);
of_node_put(cpu_ep);
of_node_put(codec_ep);
of_node_put(codec_port);
@@ -398,6 +401,7 @@ MODULE_DEVICE_TABLE(of, asoc_graph_of_match);
static struct platform_driver asoc_graph_card = {
.driver = {
.name = "asoc-audio-graph-scu-card",
+ .pm = &snd_soc_pm_ops,
.of_match_table = asoc_graph_of_match,
},
.probe = asoc_graph_card_probe,
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 26d64fa40c9c..3751a07de6aa 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -132,7 +132,7 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
/* Parse the card name from DT */
ret = snd_soc_of_parse_card_name(card, "label");
- if (ret < 0) {
+ if (ret < 0 || !card->name) {
char prop[128];
snprintf(prop, sizeof(prop), "%sname", prefix);
@@ -196,7 +196,11 @@ int asoc_simple_card_parse_clk(struct device *dev,
simple_dai->sysclk = clk_get_rate(clk);
}
- dev_dbg(dev, "%s : sysclk = %d\n", name, simple_dai->sysclk);
+ if (of_property_read_bool(node, "system-clock-direction-out"))
+ simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
+
+ dev_dbg(dev, "%s : sysclk = %d, direction %d\n", name,
+ simple_dai->sysclk, simple_dai->clk_direction);
return 0;
}
@@ -263,6 +267,9 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep)
id = i;
i++;
}
+
+ of_node_put(node);
+
if (id < 0)
return -ENODEV;
@@ -282,11 +289,6 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep,
if (!dai_name)
return 0;
- /*
- * of_graph_get_port_parent() will call
- * of_node_put(). So, call of_node_get() here
- */
- of_node_get(ep);
node = of_graph_get_port_parent(ep);
/* Get dai->name */
@@ -310,7 +312,8 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
int ret;
if (simple_dai->sysclk) {
- ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, 0);
+ ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
+ simple_dai->clk_direction);
if (ret && ret != -ENOTSUPP) {
dev_err(dai->dev, "simple-card: set_sysclk error\n");
return ret;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index dfaf48ff88b0..6959a74a6f49 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -104,12 +104,6 @@ static int asoc_simple_card_init_jack(struct snd_soc_card *card,
return 0;
}
-static void asoc_simple_card_remove_jack(struct asoc_simple_jack *sjack)
-{
- if (gpio_is_valid(sjack->gpio.gpio))
- snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio);
-}
-
static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -493,10 +487,6 @@ err:
static int asoc_simple_card_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
-
- asoc_simple_card_remove_jack(&priv->hp_jack);
- asoc_simple_card_remove_jack(&priv->mic_jack);
return asoc_simple_card_clean_reference(card);
}
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
index a75b385455c4..48606c63562a 100644
--- a/sound/soc/generic/simple-scu-card.c
+++ b/sound/soc/generic/simple-scu-card.c
@@ -191,6 +191,10 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
if (!node)
return -EINVAL;
+ ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
+ if (ret < 0)
+ return ret;
+
ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
if (ret < 0)
return ret;
@@ -296,6 +300,7 @@ MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
static struct platform_driver asoc_simple_card = {
.driver = {
.name = "simple-scu-audio-card",
+ .pm = &snd_soc_pm_ops,
.of_match_table = asoc_simple_of_match,
},
.probe = asoc_simple_card_probe,
diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c
index b193d3beb253..0c8f86d4020e 100644
--- a/sound/soc/hisilicon/hi6210-i2s.c
+++ b/sound/soc/hisilicon/hi6210-i2s.c
@@ -517,7 +517,7 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)
}
-static struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
+static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
.trigger = hi6210_i2s_trigger,
.hw_params = hi6210_i2s_hw_params,
.set_fmt = hi6210_i2s_set_fmt,
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
index 0389203f8560..567f9767fb73 100644
--- a/sound/soc/img/img-i2s-in.c
+++ b/sound/soc/img/img-i2s-in.c
@@ -443,7 +443,7 @@ static int img_i2s_in_probe(struct platform_device *pdev)
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE;
i2s->dai_driver.ops = &img_i2s_in_dai_ops;
- rst = devm_reset_control_get(dev, "rst");
+ rst = devm_reset_control_get_exclusive(dev, "rst");
if (IS_ERR(rst)) {
if (PTR_ERR(rst) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index 5f997135a8ae..78b7f6cd675b 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -446,7 +446,7 @@ static int img_i2s_out_probe(struct platform_device *pdev)
i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
- i2s->rst = devm_reset_control_get(&pdev->dev, "rst");
+ i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
if (IS_ERR(i2s->rst)) {
if (PTR_ERR(i2s->rst) != -EPROBE_DEFER)
dev_err(&pdev->dev, "No top level reset found\n");
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
index 33ceb207ee70..23b0f0f6ec9c 100644
--- a/sound/soc/img/img-parallel-out.c
+++ b/sound/soc/img/img-parallel-out.c
@@ -224,7 +224,7 @@ static int img_prl_out_probe(struct platform_device *pdev)
prl->base = base;
- prl->rst = devm_reset_control_get(&pdev->dev, "rst");
+ prl->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
if (IS_ERR(prl->rst)) {
if (PTR_ERR(prl->rst) != -EPROBE_DEFER)
dev_err(&pdev->dev, "No top level reset found\n");
diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c
index 4d9953d318af..8adfd65d4390 100644
--- a/sound/soc/img/img-spdif-in.c
+++ b/sound/soc/img/img-spdif-in.c
@@ -727,7 +727,7 @@ static int img_spdif_in_probe(struct platform_device *pdev)
if (ret)
return ret;
- rst = devm_reset_control_get(&pdev->dev, "rst");
+ rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
if (IS_ERR(rst)) {
if (PTR_ERR(rst) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c
index 08f93a5dadfe..383655da2e60 100644
--- a/sound/soc/img/img-spdif-out.c
+++ b/sound/soc/img/img-spdif-out.c
@@ -334,7 +334,7 @@ static int img_spdif_out_probe(struct platform_device *pdev)
spdif->base = base;
- spdif->rst = devm_reset_control_get(&pdev->dev, "rst");
+ spdif->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
if (IS_ERR(spdif->rst)) {
if (PTR_ERR(spdif->rst) != -EPROBE_DEFER)
dev_err(&pdev->dev, "No top level reset found\n");
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index b301bfff1c09..b3c7f554ec30 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -255,11 +255,12 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
- depends on X86_INTEL_LPSS && I2C
+ depends on X86_INTEL_LPSS && I2C && SPI
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT5663
select SND_SOC_RT5514
+ select SND_SOC_RT5514_SPI
select SND_SOC_MAX98927
select SND_SOC_HDAC_HDMI
help
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index b082b31023d5..43e7fdd19f29 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -76,7 +76,7 @@ int sst_unregister_dsp(struct sst_device *dev)
}
EXPORT_SYMBOL_GPL(sst_unregister_dsp);
-static struct snd_pcm_hardware sst_platform_pcm_hw = {
+static const struct snd_pcm_hardware sst_platform_pcm_hw = {
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_DOUBLE |
SNDRV_PCM_INFO_PAUSE |
@@ -471,7 +471,7 @@ static void sst_disable_ssp(struct snd_pcm_substream *substream,
}
}
-static struct snd_soc_dai_ops sst_media_dai_ops = {
+static const struct snd_soc_dai_ops sst_media_dai_ops = {
.startup = sst_media_open,
.shutdown = sst_media_close,
.prepare = sst_media_prepare,
@@ -480,11 +480,11 @@ static struct snd_soc_dai_ops sst_media_dai_ops = {
.mute_stream = sst_media_digital_mute,
};
-static struct snd_soc_dai_ops sst_compr_dai_ops = {
+static const struct snd_soc_dai_ops sst_compr_dai_ops = {
.mute_stream = sst_media_digital_mute,
};
-static struct snd_soc_dai_ops sst_be_dai_ops = {
+static const struct snd_soc_dai_ops sst_be_dai_ops = {
.startup = sst_enable_ssp,
.hw_params = sst_be_hw_params,
.set_fmt = sst_set_format,
@@ -705,7 +705,7 @@ static int sst_soc_probe(struct snd_soc_platform *platform)
return sst_dsp_init_v2_dpcm(platform);
}
-static struct snd_soc_platform_driver sst_soc_platform_drv = {
+static const struct snd_soc_platform_driver sst_soc_platform_drv = {
.probe = sst_soc_probe,
.ops = &sst_platform_ops,
.compr_ops = &sst_platform_compr_ops,
diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c
index ce689c5af5ab..71af5449be90 100644
--- a/sound/soc/intel/atom/sst/sst_drv_interface.c
+++ b/sound/soc/intel/atom/sst/sst_drv_interface.c
@@ -407,7 +407,7 @@ static int sst_cdev_caps(struct snd_compr_caps *caps)
return 0;
}
-static struct snd_compr_codec_caps caps_mp3 = {
+static const struct snd_compr_codec_caps caps_mp3 = {
.num_descriptors = 1,
.descriptor[0].max_ch = 2,
.descriptor[0].sample_rates[0] = 48000,
@@ -424,7 +424,7 @@ static struct snd_compr_codec_caps caps_mp3 = {
.descriptor[0].formats = 0,
};
-static struct snd_compr_codec_caps caps_aac = {
+static const struct snd_compr_codec_caps caps_aac = {
.num_descriptors = 2,
.descriptor[1].max_ch = 2,
.descriptor[0].sample_rates[0] = 48000,
diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c
index 3a0b3bf0af97..6906ee624cf6 100644
--- a/sound/soc/intel/atom/sst/sst_pci.c
+++ b/sound/soc/intel/atom/sst/sst_pci.c
@@ -181,7 +181,7 @@ static void intel_sst_remove(struct pci_dev *pci)
}
/* PCI Routines */
-static struct pci_device_id intel_sst_ids[] = {
+static const struct pci_device_id intel_sst_ids[] = {
{ PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
{ 0, }
};
diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
index 4765ad474544..c54529320f07 100644
--- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c
+++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
@@ -309,7 +309,7 @@ static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
return snd_pcm_lib_default_mmap(substream, vma);
}
-static struct snd_pcm_ops sst_byt_pcm_ops = {
+static const struct snd_pcm_ops sst_byt_pcm_ops = {
.open = sst_byt_pcm_open,
.close = sst_byt_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -395,7 +395,7 @@ static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
return 0;
}
-static struct snd_soc_platform_driver byt_soc_platform = {
+static const struct snd_soc_platform_driver byt_soc_platform = {
.probe = sst_byt_pcm_probe,
.remove = sst_byt_pcm_remove,
.ops = &sst_byt_pcm_ops,
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index 0c3a3cbcb884..7843104fadcb 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -114,7 +114,44 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
{ "iDisp2 Tx", NULL, "iDisp2_out"},
{ "hifi1", NULL, "iDisp1 Tx"},
{ "iDisp1 Tx", NULL, "iDisp1_out"},
+};
+
+static const struct snd_soc_dapm_route geminilake_rt298_map[] = {
+ /* speaker */
+ {"Speaker", NULL, "SPOR"},
+ {"Speaker", NULL, "SPOL"},
+
+ /* HP jack connectors - unknown if we have jack detect */
+ {"Headphone Jack", NULL, "HPO Pin"},
+
+ /* other jacks */
+ {"MIC1", NULL, "Mic Jack"},
+
+ /* digital mics */
+ {"DMIC1 Pin", NULL, "DMIC2"},
+ {"DMic", NULL, "SoC DMIC"},
+
+ {"HDMI1", NULL, "hif5-0 Output"},
+ {"HDMI2", NULL, "hif6-0 Output"},
+ {"HDMI2", NULL, "hif7-0 Output"},
+
+ /* CODEC BE connections */
+ { "AIF1 Playback", NULL, "ssp2 Tx"},
+ { "ssp2 Tx", NULL, "codec0_out"},
+ { "ssp2 Tx", NULL, "codec1_out"},
+
+ { "codec0_in", NULL, "ssp2 Rx" },
+ { "ssp2 Rx", NULL, "AIF1 Capture" },
+ { "dmic01_hifi", NULL, "DMIC01 Rx" },
+ { "DMIC01 Rx", NULL, "Capture" },
+
+ { "hifi3", NULL, "iDisp3 Tx"},
+ { "iDisp3 Tx", NULL, "iDisp3_out"},
+ { "hifi2", NULL, "iDisp2 Tx"},
+ { "iDisp2 Tx", NULL, "iDisp2_out"},
+ { "hifi1", NULL, "iDisp1 Tx"},
+ { "iDisp1 Tx", NULL, "iDisp1_out"},
};
static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd)
@@ -492,7 +529,6 @@ static int bxt_card_late_probe(struct snd_soc_card *card)
/* broxton audio machine driver for SPT + RT298S */
static struct snd_soc_card broxton_rt298 = {
.name = "broxton-rt298",
- .owner = THIS_MODULE,
.dai_link = broxton_rt298_dais,
.num_links = ARRAY_SIZE(broxton_rt298_dais),
.controls = broxton_controls,
@@ -506,9 +542,41 @@ static struct snd_soc_card broxton_rt298 = {
};
+static struct snd_soc_card geminilake_rt298 = {
+ .name = "geminilake-rt298",
+ .dai_link = broxton_rt298_dais,
+ .num_links = ARRAY_SIZE(broxton_rt298_dais),
+ .controls = broxton_controls,
+ .num_controls = ARRAY_SIZE(broxton_controls),
+ .dapm_widgets = broxton_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
+ .dapm_routes = geminilake_rt298_map,
+ .num_dapm_routes = ARRAY_SIZE(geminilake_rt298_map),
+ .fully_routed = true,
+ .late_probe = bxt_card_late_probe,
+};
+
static int broxton_audio_probe(struct platform_device *pdev)
{
struct bxt_rt286_private *ctx;
+ struct snd_soc_card *card =
+ (struct snd_soc_card *)pdev->id_entry->driver_data;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) {
+ if (!strncmp(card->dai_link[i].codec_name, "i2c-INT343A:00",
+ I2C_NAME_SIZE)) {
+ if (!strncmp(card->name, "broxton-rt298",
+ PLATFORM_NAME_SIZE)) {
+ card->dai_link[i].name = "SSP5-Codec";
+ card->dai_link[i].cpu_dai_name = "SSP5 Pin";
+ } else if (!strncmp(card->name, "geminilake-rt298",
+ PLATFORM_NAME_SIZE)) {
+ card->dai_link[i].name = "SSP2-Codec";
+ card->dai_link[i].cpu_dai_name = "SSP2 Pin";
+ }
+ }
+ }
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx)
@@ -516,18 +584,27 @@ static int broxton_audio_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
- broxton_rt298.dev = &pdev->dev;
- snd_soc_card_set_drvdata(&broxton_rt298, ctx);
+ card->dev = &pdev->dev;
+ snd_soc_card_set_drvdata(card, ctx);
- return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
+ return devm_snd_soc_register_card(&pdev->dev, card);
}
+static const struct platform_device_id bxt_board_ids[] = {
+ { .name = "bxt_alc298s_i2s", .driver_data =
+ (unsigned long)&broxton_rt298 },
+ { .name = "glk_alc298s_i2s", .driver_data =
+ (unsigned long)&geminilake_rt298 },
+ {}
+};
+
static struct platform_driver broxton_audio = {
.probe = broxton_audio_probe,
.driver = {
.name = "bxt_alc298s_i2s",
.pm = &snd_soc_pm_ops,
},
+ .id_table = bxt_board_ids,
};
module_platform_driver(broxton_audio)
@@ -537,3 +614,4 @@ MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
MODULE_DESCRIPTION("Intel SST Audio for Broxton");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:bxt_alc298s_i2s");
+MODULE_ALIAS("platform:glk_alc298s_i2s");
diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c
index 047be7fa0ce9..0f8b8209c020 100644
--- a/sound/soc/intel/boards/byt-max98090.c
+++ b/sound/soc/intel/boards/byt-max98090.c
@@ -173,20 +173,8 @@ static int byt_max98090_probe(struct platform_device *pdev)
return 0;
}
-static int byt_max98090_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct byt_max98090_private *priv = snd_soc_card_get_drvdata(card);
-
- snd_soc_jack_free_gpios(&priv->jack, ARRAY_SIZE(hs_jack_gpios),
- hs_jack_gpios);
-
- return 0;
-}
-
static struct platform_driver byt_max98090_driver = {
.probe = byt_max98090_probe,
- .remove = byt_max98090_remove,
.driver = {
.name = "byt-max98090",
.pm = &snd_soc_pm_ops,
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index bc2a52de06a3..f597d5582223 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -184,6 +184,13 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static const struct acpi_gpio_params headset_gpios = { 0, 0, false };
+
+static const struct acpi_gpio_mapping cht_rt5672_gpios[] = {
+ { "headset-gpios", &headset_gpios, 1 },
+ {},
+};
+
static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
@@ -191,6 +198,9 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
struct snd_soc_codec *codec = codec_dai->codec;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
+ if (devm_acpi_dev_add_driver_gpios(codec->dev, cht_rt5672_gpios))
+ dev_warn(runtime->dev, "Unable to add GPIO mapping table\n");
+
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
if (ret < 0) {
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index f9ba97788157..7f7607420706 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -34,7 +34,7 @@
#define MAXIM_DEV0_NAME "i2c-MX98927:00"
#define MAXIM_DEV1_NAME "i2c-MX98927:01"
-static struct snd_soc_card kabylake_audio_card;
+static struct snd_soc_card *kabylake_audio_card;
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
static struct snd_soc_jack skylake_hdmi[3];
@@ -52,6 +52,8 @@ struct kbl_rt5663_private {
enum {
KBL_DPCM_AUDIO_PB = 0,
KBL_DPCM_AUDIO_CP,
+ KBL_DPCM_AUDIO_HS_PB,
+ KBL_DPCM_AUDIO_ECHO_REF_CP,
KBL_DPCM_AUDIO_REF_CP,
KBL_DPCM_AUDIO_DMIC_CP,
KBL_DPCM_AUDIO_HDMI1_PB,
@@ -72,8 +74,9 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("DP", NULL),
- SND_SOC_DAPM_SPK("HDMI", NULL),
+ SND_SOC_DAPM_SPK("HDMI1", NULL),
+ SND_SOC_DAPM_SPK("HDMI2", NULL),
+ SND_SOC_DAPM_SPK("HDMI3", NULL),
};
@@ -91,20 +94,22 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "IN1N", NULL, "Headset Mic" },
{ "DMic", NULL, "SoC DMIC" },
- { "HDMI", NULL, "hif5 Output" },
- { "DP", NULL, "hif6 Output" },
-
/* CODEC BE connections */
{ "Left HiFi Playback", NULL, "ssp0 Tx" },
{ "Right HiFi Playback", NULL, "ssp0 Tx" },
- { "ssp0 Tx", NULL, "codec0_out" },
+ { "ssp0 Tx", NULL, "spk_out" },
{ "AIF Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "codec1_out" },
+ { "ssp1 Tx", NULL, "hs_out" },
- { "codec0_in", NULL, "ssp1 Rx" },
+ { "hs_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" },
+ /* IV feedback path */
+ { "codec0_fb_in", NULL, "ssp0 Rx"},
+ { "ssp0 Rx", NULL, "Left HiFi Capture" },
+ { "ssp0 Rx", NULL, "Right HiFi Capture" },
+
/* DMIC */
{ "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "DMIC AIF" },
@@ -117,6 +122,49 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "iDisp1 Tx", NULL, "iDisp1_out"},
};
+enum {
+ KBL_DPCM_AUDIO_5663_PB = 0,
+ KBL_DPCM_AUDIO_5663_CP,
+ KBL_DPCM_AUDIO_5663_HDMI1_PB,
+ KBL_DPCM_AUDIO_5663_HDMI2_PB,
+};
+
+static const struct snd_kcontrol_new kabylake_5663_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SPK("DP", NULL),
+ SND_SOC_DAPM_SPK("HDMI", NULL),
+};
+
+static const struct snd_soc_dapm_route kabylake_5663_map[] = {
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+
+ /* other jacks */
+ { "IN1P", NULL, "Headset Mic" },
+ { "IN1N", NULL, "Headset Mic" },
+
+ { "HDMI", NULL, "hif5 Output" },
+ { "DP", NULL, "hif6 Output" },
+
+ /* CODEC BE connections */
+ { "AIF Playback", NULL, "ssp1 Tx" },
+ { "ssp1 Tx", NULL, "codec1_out" },
+
+ { "codec0_in", NULL, "ssp1 Rx" },
+ { "ssp1 Rx", NULL, "AIF Capture" },
+
+ { "hifi2", NULL, "iDisp2 Tx"},
+ { "iDisp2 Tx", NULL, "iDisp2_out"},
+ { "hifi1", NULL, "iDisp1 Tx"},
+ { "iDisp1 Tx", NULL, "iDisp1_out"},
+};
+
static struct snd_soc_codec_conf max98927_codec_conf[] = {
{
.dev_name = MAXIM_DEV0_NAME,
@@ -165,7 +213,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack",
+ ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset,
NULL, 0);
@@ -173,8 +221,18 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
}
-
rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
+ return ret;
+}
+
+static int kabylake_rt5663_max98927_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+
+ ret = kabylake_rt5663_codec_init(rtd);
+ if (ret)
+ return ret;
+
ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
if (ret) {
dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret);
@@ -184,7 +242,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
{
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai;
@@ -194,7 +252,7 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
if (!pcm)
return -ENOMEM;
- pcm->device = KBL_DPCM_AUDIO_HDMI1_PB;
+ pcm->device = device;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
@@ -202,47 +260,36 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
{
- struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = rtd->codec_dai;
- struct kbl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = KBL_DPCM_AUDIO_HDMI2_PB;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
+}
- return 0;
+static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
}
static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
{
- struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = rtd->codec_dai;
- struct kbl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = KBL_DPCM_AUDIO_HDMI3_PB;
- pcm->codec_dai = dai;
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
+}
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+static int kabylake_5663_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI1_PB);
+}
- return 0;
+static int kabylake_5663_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI2_PB);
}
static unsigned int rates[] = {
48000,
};
-static struct snd_pcm_hw_constraint_list constraints_rates = {
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
@@ -252,7 +299,7 @@ static unsigned int channels[] = {
2,
};
-static struct snd_pcm_hw_constraint_list constraints_channels = {
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
.count = ARRAY_SIZE(channels),
.list = channels,
.mask = 0,
@@ -312,11 +359,13 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
- ret = snd_soc_dai_set_sysclk(codec_dai,
- RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
/* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
- rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1);
+ rt5663_sel_asrc_clk_src(codec_dai->codec,
+ RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+ RT5663_CLK_SEL_I2S1_ASRC);
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
if (ret < 0)
dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
@@ -381,7 +430,7 @@ static unsigned int rates_16000[] = {
16000,
};
-static struct snd_pcm_hw_constraint_list constraints_16000 = {
+static const struct snd_pcm_hw_constraint_list constraints_16000 = {
.count = ARRAY_SIZE(rates_16000),
.list = rates_16000,
};
@@ -443,6 +492,28 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.ops = &kabylake_rt5663_fe_ops,
},
+ [KBL_DPCM_AUDIO_HS_PB] = {
+ .name = "Kbl Audio Headset Playback",
+ .stream_name = "Headset Audio",
+ .cpu_dai_name = "System Pin2",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
+ .name = "Kbl Audio Echo Reference cap",
+ .stream_name = "Echoreference Capture",
+ .cpu_dai_name = "Echoref Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .init = NULL,
+ .capture_only = 1,
+ .nonatomic = 1,
+ },
[KBL_DPCM_AUDIO_REF_CP] = {
.name = "Kbl Audio Reference cap",
.stream_name = "Wake on Voice",
@@ -538,7 +609,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.no_pcm = 1,
.codec_name = "i2c-10EC5663:00",
.codec_dai_name = KBL_REALTEK_CODEC_DAI,
- .init = kabylake_rt5663_codec_init,
+ .init = kabylake_rt5663_max98927_codec_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1,
@@ -594,15 +665,119 @@ static struct snd_soc_dai_link kabylake_dais[] = {
},
};
+static struct snd_soc_dai_link kabylake_5663_dais[] = {
+ /* Front End DAI links */
+ [KBL_DPCM_AUDIO_5663_PB] = {
+ .name = "Kbl Audio Port",
+ .stream_name = "Audio",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:1f.3",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .nonatomic = 1,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .ops = &kabylake_rt5663_fe_ops,
+ },
+ [KBL_DPCM_AUDIO_5663_CP] = {
+ .name = "Kbl Audio Capture Port",
+ .stream_name = "Audio Record",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:1f.3",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .nonatomic = 1,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_capture = 1,
+ .ops = &kabylake_rt5663_fe_ops,
+ },
+ [KBL_DPCM_AUDIO_5663_HDMI1_PB] = {
+ .name = "Kbl HDMI Port1",
+ .stream_name = "Hdmi1",
+ .cpu_dai_name = "HDMI1 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [KBL_DPCM_AUDIO_5663_HDMI2_PB] = {
+ .name = "Kbl HDMI Port2",
+ .stream_name = "Hdmi2",
+ .cpu_dai_name = "HDMI2 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+
+ /* Back End DAI links */
+ {
+ /* SSP1 - Codec */
+ .name = "SSP1-Codec",
+ .id = 0,
+ .cpu_dai_name = "SSP1 Pin",
+ .platform_name = "0000:00:1f.3",
+ .no_pcm = 1,
+ .codec_name = "i2c-10EC5663:00",
+ .codec_dai_name = KBL_REALTEK_CODEC_DAI,
+ .init = kabylake_rt5663_codec_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = kabylake_ssp_fixup,
+ .ops = &kabylake_rt5663_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ },
+ {
+ .name = "iDisp1",
+ .id = 1,
+ .cpu_dai_name = "iDisp1 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi1",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = kabylake_5663_hdmi1_init,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp2",
+ .id = 2,
+ .cpu_dai_name = "iDisp2 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi2",
+ .platform_name = "0000:00:1f.3",
+ .init = kabylake_5663_hdmi2_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+};
+
#define NAME_SIZE 32
static int kabylake_card_late_probe(struct snd_soc_card *card)
{
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
struct kbl_hdmi_pcm *pcm;
+ struct snd_soc_codec *codec = NULL;
int err, i = 0;
char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+ codec = pcm->codec_dai->codec;
snprintf(jack_name, sizeof(jack_name),
"HDMI/DP, pcm=%d Jack", pcm->device);
err = snd_soc_card_jack_new(card, jack_name,
@@ -620,11 +795,14 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
i++;
}
- return 0;
+ if (!codec)
+ return -EINVAL;
+
+ return hdac_hdmi_jack_port_init(codec, &card->dapm);
}
/* kabylake audio machine driver for SPT + RT5663 */
-static struct snd_soc_card kabylake_audio_card = {
+static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = {
.name = "kblrt5663max",
.owner = THIS_MODULE,
.dai_link = kabylake_dais,
@@ -641,6 +819,22 @@ static struct snd_soc_card kabylake_audio_card = {
.late_probe = kabylake_card_late_probe,
};
+/* kabylake audio machine driver for RT5663 */
+static struct snd_soc_card kabylake_audio_card_rt5663 = {
+ .name = "kblrt5663",
+ .owner = THIS_MODULE,
+ .dai_link = kabylake_5663_dais,
+ .num_links = ARRAY_SIZE(kabylake_5663_dais),
+ .controls = kabylake_5663_controls,
+ .num_controls = ARRAY_SIZE(kabylake_5663_controls),
+ .dapm_widgets = kabylake_5663_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(kabylake_5663_widgets),
+ .dapm_routes = kabylake_5663_map,
+ .num_dapm_routes = ARRAY_SIZE(kabylake_5663_map),
+ .fully_routed = true,
+ .late_probe = kabylake_card_late_probe,
+};
+
static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_rt5663_private *ctx;
@@ -652,19 +846,30 @@ static int kabylake_audio_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
- kabylake_audio_card.dev = &pdev->dev;
- snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
+ kabylake_audio_card =
+ (struct snd_soc_card *)pdev->id_entry->driver_data;
+
+ kabylake_audio_card->dev = &pdev->dev;
+ snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
pdata = dev_get_drvdata(&pdev->dev);
if (pdata)
dmic_constraints = pdata->dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
- return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
+ return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
}
static const struct platform_device_id kbl_board_ids[] = {
- { .name = "kbl_rt5663_m98927" },
+ {
+ .name = "kbl_rt5663",
+ .driver_data = (kernel_ulong_t)&kabylake_audio_card_rt5663,
+ },
+ {
+ .name = "kbl_rt5663_m98927",
+ .driver_data =
+ (kernel_ulong_t)&kabylake_audio_card_rt5663_m98927,
+ },
{ }
};
@@ -684,4 +889,5 @@ MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode");
MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_rt5663");
MODULE_ALIAS("platform:kbl_rt5663_m98927");
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 3fe4a0807095..88ff54220007 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -18,6 +18,7 @@
* GNU General Public License for more details.
*/
+#include <linux/input.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
@@ -62,7 +63,10 @@ struct kbl_codec_private {
enum {
KBL_DPCM_AUDIO_PB = 0,
KBL_DPCM_AUDIO_CP,
+ KBL_DPCM_AUDIO_HS_PB,
+ KBL_DPCM_AUDIO_ECHO_REF_CP,
KBL_DPCM_AUDIO_DMIC_CP,
+ KBL_DPCM_AUDIO_RT5514_DSP,
KBL_DPCM_AUDIO_HDMI1_PB,
KBL_DPCM_AUDIO_HDMI2_PB,
};
@@ -81,8 +85,8 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
SND_SOC_DAPM_MIC("DMIC", NULL),
- SND_SOC_DAPM_SPK("DP", NULL),
- SND_SOC_DAPM_SPK("HDMI", NULL),
+ SND_SOC_DAPM_SPK("HDMI1", NULL),
+ SND_SOC_DAPM_SPK("HDMI2", NULL),
};
@@ -99,23 +103,25 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "IN1P", NULL, "Headset Mic" },
{ "IN1N", NULL, "Headset Mic" },
- { "HDMI", NULL, "hif5 Output" },
- { "DP", NULL, "hif6 Output" },
-
/* CODEC BE connections */
{ "Left HiFi Playback", NULL, "ssp0 Tx" },
{ "Right HiFi Playback", NULL, "ssp0 Tx" },
- { "ssp0 Tx", NULL, "codec0_out" },
+ { "ssp0 Tx", NULL, "spk_out" },
{ "AIF Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "codec1_out" },
+ { "ssp1 Tx", NULL, "hs_out" },
- { "codec0_in", NULL, "ssp1 Rx" },
+ { "hs_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" },
{ "codec1_in", NULL, "ssp0 Rx" },
{ "ssp0 Rx", NULL, "AIF1 Capture" },
+ /* IV feedback path */
+ { "codec0_fb_in", NULL, "ssp0 Rx"},
+ { "ssp0 Rx", NULL, "Left HiFi Capture" },
+ { "ssp0 Rx", NULL, "Right HiFi Capture" },
+
/* DMIC */
{ "DMIC1L", NULL, "DMIC" },
{ "DMIC1R", NULL, "DMIC" },
@@ -173,6 +179,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
int ret;
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_jack *jack;
/*
* Headset buttons map to the google Reference headset.
@@ -187,6 +194,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
+ jack = &ctx->kabylake_headset;
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
@@ -319,7 +332,9 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
int ret;
/* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
- rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1);
+ rt5663_sel_asrc_clk_src(codec_dai->codec,
+ RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+ RT5663_CLK_SEL_I2S1_ASRC);
ret = snd_soc_dai_set_sysclk(codec_dai,
RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
@@ -349,27 +364,25 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ret = snd_soc_dai_set_pll(codec_dai, 0,
- RT5514_PLL1_S_BCLK, RT5514_AIF1_BCLK_FREQ,
- RT5514_AIF1_SYSCLK_FREQ);
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ RT5514_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
if (ret < 0) {
- dev_err(rtd->dev, "set bclk err: %d\n", ret);
+ dev_err(rtd->dev, "set sysclk err: %d\n", ret);
return ret;
}
-
- ret = snd_soc_dai_set_sysclk(codec_dai,
- RT5514_SCLK_S_PLL1, RT5514_AIF1_SYSCLK_FREQ,
- SND_SOC_CLOCK_IN);
+ }
+ if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
if (ret < 0) {
- dev_err(rtd->dev, "set sclk err: %d\n", ret);
+ dev_err(rtd->dev, "DEV0 TDM slot err:%d\n", ret);
return ret;
}
}
- if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME) ||
- !strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF0, 3, 8, 16);
+
+ if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
if (ret < 0) {
- dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+ dev_err(rtd->dev, "DEV1 TDM slot err:%d\n", ret);
return ret;
}
}
@@ -449,6 +462,36 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.ops = &kabylake_rt5663_fe_ops,
},
+ [KBL_DPCM_AUDIO_HS_PB] = {
+ .name = "Kbl Audio Headset Playback",
+ .stream_name = "Headset Audio",
+ .cpu_dai_name = "System Pin2",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
+ .name = "Kbl Audio Echo Reference cap",
+ .stream_name = "Echoreference Capture",
+ .cpu_dai_name = "Echoref Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .init = NULL,
+ .capture_only = 1,
+ .nonatomic = 1,
+ },
+ [KBL_DPCM_AUDIO_RT5514_DSP] = {
+ .name = "rt5514 dsp",
+ .stream_name = "Wake on Voice",
+ .cpu_dai_name = "spi-PRP0001:00",
+ .platform_name = "spi-PRP0001:00",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ },
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
.stream_name = "dmiccap",
@@ -555,10 +598,12 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
{
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
struct kbl_hdmi_pcm *pcm;
+ struct snd_soc_codec *codec = NULL;
int err, i = 0;
char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+ codec = pcm->codec_dai->codec;
err = snd_soc_card_jack_new(card, jack_name,
SND_JACK_AVOUT, &ctx->kabylake_hdmi[i],
NULL, 0);
@@ -572,7 +617,10 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
i++;
}
- return 0;
+ if (!codec)
+ return -EINVAL;
+
+ return hdac_hdmi_jack_port_init(codec, &card->dapm);
}
/*
diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c
index 4e08885f37aa..6f44acfb4aae 100644
--- a/sound/soc/intel/boards/mfld_machine.c
+++ b/sound/soc/intel/boards/mfld_machine.c
@@ -376,10 +376,8 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
/* audio interrupt base of SRAM location where
* interrupts are stored by System FW */
mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
- if (!mc_drv_ctx) {
- pr_err("allocation failed\n");
+ if (!mc_drv_ctx)
return -ENOMEM;
- }
irq_mem = platform_get_resource_byname(
pdev, IORESOURCE_MEM, "IRQ_BASE");
diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c
index 9e4094e2c6e3..c044400540ec 100644
--- a/sound/soc/intel/haswell/sst-haswell-pcm.c
+++ b/sound/soc/intel/haswell/sst-haswell-pcm.c
@@ -1135,7 +1135,7 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
return 0;
}
-static struct snd_soc_platform_driver hsw_soc_platform = {
+static const struct snd_soc_platform_driver hsw_soc_platform = {
.probe = hsw_pcm_probe,
.remove = hsw_pcm_remove,
.ops = &hsw_pcm_ops,
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile
index e7d77722d560..3380deb81015 100644
--- a/sound/soc/intel/skylake/Makefile
+++ b/sound/soc/intel/skylake/Makefile
@@ -8,7 +8,8 @@ endif
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support
-snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \
- skl-sst.o bxt-sst.o skl-sst-utils.o
+snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \
+ skl-sst-cldma.o skl-sst.o bxt-sst.o cnl-sst.o \
+ skl-sst-utils.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c
index cf11b84888b9..4524211960e4 100644
--- a/sound/soc/intel/skylake/bxt-sst.c
+++ b/sound/soc/intel/skylake/bxt-sst.c
@@ -530,7 +530,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
return 0;
}
-static struct skl_dsp_fw_ops bxt_fw_ops = {
+static const struct skl_dsp_fw_ops bxt_fw_ops = {
.set_state_D0 = bxt_set_dsp_D0,
.set_state_D3 = bxt_set_dsp_D3,
.set_state_D0i3 = bxt_schedule_dsp_D0i3,
@@ -581,10 +581,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
+ ret = skl_ipc_init(dev, skl);
+ if (ret) {
+ skl_dsp_free(sst);
+ return ret;
+ }
+
/* set the D0i3 check */
skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
- skl->cores.count = 2;
skl->boot_complete = false;
init_waitqueue_head(&skl->boot_wait);
INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
@@ -629,11 +634,6 @@ void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
release_firmware(ctx->dsp->fw);
skl_freeup_uuid_list(ctx);
skl_ipc_free(&ctx->ipc);
- ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
-
- if (ctx->dsp->addr.lpe)
- iounmap(ctx->dsp->addr.lpe);
-
ctx->dsp->ops->free(ctx->dsp);
}
EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);
diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.c b/sound/soc/intel/skylake/cnl-sst-dsp.c
new file mode 100644
index 000000000000..2f8326707c21
--- /dev/null
+++ b/sound/soc/intel/skylake/cnl-sst-dsp.c
@@ -0,0 +1,274 @@
+/*
+ * cnl-sst-dsp.c - CNL SST library generic function
+ *
+ * Copyright (C) 2016-17, Intel Corporation.
+ * Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
+ *
+ * Modified from:
+ * SKL SST library generic function
+ * Copyright (C) 2014-15, Intel Corporation.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/device.h>
+#include "../common/sst-dsp.h"
+#include "../common/sst-ipc.h"
+#include "../common/sst-dsp-priv.h"
+#include "cnl-sst-dsp.h"
+
+/* various timeout values */
+#define CNL_DSP_PU_TO 50
+#define CNL_DSP_PD_TO 50
+#define CNL_DSP_RESET_TO 50
+
+static int
+cnl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
+{
+ /* update bits */
+ sst_dsp_shim_update_bits_unlocked(ctx,
+ CNL_ADSP_REG_ADSPCS, CNL_ADSPCS_CRST(core_mask),
+ CNL_ADSPCS_CRST(core_mask));
+
+ /* poll with timeout to check if operation successful */
+ return sst_dsp_register_poll(ctx,
+ CNL_ADSP_REG_ADSPCS,
+ CNL_ADSPCS_CRST(core_mask),
+ CNL_ADSPCS_CRST(core_mask),
+ CNL_DSP_RESET_TO,
+ "Set reset");
+}
+
+static int
+cnl_dsp_core_unset_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
+{
+ /* update bits */
+ sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+ CNL_ADSPCS_CRST(core_mask), 0);
+
+ /* poll with timeout to check if operation successful */
+ return sst_dsp_register_poll(ctx,
+ CNL_ADSP_REG_ADSPCS,
+ CNL_ADSPCS_CRST(core_mask),
+ 0,
+ CNL_DSP_RESET_TO,
+ "Unset reset");
+}
+
+static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
+{
+ int val;
+ bool is_enable;
+
+ val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS);
+
+ is_enable = (val & CNL_ADSPCS_CPA(core_mask)) &&
+ (val & CNL_ADSPCS_SPA(core_mask)) &&
+ !(val & CNL_ADSPCS_CRST(core_mask)) &&
+ !(val & CNL_ADSPCS_CSTALL(core_mask));
+
+ dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n",
+ is_enable, core_mask);
+
+ return is_enable;
+}
+
+static int cnl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
+{
+ /* stall core */
+ sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+ CNL_ADSPCS_CSTALL(core_mask),
+ CNL_ADSPCS_CSTALL(core_mask));
+
+ /* set reset state */
+ return cnl_dsp_core_set_reset_state(ctx, core_mask);
+}
+
+static int cnl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
+{
+ int ret;
+
+ /* unset reset state */
+ ret = cnl_dsp_core_unset_reset_state(ctx, core_mask);
+ if (ret < 0)
+ return ret;
+
+ /* run core */
+ sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+ CNL_ADSPCS_CSTALL(core_mask), 0);
+
+ if (!is_cnl_dsp_core_enable(ctx, core_mask)) {
+ cnl_dsp_reset_core(ctx, core_mask);
+ dev_err(ctx->dev, "DSP core mask %#x enable failed\n",
+ core_mask);
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int cnl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
+{
+ /* update bits */
+ sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+ CNL_ADSPCS_SPA(core_mask),
+ CNL_ADSPCS_SPA(core_mask));
+
+ /* poll with timeout to check if operation successful */
+ return sst_dsp_register_poll(ctx, CNL_ADSP_REG_ADSPCS,
+ CNL_ADSPCS_CPA(core_mask),
+ CNL_ADSPCS_CPA(core_mask),
+ CNL_DSP_PU_TO,
+ "Power up");
+}
+
+static int cnl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask)
+{
+ /* update bits */
+ sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
+ CNL_ADSPCS_SPA(core_mask), 0);
+
+ /* poll with timeout to check if operation successful */
+ return sst_dsp_register_poll(ctx,
+ CNL_ADSP_REG_ADSPCS,
+ CNL_ADSPCS_CPA(core_mask),
+ 0,
+ CNL_DSP_PD_TO,
+ "Power down");
+}
+
+int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask)
+{
+ int ret;
+
+ /* power up */
+ ret = cnl_dsp_core_power_up(ctx, core_mask);
+ if (ret < 0) {
+ dev_dbg(ctx->dev, "DSP core mask %#x power up failed",
+ core_mask);
+ return ret;
+ }
+
+ return cnl_dsp_start_core(ctx, core_mask);
+}
+
+int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
+{
+ int ret;
+
+ ret = cnl_dsp_reset_core(ctx, core_mask);
+ if (ret < 0) {
+ dev_err(ctx->dev, "DSP core mask %#x reset failed\n",
+ core_mask);
+ return ret;
+ }
+
+ /* power down core*/
+ ret = cnl_dsp_core_power_down(ctx, core_mask);
+ if (ret < 0) {
+ dev_err(ctx->dev, "DSP core mask %#x power down failed\n",
+ core_mask);
+ return ret;
+ }
+
+ if (is_cnl_dsp_core_enable(ctx, core_mask)) {
+ dev_err(ctx->dev, "DSP core mask %#x disable failed\n",
+ core_mask);
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id)
+{
+ struct sst_dsp *ctx = dev_id;
+ u32 val;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock(&ctx->spinlock);
+
+ val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS);
+ ctx->intr_status = val;
+
+ if (val == 0xffffffff) {
+ spin_unlock(&ctx->spinlock);
+ return IRQ_NONE;
+ }
+
+ if (val & CNL_ADSPIS_IPC) {
+ cnl_ipc_int_disable(ctx);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ spin_unlock(&ctx->spinlock);
+
+ return ret;
+}
+
+void cnl_dsp_free(struct sst_dsp *dsp)
+{
+ cnl_ipc_int_disable(dsp);
+
+ free_irq(dsp->irq, dsp);
+ cnl_ipc_op_int_disable(dsp);
+ cnl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
+}
+EXPORT_SYMBOL_GPL(cnl_dsp_free);
+
+void cnl_ipc_int_enable(struct sst_dsp *ctx)
+{
+ sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC,
+ CNL_ADSPIC_IPC, CNL_ADSPIC_IPC);
+}
+
+void cnl_ipc_int_disable(struct sst_dsp *ctx)
+{
+ sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPIC,
+ CNL_ADSPIC_IPC, 0);
+}
+
+void cnl_ipc_op_int_enable(struct sst_dsp *ctx)
+{
+ /* enable IPC DONE interrupt */
+ sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
+ CNL_ADSP_REG_HIPCCTL_DONE,
+ CNL_ADSP_REG_HIPCCTL_DONE);
+
+ /* enable IPC BUSY interrupt */
+ sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
+ CNL_ADSP_REG_HIPCCTL_BUSY,
+ CNL_ADSP_REG_HIPCCTL_BUSY);
+}
+
+void cnl_ipc_op_int_disable(struct sst_dsp *ctx)
+{
+ /* disable IPC DONE interrupt */
+ sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
+ CNL_ADSP_REG_HIPCCTL_DONE, 0);
+
+ /* disable IPC BUSY interrupt */
+ sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
+ CNL_ADSP_REG_HIPCCTL_BUSY, 0);
+}
+
+bool cnl_ipc_int_status(struct sst_dsp *ctx)
+{
+ return sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS) &
+ CNL_ADSPIS_IPC;
+}
+
+void cnl_ipc_free(struct sst_generic_ipc *ipc)
+{
+ cnl_ipc_op_int_disable(ipc->dsp);
+ sst_ipc_fini(ipc);
+}
diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h
new file mode 100644
index 000000000000..09bd218df5c4
--- /dev/null
+++ b/sound/soc/intel/skylake/cnl-sst-dsp.h
@@ -0,0 +1,112 @@
+/*
+ * Cannonlake SST DSP Support
+ *
+ * Copyright (C) 2016-17, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __CNL_SST_DSP_H__
+#define __CNL_SST_DSP_H__
+
+struct sst_dsp;
+struct skl_sst;
+struct sst_dsp_device;
+struct sst_generic_ipc;
+
+/* Intel HD Audio General DSP Registers */
+#define CNL_ADSP_GEN_BASE 0x0
+#define CNL_ADSP_REG_ADSPCS (CNL_ADSP_GEN_BASE + 0x04)
+#define CNL_ADSP_REG_ADSPIC (CNL_ADSP_GEN_BASE + 0x08)
+#define CNL_ADSP_REG_ADSPIS (CNL_ADSP_GEN_BASE + 0x0c)
+
+/* Intel HD Audio Inter-Processor Communication Registers */
+#define CNL_ADSP_IPC_BASE 0xc0
+#define CNL_ADSP_REG_HIPCTDR (CNL_ADSP_IPC_BASE + 0x00)
+#define CNL_ADSP_REG_HIPCTDA (CNL_ADSP_IPC_BASE + 0x04)
+#define CNL_ADSP_REG_HIPCTDD (CNL_ADSP_IPC_BASE + 0x08)
+#define CNL_ADSP_REG_HIPCIDR (CNL_ADSP_IPC_BASE + 0x10)
+#define CNL_ADSP_REG_HIPCIDA (CNL_ADSP_IPC_BASE + 0x14)
+#define CNL_ADSP_REG_HIPCIDD (CNL_ADSP_IPC_BASE + 0x18)
+#define CNL_ADSP_REG_HIPCCTL (CNL_ADSP_IPC_BASE + 0x28)
+
+/* HIPCTDR */
+#define CNL_ADSP_REG_HIPCTDR_BUSY BIT(31)
+
+/* HIPCTDA */
+#define CNL_ADSP_REG_HIPCTDA_DONE BIT(31)
+
+/* HIPCIDR */
+#define CNL_ADSP_REG_HIPCIDR_BUSY BIT(31)
+
+/* HIPCIDA */
+#define CNL_ADSP_REG_HIPCIDA_DONE BIT(31)
+
+/* CNL HIPCCTL */
+#define CNL_ADSP_REG_HIPCCTL_DONE BIT(1)
+#define CNL_ADSP_REG_HIPCCTL_BUSY BIT(0)
+
+/* CNL HIPCT */
+#define CNL_ADSP_REG_HIPCT_BUSY BIT(31)
+
+/* Intel HD Audio SRAM Window 1 */
+#define CNL_ADSP_SRAM1_BASE 0xa0000
+
+#define CNL_ADSP_MMIO_LEN 0x10000
+
+#define CNL_ADSP_W0_STAT_SZ 0x1000
+
+#define CNL_ADSP_W0_UP_SZ 0x1000
+
+#define CNL_ADSP_W1_SZ 0x1000
+
+#define CNL_FW_STS_MASK 0xf
+
+#define CNL_ADSPIC_IPC 0x1
+#define CNL_ADSPIS_IPC 0x1
+
+#define CNL_DSP_CORES 4
+#define CNL_DSP_CORES_MASK ((1 << CNL_DSP_CORES) - 1)
+
+/* core reset - asserted high */
+#define CNL_ADSPCS_CRST_SHIFT 0
+#define CNL_ADSPCS_CRST(x) (x << CNL_ADSPCS_CRST_SHIFT)
+
+/* core run/stall - when set to 1 core is stalled */
+#define CNL_ADSPCS_CSTALL_SHIFT 8
+#define CNL_ADSPCS_CSTALL(x) (x << CNL_ADSPCS_CSTALL_SHIFT)
+
+/* set power active - when set to 1 turn core on */
+#define CNL_ADSPCS_SPA_SHIFT 16
+#define CNL_ADSPCS_SPA(x) (x << CNL_ADSPCS_SPA_SHIFT)
+
+/* current power active - power status of cores, set by hardware */
+#define CNL_ADSPCS_CPA_SHIFT 24
+#define CNL_ADSPCS_CPA(x) (x << CNL_ADSPCS_CPA_SHIFT)
+
+int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core);
+int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core);
+irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id);
+void cnl_dsp_free(struct sst_dsp *dsp);
+
+void cnl_ipc_int_enable(struct sst_dsp *ctx);
+void cnl_ipc_int_disable(struct sst_dsp *ctx);
+void cnl_ipc_op_int_enable(struct sst_dsp *ctx);
+void cnl_ipc_op_int_disable(struct sst_dsp *ctx);
+bool cnl_ipc_int_status(struct sst_dsp *ctx);
+void cnl_ipc_free(struct sst_generic_ipc *ipc);
+
+int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
+ const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
+ struct skl_sst **dsp);
+int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx);
+void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
+
+#endif /*__CNL_SST_DSP_H__*/
diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c
new file mode 100644
index 000000000000..387de388ce29
--- /dev/null
+++ b/sound/soc/intel/skylake/cnl-sst.c
@@ -0,0 +1,497 @@
+/*
+ * cnl-sst.c - DSP library functions for CNL platform
+ *
+ * Copyright (C) 2016-17, Intel Corporation.
+ *
+ * Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
+ *
+ * Modified from:
+ * HDA DSP library functions for SKL platform
+ * Copyright (C) 2014-15, Intel Corporation.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/device.h>
+
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "../common/sst-ipc.h"
+#include "cnl-sst-dsp.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
+
+#define CNL_FW_ROM_INIT 0x1
+#define CNL_FW_INIT 0x5
+#define CNL_IPC_PURGE 0x01004000
+#define CNL_INIT_TIMEOUT 300
+#define CNL_BASEFW_TIMEOUT 3000
+
+#define CNL_ADSP_SRAM0_BASE 0x80000
+
+/* Firmware status window */
+#define CNL_ADSP_FW_STATUS CNL_ADSP_SRAM0_BASE
+#define CNL_ADSP_ERROR_CODE (CNL_ADSP_FW_STATUS + 0x4)
+
+#define CNL_INSTANCE_ID 0
+#define CNL_BASE_FW_MODULE_ID 0
+#define CNL_ADSP_FW_HDR_OFFSET 0x2000
+#define CNL_ROM_CTRL_DMA_ID 0x9
+
+static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize)
+{
+
+ int ret, stream_tag;
+
+ stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
+ if (stream_tag <= 0) {
+ dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag);
+ return stream_tag;
+ }
+
+ ctx->dsp_ops.stream_tag = stream_tag;
+ memcpy(ctx->dmab.area, fwdata, fwsize);
+
+ /* purge FW request */
+ sst_dsp_shim_write(ctx, CNL_ADSP_REG_HIPCIDR,
+ CNL_ADSP_REG_HIPCIDR_BUSY | (CNL_IPC_PURGE |
+ ((stream_tag - 1) << CNL_ROM_CTRL_DMA_ID)));
+
+ ret = cnl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK);
+ if (ret < 0) {
+ dev_err(ctx->dev, "dsp boot core failed ret: %d\n", ret);
+ ret = -EIO;
+ goto base_fw_load_failed;
+ }
+
+ /* enable interrupt */
+ cnl_ipc_int_enable(ctx);
+ cnl_ipc_op_int_enable(ctx);
+
+ ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
+ CNL_FW_ROM_INIT, CNL_INIT_TIMEOUT,
+ "rom load");
+ if (ret < 0) {
+ dev_err(ctx->dev, "rom init timeout, ret: %d\n", ret);
+ goto base_fw_load_failed;
+ }
+
+ return 0;
+
+base_fw_load_failed:
+ ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag);
+ cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
+
+ return ret;
+}
+
+static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
+{
+ int ret;
+
+ ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag);
+ ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
+ CNL_FW_INIT, CNL_BASEFW_TIMEOUT,
+ "firmware boot");
+
+ ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag);
+ ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag);
+
+ return ret;
+}
+
+static int cnl_load_base_firmware(struct sst_dsp *ctx)
+{
+ struct firmware stripped_fw;
+ struct skl_sst *cnl = ctx->thread_context;
+ int ret;
+
+ if (!ctx->fw) {
+ ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
+ if (ret < 0) {
+ dev_err(ctx->dev, "request firmware failed: %d\n", ret);
+ goto cnl_load_base_firmware_failed;
+ }
+ }
+
+ /* parse uuids if first boot */
+ if (cnl->is_first_boot) {
+ ret = snd_skl_parse_uuids(ctx, ctx->fw,
+ CNL_ADSP_FW_HDR_OFFSET, 0);
+ if (ret < 0)
+ goto cnl_load_base_firmware_failed;
+ }
+
+ stripped_fw.data = ctx->fw->data;
+ stripped_fw.size = ctx->fw->size;
+ skl_dsp_strip_extended_manifest(&stripped_fw);
+
+ ret = cnl_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
+ if (ret < 0) {
+ dev_err(ctx->dev, "prepare firmware failed: %d\n", ret);
+ goto cnl_load_base_firmware_failed;
+ }
+
+ ret = sst_transfer_fw_host_dma(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "transfer firmware failed: %d\n", ret);
+ cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
+ goto cnl_load_base_firmware_failed;
+ }
+
+ ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
+ msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
+ if (ret == 0) {
+ dev_err(ctx->dev, "FW ready timed-out\n");
+ cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
+ ret = -EIO;
+ goto cnl_load_base_firmware_failed;
+ }
+
+ cnl->fw_loaded = true;
+
+ return 0;
+
+cnl_load_base_firmware_failed:
+ release_firmware(ctx->fw);
+ ctx->fw = NULL;
+
+ return ret;
+}
+
+static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
+{
+ struct skl_sst *cnl = ctx->thread_context;
+ unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
+ struct skl_ipc_dxstate_info dx;
+ int ret;
+
+ if (!cnl->fw_loaded) {
+ cnl->boot_complete = false;
+ ret = cnl_load_base_firmware(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "fw reload failed: %d\n", ret);
+ return ret;
+ }
+
+ cnl->cores.state[core_id] = SKL_DSP_RUNNING;
+ return ret;
+ }
+
+ ret = cnl_dsp_enable_core(ctx, core_mask);
+ if (ret < 0) {
+ dev_err(ctx->dev, "enable dsp core %d failed: %d\n",
+ core_id, ret);
+ goto err;
+ }
+
+ if (core_id == SKL_DSP_CORE0_ID) {
+ /* enable interrupt */
+ cnl_ipc_int_enable(ctx);
+ cnl_ipc_op_int_enable(ctx);
+ cnl->boot_complete = false;
+
+ ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
+ msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
+ if (ret == 0) {
+ dev_err(ctx->dev,
+ "dsp boot timeout, status=%#x error=%#x\n",
+ sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS),
+ sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE));
+ goto err;
+ }
+ } else {
+ dx.core_mask = core_mask;
+ dx.dx_mask = core_mask;
+
+ ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
+ CNL_BASE_FW_MODULE_ID, &dx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "set_dx failed, core: %d ret: %d\n",
+ core_id, ret);
+ goto err;
+ }
+ }
+ cnl->cores.state[core_id] = SKL_DSP_RUNNING;
+
+ return 0;
+err:
+ cnl_dsp_disable_core(ctx, core_mask);
+
+ return ret;
+}
+
+static int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
+{
+ struct skl_sst *cnl = ctx->thread_context;
+ unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
+ struct skl_ipc_dxstate_info dx;
+ int ret;
+
+ dx.core_mask = core_mask;
+ dx.dx_mask = SKL_IPC_D3_MASK;
+
+ ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
+ CNL_BASE_FW_MODULE_ID, &dx);
+ if (ret < 0) {
+ dev_err(ctx->dev,
+ "dsp core %d to d3 failed; continue reset\n",
+ core_id);
+ cnl->fw_loaded = false;
+ }
+
+ /* disable interrupts if core 0 */
+ if (core_id == SKL_DSP_CORE0_ID) {
+ skl_ipc_op_int_disable(ctx);
+ skl_ipc_int_disable(ctx);
+ }
+
+ ret = cnl_dsp_disable_core(ctx, core_mask);
+ if (ret < 0) {
+ dev_err(ctx->dev, "disable dsp core %d failed: %d\n",
+ core_id, ret);
+ return ret;
+ }
+
+ cnl->cores.state[core_id] = SKL_DSP_RESET;
+
+ return ret;
+}
+
+static unsigned int cnl_get_errno(struct sst_dsp *ctx)
+{
+ return sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE);
+}
+
+static const struct skl_dsp_fw_ops cnl_fw_ops = {
+ .set_state_D0 = cnl_set_dsp_D0,
+ .set_state_D3 = cnl_set_dsp_D3,
+ .load_fw = cnl_load_base_firmware,
+ .get_fw_errcode = cnl_get_errno,
+};
+
+static struct sst_ops cnl_ops = {
+ .irq_handler = cnl_dsp_sst_interrupt,
+ .write = sst_shim32_write,
+ .read = sst_shim32_read,
+ .ram_read = sst_memcpy_fromio_32,
+ .ram_write = sst_memcpy_toio_32,
+ .free = cnl_dsp_free,
+};
+
+#define CNL_IPC_GLB_NOTIFY_RSP_SHIFT 29
+#define CNL_IPC_GLB_NOTIFY_RSP_MASK 0x1
+#define CNL_IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> CNL_IPC_GLB_NOTIFY_RSP_SHIFT) \
+ & CNL_IPC_GLB_NOTIFY_RSP_MASK)
+
+static irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context)
+{
+ struct sst_dsp *dsp = context;
+ struct skl_sst *cnl = sst_dsp_get_thread_context(dsp);
+ struct sst_generic_ipc *ipc = &cnl->ipc;
+ struct skl_ipc_header header = {0};
+ u32 hipcida, hipctdr, hipctdd;
+ int ipc_irq = 0;
+
+ /* here we handle ipc interrupts only */
+ if (!(dsp->intr_status & CNL_ADSPIS_IPC))
+ return IRQ_NONE;
+
+ hipcida = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDA);
+ hipctdr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDR);
+
+ /* reply message from dsp */
+ if (hipcida & CNL_ADSP_REG_HIPCIDA_DONE) {
+ sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
+ CNL_ADSP_REG_HIPCCTL_DONE, 0);
+
+ /* clear done bit - tell dsp operation is complete */
+ sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCIDA,
+ CNL_ADSP_REG_HIPCIDA_DONE, CNL_ADSP_REG_HIPCIDA_DONE);
+
+ ipc_irq = 1;
+
+ /* unmask done interrupt */
+ sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
+ CNL_ADSP_REG_HIPCCTL_DONE, CNL_ADSP_REG_HIPCCTL_DONE);
+ }
+
+ /* new message from dsp */
+ if (hipctdr & CNL_ADSP_REG_HIPCTDR_BUSY) {
+ hipctdd = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDD);
+ header.primary = hipctdr;
+ header.extension = hipctdd;
+ dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x",
+ header.primary);
+ dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x",
+ header.extension);
+
+ if (CNL_IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) {
+ /* Handle Immediate reply from DSP Core */
+ skl_ipc_process_reply(ipc, header);
+ } else {
+ dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n");
+ skl_ipc_process_notification(ipc, header);
+ }
+ /* clear busy interrupt */
+ sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDR,
+ CNL_ADSP_REG_HIPCTDR_BUSY, CNL_ADSP_REG_HIPCTDR_BUSY);
+
+ /* set done bit to ack dsp */
+ sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDA,
+ CNL_ADSP_REG_HIPCTDA_DONE, CNL_ADSP_REG_HIPCTDA_DONE);
+ ipc_irq = 1;
+ }
+
+ if (ipc_irq == 0)
+ return IRQ_NONE;
+
+ cnl_ipc_int_enable(dsp);
+
+ /* continue to send any remaining messages */
+ schedule_work(&ipc->kwork);
+
+ return IRQ_HANDLED;
+}
+
+static struct sst_dsp_device cnl_dev = {
+ .thread = cnl_dsp_irq_thread_handler,
+ .ops = &cnl_ops,
+};
+
+static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
+{
+ struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header);
+
+ if (msg->tx_size)
+ sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
+ sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD,
+ header->extension);
+ sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR,
+ header->primary | CNL_ADSP_REG_HIPCIDR_BUSY);
+}
+
+static bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp)
+{
+ u32 hipcidr;
+
+ hipcidr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDR);
+
+ return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY);
+}
+
+static int cnl_ipc_init(struct device *dev, struct skl_sst *cnl)
+{
+ struct sst_generic_ipc *ipc;
+ int err;
+
+ ipc = &cnl->ipc;
+ ipc->dsp = cnl->dsp;
+ ipc->dev = dev;
+
+ ipc->tx_data_max_size = CNL_ADSP_W1_SZ;
+ ipc->rx_data_max_size = CNL_ADSP_W0_UP_SZ;
+
+ err = sst_ipc_init(ipc);
+ if (err)
+ return err;
+
+ /*
+ * overriding tx_msg and is_dsp_busy since
+ * ipc registers are different for cnl
+ */
+ ipc->ops.tx_msg = cnl_ipc_tx_msg;
+ ipc->ops.tx_data_copy = skl_ipc_tx_data_copy;
+ ipc->ops.is_dsp_busy = cnl_ipc_is_dsp_busy;
+
+ return 0;
+}
+
+int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
+ const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
+ struct skl_sst **dsp)
+{
+ struct skl_sst *cnl;
+ struct sst_dsp *sst;
+ int ret;
+
+ ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &cnl_dev);
+ if (ret < 0) {
+ dev_err(dev, "%s: no device\n", __func__);
+ return ret;
+ }
+
+ cnl = *dsp;
+ sst = cnl->dsp;
+ sst->fw_ops = cnl_fw_ops;
+ sst->addr.lpe = mmio_base;
+ sst->addr.shim = mmio_base;
+ sst->addr.sram0_base = CNL_ADSP_SRAM0_BASE;
+ sst->addr.sram1_base = CNL_ADSP_SRAM1_BASE;
+ sst->addr.w0_stat_sz = CNL_ADSP_W0_STAT_SZ;
+ sst->addr.w0_up_sz = CNL_ADSP_W0_UP_SZ;
+
+ sst_dsp_mailbox_init(sst, (CNL_ADSP_SRAM0_BASE + CNL_ADSP_W0_STAT_SZ),
+ CNL_ADSP_W0_UP_SZ, CNL_ADSP_SRAM1_BASE,
+ CNL_ADSP_W1_SZ);
+
+ ret = cnl_ipc_init(dev, cnl);
+ if (ret) {
+ skl_dsp_free(sst);
+ return ret;
+ }
+
+ cnl->boot_complete = false;
+ init_waitqueue_head(&cnl->boot_wait);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
+
+int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
+{
+ int ret;
+ struct sst_dsp *sst = ctx->dsp;
+
+ ret = ctx->dsp->fw_ops.load_fw(sst);
+ if (ret < 0) {
+ dev_err(dev, "load base fw failed: %d", ret);
+ return ret;
+ }
+
+ skl_dsp_init_core_state(sst);
+
+ ctx->is_first_boot = false;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cnl_sst_init_fw);
+
+void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
+{
+ if (ctx->dsp->fw)
+ release_firmware(ctx->dsp->fw);
+
+ skl_freeup_uuid_list(ctx);
+ cnl_ipc_free(&ctx->ipc);
+
+ ctx->dsp->ops->free(ctx->dsp);
+}
+EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Cannonlake IPC driver");
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index eca85827dbd2..89f70133c8e4 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -22,6 +22,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include "skl-sst-dsp.h"
+#include "cnl-sst-dsp.h"
#include "skl-sst-ipc.h"
#include "skl.h"
#include "../common/sst-dsp.h"
@@ -201,6 +202,7 @@ static struct skl_dsp_loader_ops bxt_get_loader_ops(void)
static const struct skl_dsp_ops dsp_ops[] = {
{
.id = 0x9d70,
+ .num_cores = 2,
.loader_ops = skl_get_loader_ops,
.init = skl_sst_dsp_init,
.init_fw = skl_sst_init_fw,
@@ -208,6 +210,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
},
{
.id = 0x9d71,
+ .num_cores = 2,
.loader_ops = skl_get_loader_ops,
.init = kbl_sst_dsp_init,
.init_fw = skl_sst_init_fw,
@@ -215,6 +218,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
},
{
.id = 0x5a98,
+ .num_cores = 2,
.loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init,
.init_fw = bxt_sst_init_fw,
@@ -222,11 +226,20 @@ static const struct skl_dsp_ops dsp_ops[] = {
},
{
.id = 0x3198,
+ .num_cores = 2,
.loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init,
.init_fw = bxt_sst_init_fw,
.cleanup = bxt_sst_dsp_cleanup
},
+ {
+ .id = 0x9dc8,
+ .num_cores = 4,
+ .loader_ops = bxt_get_loader_ops,
+ .init = cnl_sst_dsp_init,
+ .init_fw = cnl_sst_init_fw,
+ .cleanup = cnl_sst_dsp_cleanup
+ },
};
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
@@ -249,6 +262,7 @@ int skl_init_dsp(struct skl *skl)
struct skl_dsp_loader_ops loader_ops;
int irq = bus->irq;
const struct skl_dsp_ops *ops;
+ struct skl_dsp_cores *cores;
int ret;
/* enable ppcap interrupt */
@@ -263,8 +277,10 @@ int skl_init_dsp(struct skl *skl)
}
ops = skl_get_dsp_ops(skl->pci->device);
- if (!ops)
- return -EIO;
+ if (!ops) {
+ ret = -EIO;
+ goto unmap_mmio;
+ }
loader_ops = ops->loader_ops();
ret = ops->init(bus->dev, mmio_base, irq,
@@ -272,11 +288,35 @@ int skl_init_dsp(struct skl *skl)
&skl->skl_sst);
if (ret < 0)
- return ret;
+ goto unmap_mmio;
skl->skl_sst->dsp_ops = ops;
+ cores = &skl->skl_sst->cores;
+ cores->count = ops->num_cores;
+
+ cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL);
+ if (!cores->state) {
+ ret = -ENOMEM;
+ goto unmap_mmio;
+ }
+
+ cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count),
+ GFP_KERNEL);
+ if (!cores->usage_count) {
+ ret = -ENOMEM;
+ goto free_core_state;
+ }
+
dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
+ return 0;
+
+free_core_state:
+ kfree(cores->state);
+
+unmap_mmio:
+ iounmap(mmio_base);
+
return ret;
}
@@ -291,6 +331,9 @@ int skl_free_dsp(struct skl *skl)
ctx->dsp_ops->cleanup(bus->dev, ctx);
+ kfree(ctx->cores.state);
+ kfree(ctx->cores.usage_count);
+
if (ctx->dsp->addr.lpe)
iounmap(ctx->dsp->addr.lpe);
@@ -400,9 +443,12 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_base_cfg *base_cfg)
{
- struct skl_module_fmt *format = &mconfig->in_fmt[0];
+ struct skl_module *module = mconfig->module;
+ struct skl_module_res *res = &module->resources[mconfig->res_idx];
+ struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
+ struct skl_module_fmt *format = &fmt->inputs[0].fmt;
- base_cfg->audio_fmt.number_of_channels = (u8)format->channels;
+ base_cfg->audio_fmt.number_of_channels = format->channels;
base_cfg->audio_fmt.s_freq = format->s_freq;
base_cfg->audio_fmt.bit_depth = format->bit_depth;
@@ -417,10 +463,10 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
base_cfg->audio_fmt.interleaving = format->interleaving_style;
- base_cfg->cps = mconfig->mcps;
- base_cfg->ibs = mconfig->ibs;
- base_cfg->obs = mconfig->obs;
- base_cfg->is_pages = mconfig->mem_pages;
+ base_cfg->cps = res->cps;
+ base_cfg->ibs = res->ibs;
+ base_cfg->obs = res->obs;
+ base_cfg->is_pages = res->is_pages;
}
/*
@@ -508,6 +554,9 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
struct skl_cpr_cfg *cpr_mconfig)
{
u32 dma_io_buf;
+ struct skl_module_res *res;
+ int res_idx = mconfig->res_idx;
+ struct skl *skl = get_skl_ctx(ctx->dev);
cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig);
@@ -516,19 +565,27 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
return;
}
+ if (skl->nr_modules) {
+ res = &mconfig->module->resources[mconfig->res_idx];
+ cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size;
+ goto skip_buf_size_calc;
+ } else {
+ res = &mconfig->module->resources[res_idx];
+ }
+
switch (mconfig->hw_conn_type) {
case SKL_CONN_SOURCE:
if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
- dma_io_buf = mconfig->ibs;
+ dma_io_buf = res->ibs;
else
- dma_io_buf = mconfig->obs;
+ dma_io_buf = res->obs;
break;
case SKL_CONN_SINK:
if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
- dma_io_buf = mconfig->obs;
+ dma_io_buf = res->obs;
else
- dma_io_buf = mconfig->ibs;
+ dma_io_buf = res->ibs;
break;
default:
@@ -540,6 +597,15 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
cpr_mconfig->gtw_cfg.dma_buffer_size =
mconfig->dma_buffer_size * dma_io_buf;
+ /* fallback to 2ms default value */
+ if (!cpr_mconfig->gtw_cfg.dma_buffer_size) {
+ if (mconfig->hw_conn_type == SKL_CONN_SOURCE)
+ cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs;
+ else
+ cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs;
+ }
+
+skip_buf_size_calc:
cpr_mconfig->cpr_feature_mask = 0;
cpr_mconfig->gtw_cfg.config_length = 0;
@@ -587,7 +653,9 @@ static void skl_setup_out_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_audio_data_format *out_fmt)
{
- struct skl_module_fmt *format = &mconfig->out_fmt[0];
+ struct skl_module *module = mconfig->module;
+ struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
+ struct skl_module_fmt *format = &fmt->outputs[0].fmt;
out_fmt->number_of_channels = (u8)format->channels;
out_fmt->s_freq = format->s_freq;
@@ -612,7 +680,9 @@ static void skl_set_src_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_src_module_cfg *src_mconfig)
{
- struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
+ struct skl_module *module = mconfig->module;
+ struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
+ struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
skl_set_base_module_format(ctx, mconfig,
(struct skl_base_cfg *)src_mconfig);
@@ -629,7 +699,9 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_up_down_mixer_cfg *mixer_mconfig)
{
- struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
+ struct skl_module *module = mconfig->module;
+ struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
+ struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
int i = 0;
skl_set_base_module_format(ctx, mconfig,
@@ -942,7 +1014,7 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg
{
dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n",
__func__, src_module->id.module_id, src_module->id.pvt_id);
- dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__,
+ dev_dbg(ctx->dev, "%s: dst_module=%d dst_instance=%d\n", __func__,
dst_module->id.module_id, dst_module->id.pvt_id);
dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n",
@@ -962,8 +1034,8 @@ int skl_unbind_modules(struct skl_sst *ctx,
struct skl_ipc_bind_unbind_msg msg;
struct skl_module_inst_id src_id = src_mcfg->id;
struct skl_module_inst_id dst_id = dst_mcfg->id;
- int in_max = dst_mcfg->max_in_queue;
- int out_max = src_mcfg->max_out_queue;
+ int in_max = dst_mcfg->module->max_input_pins;
+ int out_max = src_mcfg->module->max_output_pins;
int src_index, dst_index, src_pin_state, dst_pin_state;
skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
@@ -1011,6 +1083,21 @@ int skl_unbind_modules(struct skl_sst *ctx,
return ret;
}
+static void fill_pin_params(struct skl_audio_data_format *pin_fmt,
+ struct skl_module_fmt *format)
+{
+ pin_fmt->number_of_channels = format->channels;
+ pin_fmt->s_freq = format->s_freq;
+ pin_fmt->bit_depth = format->bit_depth;
+ pin_fmt->valid_bit_depth = format->valid_bit_depth;
+ pin_fmt->ch_cfg = format->ch_cfg;
+ pin_fmt->sample_type = format->sample_type;
+ pin_fmt->channel_map = format->ch_map;
+ pin_fmt->interleaving = format->interleaving_style;
+}
+
+#define CPR_SINK_FMT_PARAM_ID 2
+
/*
* Once a module is instantiated it need to be 'bind' with other modules in
* the pipeline. For binding we need to find the module pins which are bind
@@ -1022,11 +1109,15 @@ int skl_bind_modules(struct skl_sst *ctx,
struct skl_module_cfg *src_mcfg,
struct skl_module_cfg *dst_mcfg)
{
- int ret;
+ int ret = 0;
struct skl_ipc_bind_unbind_msg msg;
- int in_max = dst_mcfg->max_in_queue;
- int out_max = src_mcfg->max_out_queue;
+ int in_max = dst_mcfg->module->max_input_pins;
+ int out_max = src_mcfg->module->max_output_pins;
int src_index, dst_index;
+ struct skl_module_fmt *format;
+ struct skl_cpr_pin_fmt pin_fmt;
+ struct skl_module *module;
+ struct skl_module_iface *fmt;
skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
@@ -1045,6 +1136,29 @@ int skl_bind_modules(struct skl_sst *ctx,
return -EINVAL;
}
+ /*
+ * Copier module requires the separate large_config_set_ipc to
+ * configure the pins other than 0
+ */
+ if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) {
+ pin_fmt.sink_id = src_index;
+ module = src_mcfg->module;
+ fmt = &module->formats[src_mcfg->fmt_idx];
+
+ /* Input fmt is same as that of src module input cfg */
+ format = &fmt->inputs[0].fmt;
+ fill_pin_params(&(pin_fmt.src_fmt), format);
+
+ format = &fmt->outputs[src_index].fmt;
+ fill_pin_params(&(pin_fmt.dst_fmt), format);
+ ret = skl_set_module_params(ctx, (void *)&pin_fmt,
+ sizeof(struct skl_cpr_pin_fmt),
+ CPR_SINK_FMT_PARAM_ID, src_mcfg);
+
+ if (ret < 0)
+ goto out;
+ }
+
msg.dst_queue = dst_index;
dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
@@ -1062,11 +1176,12 @@ int skl_bind_modules(struct skl_sst *ctx,
src_mcfg->m_state = SKL_MODULE_BIND_DONE;
src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
- } else {
- /* error case , if IPC fails, clear the queue index */
- skl_free_queue(src_mcfg->m_out_pin, src_index);
- skl_free_queue(dst_mcfg->m_in_pin, dst_index);
+ return ret;
}
+out:
+ /* error case , if IPC fails, clear the queue index */
+ skl_free_queue(src_mcfg->m_out_pin, src_index);
+ skl_free_queue(dst_mcfg->m_in_pin, dst_index);
return ret;
}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 0ebea34a4988..2b1e513b1680 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -33,7 +33,7 @@
#define HDA_STEREO 2
#define HDA_QUAD 4
-static struct snd_pcm_hardware azx_pcm_hw = {
+static const struct snd_pcm_hardware azx_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -628,7 +628,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_soc_dai_ops skl_pcm_dai_ops = {
+static const struct snd_soc_dai_ops skl_pcm_dai_ops = {
.startup = skl_pcm_open,
.shutdown = skl_pcm_close,
.prepare = skl_pcm_prepare,
@@ -637,15 +637,15 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
.trigger = skl_pcm_trigger,
};
-static struct snd_soc_dai_ops skl_dmic_dai_ops = {
+static const struct snd_soc_dai_ops skl_dmic_dai_ops = {
.hw_params = skl_be_hw_params,
};
-static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
+static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
.hw_params = skl_be_hw_params,
};
-static struct snd_soc_dai_ops skl_link_dai_ops = {
+static const struct snd_soc_dai_ops skl_link_dai_ops = {
.prepare = skl_link_pcm_prepare,
.hw_params = skl_link_hw_params,
.hw_free = skl_link_hw_free,
@@ -675,6 +675,32 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
},
},
{
+ .name = "System Pin2",
+ .ops = &skl_pcm_dai_ops,
+ .playback = {
+ .stream_name = "Headset Playback",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ },
+},
+{
+ .name = "Echoref Pin",
+ .ops = &skl_pcm_dai_ops,
+ .capture = {
+ .stream_name = "Echoreference Capture",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ },
+},
+{
.name = "Reference Pin",
.ops = &skl_pcm_dai_ops,
.capture = {
@@ -1194,8 +1220,11 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
{
struct skl_sst *ctx = skl->skl_sst;
+ struct skl_module_inst_id *pin_id;
+ uuid_le *uuid_mod, *uuid_tplg;
+ struct skl_module *skl_module;
struct uuid_module *module;
- uuid_le *uuid_mod;
+ int i, ret = -EIO;
uuid_mod = (uuid_le *)mconfig->guid;
@@ -1207,12 +1236,45 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
list_for_each_entry(module, &ctx->uuid_list, list) {
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
mconfig->id.module_id = module->id;
- mconfig->is_loadable = module->is_loadable;
- return 0;
+ if (mconfig->module)
+ mconfig->module->loadable = module->is_loadable;
+ ret = 0;
+ break;
+ }
+ }
+
+ if (ret)
+ return ret;
+
+ uuid_mod = &module->uuid;
+ ret = -EIO;
+ for (i = 0; i < skl->nr_modules; i++) {
+ skl_module = skl->modules[i];
+ uuid_tplg = &skl_module->uuid;
+ if (!uuid_le_cmp(*uuid_mod, *uuid_tplg)) {
+ mconfig->module = skl_module;
+ ret = 0;
+ break;
}
}
+ if (skl->nr_modules && ret)
+ return ret;
- return -EIO;
+ list_for_each_entry(module, &ctx->uuid_list, list) {
+ for (i = 0; i < MAX_IN_QUEUE; i++) {
+ pin_id = &mconfig->m_in_pin[i].id;
+ if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid))
+ pin_id->module_id = module->id;
+ }
+
+ for (i = 0; i < MAX_OUT_QUEUE; i++) {
+ pin_id = &mconfig->m_out_pin[i].id;
+ if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid))
+ pin_id->module_id = module->id;
+ }
+ }
+
+ return 0;
}
static int skl_populate_modules(struct skl *skl)
@@ -1284,7 +1346,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
return 0;
}
-static struct snd_soc_platform_driver skl_platform_drv = {
+static const struct snd_soc_platform_driver skl_platform_drv = {
.probe = skl_platform_soc_probe,
.ops = &skl_platform_ops,
.pcm_new = skl_pcm_new,
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c
index 08332723c700..19ee1d4f3bdf 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.c
+++ b/sound/soc/intel/skylake/skl-sst-dsp.c
@@ -47,7 +47,7 @@ void skl_dsp_init_core_state(struct sst_dsp *ctx)
skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1;
- for (i = SKL_DSP_CORE0_ID + 1; i < SKL_DSP_CORES_MAX; i++) {
+ for (i = SKL_DSP_CORE0_ID + 1; i < skl->cores.count; i++) {
skl->cores.state[i] = SKL_DSP_RESET;
skl->cores.usage_count[i] = 0;
}
@@ -351,6 +351,8 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
return -EINVAL;
}
+ skl->cores.usage_count[core_id]++;
+
if (skl->cores.state[core_id] == SKL_DSP_RESET) {
ret = ctx->fw_ops.set_state_D0(ctx, core_id);
if (ret < 0) {
@@ -359,8 +361,6 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
}
}
- skl->cores.usage_count[core_id]++;
-
out:
dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
core_id, skl->cores.state[core_id],
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 498b15345b1a..5234fafb758a 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -283,7 +283,7 @@ enum skl_ipc_module_msg {
IPC_MOD_SET_D0IX = 8
};
-static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
+void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
size_t tx_size)
{
if (tx_size)
@@ -347,7 +347,7 @@ out:
}
-static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
+int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
struct skl_ipc_header header)
{
struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
@@ -406,7 +406,7 @@ static int skl_ipc_set_reply_error_code(u32 reply)
}
}
-static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
+void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
struct skl_ipc_header header)
{
struct ipc_message *msg;
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index e057da2713c6..55f2d2ce09df 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -44,12 +44,10 @@ struct skl_ipc_header {
u32 extension;
};
-#define SKL_DSP_CORES_MAX 2
-
struct skl_dsp_cores {
unsigned int count;
- enum skl_dsp_states state[SKL_DSP_CORES_MAX];
- int usage_count[SKL_DSP_CORES_MAX];
+ enum skl_dsp_states *state;
+ int *usage_count;
};
/**
@@ -214,4 +212,10 @@ void skl_ipc_free(struct sst_generic_ipc *ipc);
int skl_ipc_init(struct device *dev, struct skl_sst *skl);
void skl_clear_module_cnt(struct sst_dsp *ctx);
+void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
+ struct skl_ipc_header header);
+int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
+ struct skl_ipc_header header);
+void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
+ size_t tx_size);
#endif /* __SKL_IPC_H */
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
index 81ee251881b4..369ef7ce981c 100644
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
@@ -368,7 +368,6 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
{
struct skl_sst *skl;
struct sst_dsp *sst;
- int ret;
skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
if (skl == NULL)
@@ -388,15 +387,12 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
sst->dsp_ops = dsp_ops;
init_waitqueue_head(&skl->mod_load_wait);
INIT_LIST_HEAD(&sst->module_list);
- ret = skl_ipc_init(dev, skl);
- if (ret)
- return ret;
skl->is_first_boot = true;
if (dsp)
*dsp = skl;
- return ret;
+ return 0;
}
int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo,
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index aba9ea11ac74..a436abf2fe3f 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -503,7 +503,7 @@ static void skl_clear_module_table(struct sst_dsp *ctx)
}
}
-static struct skl_dsp_fw_ops skl_fw_ops = {
+static const struct skl_dsp_fw_ops skl_fw_ops = {
.set_state_D0 = skl_set_dsp_D0,
.set_state_D3 = skl_set_dsp_D3,
.load_fw = skl_load_base_firmware,
@@ -512,7 +512,7 @@ static struct skl_dsp_fw_ops skl_fw_ops = {
.unload_mod = skl_unload_module,
};
-static struct skl_dsp_fw_ops kbl_fw_ops = {
+static const struct skl_dsp_fw_ops kbl_fw_ops = {
.set_state_D0 = skl_set_dsp_D0,
.set_state_D3 = skl_set_dsp_D3,
.load_fw = skl_load_base_firmware,
@@ -561,9 +561,13 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
- sst->fw_ops = skl_fw_ops;
+ ret = skl_ipc_init(dev, skl);
+ if (ret) {
+ skl_dsp_free(sst);
+ return ret;
+ }
- skl->cores.count = 2;
+ sst->fw_ops = skl_fw_ops;
return 0;
}
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 68c3f121efc3..22f768ca3c73 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -49,6 +49,9 @@ static const int mic_quatro_list[][SKL_CH_QUATRO] = {
{0, 1, 2, 3},
};
+#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
+ ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
+
void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
{
struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3;
@@ -153,8 +156,10 @@ static bool skl_is_pipe_mcps_avail(struct skl *skl,
struct skl_module_cfg *mconfig)
{
struct skl_sst *ctx = skl->skl_sst;
+ u8 res_idx = mconfig->res_idx;
+ struct skl_module_res *res = &mconfig->module->resources[res_idx];
- if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) {
+ if (skl->resource.mcps + res->cps > skl->resource.max_mcps) {
dev_err(ctx->dev,
"%s: module_id %d instance %d\n", __func__,
mconfig->id.module_id, mconfig->id.instance_id);
@@ -170,7 +175,10 @@ static bool skl_is_pipe_mcps_avail(struct skl *skl,
static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
struct skl_module_cfg *mconfig)
{
- skl->resource.mcps += mconfig->mcps;
+ u8 res_idx = mconfig->res_idx;
+ struct skl_module_res *res = &mconfig->module->resources[res_idx];
+
+ skl->resource.mcps += res->cps;
}
/*
@@ -179,7 +187,11 @@ static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
static void
skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
{
- skl->resource.mcps -= mconfig->mcps;
+ u8 res_idx = mconfig->res_idx;
+ struct skl_module_res *res = &mconfig->module->resources[res_idx];
+
+ res = &mconfig->module->resources[res_idx];
+ skl->resource.mcps -= res->cps;
}
/*
@@ -195,17 +207,21 @@ skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
static void skl_dump_mconfig(struct skl_sst *ctx,
struct skl_module_cfg *mcfg)
{
+ struct skl_module_iface *iface = &mcfg->module->formats[0];
+
dev_dbg(ctx->dev, "Dumping config\n");
dev_dbg(ctx->dev, "Input Format:\n");
- dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
- dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
- dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
- dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
+ dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
+ dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
+ dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
+ dev_dbg(ctx->dev, "valid bit depth = %d\n",
+ iface->inputs[0].fmt.valid_bit_depth);
dev_dbg(ctx->dev, "Output Format:\n");
- dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
- dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
- dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
- dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
+ dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
+ dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
+ dev_dbg(ctx->dev, "valid bit depth = %d\n",
+ iface->outputs[0].fmt.valid_bit_depth);
+ dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
}
static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
@@ -273,8 +289,8 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
struct skl_module_fmt *in_fmt, *out_fmt;
/* Fixups will be applied to pin 0 only */
- in_fmt = &m_cfg->in_fmt[0];
- out_fmt = &m_cfg->out_fmt[0];
+ in_fmt = &m_cfg->module->formats[0].inputs[0].fmt;
+ out_fmt = &m_cfg->module->formats[0].outputs[0].fmt;
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (is_fe) {
@@ -312,21 +328,23 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
{
int multiplier = 1;
struct skl_module_fmt *in_fmt, *out_fmt;
+ struct skl_module_res *res;
/* Since fixups is applied to pin 0 only, ibs, obs needs
* change for pin 0 only
*/
- in_fmt = &mcfg->in_fmt[0];
- out_fmt = &mcfg->out_fmt[0];
+ res = &mcfg->module->resources[0];
+ in_fmt = &mcfg->module->formats[0].inputs[0].fmt;
+ out_fmt = &mcfg->module->formats[0].outputs[0].fmt;
if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
multiplier = 5;
- mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
+ res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
in_fmt->channels * (in_fmt->bit_depth >> 3) *
multiplier;
- mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
+ res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
out_fmt->channels * (out_fmt->bit_depth >> 3) *
multiplier;
}
@@ -365,6 +383,8 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
struct nhlt_specific_cfg *cfg;
struct skl *skl = get_skl_ctx(ctx->dev);
u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
+ int fmt_idx = m_cfg->fmt_idx;
+ struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
/* check if we already have blob */
if (m_cfg->formats_config.caps_size > 0)
@@ -375,23 +395,23 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
case SKL_DEVICE_DMIC:
link_type = NHLT_LINK_DMIC;
dir = SNDRV_PCM_STREAM_CAPTURE;
- s_freq = m_cfg->in_fmt[0].s_freq;
- s_fmt = m_cfg->in_fmt[0].bit_depth;
- ch = m_cfg->in_fmt[0].channels;
+ s_freq = m_iface->inputs[0].fmt.s_freq;
+ s_fmt = m_iface->inputs[0].fmt.bit_depth;
+ ch = m_iface->inputs[0].fmt.channels;
break;
case SKL_DEVICE_I2S:
link_type = NHLT_LINK_SSP;
if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
dir = SNDRV_PCM_STREAM_PLAYBACK;
- s_freq = m_cfg->out_fmt[0].s_freq;
- s_fmt = m_cfg->out_fmt[0].bit_depth;
- ch = m_cfg->out_fmt[0].channels;
+ s_freq = m_iface->outputs[0].fmt.s_freq;
+ s_fmt = m_iface->outputs[0].fmt.bit_depth;
+ ch = m_iface->outputs[0].fmt.channels;
} else {
dir = SNDRV_PCM_STREAM_CAPTURE;
- s_freq = m_cfg->in_fmt[0].s_freq;
- s_fmt = m_cfg->in_fmt[0].bit_depth;
- ch = m_cfg->in_fmt[0].channels;
+ s_freq = m_iface->inputs[0].fmt.s_freq;
+ s_fmt = m_iface->inputs[0].fmt.bit_depth;
+ ch = m_iface->inputs[0].fmt.channels;
}
break;
@@ -549,6 +569,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
struct snd_soc_dapm_widget *w;
struct skl_module_cfg *mconfig;
struct skl_sst *ctx = skl->skl_sst;
+ u8 cfg_idx;
int ret = 0;
list_for_each_entry(w_module, &pipe->w_list, node) {
@@ -564,11 +585,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
return -EIO;
}
+ cfg_idx = mconfig->pipe->cur_config_idx;
+ mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
+ mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
+
/* check resource available */
if (!skl_is_pipe_mcps_avail(skl, mconfig))
return -ENOMEM;
- if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
+ if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) {
ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
mconfig->id.module_id, mconfig->guid);
if (ret < 0)
@@ -596,24 +621,35 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
if (mconfig->id.pvt_id < 0)
return ret;
skl_tplg_set_module_init_data(w);
+
+ ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n",
+ mconfig->core_id, ret);
+ return ret;
+ }
+
ret = skl_init_module(ctx, mconfig);
if (ret < 0) {
skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
- return ret;
+ goto err;
}
skl_tplg_alloc_pipe_mcps(skl, mconfig);
ret = skl_tplg_set_module_params(w, ctx);
if (ret < 0)
- return ret;
+ goto err;
}
return 0;
+err:
+ skl_dsp_put_core(ctx->dsp, mconfig->core_id);
+ return ret;
}
static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
struct skl_pipe *pipe)
{
- int ret;
+ int ret = 0;
struct skl_pipe_module *w_module = NULL;
struct skl_module_cfg *mconfig = NULL;
@@ -622,7 +658,7 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
mconfig = w_module->w->priv;
uuid_mod = (uuid_le *)mconfig->guid;
- if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
+ if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod &&
mconfig->m_state > SKL_MODULE_UNINIT) {
ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
mconfig->id.module_id);
@@ -630,10 +666,76 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
return -EIO;
}
skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
+
+ ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id);
+ if (ret < 0) {
+ /* don't return; continue with other modules */
+ dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n",
+ mconfig->core_id, ret);
+ }
}
/* no modules to unload in this path, so return */
- return 0;
+ return ret;
+}
+
+/*
+ * Here, we select pipe format based on the pipe type and pipe
+ * direction to determine the current config index for the pipeline.
+ * The config index is then used to select proper module resources.
+ * Intermediate pipes currently have a fixed format hence we select the
+ * 0th configuratation by default for such pipes.
+ */
+static int
+skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig)
+{
+ struct skl_sst *ctx = skl->skl_sst;
+ struct skl_pipe *pipe = mconfig->pipe;
+ struct skl_pipe_params *params = pipe->p_params;
+ struct skl_path_config *pconfig = &pipe->configs[0];
+ struct skl_pipe_fmt *fmt = NULL;
+ bool in_fmt = false;
+ int i;
+
+ if (pipe->nr_cfgs == 0) {
+ pipe->cur_config_idx = 0;
+ return 0;
+ }
+
+ if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
+ dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n");
+ pipe->cur_config_idx = 0;
+ pipe->memory_pages = pconfig->mem_pages;
+
+ return 0;
+ }
+
+ if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
+ pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
+ (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
+ pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
+ in_fmt = true;
+
+ for (i = 0; i < pipe->nr_cfgs; i++) {
+ pconfig = &pipe->configs[i];
+ if (in_fmt)
+ fmt = &pconfig->in_fmt;
+ else
+ fmt = &pconfig->out_fmt;
+
+ if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
+ fmt->channels, fmt->freq, fmt->bps)) {
+ pipe->cur_config_idx = i;
+ pipe->memory_pages = pconfig->mem_pages;
+ dev_dbg(ctx->dev, "Using pipe config: %d\n", i);
+
+ return 0;
+ }
+ }
+
+ dev_err(ctx->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
+ params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
+ return -EINVAL;
}
/*
@@ -655,6 +757,10 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
struct skl_sst *ctx = skl->skl_sst;
struct skl_module_deferred_bind *modules;
+ ret = skl_tplg_get_pipe_config(skl, mconfig);
+ if (ret < 0)
+ return ret;
+
/* check resource available */
if (!skl_is_pipe_mcps_avail(skl, mconfig))
return -EBUSY;
@@ -758,12 +864,12 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
* check all out/in pins are in bind state.
* if so set the module param
*/
- for (i = 0; i < mcfg->max_out_queue; i++) {
+ for (i = 0; i < mcfg->module->max_output_pins; i++) {
if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
return 0;
}
- for (i = 0; i < mcfg->max_in_queue; i++) {
+ for (i = 0; i < mcfg->module->max_input_pins; i++) {
if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
return 0;
}
@@ -814,7 +920,7 @@ static int skl_tplg_module_add_deferred_bind(struct skl *skl,
int i;
/* only supported for module with static pin connection */
- for (i = 0; i < dst->max_in_queue; i++) {
+ for (i = 0; i < dst->module->max_input_pins; i++) {
struct skl_module_pin *pin = &dst->m_in_pin[i];
if (pin->is_dynamic)
@@ -925,7 +1031,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
}
}
- if (!sink)
+ if (!sink && next_sink)
return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
return 0;
@@ -1074,7 +1180,7 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
- for (i = 0; i < sink_mconfig->max_in_queue; i++) {
+ for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
if (!src_mconfig)
@@ -1185,7 +1291,7 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
- for (i = 0; i < src_mconfig->max_out_queue; i++) {
+ for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
if (!sink_mconfig)
@@ -1479,14 +1585,22 @@ int skl_tplg_update_pipe_params(struct device *dev,
struct skl_module_cfg *mconfig,
struct skl_pipe_params *params)
{
+ struct skl_module_res *res = &mconfig->module->resources[0];
+ struct skl *skl = get_skl_ctx(dev);
struct skl_module_fmt *format = NULL;
+ u8 cfg_idx = mconfig->pipe->cur_config_idx;
skl_tplg_fill_dma_id(mconfig, params);
+ mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
+ mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
+
+ if (skl->nr_modules)
+ return 0;
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
- format = &mconfig->in_fmt[0];
+ format = &mconfig->module->formats[0].inputs[0].fmt;
else
- format = &mconfig->out_fmt[0];
+ format = &mconfig->module->formats[0].outputs[0].fmt;
/* set the hw_params */
format->s_freq = params->s_freq;
@@ -1514,11 +1628,11 @@ int skl_tplg_update_pipe_params(struct device *dev,
}
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- mconfig->ibs = (format->s_freq / 1000) *
+ res->ibs = (format->s_freq / 1000) *
(format->channels) *
(format->bit_depth >> 3);
} else {
- mconfig->obs = (format->s_freq / 1000) *
+ res->obs = (format->s_freq / 1000) *
(format->channels) *
(format->bit_depth >> 3);
}
@@ -1792,6 +1906,54 @@ static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
},
};
+static int skl_tplg_fill_pipe_cfg(struct device *dev,
+ struct skl_pipe *pipe, u32 tkn,
+ u32 tkn_val, int conf_idx, int dir)
+{
+ struct skl_pipe_fmt *fmt;
+ struct skl_path_config *config;
+
+ switch (dir) {
+ case SKL_DIR_IN:
+ fmt = &pipe->configs[conf_idx].in_fmt;
+ break;
+
+ case SKL_DIR_OUT:
+ fmt = &pipe->configs[conf_idx].out_fmt;
+ break;
+
+ default:
+ dev_err(dev, "Invalid direction: %d\n", dir);
+ return -EINVAL;
+ }
+
+ config = &pipe->configs[conf_idx];
+
+ switch (tkn) {
+ case SKL_TKN_U32_CFG_FREQ:
+ fmt->freq = tkn_val;
+ break;
+
+ case SKL_TKN_U8_CFG_CHAN:
+ fmt->channels = tkn_val;
+ break;
+
+ case SKL_TKN_U8_CFG_BPS:
+ fmt->bps = tkn_val;
+ break;
+
+ case SKL_TKN_U32_PATH_MEM_PGS:
+ config->mem_pages = tkn_val;
+ break;
+
+ default:
+ dev_err(dev, "Invalid token config: %d\n", tkn);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int skl_tplg_fill_pipe_tkn(struct device *dev,
struct skl_pipe *pipe, u32 tkn,
u32 tkn_val)
@@ -1814,6 +1976,14 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev,
pipe->lp_mode = tkn_val;
break;
+ case SKL_TKN_U32_PIPE_DIRECTION:
+ pipe->direction = tkn_val;
+ break;
+
+ case SKL_TKN_U32_NUM_CONFIGS:
+ pipe->nr_cfgs = tkn_val;
+ break;
+
default:
dev_err(dev, "Token not handled %d\n", tkn);
return -EINVAL;
@@ -1930,27 +2100,9 @@ static int skl_tplg_fill_pins_info(struct device *dev,
* on the direction
*/
static int skl_tplg_fill_fmt(struct device *dev,
- struct skl_module_cfg *mconfig, u32 tkn,
- u32 value, u32 dir, u32 pin_count)
+ struct skl_module_fmt *dst_fmt,
+ u32 tkn, u32 value)
{
- struct skl_module_fmt *dst_fmt;
-
- switch (dir) {
- case SKL_DIR_IN:
- dst_fmt = mconfig->in_fmt;
- dst_fmt += pin_count;
- break;
-
- case SKL_DIR_OUT:
- dst_fmt = mconfig->out_fmt;
- dst_fmt += pin_count;
- break;
-
- default:
- dev_err(dev, "Invalid direction value\n");
- return -EINVAL;
- }
-
switch (tkn) {
case SKL_TKN_U32_FMT_CH:
dst_fmt->channels = value;
@@ -1992,6 +2144,32 @@ static int skl_tplg_fill_fmt(struct device *dev,
return 0;
}
+static int skl_tplg_widget_fill_fmt(struct device *dev,
+ struct skl_module_iface *fmt,
+ u32 tkn, u32 val, u32 dir, int fmt_idx)
+{
+ struct skl_module_fmt *dst_fmt;
+
+ if (!fmt)
+ return -EINVAL;
+
+ switch (dir) {
+ case SKL_DIR_IN:
+ dst_fmt = &fmt->inputs[fmt_idx].fmt;
+ break;
+
+ case SKL_DIR_OUT:
+ dst_fmt = &fmt->outputs[fmt_idx].fmt;
+ break;
+
+ default:
+ dev_err(dev, "Invalid direction: %d\n", dir);
+ return -EINVAL;
+ }
+
+ return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
+}
+
static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
{
@@ -2015,6 +2193,108 @@ static void skl_tplg_fill_pin_dynamic_val(
}
/*
+ * Resource table in the manifest has pin specific resources
+ * like pin and pin buffer size
+ */
+static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
+ struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+ struct skl_module_res *res, int pin_idx, int dir)
+{
+ struct skl_module_pin_resources *m_pin;
+
+ switch (dir) {
+ case SKL_DIR_IN:
+ m_pin = &res->input[pin_idx];
+ break;
+
+ case SKL_DIR_OUT:
+ m_pin = &res->output[pin_idx];
+ break;
+
+ default:
+ dev_err(dev, "Invalid pin direction: %d\n", dir);
+ return -EINVAL;
+ }
+
+ switch (tkn_elem->token) {
+ case SKL_TKN_MM_U32_RES_PIN_ID:
+ m_pin->pin_index = tkn_elem->value;
+ break;
+
+ case SKL_TKN_MM_U32_PIN_BUF:
+ m_pin->buf_size = tkn_elem->value;
+ break;
+
+ default:
+ dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Fill module specific resources from the manifest's resource
+ * table like CPS, DMA size, mem_pages.
+ */
+static int skl_tplg_fill_res_tkn(struct device *dev,
+ struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+ struct skl_module_res *res,
+ int pin_idx, int dir)
+{
+ int ret, tkn_count = 0;
+
+ if (!res)
+ return -EINVAL;
+
+ switch (tkn_elem->token) {
+ case SKL_TKN_MM_U32_CPS:
+ res->cps = tkn_elem->value;
+ break;
+
+ case SKL_TKN_MM_U32_DMA_SIZE:
+ res->dma_buffer_size = tkn_elem->value;
+ break;
+
+ case SKL_TKN_MM_U32_CPC:
+ res->cpc = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U32_MEM_PAGES:
+ res->is_pages = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U32_OBS:
+ res->obs = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U32_IBS:
+ res->ibs = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U32_MAX_MCPS:
+ res->cps = tkn_elem->value;
+ break;
+
+ case SKL_TKN_MM_U32_RES_PIN_ID:
+ case SKL_TKN_MM_U32_PIN_BUF:
+ ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
+ pin_idx, dir);
+ if (ret < 0)
+ return ret;
+ break;
+
+ default:
+ dev_err(dev, "Not a res type token: %d", tkn_elem->token);
+ return -EINVAL;
+
+ }
+ tkn_count++;
+
+ return tkn_count;
+}
+
+/*
* Parse tokens to fill up the module private data
*/
static int skl_tplg_get_token(struct device *dev,
@@ -2024,49 +2304,54 @@ static int skl_tplg_get_token(struct device *dev,
int tkn_count = 0;
int ret;
static int is_pipe_exists;
- static int pin_index, dir;
+ static int pin_index, dir, conf_idx;
+ struct skl_module_iface *iface = NULL;
+ struct skl_module_res *res = NULL;
+ int res_idx = mconfig->res_idx;
+ int fmt_idx = mconfig->fmt_idx;
+
+ /*
+ * If the manifest structure contains no modules, fill all
+ * the module data to 0th index.
+ * res_idx and fmt_idx are default set to 0.
+ */
+ if (skl->nr_modules == 0) {
+ res = &mconfig->module->resources[res_idx];
+ iface = &mconfig->module->formats[fmt_idx];
+ }
if (tkn_elem->token > SKL_TKN_MAX)
return -EINVAL;
switch (tkn_elem->token) {
case SKL_TKN_U8_IN_QUEUE_COUNT:
- mconfig->max_in_queue = tkn_elem->value;
- mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue *
- sizeof(*mconfig->m_in_pin),
- GFP_KERNEL);
- if (!mconfig->m_in_pin)
- return -ENOMEM;
-
+ mconfig->module->max_input_pins = tkn_elem->value;
break;
case SKL_TKN_U8_OUT_QUEUE_COUNT:
- mconfig->max_out_queue = tkn_elem->value;
- mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue *
- sizeof(*mconfig->m_out_pin),
- GFP_KERNEL);
-
- if (!mconfig->m_out_pin)
- return -ENOMEM;
-
+ mconfig->module->max_output_pins = tkn_elem->value;
break;
case SKL_TKN_U8_DYN_IN_PIN:
if (!mconfig->m_in_pin)
+ mconfig->m_in_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
+ sizeof(*mconfig->m_in_pin), GFP_KERNEL);
+ if (!mconfig->m_in_pin)
return -ENOMEM;
- skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin,
- mconfig->max_in_queue, tkn_elem->value);
-
+ skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
+ tkn_elem->value);
break;
case SKL_TKN_U8_DYN_OUT_PIN:
if (!mconfig->m_out_pin)
+ mconfig->m_out_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
+ sizeof(*mconfig->m_in_pin), GFP_KERNEL);
+ if (!mconfig->m_out_pin)
return -ENOMEM;
- skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin,
- mconfig->max_out_queue, tkn_elem->value);
-
+ skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
+ tkn_elem->value);
break;
case SKL_TKN_U8_TIME_SLOT:
@@ -2094,19 +2379,13 @@ static int skl_tplg_get_token(struct device *dev,
break;
case SKL_TKN_U32_MEM_PAGES:
- mconfig->mem_pages = tkn_elem->value;
- break;
-
case SKL_TKN_U32_MAX_MCPS:
- mconfig->mcps = tkn_elem->value;
- break;
-
case SKL_TKN_U32_OBS:
- mconfig->obs = tkn_elem->value;
- break;
-
case SKL_TKN_U32_IBS:
- mconfig->ibs = tkn_elem->value;
+ ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, dir, pin_index);
+ if (ret < 0)
+ return ret;
+
break;
case SKL_TKN_U32_VBUS_ID:
@@ -2139,10 +2418,16 @@ static int skl_tplg_get_token(struct device *dev,
break;
+ case SKL_TKN_U32_PIPE_CONFIG_ID:
+ conf_idx = tkn_elem->value;
+ break;
+
case SKL_TKN_U32_PIPE_CONN_TYPE:
case SKL_TKN_U32_PIPE_PRIORITY:
case SKL_TKN_U32_PIPE_MEM_PGS:
case SKL_TKN_U32_PMODE:
+ case SKL_TKN_U32_PIPE_DIRECTION:
+ case SKL_TKN_U32_NUM_CONFIGS:
if (is_pipe_exists) {
ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
tkn_elem->token, tkn_elem->value);
@@ -2152,6 +2437,27 @@ static int skl_tplg_get_token(struct device *dev,
break;
+ case SKL_TKN_U32_PATH_MEM_PGS:
+ case SKL_TKN_U32_CFG_FREQ:
+ case SKL_TKN_U8_CFG_CHAN:
+ case SKL_TKN_U8_CFG_BPS:
+ if (mconfig->pipe->nr_cfgs) {
+ ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
+ tkn_elem->token, tkn_elem->value,
+ conf_idx, dir);
+ if (ret < 0)
+ return ret;
+ }
+ break;
+
+ case SKL_TKN_CFG_MOD_RES_ID:
+ mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
+ break;
+
+ case SKL_TKN_CFG_MOD_FMT_ID:
+ mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
+ break;
+
/*
* SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
* direction and the pin count. The first four bits represent
@@ -2172,7 +2478,7 @@ static int skl_tplg_get_token(struct device *dev,
case SKL_TKN_U32_FMT_INTERLEAVE:
case SKL_TKN_U32_FMT_SAMPLE_TYPE:
case SKL_TKN_U32_FMT_CH_MAP:
- ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token,
+ ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
tkn_elem->value, dir, pin_index);
if (ret < 0)
@@ -2397,11 +2703,11 @@ static void skl_clear_pin_config(struct snd_soc_platform *platform,
strlen(platform->component.name))) {
mconfig = w->priv;
pipe = mconfig->pipe;
- for (i = 0; i < mconfig->max_in_queue; i++) {
+ for (i = 0; i < mconfig->module->max_input_pins; i++) {
mconfig->m_in_pin[i].in_use = false;
mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
}
- for (i = 0; i < mconfig->max_out_queue; i++) {
+ for (i = 0; i < mconfig->module->max_output_pins; i++) {
mconfig->m_out_pin[i].in_use = false;
mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
}
@@ -2460,6 +2766,13 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
if (!mconfig)
return -ENOMEM;
+ if (skl->nr_modules == 0) {
+ mconfig->module = devm_kzalloc(bus->dev,
+ sizeof(*mconfig->module), GFP_KERNEL);
+ if (!mconfig->module)
+ return -ENOMEM;
+ }
+
w->priv = mconfig;
/*
@@ -2602,13 +2915,13 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
str_elem->string,
ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
ref_count++;
- tkn_count++;
break;
default:
dev_err(dev, "Not a string token %d\n", str_elem->token);
break;
}
+ tkn_count++;
return tkn_count;
}
@@ -2634,26 +2947,236 @@ static int skl_tplg_get_str_tkn(struct device *dev,
return tkn_count;
}
+static int skl_tplg_manifest_fill_fmt(struct device *dev,
+ struct skl_module_iface *fmt,
+ struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+ u32 dir, int fmt_idx)
+{
+ struct skl_module_pin_fmt *dst_fmt;
+ struct skl_module_fmt *mod_fmt;
+ int ret;
+
+ if (!fmt)
+ return -EINVAL;
+
+ switch (dir) {
+ case SKL_DIR_IN:
+ dst_fmt = &fmt->inputs[fmt_idx];
+ break;
+
+ case SKL_DIR_OUT:
+ dst_fmt = &fmt->outputs[fmt_idx];
+ break;
+
+ default:
+ dev_err(dev, "Invalid direction: %d\n", dir);
+ return -EINVAL;
+ }
+
+ mod_fmt = &dst_fmt->fmt;
+
+ switch (tkn_elem->token) {
+ case SKL_TKN_MM_U32_INTF_PIN_ID:
+ dst_fmt->id = tkn_elem->value;
+ break;
+
+ default:
+ ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
+ tkn_elem->value);
+ if (ret < 0)
+ return ret;
+ break;
+ }
+
+ return 0;
+}
+
+static int skl_tplg_fill_mod_info(struct device *dev,
+ struct snd_soc_tplg_vendor_value_elem *tkn_elem,
+ struct skl_module *mod)
+{
+
+ if (!mod)
+ return -EINVAL;
+
+ switch (tkn_elem->token) {
+ case SKL_TKN_U8_IN_PIN_TYPE:
+ mod->input_pin_type = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U8_OUT_PIN_TYPE:
+ mod->output_pin_type = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U8_IN_QUEUE_COUNT:
+ mod->max_input_pins = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U8_OUT_QUEUE_COUNT:
+ mod->max_output_pins = tkn_elem->value;
+ break;
+
+ case SKL_TKN_MM_U8_NUM_RES:
+ mod->nr_resources = tkn_elem->value;
+ break;
+
+ case SKL_TKN_MM_U8_NUM_INTF:
+ mod->nr_interfaces = tkn_elem->value;
+ break;
+
+ default:
+ dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
static int skl_tplg_get_int_tkn(struct device *dev,
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
struct skl *skl)
{
- int tkn_count = 0;
+ int tkn_count = 0, ret;
+ static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
+ struct skl_module_res *res = NULL;
+ struct skl_module_iface *fmt = NULL;
+ struct skl_module *mod = NULL;
+ int i;
+
+ if (skl->modules) {
+ mod = skl->modules[mod_idx];
+ res = &mod->resources[res_val_idx];
+ fmt = &mod->formats[intf_val_idx];
+ }
switch (tkn_elem->token) {
case SKL_TKN_U32_LIB_COUNT:
skl->skl_sst->lib_count = tkn_elem->value;
- tkn_count++;
+ break;
+
+ case SKL_TKN_U8_NUM_MOD:
+ skl->nr_modules = tkn_elem->value;
+ skl->modules = devm_kcalloc(dev, skl->nr_modules,
+ sizeof(*skl->modules), GFP_KERNEL);
+ if (!skl->modules)
+ return -ENOMEM;
+
+ for (i = 0; i < skl->nr_modules; i++) {
+ skl->modules[i] = devm_kzalloc(dev,
+ sizeof(struct skl_module), GFP_KERNEL);
+ if (!skl->modules[i])
+ return -ENOMEM;
+ }
+ break;
+
+ case SKL_TKN_MM_U8_MOD_IDX:
+ mod_idx = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U8_IN_PIN_TYPE:
+ case SKL_TKN_U8_OUT_PIN_TYPE:
+ case SKL_TKN_U8_IN_QUEUE_COUNT:
+ case SKL_TKN_U8_OUT_QUEUE_COUNT:
+ case SKL_TKN_MM_U8_NUM_RES:
+ case SKL_TKN_MM_U8_NUM_INTF:
+ ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
+ if (ret < 0)
+ return ret;
+ break;
+
+ case SKL_TKN_U32_DIR_PIN_COUNT:
+ dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
+ pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
+ break;
+
+ case SKL_TKN_MM_U32_RES_ID:
+ if (!res)
+ return -EINVAL;
+
+ res->id = tkn_elem->value;
+ res_val_idx = tkn_elem->value;
+ break;
+
+ case SKL_TKN_MM_U32_FMT_ID:
+ if (!fmt)
+ return -EINVAL;
+
+ fmt->fmt_idx = tkn_elem->value;
+ intf_val_idx = tkn_elem->value;
+ break;
+
+ case SKL_TKN_MM_U32_CPS:
+ case SKL_TKN_MM_U32_DMA_SIZE:
+ case SKL_TKN_MM_U32_CPC:
+ case SKL_TKN_U32_MEM_PAGES:
+ case SKL_TKN_U32_OBS:
+ case SKL_TKN_U32_IBS:
+ case SKL_TKN_MM_U32_RES_PIN_ID:
+ case SKL_TKN_MM_U32_PIN_BUF:
+ ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
+ if (ret < 0)
+ return ret;
+
+ break;
+
+ case SKL_TKN_MM_U32_NUM_IN_FMT:
+ if (!fmt)
+ return -EINVAL;
+
+ res->nr_input_pins = tkn_elem->value;
+ break;
+
+ case SKL_TKN_MM_U32_NUM_OUT_FMT:
+ if (!fmt)
+ return -EINVAL;
+
+ res->nr_output_pins = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U32_FMT_CH:
+ case SKL_TKN_U32_FMT_FREQ:
+ case SKL_TKN_U32_FMT_BIT_DEPTH:
+ case SKL_TKN_U32_FMT_SAMPLE_SIZE:
+ case SKL_TKN_U32_FMT_CH_CONFIG:
+ case SKL_TKN_U32_FMT_INTERLEAVE:
+ case SKL_TKN_U32_FMT_SAMPLE_TYPE:
+ case SKL_TKN_U32_FMT_CH_MAP:
+ case SKL_TKN_MM_U32_INTF_PIN_ID:
+ ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
+ dir, pin_idx);
+ if (ret < 0)
+ return ret;
break;
default:
dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
return -EINVAL;
}
+ tkn_count++;
return tkn_count;
}
+static int skl_tplg_get_manifest_uuid(struct device *dev,
+ struct skl *skl,
+ struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
+{
+ static int ref_count;
+ struct skl_module *mod;
+
+ if (uuid_tkn->token == SKL_TKN_UUID) {
+ mod = skl->modules[ref_count];
+ memcpy(&mod->uuid, &uuid_tkn->uuid, sizeof(uuid_tkn->uuid));
+ ref_count++;
+ } else {
+ dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/*
* Fill the manifest structure by parsing the tokens based on the
* type.
@@ -2686,7 +3209,11 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
continue;
case SND_SOC_TPLG_TUPLE_TYPE_UUID:
- dev_warn(dev, "no uuid tokens for skl tplf manifest\n");
+ ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid);
+ if (ret < 0)
+ return ret;
+
+ tuple_size += sizeof(*array->uuid);
continue;
default:
@@ -2703,14 +3230,12 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
tkn_count = tkn_count + ret;
tkn_elem++;
- tuple_size += tkn_count *
- sizeof(struct snd_soc_tplg_vendor_value_elem);
- break;
}
+ tuple_size += (tkn_count * sizeof(*tkn_elem));
tkn_count = 0;
}
- return 0;
+ return off;
}
/*
@@ -2733,11 +3258,10 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
num_blocks = ret;
off += array->size;
- array = (struct snd_soc_tplg_vendor_array *)
- (manifest->priv.data + off);
-
/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
while (num_blocks > 0) {
+ array = (struct snd_soc_tplg_vendor_array *)
+ (manifest->priv.data + off);
ret = skl_tplg_get_desc_blocks(dev, array);
if (ret < 0)
@@ -2771,6 +3295,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
} else {
return -EINVAL;
}
+ off += ret;
}
return 0;
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index c25e8868b84e..2717db92036b 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -44,6 +44,13 @@
#define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF
#define SKL_MIC_SEL_SWITCH 0x3
+#define SKL_OUTPUT_PIN 0
+#define SKL_INPUT_PIN 1
+#define SKL_MAX_PATH_CONFIGS 8
+#define SKL_MAX_MODULES_IN_PIPE 8
+#define SKL_MAX_MODULE_FORMATS 32
+#define SKL_MAX_MODULE_RESOURCES 32
+
enum skl_channel_index {
SKL_CHANNEL_LEFT = 0,
SKL_CHANNEL_RIGHT = 1,
@@ -131,6 +138,11 @@ struct skl_cpr_cfg {
struct skl_cpr_gtw_cfg gtw_cfg;
} __packed;
+struct skl_cpr_pin_fmt {
+ u32 sink_id;
+ struct skl_audio_data_format src_fmt;
+ struct skl_audio_data_format dst_fmt;
+} __packed;
struct skl_src_module_cfg {
struct skl_base_cfg base_cfg;
@@ -214,6 +226,7 @@ struct skl_kpb_params {
};
struct skl_module_inst_id {
+ uuid_le mod_uuid;
int module_id;
u32 instance_id;
int pvt_id;
@@ -266,6 +279,23 @@ struct skl_pipe_params {
unsigned int link_bps;
};
+struct skl_pipe_fmt {
+ u32 freq;
+ u8 channels;
+ u8 bps;
+};
+
+struct skl_pipe_mcfg {
+ u8 res_idx;
+ u8 fmt_idx;
+};
+
+struct skl_path_config {
+ u8 mem_pages;
+ struct skl_pipe_fmt in_fmt;
+ struct skl_pipe_fmt out_fmt;
+};
+
struct skl_pipe {
u8 ppl_id;
u8 pipe_priority;
@@ -274,6 +304,10 @@ struct skl_pipe {
u8 lp_mode;
struct skl_pipe_params *p_params;
enum skl_pipe_state state;
+ u8 direction;
+ u8 cur_config_idx;
+ u8 nr_cfgs;
+ struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
struct list_head w_list;
bool passthru;
};
@@ -292,9 +326,57 @@ enum d0i3_capability {
SKL_D0I3_NON_STREAMING = 2,
};
+struct skl_module_pin_fmt {
+ u8 id;
+ struct skl_module_fmt fmt;
+};
+
+struct skl_module_iface {
+ u8 fmt_idx;
+ u8 nr_in_fmt;
+ u8 nr_out_fmt;
+ struct skl_module_pin_fmt inputs[MAX_IN_QUEUE];
+ struct skl_module_pin_fmt outputs[MAX_OUT_QUEUE];
+};
+
+struct skl_module_pin_resources {
+ u8 pin_index;
+ u32 buf_size;
+};
+
+struct skl_module_res {
+ u8 id;
+ u32 is_pages;
+ u32 cps;
+ u32 ibs;
+ u32 obs;
+ u32 dma_buffer_size;
+ u32 cpc;
+ u8 nr_input_pins;
+ u8 nr_output_pins;
+ struct skl_module_pin_resources input[MAX_IN_QUEUE];
+ struct skl_module_pin_resources output[MAX_OUT_QUEUE];
+};
+
+struct skl_module {
+ uuid_le uuid;
+ u8 loadable;
+ u8 input_pin_type;
+ u8 output_pin_type;
+ u8 max_input_pins;
+ u8 max_output_pins;
+ u8 nr_resources;
+ u8 nr_interfaces;
+ struct skl_module_res resources[SKL_MAX_MODULE_RESOURCES];
+ struct skl_module_iface formats[SKL_MAX_MODULE_FORMATS];
+};
+
struct skl_module_cfg {
u8 guid[16];
struct skl_module_inst_id id;
+ struct skl_module *module;
+ int res_idx;
+ int fmt_idx;
u8 domain;
bool homogenous_inputs;
bool homogenous_outputs;
@@ -329,6 +411,7 @@ struct skl_module_cfg {
enum skl_module_state m_state;
struct skl_pipe *pipe;
struct skl_specific_cfg formats_config;
+ struct skl_pipe_mcfg mod_cfg[SKL_MAX_MODULES_IN_PIPE];
};
struct skl_algo_data {
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 334917ee41cf..f94b484abb99 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -415,7 +415,7 @@ static int skl_free(struct hdac_ext_bus *ebus)
snd_hdac_ext_stop_streams(ebus);
if (bus->irq >= 0)
- free_irq(bus->irq, (void *)bus);
+ free_irq(bus->irq, (void *)ebus);
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_stream_free_all(ebus);
snd_hdac_link_free_all(ebus);
@@ -528,7 +528,7 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr)
}
/* Codec initialization */
-static int skl_codec_create(struct hdac_ext_bus *ebus)
+static void skl_codec_create(struct hdac_ext_bus *ebus)
{
struct hdac_bus *bus = ebus_to_hbus(ebus);
int c, max_slots;
@@ -559,8 +559,6 @@ static int skl_codec_create(struct hdac_ext_bus *ebus)
}
}
}
-
- return 0;
}
static const struct hdac_bus_ops bus_core_ops = {
@@ -612,9 +610,7 @@ static void skl_probe_work(struct work_struct *work)
dev_info(bus->dev, "no hda codecs found!\n");
/* create codec instances */
- err = skl_codec_create(ebus);
- if (err < 0)
- goto out_err;
+ skl_codec_create(ebus);
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
err = snd_hdac_display_power(bus, false);
@@ -702,6 +698,8 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
return -ENXIO;
}
+ skl_init_chip(bus, true);
+
snd_hdac_bus_parse_capabilities(bus);
if (skl_acquire_irq(ebus, 0) < 0)
@@ -879,12 +877,12 @@ static void skl_remove(struct pci_dev *pci)
static struct sst_codecs skl_codecs = {
.num_codecs = 1,
- .codecs = {"NAU88L25"}
+ .codecs = {"10508825"}
};
static struct sst_codecs kbl_codecs = {
.num_codecs = 1,
- .codecs = {"NAU88L25"}
+ .codecs = {"10508825"}
};
static struct sst_codecs bxt_codecs = {
@@ -941,6 +939,7 @@ static struct sst_acpi_mach sst_bxtp_devdata[] = {
.machine_quirk = sst_acpi_codec_list,
.quirk_data = &bxt_codecs,
},
+ {}
};
static struct sst_acpi_mach sst_kbl_devdata[] = {
@@ -981,6 +980,11 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
.quirk_data = &kbl_poppy_codecs,
.pdata = &skl_dmic_data
},
+ {
+ .id = "10EC5663",
+ .drv_name = "kbl_rt5663",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ },
{}
};
@@ -991,6 +995,15 @@ static struct sst_acpi_mach sst_glk_devdata[] = {
.drv_name = "glk_alc298s_i2s",
.fw_filename = "intel/dsp_fw_glk.bin",
},
+ {}
+};
+
+static const struct sst_acpi_mach sst_cnl_devdata[] = {
+ {
+ .id = "INT34C2",
+ .drv_name = "cnl_rt274",
+ .fw_filename = "intel/dsp_fw_cnl.bin",
+ },
};
/* PCI IDs */
@@ -1007,6 +1020,9 @@ static const struct pci_device_id skl_ids[] = {
/* GLK */
{ PCI_DEVICE(0x8086, 0x3198),
.driver_data = (unsigned long)&sst_glk_devdata},
+ /* CNL */
+ { PCI_DEVICE(0x8086, 0x9dc8),
+ .driver_data = (unsigned long)&sst_cnl_devdata},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, skl_ids);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index a6b134b4c037..8d9d6899f761 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -71,6 +71,8 @@ struct skl {
struct work_struct probe_work;
struct skl_debug *debugfs;
+ u8 nr_modules;
+ struct skl_module **modules;
};
#define skl_to_ebus(s) (&(s)->ebus)
@@ -90,6 +92,7 @@ struct skl_machine_pdata {
struct skl_dsp_ops {
int id;
+ unsigned int num_cores;
struct skl_dsp_loader_ops (*loader_ops)(void);
int (*init)(struct device *dev, void __iomem *mmio_base,
int irq, const char *fw_name,
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 794a3499e567..99394c036998 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -133,6 +133,7 @@ static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf, ctrl;
+ int ret;
if (dai->active)
return 0;
@@ -141,7 +142,9 @@ static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
ctrl |= JZ_AIC_CTRL_FLUSH;
jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
- clk_prepare_enable(i2s->clk_i2s);
+ ret = clk_prepare_enable(i2s->clk_i2s);
+ if (ret)
+ return ret;
conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
conf |= JZ_AIC_CONF_ENABLE;
@@ -352,11 +355,18 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai)
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
+ int ret;
- clk_prepare_enable(i2s->clk_aic);
+ ret = clk_prepare_enable(i2s->clk_aic);
+ if (ret)
+ return ret;
if (dai->active) {
- clk_prepare_enable(i2s->clk_i2s);
+ ret = clk_prepare_enable(i2s->clk_i2s);
+ if (ret) {
+ clk_disable_unprepare(i2s->clk_aic);
+ return ret;
+ }
conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
conf |= JZ_AIC_CONF_ENABLE;
@@ -387,8 +397,11 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
+ int ret;
- clk_prepare_enable(i2s->clk_aic);
+ ret = clk_prepare_enable(i2s->clk_aic);
+ if (ret)
+ return ret;
jz4740_i2c_init_pcm_config(i2s);
snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index dafd22e874e9..cf23af159acf 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -27,7 +27,7 @@ static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
return snd_soc_dai_get_drvdata(soc_runtime->cpu_dai);
}
-static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
+static const struct snd_pcm_hardware kirkwood_dma_snd_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 3a36d60e1785..105a73cc5158 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -538,10 +538,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
int err;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(&pdev->dev, "allocation failed\n");
+ if (!priv)
return -ENOMEM;
- }
+
dev_set_drvdata(&pdev->dev, priv);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -550,9 +549,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
return PTR_ERR(priv->io);
priv->irq = platform_get_irq(pdev, 0);
- if (priv->irq <= 0) {
- dev_err(&pdev->dev, "platform_get_irq failed\n");
- return -ENXIO;
+ if (priv->irq < 0) {
+ dev_err(&pdev->dev, "platform_get_irq failed: %d\n", priv->irq);
+ return priv->irq;
}
if (np) {
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
index b815ecc6bbf6..affa7fb25dd9 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
@@ -75,7 +75,7 @@ int mt2701_init_clock(struct mtk_base_afe *afe)
for (i = 0; i < MT2701_CLOCK_NUM; i++) {
afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
- if (IS_ERR(aud_clks[i])) {
+ if (IS_ERR(afe_priv->clocks[i])) {
dev_warn(afe->dev, "%s devm_clk_get %s fail\n",
__func__, aud_clks[i]);
return PTR_ERR(aud_clks[i]);
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index bc5d4db94de6..8fda182f849b 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -595,7 +595,7 @@ static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = {
};
/* MRG BE DAIs */
-static struct snd_soc_dai_ops mt2701_btmrg_ops = {
+static const struct snd_soc_dai_ops mt2701_btmrg_ops = {
.startup = mt2701_btmrg_startup,
.shutdown = mt2701_btmrg_shutdown,
.hw_params = mt2701_btmrg_hw_params,
@@ -1496,14 +1496,12 @@ static int mt2701_afe_runtime_resume(struct device *dev)
static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
{
- int ret, i;
- unsigned int irq_id;
struct mtk_base_afe *afe;
struct mt2701_afe_private *afe_priv;
struct resource *res;
struct device *dev;
+ int i, irq_id, ret;
- ret = 0;
afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
if (!afe)
return -ENOMEM;
@@ -1516,11 +1514,12 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
afe->dev = &pdev->dev;
dev = afe->dev;
- irq_id = platform_get_irq(pdev, 0);
- if (!irq_id) {
- dev_err(dev, "%s no irq found\n", dev->of_node->name);
- return -ENXIO;
+ irq_id = platform_get_irq_byname(pdev, "asys");
+ if (irq_id < 0) {
+ dev_err(dev, "unable to get ASYS IRQ\n");
+ return irq_id;
}
+
ret = devm_request_irq(dev, irq_id, mt2701_asys_isr,
IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
if (ret) {
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index 5e383eb456a4..99c15219dbc8 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -222,7 +222,6 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
mt8173_rt5650_rt5514_codecs[1].of_node;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index fed1f15a39c2..42de84ca8c84 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -279,7 +279,6 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
}
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index a78470839b65..e69c141d8ed4 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -311,7 +311,6 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
return -EINVAL;
}
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index b42f301c6b96..156aa7c00787 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -125,7 +125,9 @@ static int mxs_saif_set_clk(struct mxs_saif *saif,
*
* If MCLK is not used, we just set saif clk to 512*fs.
*/
- clk_prepare_enable(master_saif->clk);
+ ret = clk_prepare_enable(master_saif->clk);
+ if (ret)
+ return ret;
if (master_saif->mclk_in_use) {
switch (mclk / rate) {
@@ -388,6 +390,7 @@ static int mxs_saif_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
/* clear error status to 0 for each re-open */
saif->fifo_underrun = 0;
@@ -401,7 +404,9 @@ static int mxs_saif_startup(struct snd_pcm_substream *substream,
__raw_writel(BM_SAIF_CTRL_CLKGATE,
saif->base + SAIF_CTRL + MXS_CLR_ADDR);
- clk_prepare(saif->clk);
+ ret = clk_prepare(saif->clk);
+ if (ret)
+ return ret;
return 0;
}
@@ -468,7 +473,9 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
if (ret)
return ret;
- clk_prepare(master_saif->clk);
+ ret = clk_prepare(master_saif->clk);
+ if (ret)
+ return ret;
}
scr = __raw_readl(saif->base + SAIF_CTRL);
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index a96276e77332..2ed3240cc682 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -140,7 +140,6 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
}
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
index 2cca055fd806..bd6dfa218d59 100644
--- a/sound/soc/nuc900/nuc900-pcm.c
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -271,7 +271,7 @@ static int nuc900_dma_mmap(struct snd_pcm_substream *substream,
runtime->dma_addr, runtime->dma_bytes);
}
-static struct snd_pcm_ops nuc900_dma_ops = {
+static const struct snd_pcm_ops nuc900_dma_ops = {
.open = nuc900_dma_open,
.close = nuc900_dma_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -299,7 +299,7 @@ static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static struct snd_soc_platform_driver nuc900_soc_platform = {
+static const struct snd_soc_platform_driver nuc900_soc_platform = {
.ops = &nuc900_dma_ops,
.pcm_new = nuc900_dma_new,
};
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 16cc95fa4573..6c49f3d6fd96 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -513,15 +513,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int ams_delta_card_remove(struct snd_soc_card *card)
-{
- snd_soc_jack_free_gpios(&ams_delta_hook_switch,
- ARRAY_SIZE(ams_delta_hook_switch_gpios),
- ams_delta_hook_switch_gpios);
-
- return 0;
-}
-
/* DAI glue - connects codec <--> CPU */
static struct snd_soc_dai_link ams_delta_dai_link = {
.name = "CX20442",
@@ -540,7 +531,6 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
static struct snd_soc_card ams_delta_audio_card = {
.name = "AMS_DELTA",
.owner = THIS_MODULE,
- .remove = ams_delta_card_remove,
.dai_link = &ams_delta_dai_link,
.num_links = 1,
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 94e9ff791f3a..aca2c43d0f03 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -162,7 +162,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
runtime->dma_addr, runtime->dma_bytes);
}
-static struct snd_pcm_ops omap_pcm_ops = {
+static const struct snd_pcm_ops omap_pcm_ops = {
.open = omap_pcm_open,
.close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl,
@@ -243,7 +243,7 @@ out:
return ret;
}
-static struct snd_soc_platform_driver omap_soc_platform = {
+static const struct snd_soc_platform_driver omap_soc_platform = {
.ops = &omap_pcm_ops,
.pcm_new = omap_pcm_new,
.pcm_free = omap_pcm_free_dma_buffers,
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
index a24b0dedabb9..cccc316743fa 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/omap/omap-twl4030.c
@@ -208,18 +208,6 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-static int omap_twl4030_card_remove(struct snd_soc_card *card)
-{
- struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
-
- if (priv->jack_detect > 0)
- snd_soc_jack_free_gpios(&priv->hs_jack,
- ARRAY_SIZE(hs_jack_gpios),
- hs_jack_gpios);
-
- return 0;
-}
-
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
{
@@ -247,7 +235,6 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
/* Audio machine driver */
static struct snd_soc_card omap_twl4030_card = {
.owner = THIS_MODULE,
- .remove = omap_twl4030_card_remove,
.dai_link = omap_twl4030_dai_links,
.num_links = ARRAY_SIZE(omap_twl4030_dai_links),
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 3aeb65feaea1..57448bd5ad77 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -311,14 +311,6 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
return err;
}
-static int rx51_card_remove(struct snd_soc_card *card)
-{
- snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
- rx51_av_jack_gpios);
-
- return 0;
-}
-
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link rx51_dai[] = {
{
@@ -361,7 +353,6 @@ static struct snd_soc_codec_conf rx51_codec_conf[] = {
static struct snd_soc_card rx51_sound_card = {
.name = "RX-51",
.owner = THIS_MODULE,
- .remove = rx51_card_remove,
.dai_link = rx51_dai,
.num_links = ARRAY_SIZE(rx51_dai),
.aux_dev = rx51_aux_dev,
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 960744e46edc..484ab3c2ad67 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -1,6 +1,7 @@
config SND_PXA2XX_SOC
tristate "SoC Audio for the Intel PXA2xx chip"
depends on ARCH_PXA || COMPILE_TEST
+ depends on HAS_DMA
select SND_PXA2XX_LIB
help
Say Y or M if you want to add support for codecs attached to
diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c
index a9ac881c2e14..6cdef5d4954e 100644
--- a/sound/soc/pxa/hx4700.c
+++ b/sound/soc/pxa/hx4700.c
@@ -138,13 +138,6 @@ static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
return err;
}
-static int hx4700_card_remove(struct snd_soc_card *card)
-{
- snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
-
- return 0;
-}
-
/* hx4700 digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link hx4700_dai = {
.name = "ak4641",
@@ -163,7 +156,6 @@ static struct snd_soc_dai_link hx4700_dai = {
static struct snd_soc_card snd_soc_card_hx4700 = {
.name = "iPAQ hx4700",
.owner = THIS_MODULE,
- .remove = hx4700_card_remove,
.dai_link = &hx4700_dai,
.num_links = 1,
.dapm_widgets = hx4700_dapm_widgets,
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 5b5f1a442891..624d9bd5dadd 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -131,7 +131,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
}
-static struct snd_pcm_ops mmp_pcm_ops = {
+static const struct snd_pcm_ops mmp_pcm_ops = {
.open = mmp_pcm_open,
.close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl,
@@ -211,7 +211,7 @@ err:
return ret;
}
-static struct snd_soc_platform_driver mmp_soc_platform = {
+static const struct snd_soc_platform_driver mmp_soc_platform = {
.ops = &mmp_pcm_ops,
.pcm_new = mmp_pcm_new,
.pcm_free = mmp_pcm_free_dma_buffers,
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index 9cc35012e6e5..64b85e30c1f8 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -380,7 +380,7 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai)
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops mmp_sspa_dai_ops = {
+static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
.startup = mmp_sspa_startup,
.shutdown = mmp_sspa_shutdown,
.trigger = mmp_sspa_trigger,
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index b51d7a0755d5..e64958d8bff0 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -45,7 +45,7 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
return 0;
}
-static struct snd_pcm_ops pxa2xx_pcm_ops = {
+static const struct snd_pcm_ops pxa2xx_pcm_ops = {
.open = __pxa2xx_pcm_open,
.close = __pxa2xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -84,7 +84,7 @@ static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-static struct snd_soc_platform_driver pxa2xx_soc_platform = {
+static const struct snd_soc_platform_driver pxa2xx_soc_platform = {
.ops = &pxa2xx_pcm_ops,
.pcm_new = pxa2xx_soc_pcm_new,
.pcm_free = pxa2xx_pcm_free_dma_buffers,
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index d084d7468299..d49adc822a11 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -21,12 +21,16 @@
#include <linux/platform_device.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/jack.h>
#include <sound/soc.h>
+#include <uapi/linux/input-event-codes.h>
#include <dt-bindings/sound/apq8016-lpass.h>
struct apq8016_sbc_data {
void __iomem *mic_iomux;
void __iomem *spkr_iomux;
+ struct snd_soc_jack jack;
+ bool jack_setup;
struct snd_soc_dai_link dai_link[]; /* dynamically allocated */
};
@@ -34,13 +38,16 @@ struct apq8016_sbc_data {
#define MIC_CTRL_QUA_WS_SLAVE_SEL_10 BIT(17)
#define MIC_CTRL_TLMM_SCLK_EN BIT(1)
#define SPKR_CTL_PRI_WS_SLAVE_SEL_11 (BIT(17) | BIT(16))
+#define DEFAULT_MCLK_RATE 9600000
static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_codec *codec;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_card *card = rtd->card;
struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card);
- int rval = 0;
+ int i, rval;
switch (cpu_dai->id) {
case MI2S_PRIMARY:
@@ -63,12 +70,54 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
default:
dev_err(card->dev, "unsupported cpu dai configuration\n");
- rval = -EINVAL;
- break;
+ return -EINVAL;
+
+ }
+
+ if (!pdata->jack_setup) {
+ struct snd_jack *jack;
+
+ rval = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4,
+ &pdata->jack, NULL, 0);
+
+ if (rval < 0) {
+ dev_err(card->dev, "Unable to add Headphone Jack\n");
+ return rval;
+ }
+ jack = pdata->jack.jack;
+
+ snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_MEDIA);
+ snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ pdata->jack_setup = true;
+ }
+
+ for (i = 0 ; i < dai_link->num_codecs; i++) {
+ struct snd_soc_dai *dai = rtd->codec_dais[i];
+
+ codec = dai->codec;
+ /* Set default mclk for internal codec */
+ rval = snd_soc_codec_set_sysclk(codec, 0, 0, DEFAULT_MCLK_RATE,
+ SND_SOC_CLOCK_IN);
+ if (rval != 0 && rval != -ENOTSUPP) {
+ dev_warn(card->dev, "Failed to set mclk: %d\n", rval);
+ return rval;
+ }
+ rval = snd_soc_codec_set_jack(codec, &pdata->jack, NULL);
+ if (rval != 0 && rval != -ENOTSUPP) {
+ dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+ return rval;
+ }
}
- return rval;
+ return 0;
}
static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
@@ -191,7 +240,6 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev)
if (IS_ERR(data->spkr_iomux))
return PTR_ERR(data->spkr_iomux);
- platform_set_drvdata(pdev, data);
snd_soc_card_set_drvdata(card, data);
return devm_snd_soc_register_card(&pdev->dev, card);
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 7aabf08de3d4..e1945e1772cd 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -32,7 +32,7 @@ struct lpass_pcm_data {
#define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024)
#define LPASS_PLATFORM_PERIODS 2
-static struct snd_pcm_hardware lpass_platform_pcm_hardware = {
+static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
@@ -557,7 +557,7 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
}
}
-static struct snd_soc_platform_driver lpass_platform_driver = {
+static const struct snd_soc_platform_driver lpass_platform_driver = {
.pcm_new = lpass_platform_pcm_new,
.pcm_free = lpass_platform_pcm_free,
.ops = &lpass_platform_pcm_ops,
diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c
index c5207af14104..a9fa972466ad 100644
--- a/sound/soc/qcom/storm.c
+++ b/sound/soc/qcom/storm.c
@@ -99,7 +99,6 @@ static int storm_platform_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
ret = snd_soc_of_parse_card_name(card, "qcom,model");
if (ret) {
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index c84487805876..b0825370d262 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -68,6 +68,8 @@ config SND_SOC_RK3399_GRU_SOUND
select SND_SOC_RT5514
select SND_SOC_DA7219
select SND_SOC_RT5514_SPI
+ select SND_SOC_HDMI_CODEC
+ select SND_SOC_DMIC
help
Say Y or M here if you want to add support multiple codecs for SoC
audio on Rockchip RK3399 GRU boards.
diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c
index dbc53e48c52c..fa44e3901336 100644
--- a/sound/soc/rockchip/rk3288_hdmi_analog.c
+++ b/sound/soc/rockchip/rk3288_hdmi_analog.c
@@ -147,7 +147,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
return 0;
}
-static struct snd_soc_ops rk_ops = {
+static const struct snd_soc_ops rk_ops = {
.hw_params = rk_hw_params,
};
@@ -272,8 +272,6 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
return ret;
}
- platform_set_drvdata(pdev, card);
-
return ret;
}
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 3475c61a5fa0..0513fe480353 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -38,7 +38,7 @@
#define SOUND_FS 256
-static unsigned int rt5514_dmic_delay;
+static unsigned int dmic_wakeup_delay;
static struct snd_soc_jack rockchip_sound_jack;
@@ -126,7 +126,7 @@ static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
}
/* Wait for DMIC stable */
- msleep(rt5514_dmic_delay);
+ msleep(dmic_wakeup_delay);
return 0;
}
@@ -228,6 +228,67 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int rockchip_sound_cdndp_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int mclk, ret;
+
+ /* in bypass mode, the mclk has to be one of the frequencies below */
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ case 64000:
+ case 96000:
+ mclk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ mclk = 11289600;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned int mclk;
+ int ret;
+
+ mclk = params_rate(params) * SOUND_FS;
+
+ ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
+ if (ret) {
+ dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+ __func__, mclk, ret);
+ return ret;
+ }
+
+ /* Wait for DMIC stable */
+ msleep(dmic_wakeup_delay);
+
+ return 0;
+}
+
static const struct snd_soc_ops rockchip_sound_max98357a_ops = {
.hw_params = rockchip_sound_max98357a_hw_params,
};
@@ -240,16 +301,70 @@ static const struct snd_soc_ops rockchip_sound_da7219_ops = {
.hw_params = rockchip_sound_da7219_hw_params,
};
+static const struct snd_soc_ops rockchip_sound_cdndp_ops = {
+ .hw_params = rockchip_sound_cdndp_hw_params,
+};
+
+static const struct snd_soc_ops rockchip_sound_dmic_ops = {
+ .hw_params = rockchip_sound_dmic_hw_params,
+};
+
+static struct snd_soc_card rockchip_sound_card = {
+ .name = "rk3399-gru-sound",
+ .owner = THIS_MODULE,
+ .dapm_widgets = rockchip_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
+ .dapm_routes = rockchip_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
+ .controls = rockchip_controls,
+ .num_controls = ARRAY_SIZE(rockchip_controls),
+};
+
enum {
+ DAILINK_CDNDP,
+ DAILINK_DA7219,
+ DAILINK_DMIC,
DAILINK_MAX98357A,
DAILINK_RT5514,
- DAILINK_DA7219,
DAILINK_RT5514_DSP,
};
-#define DAILINK_ENTITIES (DAILINK_DA7219 + 1)
+static const char * const dailink_compat[] = {
+ [DAILINK_CDNDP] = "rockchip,rk3399-cdn-dp",
+ [DAILINK_DA7219] = "dlg,da7219",
+ [DAILINK_DMIC] = "dmic-codec",
+ [DAILINK_MAX98357A] = "maxim,max98357a",
+ [DAILINK_RT5514] = "realtek,rt5514-i2c",
+ [DAILINK_RT5514_DSP] = "realtek,rt5514-spi",
+};
-static struct snd_soc_dai_link rockchip_dailinks[] = {
+static const struct snd_soc_dai_link rockchip_dais[] = {
+ [DAILINK_CDNDP] = {
+ .name = "DP",
+ .stream_name = "DP PCM",
+ .codec_dai_name = "i2s-hifi",
+ .ops = &rockchip_sound_cdndp_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ },
+ [DAILINK_DA7219] = {
+ .name = "DA7219",
+ .stream_name = "DA7219 PCM",
+ .codec_dai_name = "da7219-hifi",
+ .init = rockchip_sound_da7219_init,
+ .ops = &rockchip_sound_da7219_ops,
+ /* set da7219 as slave */
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ },
+ [DAILINK_DMIC] = {
+ .name = "DMIC",
+ .stream_name = "DMIC PCM",
+ .codec_dai_name = "dmic-hifi",
+ .ops = &rockchip_sound_dmic_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ },
[DAILINK_MAX98357A] = {
.name = "MAX98357A",
.stream_name = "MAX98357A PCM",
@@ -268,108 +383,95 @@ static struct snd_soc_dai_link rockchip_dailinks[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
},
- [DAILINK_DA7219] = {
- .name = "DA7219",
- .stream_name = "DA7219 PCM",
- .codec_dai_name = "da7219-hifi",
- .init = rockchip_sound_da7219_init,
- .ops = &rockchip_sound_da7219_ops,
- /* set da7219 as slave */
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
- },
/* RT5514 DSP for voice wakeup via spi bus */
[DAILINK_RT5514_DSP] = {
.name = "RT5514 DSP",
.stream_name = "Wake on Voice",
- .codec_name = "snd-soc-dummy",
- .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_dai_name = "rt5514-dsp-cpu-dai",
},
};
-static struct snd_soc_card rockchip_sound_card = {
- .name = "rk3399-gru-sound",
- .owner = THIS_MODULE,
- .dai_link = rockchip_dailinks,
- .num_links = ARRAY_SIZE(rockchip_dailinks),
- .dapm_widgets = rockchip_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
- .dapm_routes = rockchip_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
- .controls = rockchip_controls,
- .num_controls = ARRAY_SIZE(rockchip_controls),
-};
-
-static int rockchip_sound_match_stub(struct device *dev, void *data)
+static int rockchip_sound_codec_node_match(struct device_node *np_codec)
{
- return 1;
-}
+ int i;
-static int rockchip_sound_probe(struct platform_device *pdev)
-{
- struct snd_soc_card *card = &rockchip_sound_card;
- struct device_node *cpu_node;
- struct device *dev;
- struct device_driver *drv;
- int i, ret;
-
- cpu_node = of_parse_phandle(pdev->dev.of_node, "rockchip,cpu", 0);
- if (!cpu_node) {
- dev_err(&pdev->dev, "Property 'rockchip,cpu' missing or invalid\n");
- return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(dailink_compat); i++) {
+ if (of_device_is_compatible(np_codec, dailink_compat[i]))
+ return i;
}
+ return -1;
+}
- for (i = 0; i < DAILINK_ENTITIES; i++) {
- rockchip_dailinks[i].platform_of_node = cpu_node;
- rockchip_dailinks[i].cpu_of_node = cpu_node;
-
- rockchip_dailinks[i].codec_of_node =
- of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i);
- if (!rockchip_dailinks[i].codec_of_node) {
- dev_err(&pdev->dev,
- "Property[%d] 'rockchip,codec' missing or invalid\n", i);
+static int rockchip_sound_of_parse_dais(struct device *dev,
+ struct snd_soc_card *card)
+{
+ struct device_node *np_cpu, *np_cpu0, *np_cpu1;
+ struct device_node *np_codec;
+ struct snd_soc_dai_link *dai;
+ int i, index;
+
+ card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
+ GFP_KERNEL);
+ if (!card->dai_link)
+ return -ENOMEM;
+
+ np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);
+ np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);
+
+ card->num_links = 0;
+ for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {
+ np_codec = of_parse_phandle(dev->of_node,
+ "rockchip,codec", i);
+ if (!np_codec)
+ break;
+
+ if (!of_device_is_available(np_codec))
+ continue;
+
+ index = rockchip_sound_codec_node_match(np_codec);
+ if (index < 0)
+ continue;
+
+ np_cpu = (index == DAILINK_CDNDP) ? np_cpu1 : np_cpu0;
+ if (!np_cpu) {
+ dev_err(dev, "Missing 'rockchip,cpu' for %s\n",
+ rockchip_dais[index].name);
return -EINVAL;
}
- }
- /**
- * To acquire the spi driver of the rt5514 and set the dai-links names
- * for soc_bind_dai_link
- */
- drv = driver_find("rt5514", &spi_bus_type);
- if (!drv) {
- dev_err(&pdev->dev, "Can not find the rt5514 driver at the spi bus\n");
- return -EINVAL;
+ dai = &card->dai_link[card->num_links++];
+ *dai = rockchip_dais[index];
+
+ dai->codec_of_node = np_codec;
+ dai->platform_of_node = np_cpu;
+ dai->cpu_of_node = np_cpu;
}
- dev = driver_find_device(drv, NULL, NULL, rockchip_sound_match_stub);
- if (!dev) {
- dev_err(&pdev->dev, "Can not find the rt5514 device\n");
- return -ENODEV;
+ return 0;
+}
+
+static int rockchip_sound_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &rockchip_sound_card;
+ int ret;
+
+ ret = rockchip_sound_of_parse_dais(&pdev->dev, card);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to parse dais: %d\n", ret);
+ return ret;
}
- /* Set DMIC delay */
- ret = device_property_read_u32(&pdev->dev, "dmic-delay",
- &rt5514_dmic_delay);
+ /* Set DMIC wakeup delay */
+ ret = device_property_read_u32(&pdev->dev, "dmic-wakeup-delay-ms",
+ &dmic_wakeup_delay);
if (ret) {
- rt5514_dmic_delay = 0;
+ dmic_wakeup_delay = 0;
dev_dbg(&pdev->dev,
- "no optional property 'dmic-delay' found, default: no delay\n");
+ "no optional property 'dmic-wakeup-delay-ms' found, default: no delay\n");
}
- rockchip_dailinks[DAILINK_RT5514_DSP].cpu_name = kstrdup_const(dev_name(dev), GFP_KERNEL);
- rockchip_dailinks[DAILINK_RT5514_DSP].cpu_dai_name = kstrdup_const(dev_name(dev), GFP_KERNEL);
- rockchip_dailinks[DAILINK_RT5514_DSP].platform_name = kstrdup_const(dev_name(dev), GFP_KERNEL);
-
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
-
- ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret)
- dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
- __func__, ret);
-
- return ret;
+ return devm_snd_soc_register_card(&pdev->dev, card);
}
static const struct of_device_id rockchip_sound_of_match[] = {
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 199338fdeda0..b6590467fd14 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -579,10 +579,8 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
int val;
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
- if (!i2s) {
- dev_err(&pdev->dev, "Can't allocate rk_i2s_dev\n");
+ if (!i2s)
return -ENOMEM;
- }
i2s->dev = &pdev->dev;
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index c5ddeed97260..400e29edb1c9 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -249,7 +249,7 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-static struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
+static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
.set_fmt = rockchip_pdm_set_fmt,
.trigger = rockchip_pdm_trigger,
.hw_params = rockchip_pdm_hw_params,
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index 5f5825faeb2a..051935162d7b 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -170,14 +170,6 @@ static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int h1940_uda1380_card_remove(struct snd_soc_card *card)
-{
- snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
- hp_jack_gpios);
-
- return 0;
-}
-
/* s3c24xx digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link h1940_uda1380_dai[] = {
{
@@ -197,7 +189,6 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = {
static struct snd_soc_card h1940_asoc = {
.name = "h1940",
.owner = THIS_MODULE,
- .remove = h1940_uda1380_card_remove,
.dai_link = h1940_uda1380_dai,
.num_links = ARRAY_SIZE(h1940_uda1380_dai),
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index af3ba4d4ccc5..10a4da06c0a1 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -50,6 +50,7 @@ struct samsung_i2s_variant_regs {
struct samsung_i2s_dai_data {
u32 quirks;
+ unsigned int pcm_rates;
const struct samsung_i2s_variant_regs *i2s_variant_regs;
};
@@ -550,7 +551,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
goto err;
}
- clk_prepare_enable(i2s->op_clk);
+ ret = clk_prepare_enable(i2s->op_clk);
+ if (ret)
+ goto err;
i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
/* Over-ride the other's */
@@ -1076,13 +1079,13 @@ 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 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE)
-static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
+static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev,
+ const struct samsung_i2s_dai_data *i2s_dai_data,
+ bool sec)
{
struct i2s_dai *i2s;
@@ -1101,13 +1104,13 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
i2s->i2s_dai_drv.resume = i2s_resume;
i2s->i2s_dai_drv.playback.channels_min = 1;
i2s->i2s_dai_drv.playback.channels_max = 2;
- i2s->i2s_dai_drv.playback.rates = SAMSUNG_I2S_RATES;
+ i2s->i2s_dai_drv.playback.rates = i2s_dai_data->pcm_rates;
i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS;
if (!sec) {
i2s->i2s_dai_drv.capture.channels_min = 1;
i2s->i2s_dai_drv.capture.channels_max = 2;
- i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES;
+ i2s->i2s_dai_drv.capture.rates = i2s_dai_data->pcm_rates;
i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
}
return i2s;
@@ -1132,10 +1135,19 @@ static int i2s_runtime_suspend(struct device *dev)
static int i2s_runtime_resume(struct device *dev)
{
struct i2s_dai *i2s = dev_get_drvdata(dev);
+ int ret;
- clk_prepare_enable(i2s->clk);
- if (i2s->op_clk)
- clk_prepare_enable(i2s->op_clk);
+ ret = clk_prepare_enable(i2s->clk);
+ if (ret)
+ return ret;
+
+ if (i2s->op_clk) {
+ ret = clk_prepare_enable(i2s->op_clk);
+ if (ret) {
+ clk_disable_unprepare(i2s->clk);
+ return ret;
+ }
+ }
writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
@@ -1242,7 +1254,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
i2s_dai_data = (struct samsung_i2s_dai_data *)
platform_get_device_id(pdev)->driver_data;
- pri_dai = i2s_alloc_dai(pdev, false);
+ pri_dai = i2s_alloc_dai(pdev, i2s_dai_data, false);
if (!pri_dai) {
dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
return -ENOMEM;
@@ -1316,7 +1328,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
goto err_disable_clk;
if (quirks & QUIRK_SEC_DAI) {
- sec_dai = i2s_alloc_dai(pdev, true);
+ sec_dai = i2s_alloc_dai(pdev, i2s_dai_data, true);
if (!sec_dai) {
dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
ret = -ENOMEM;
@@ -1376,13 +1388,9 @@ err_disable_clk:
static int samsung_i2s_remove(struct platform_device *pdev)
{
- struct i2s_dai *pri_dai, *sec_dai;
+ struct i2s_dai *pri_dai;
pri_dai = dev_get_drvdata(&pdev->dev);
- sec_dai = pri_dai->sec_dai;
-
- pri_dai->sec_dai = NULL;
- sec_dai->pri_dai = NULL;
pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -1452,29 +1460,34 @@ static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = {
static const struct samsung_i2s_dai_data i2sv3_dai_type = {
.quirks = QUIRK_NO_MUXPSR,
+ .pcm_rates = SNDRV_PCM_RATE_8000_96000,
.i2s_variant_regs = &i2sv3_regs,
};
static const struct samsung_i2s_dai_data i2sv5_dai_type = {
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
QUIRK_SUPPORTS_IDMA,
+ .pcm_rates = SNDRV_PCM_RATE_8000_96000,
.i2s_variant_regs = &i2sv3_regs,
};
static const struct samsung_i2s_dai_data i2sv6_dai_type = {
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA,
+ .pcm_rates = SNDRV_PCM_RATE_8000_96000,
.i2s_variant_regs = &i2sv6_regs,
};
static const struct samsung_i2s_dai_data i2sv7_dai_type = {
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
QUIRK_SUPPORTS_TDM,
+ .pcm_rates = SNDRV_PCM_RATE_8000_192000,
.i2s_variant_regs = &i2sv7_regs,
};
static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = {
.quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR,
+ .pcm_rates = SNDRV_PCM_RATE_8000_96000,
.i2s_variant_regs = &i2sv5_i2s1_regs,
};
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index 3e408158625d..a635df61f928 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -325,7 +325,7 @@ static int idma_close(struct snd_pcm_substream *substream)
return 0;
}
-static struct snd_pcm_ops idma_ops = {
+static const struct snd_pcm_ops idma_ops = {
.open = idma_open,
.close = idma_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -399,7 +399,7 @@ void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr)
}
EXPORT_SYMBOL_GPL(idma_reg_addr_init);
-static struct snd_soc_platform_driver asoc_idma_platform = {
+static const struct snd_soc_platform_driver asoc_idma_platform = {
.ops = &idma_ops,
.pcm_new = idma_new,
.pcm_free = idma_free,
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
index 7fcb51faa2a0..529b10dc532b 100644
--- a/sound/soc/samsung/jive_wm8750.c
+++ b/sound/soc/samsung/jive_wm8750.c
@@ -79,7 +79,7 @@ static int jive_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_soc_ops jive_ops = {
+static const struct snd_soc_ops jive_ops = {
.hw_params = jive_hw_params,
};
diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c
index 0c0b00e40646..44b6de5a331a 100644
--- a/sound/soc/samsung/odroid.c
+++ b/sound/soc/samsung/odroid.c
@@ -19,8 +19,8 @@ struct odroid_priv {
struct snd_soc_card card;
struct snd_soc_dai_link dai_link;
- struct clk *pll;
- struct clk *rclk;
+ struct clk *clk_i2s_bus;
+ struct clk *sclk_i2s;
};
static int odroid_card_startup(struct snd_pcm_substream *substream)
@@ -42,29 +42,34 @@ static int odroid_card_hw_params(struct snd_pcm_substream *substream,
switch (params_rate(params)) {
case 32000:
case 64000:
- pll_freq = 131072000U;
+ pll_freq = 131072006U;
break;
case 44100:
case 88200:
case 176400:
- pll_freq = 180633600U;
+ pll_freq = 180633609U;
break;
case 48000:
case 96000:
case 192000:
- pll_freq = 196608000U;
+ pll_freq = 196608001U;
break;
default:
return -EINVAL;
}
- ret = clk_set_rate(priv->pll, pll_freq + 1);
+ ret = clk_set_rate(priv->clk_i2s_bus, pll_freq / 2 + 1);
if (ret < 0)
return ret;
- rclk_freq = params_rate(params) * 256 * 4;
+ /*
+ * We add 1 to the rclk_freq value in order to avoid too low clock
+ * frequency values due to the EPLL output frequency not being exact
+ * multiple of the audio sampling rate.
+ */
+ rclk_freq = params_rate(params) * 256 + 1;
- ret = clk_set_rate(priv->rclk, rclk_freq);
+ ret = clk_set_rate(priv->sclk_i2s, rclk_freq);
if (ret < 0)
return ret;
@@ -118,14 +123,6 @@ static int odroid_audio_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(card, priv);
- priv->pll = devm_clk_get(dev, "epll");
- if (IS_ERR(priv->pll))
- return PTR_ERR(priv->pll);
-
- priv->rclk = devm_clk_get(dev, "i2s_rclk");
- if (IS_ERR(priv->rclk))
- return PTR_ERR(priv->rclk);
-
ret = snd_soc_of_parse_card_name(card, "model");
if (ret < 0)
return ret;
@@ -171,14 +168,31 @@ static int odroid_audio_probe(struct platform_device *pdev)
link->name = "Primary";
link->stream_name = link->name;
+
+ priv->sclk_i2s = of_clk_get_by_name(link->cpu_of_node, "i2s_opclk1");
+ if (IS_ERR(priv->sclk_i2s)) {
+ ret = PTR_ERR(priv->sclk_i2s);
+ goto err_put_i2s_n;
+ }
+
+ priv->clk_i2s_bus = of_clk_get_by_name(link->cpu_of_node, "iis");
+ if (IS_ERR(priv->clk_i2s_bus)) {
+ ret = PTR_ERR(priv->clk_i2s_bus);
+ goto err_put_sclk;
+ }
+
ret = devm_snd_soc_register_card(dev, card);
if (ret < 0) {
dev_err(dev, "snd_soc_register_card() failed: %d\n", ret);
- goto err_put_i2s_n;
+ goto err_put_clk_i2s;
}
return 0;
+err_put_clk_i2s:
+ clk_put(priv->clk_i2s_bus);
+err_put_sclk:
+ clk_put(priv->sclk_i2s);
err_put_i2s_n:
of_node_put(link->cpu_of_node);
err_put_codec_n:
@@ -192,6 +206,8 @@ static int odroid_audio_remove(struct platform_device *pdev)
of_node_put(priv->dai_link.cpu_of_node);
odroid_put_codec_of_nodes(&priv->dai_link);
+ clk_put(priv->sclk_i2s);
+ clk_put(priv->clk_i2s_bus);
return 0;
}
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index d50a6377c23d..37f95eee1558 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -522,7 +522,9 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to get audio-bus clock\n");
return PTR_ERR(pcm->cclk);
}
- clk_prepare_enable(pcm->cclk);
+ ret = clk_prepare_enable(pcm->cclk);
+ if (ret)
+ return ret;
/* record our pcm structure for later use in the callbacks */
dev_set_drvdata(&pdev->dev, pcm);
@@ -533,7 +535,9 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
ret = PTR_ERR(pcm->pclk);
goto err_dis_cclk;
}
- clk_prepare_enable(pcm->pclk);
+ ret = clk_prepare_enable(pcm->pclk);
+ if (ret)
+ goto err_dis_cclk;
s3c_pcm_stereo_in[pdev->id].addr = mem_res->start + S3C_PCM_RXFIFO;
s3c_pcm_stereo_out[pdev->id].addr = mem_res->start + S3C_PCM_TXFIFO;
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index fa096abe9e75..a064ca7d78c3 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -31,7 +31,6 @@
#include "s3c24xx-i2s.h"
static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
-static int rx1950_uda1380_card_remove(struct snd_soc_card *card);
static int rx1950_startup(struct snd_pcm_substream *substream);
static int rx1950_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params);
@@ -118,7 +117,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
static struct snd_soc_card rx1950_asoc = {
.name = "rx1950",
.owner = THIS_MODULE,
- .remove = rx1950_uda1380_card_remove,
.dai_link = rx1950_uda1380_dai,
.num_links = ARRAY_SIZE(rx1950_uda1380_dai),
@@ -219,14 +217,6 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int rx1950_uda1380_card_remove(struct snd_soc_card *card)
-{
- snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
- hp_jack_gpios);
-
- return 0;
-}
-
static int __init rx1950_init(void)
{
int ret;
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index 8f42deaa184b..58c3e9bfc6b7 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -27,7 +27,7 @@
#undef S3C_IIS_V2_SUPPORTED
-#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \
+#if defined(CONFIG_CPU_S3C2412) \
|| defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_CPU_S5PV210)
#define S3C_IIS_V2_SUPPORTED
#endif
@@ -634,11 +634,10 @@ int s3c_i2sv2_probe(struct snd_soc_dai *dai,
i2s->iis_pclk = clk_get(dev, "iis");
if (IS_ERR(i2s->iis_pclk)) {
dev_err(dev, "failed to get iis_clock\n");
- iounmap(i2s->regs);
return -ENOENT;
}
- clk_enable(i2s->iis_pclk);
+ clk_prepare_enable(i2s->iis_pclk);
/* Mark ourselves as in TXRX mode so we can run through our cleanup
* process without warnings. */
@@ -652,6 +651,15 @@ int s3c_i2sv2_probe(struct snd_soc_dai *dai,
}
EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
+void s3c_i2sv2_cleanup(struct snd_soc_dai *dai,
+ struct s3c_i2sv2_info *i2s)
+{
+ clk_disable_unprepare(i2s->iis_pclk);
+ clk_put(i2s->iis_pclk);
+ i2s->iis_pclk = NULL;
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_cleanup);
+
#ifdef CONFIG_PM
static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
{
diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h
index 182d80564e37..3fca20f7a853 100644
--- a/sound/soc/samsung/s3c-i2s-v2.h
+++ b/sound/soc/samsung/s3c-i2s-v2.h
@@ -92,6 +92,13 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
unsigned long base);
/**
+ * s3c_i2sv2_cleanup - cleanup resources allocated in s3c_i2sv2_probe
+ * @dai: The ASoC DAI structure supplied to the original probe.
+ * @i2s: Our local i2s structure to fill in.
+ */
+extern void s3c_i2sv2_cleanup(struct snd_soc_dai *dai,
+ struct s3c_i2sv2_info *i2s);
+/**
* s3c_i2sv2_register_component - register component and dai with soc core
* @dev: DAI device
* @id: DAI ID
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index 0a4718207e6e..cc0840fff5aa 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -65,26 +65,33 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
s3c2412_i2s.iis_cclk = devm_clk_get(dai->dev, "i2sclk");
if (IS_ERR(s3c2412_i2s.iis_cclk)) {
pr_err("failed to get i2sclk clock\n");
- return PTR_ERR(s3c2412_i2s.iis_cclk);
+ ret = PTR_ERR(s3c2412_i2s.iis_cclk);
+ goto err;
}
/* Set MPLL as the source for IIS CLK */
clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
- clk_prepare_enable(s3c2412_i2s.iis_cclk);
-
- s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
+ ret = clk_prepare_enable(s3c2412_i2s.iis_cclk);
+ if (ret)
+ goto err;
/* Configure the I2S pins (GPE0...GPE4) in correct mode */
s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
S3C_GPIO_PULL_NONE);
return 0;
+
+err:
+ s3c_i2sv2_cleanup(dai, &s3c2412_i2s);
+
+ return ret;
}
static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
{
clk_disable_unprepare(s3c2412_i2s.iis_cclk);
+ s3c_i2sv2_cleanup(dai, &s3c2412_i2s);
return 0;
}
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 91e6871e5413..8d58d02183bf 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -340,6 +340,7 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
{
+ int ret;
snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out,
&s3c24xx_i2s_pcm_stereo_in);
@@ -348,7 +349,9 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
pr_err("failed to get iis_clock\n");
return PTR_ERR(s3c24xx_i2s.iis_clk);
}
- clk_prepare_enable(s3c24xx_i2s.iis_clk);
+ ret = clk_prepare_enable(s3c24xx_i2s.iis_clk);
+ if (ret)
+ return ret;
/* Configure the I2S pins (GPE0...GPE4) in correct mode */
s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
@@ -377,7 +380,11 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
{
- clk_prepare_enable(s3c24xx_i2s.iis_clk);
+ int ret;
+
+ ret = clk_prepare_enable(s3c24xx_i2s.iis_clk);
+ if (ret)
+ return ret;
writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c
index dcc008d1e1ab..6de63f3e37d5 100644
--- a/sound/soc/samsung/s3c24xx_simtec.c
+++ b/sound/soc/samsung/s3c24xx_simtec.c
@@ -211,7 +211,7 @@ static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd)
return 0;
}
-static struct snd_soc_ops simtec_snd_ops = {
+static const struct snd_soc_ops simtec_snd_ops = {
.hw_params = simtec_hw_params,
};
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
index 55538e333cc8..5fb3bab6bbfe 100644
--- a/sound/soc/samsung/s3c24xx_uda134x.c
+++ b/sound/soc/samsung/s3c24xx_uda134x.c
@@ -199,7 +199,7 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_soc_ops s3c24xx_uda134x_ops = {
+static const struct snd_soc_ops s3c24xx_uda134x_ops = {
.startup = s3c24xx_uda134x_startup,
.shutdown = s3c24xx_uda134x_shutdown,
.hw_params = s3c24xx_uda134x_hw_params,
@@ -237,7 +237,6 @@ static int s3c24xx_uda134x_probe(struct platform_device *pdev)
mutex_init(&priv->clk_lock);
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, priv);
ret = devm_snd_soc_register_card(&pdev->dev, card);
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index 425ee2ba37f0..cf0f54e652c1 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -160,14 +160,6 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
return err;
}
-static int smartq_wm8987_card_remove(struct snd_soc_card *card)
-{
- snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
- smartq_jack_gpios);
-
- return 0;
-}
-
static struct snd_soc_dai_link smartq_dai[] = {
{
.name = "wm8987",
@@ -186,7 +178,6 @@ static struct snd_soc_dai_link smartq_dai[] = {
static struct snd_soc_card snd_soc_smartq = {
.name = "SmartQ",
.owner = THIS_MODULE,
- .remove = smartq_wm8987_card_remove,
.dai_link = smartq_dai,
.num_links = ARRAY_SIZE(smartq_dai),
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
index a2f2363fe1c2..7fc7cc6d1530 100644
--- a/sound/soc/samsung/smdk_spdif.c
+++ b/sound/soc/samsung/smdk_spdif.c
@@ -144,7 +144,7 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_soc_ops smdk_spdif_ops = {
+static const struct snd_soc_ops smdk_spdif_ops = {
.hw_params = smdk_hw_params,
};
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 779504f54bc0..cb59911e65c0 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -391,7 +391,9 @@ static int spdif_probe(struct platform_device *pdev)
ret = -ENOENT;
goto err0;
}
- clk_prepare_enable(spdif->pclk);
+ ret = clk_prepare_enable(spdif->pclk);
+ if (ret)
+ goto err0;
spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif");
if (IS_ERR(spdif->sclk)) {
@@ -399,7 +401,9 @@ static int spdif_probe(struct platform_device *pdev)
ret = -ENOENT;
goto err1;
}
- clk_prepare_enable(spdif->sclk);
+ ret = clk_prepare_enable(spdif->sclk);
+ if (ret)
+ goto err1;
/* Request S/PDIF Register's memory region */
if (!request_mem_region(mem_res->start,
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
index 24cc9d63ce87..68698f3d72f9 100644
--- a/sound/soc/samsung/tm2_wm5110.c
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -318,7 +318,7 @@ static const struct snd_kcontrol_new tm2_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
-const struct snd_soc_dapm_widget tm2_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget tm2_dapm_widgets[] = {
SND_SOC_DAPM_HP("HP", NULL),
SND_SOC_DAPM_SPK("SPK", NULL),
SND_SOC_DAPM_SPK("RCV", NULL),
@@ -521,7 +521,7 @@ static void tm2_pm_complete(struct device *dev)
tm2_start_sysclk(card);
}
-const struct dev_pm_ops tm2_pm_ops = {
+static const struct dev_pm_ops tm2_pm_ops = {
.prepare = tm2_pm_prepare,
.suspend = snd_soc_suspend,
.resume = snd_soc_resume,
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 8fad4441c87d..1e7d417b53ef 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -89,7 +89,7 @@ struct camelot_pcm {
#define DMABRG_PREALLOC_BUFFER 32 * 1024
#define DMABRG_PREALLOC_BUFFER_MAX 32 * 1024
-static struct snd_pcm_hardware camelot_pcm_hardware = {
+static const struct snd_pcm_hardware camelot_pcm_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -294,7 +294,7 @@ static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
return bytes_to_frames(runtime, pos);
}
-static struct snd_pcm_ops camelot_pcm_ops = {
+static const struct snd_pcm_ops camelot_pcm_ops = {
.open = camelot_pcm_open,
.close = camelot_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -320,7 +320,7 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static struct snd_soc_platform_driver sh7760_soc_platform = {
+static const struct snd_soc_platform_driver sh7760_soc_platform = {
.ops = &camelot_pcm_ops,
.pcm_new = camelot_pcm_new,
};
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 7c4bdd82bb95..6d3c7706d93f 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1710,7 +1710,7 @@ static const struct snd_soc_dai_ops fsi_dai_ops = {
* pcm ops
*/
-static struct snd_pcm_hardware fsi_pcm_hardware = {
+static const struct snd_pcm_hardware fsi_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID,
@@ -1755,7 +1755,7 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
return fsi_sample2frame(fsi, io->buff_sample_pos);
}
-static struct snd_pcm_ops fsi_pcm_ops = {
+static const struct snd_pcm_ops fsi_pcm_ops = {
.open = fsi_pcm_open,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = fsi_hw_params,
@@ -1818,7 +1818,7 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
},
};
-static struct snd_soc_platform_driver fsi_soc_platform = {
+static const struct snd_soc_platform_driver fsi_soc_platform = {
.ops = &fsi_pcm_ops,
.pcm_new = fsi_pcm_new,
};
@@ -1962,10 +1962,8 @@ static int fsi_probe(struct platform_device *pdev)
}
master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
- if (!master) {
- dev_err(&pdev->dev, "Could not allocate master\n");
+ if (!master)
return -ENOMEM;
- }
master->base = devm_ioremap_nocache(&pdev->dev,
res->start, resource_size(res));
@@ -2109,7 +2107,7 @@ static int fsi_resume(struct device *dev)
return 0;
}
-static struct dev_pm_ops fsi_pm_ops = {
+static const struct dev_pm_ops fsi_pm_ops = {
.suspend = fsi_suspend,
.resume = fsi_resume,
};
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index 84c51037a7d0..624aaf569fef 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -315,6 +315,8 @@ static const struct snd_soc_component_driver sh4_hac_component = {
static int hac_soc_platform_probe(struct platform_device *pdev)
{
+ int ret;
+
ret = snd_soc_set_ac97_ops(&hac_ac97_ops);
if (ret != 0)
return ret;
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
index 672bcd4c252b..ecb057ff9fbb 100644
--- a/sound/soc/sh/migor.c
+++ b/sound/soc/sh/migor.c
@@ -98,7 +98,7 @@ static int migor_hw_free(struct snd_pcm_substream *substream)
return 0;
}
-static struct snd_soc_ops migor_dai_ops = {
+static const struct snd_soc_ops migor_dai_ops = {
.hw_params = migor_hw_params,
.hw_free = migor_hw_free,
};
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 197cb3ec075f..938baff86ef2 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -586,10 +586,8 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
int ret;
adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
- if (!adg) {
- dev_err(dev, "ADG allocate failed\n");
+ if (!adg)
return -ENOMEM;
- }
ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
NULL, NULL, 0, 0);
@@ -610,6 +608,13 @@ void rsnd_adg_remove(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np = dev->of_node;
+ struct rsnd_adg *adg = priv->adg;
+ struct clk *clk;
+ int i;
+
+ for_each_rsnd_clkout(clk, adg, i)
+ if (adg->clkout[i])
+ clk_unregister_fixed_rate(adg->clkout[i]);
of_clk_del_provider(np);
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 3f2ced26ed37..107133297e8d 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -726,7 +726,6 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
case 2:
case 6:
case 8:
- case 16:
/* TDM Extend Mode */
rsnd_rdai_channels_set(rdai, slots);
rsnd_rdai_ssi_lane_set(rdai, 1);
@@ -740,7 +739,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
}
static unsigned int rsnd_soc_hw_channels_list[] = {
- 2, 6, 8, 16,
+ 2, 6, 8,
};
static unsigned int rsnd_soc_hw_rate_list[] = {
@@ -844,12 +843,28 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
ir, &ic);
}
-static void rsnd_soc_hw_constraint(struct snd_pcm_runtime *runtime,
- struct snd_soc_dai *dai)
+static const struct snd_pcm_hardware rsnd_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .buffer_bytes_max = 64 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 32,
+ .fifo_size = 256,
+};
+
+static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
{
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint;
+ struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int max_channels = rsnd_rdai_channels_get(rdai);
+ int ret;
int i;
/*
@@ -866,34 +881,26 @@ static void rsnd_soc_hw_constraint(struct snd_pcm_runtime *runtime,
constraint->count = i + 1;
}
+ snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
+
snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS, constraint);
+ snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+
/*
* Sampling Rate / Channel Limitation
* It depends on Clock Master Mode
*/
- if (!rsnd_rdai_is_clk_master(rdai))
- return;
-
- snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- rsnd_soc_hw_rule_rate, dai,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- rsnd_soc_hw_rule_channels, dai,
- SNDRV_PCM_HW_PARAM_RATE, -1);
-}
-
-static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
- struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
- struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
- int ret;
-
- /* rsnd_io_to_runtime() is not yet enabled here */
- rsnd_soc_hw_constraint(substream->runtime, dai);
+ if (rsnd_rdai_is_clk_master(rdai)) {
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ rsnd_soc_hw_rule_rate, dai,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ rsnd_soc_hw_rule_channels, dai,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ }
/*
* call rsnd_dai_call without spinlock
@@ -1017,7 +1024,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
drv->playback.rates = RSND_RATES;
drv->playback.formats = RSND_FMTS;
drv->playback.channels_min = 2;
- drv->playback.channels_max = 16;
+ drv->playback.channels_max = 8;
drv->playback.stream_name = rdai->playback.name;
snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
@@ -1025,7 +1032,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
drv->capture.rates = RSND_RATES;
drv->capture.formats = RSND_FMTS;
drv->capture.channels_min = 2;
- drv->capture.channels_max = 16;
+ drv->capture.channels_max = 8;
drv->capture.stream_name = rdai->capture.name;
rdai->playback.rdai = rdai;
@@ -1105,31 +1112,6 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
/*
* pcm ops
*/
-static struct snd_pcm_hardware rsnd_pcm_hardware = {
- .info = SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID,
- .buffer_bytes_max = 64 * 1024,
- .period_bytes_min = 32,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 32,
- .fifo_size = 256,
-};
-
-static int rsnd_pcm_open(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret = 0;
-
- snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
-
- ret = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
-
- return ret;
-}
-
static int rsnd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
@@ -1158,8 +1140,7 @@ static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
return pointer;
}
-static struct snd_pcm_ops rsnd_pcm_ops = {
- .open = rsnd_pcm_open,
+static const struct snd_pcm_ops rsnd_pcm_ops = {
.ioctl = snd_pcm_lib_ioctl,
.hw_params = rsnd_hw_params,
.hw_free = snd_pcm_lib_free_pages,
@@ -1169,11 +1150,10 @@ static struct snd_pcm_ops rsnd_pcm_ops = {
/*
* snd_kcontrol
*/
-#define kcontrol_to_cfg(kctrl) ((struct rsnd_kctrl_cfg *)kctrl->private_value)
static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_info *uinfo)
{
- struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+ struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
if (cfg->texts) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -1199,7 +1179,7 @@ static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *uc)
{
- struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+ struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
int i;
for (i = 0; i < cfg->size; i++)
@@ -1214,8 +1194,7 @@ static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *uc)
{
- struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
- struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+ struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
int i, change = 0;
if (!cfg->accept(cfg->io))
@@ -1232,7 +1211,7 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
}
if (change && cfg->update)
- cfg->update(cfg->io, mod);
+ cfg->update(cfg->io, cfg->mod);
return change;
}
@@ -1284,14 +1263,13 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
.index = rtd->num,
.get = rsnd_kctrl_get,
.put = rsnd_kctrl_put,
- .private_value = (unsigned long)cfg,
};
int ret;
if (size > RSND_MAX_CHANNELS)
return -EINVAL;
- kctrl = snd_ctl_new1(&knew, mod);
+ kctrl = snd_ctl_new1(&knew, cfg);
if (!kctrl)
return -ENOMEM;
@@ -1307,6 +1285,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
cfg->card = card;
cfg->kctrl = kctrl;
cfg->io = io;
+ cfg->mod = mod;
return 0;
}
@@ -1339,7 +1318,7 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
}
-static struct snd_soc_platform_driver rsnd_soc_platform = {
+static const struct snd_soc_platform_driver rsnd_soc_platform = {
.ops = &rsnd_pcm_ops,
.pcm_new = rsnd_pcm_new,
};
@@ -1422,10 +1401,8 @@ static int rsnd_probe(struct platform_device *pdev)
* init priv data
*/
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(dev, "priv allocate failed\n");
+ if (!priv)
return -ENODEV;
- }
priv->pdev = pdev;
priv->flags = (unsigned long)of_device_get_match_data(dev);
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index 4ba8f2fe7a4c..e7f53f44165d 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -394,13 +394,16 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
+ of_node_put(np);
goto rsnd_ctu_probe_done;
}
ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
- if (ret)
+ if (ret) {
+ of_node_put(np);
goto rsnd_ctu_probe_done;
+ }
i++;
}
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 60aa5e96a49f..041ec1080d52 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -604,8 +604,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
dma_addr_t in_addr;
} dma_addrs[3][2][3] = {
/* SRC */
+ /* Capture */
{{{ 0, 0 },
- /* Capture */
{ RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) },
{ RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } },
/* Playback */
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 99d2d9459e75..1743ade3cc55 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -380,13 +380,16 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
+ of_node_put(np);
goto rsnd_dvc_probe_done;
}
ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
clk, rsnd_mod_get_status, RSND_MOD_DVC, i);
- if (ret)
+ if (ret) {
+ of_node_put(np);
goto rsnd_dvc_probe_done;
+ }
i++;
}
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index ee00e3516911..f04c4100043a 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -406,10 +406,8 @@ int rsnd_gen_probe(struct rsnd_priv *priv)
int ret;
gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
- if (!gen) {
- dev_err(dev, "GEN allocate failed\n");
+ if (!gen)
return -ENOMEM;
- }
priv->gen = gen;
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 195fc7bb22af..6c4826c189a4 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -168,13 +168,16 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
+ of_node_put(np);
goto rsnd_mix_probe_done;
}
ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
- if (ret)
+ if (ret) {
+ of_node_put(np);
goto rsnd_mix_probe_done;
+ }
i++;
}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 99c57611df88..c5de71f2dc8c 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -614,6 +614,7 @@ struct rsnd_kctrl_cfg {
struct rsnd_dai_stream *io;
struct snd_card *card;
struct snd_kcontrol *kctrl;
+ struct rsnd_mod *mod;
};
#define RSND_MAX_CHANNELS 8
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 7aa239e28491..510b68a483b4 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -27,7 +27,6 @@ struct rsnd_src {
#define RSND_SRC_NAME_SIZE 16
#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)
-#define rsnd_src_to_dma(src) ((src)->dma)
#define rsnd_src_nr(priv) ((priv)->src_nr)
#define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val)
@@ -108,7 +107,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
int is_play = rsnd_io_is_play(io);
/*
- *
* Playback
* runtime_rate -> [SRC] -> convert_rate
*
@@ -203,13 +201,13 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod);
/*
- * SRC_ADINR
+ * SRC_ADINR
*/
adinr = rsnd_get_adinr_bit(mod, io) |
rsnd_runtime_channel_original(io);
/*
- * SRC_IFSCR / SRC_IFSVR
+ * SRC_IFSCR / SRC_IFSVR
*/
ifscr = 0;
fsrate = 0;
@@ -223,7 +221,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
}
/*
- * SRC_SRCCR / SRC_ROUTE_MODE0
+ * SRC_SRCCR / SRC_ROUTE_MODE0
*/
cr = 0x00011110;
route = 0x0;
@@ -581,20 +579,24 @@ int rsnd_src_probe(struct rsnd_priv *priv)
src->irq = irq_of_parse_and_map(np, 0);
if (!src->irq) {
ret = -EINVAL;
+ of_node_put(np);
goto rsnd_src_probe_done;
}
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
+ of_node_put(np);
goto rsnd_src_probe_done;
}
ret = rsnd_mod_init(priv, rsnd_mod_get(src),
&rsnd_src_ops, clk, rsnd_mod_get_status,
RSND_MOD_SRC, i);
- if (ret)
+ if (ret) {
+ of_node_put(np);
goto rsnd_src_probe_done;
+ }
skip:
i++;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 46feddd78ee2..fffc07e72627 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -72,6 +72,7 @@ struct rsnd_ssi {
u32 cr_own;
u32 cr_clk;
u32 cr_mode;
+ u32 cr_en;
u32 wsr;
int chan;
int rate;
@@ -89,6 +90,7 @@ struct rsnd_ssi {
#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */
#define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */
#define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */
+#define RSND_SSI_PROBED (1 << 4)
#define for_each_rsnd_ssi(pos, priv, i) \
for (i = 0; \
@@ -97,25 +99,27 @@ struct rsnd_ssi {
i++)
#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
-#define rsnd_ssi_to_dma(mod) ((ssi)->dma)
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
-#define rsnd_ssi_mode_flags(p) ((p)->flags)
+#define rsnd_ssi_flags_has(p, f) ((p)->flags & f)
+#define rsnd_ssi_flags_set(p, f) ((p)->flags |= f)
+#define rsnd_ssi_flags_del(p, f) ((p)->flags = ((p)->flags & ~f))
#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
#define rsnd_ssi_is_multi_slave(mod, io) \
(rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod)))
#define rsnd_ssi_is_run_mods(mod, io) \
(rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
+#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
{
struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI0)
+ if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI0))
return RSND_SSI_HDMI_PORT0;
- if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI1)
+ if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI1))
return RSND_SSI_HDMI_PORT1;
return 0;
@@ -130,7 +134,7 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
if (!rsnd_ssi_is_dma_mode(mod))
return 0;
- if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF))
+ if (!(rsnd_ssi_flags_has(ssi, RSND_SSI_NO_BUSIF)))
use_busif = 1;
if (rsnd_io_to_mod_src(io))
use_busif = 1;
@@ -255,7 +259,6 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
int chan = rsnd_runtime_channel_for_ssi(io);
int idx, ret;
unsigned int main_rate;
@@ -266,7 +269,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
if (!rsnd_rdai_is_clk_master(rdai))
return 0;
- if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+ if (!rsnd_ssi_can_output_clk(mod))
return 0;
if (rsnd_ssi_is_multi_slave(mod, io))
@@ -291,6 +294,16 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
if (ret < 0)
return ret;
+ /*
+ * SSI clock will be output contiguously
+ * by below settings.
+ * This means, rsnd_ssi_master_clk_start()
+ * and rsnd_ssi_register_setup() are necessary
+ * for SSI parent
+ *
+ * SSICR : FORCE, SCKD, SWSD
+ * SSIWSR : CONT
+ */
ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx);
ssi->wsr = CONT;
ssi->rate = rate;
@@ -307,12 +320,11 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
if (!rsnd_rdai_is_clk_master(rdai))
return;
- if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+ if (!rsnd_ssi_can_output_clk(mod))
return;
if (ssi->usrcnt > 1)
@@ -335,6 +347,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
u32 wsr;
int is_tdm;
+ if (rsnd_ssi_is_parent(mod, io))
+ return;
+
is_tdm = rsnd_runtime_is_ssi_tdm(io);
/*
@@ -393,7 +408,8 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
rsnd_mod_write(mod, SSIWSR, ssi->wsr);
rsnd_mod_write(mod, SSICR, ssi->cr_own |
ssi->cr_clk |
- ssi->cr_mode); /* without EN */
+ ssi->cr_mode |
+ ssi->cr_en);
}
static void rsnd_ssi_pointer_init(struct rsnd_mod *mod,
@@ -472,8 +488,7 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
if (ret < 0)
return ret;
- if (!rsnd_ssi_is_parent(mod, io))
- rsnd_ssi_config_init(mod, io);
+ rsnd_ssi_config_init(mod, io);
rsnd_ssi_register_setup(mod);
@@ -544,6 +559,8 @@ static int rsnd_ssi_start(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
if (!rsnd_ssi_is_run_mods(mod, io))
return 0;
@@ -554,7 +571,19 @@ static int rsnd_ssi_start(struct rsnd_mod *mod,
if (rsnd_ssi_multi_slaves_runtime(io))
return 0;
- rsnd_mod_bset(mod, SSICR, EN, EN);
+ /*
+ * EN is for data output.
+ * SSI parent EN is not needed.
+ */
+ if (rsnd_ssi_is_parent(mod, io))
+ return 0;
+
+ ssi->cr_en = EN;
+
+ rsnd_mod_write(mod, SSICR, ssi->cr_own |
+ ssi->cr_clk |
+ ssi->cr_mode |
+ ssi->cr_en);
return 0;
}
@@ -569,13 +598,7 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
if (!rsnd_ssi_is_run_mods(mod, io))
return 0;
- /*
- * don't stop if not last user
- * see also
- * rsnd_ssi_start
- * rsnd_ssi_interrupt
- */
- if (ssi->usrcnt > 1)
+ if (rsnd_ssi_is_parent(mod, io))
return 0;
/*
@@ -595,6 +618,8 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
rsnd_mod_write(mod, SSICR, cr); /* disabled all */
rsnd_ssi_status_check(mod, IIRQ);
+ ssi->cr_en = 0;
+
return 0;
}
@@ -760,15 +785,47 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
/*
* SSI might be called again as PIO fallback
* It is easy to manual handling for IRQ request/free
+ *
+ * OTOH, this function might be called many times if platform is
+ * using MIX. It needs xxx_attach() many times on xxx_probe().
+ * Because of it, we can't control .probe/.remove calling count by
+ * mod->status.
+ * But it don't need to call request_irq() many times.
+ * Let's control it by RSND_SSI_PROBED flag.
*/
- ret = request_irq(ssi->irq,
- rsnd_ssi_interrupt,
- IRQF_SHARED,
- dev_name(dev), mod);
+ if (!rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) {
+ ret = request_irq(ssi->irq,
+ rsnd_ssi_interrupt,
+ IRQF_SHARED,
+ dev_name(dev), mod);
+
+ rsnd_ssi_flags_set(ssi, RSND_SSI_PROBED);
+ }
return ret;
}
+static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io);
+
+ /* Do nothing if non SSI (= SSI parent, multi SSI) mod */
+ if (pure_ssi_mod != mod)
+ return 0;
+
+ /* PIO will request IRQ again */
+ if (rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) {
+ free_irq(ssi->irq, mod);
+
+ rsnd_ssi_flags_del(ssi, RSND_SSI_PROBED);
+ }
+
+ return 0;
+}
+
static int rsnd_ssi_pointer(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
snd_pcm_uframes_t *pointer)
@@ -784,6 +841,7 @@ static int rsnd_ssi_pointer(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
.name = SSI_NAME,
.probe = rsnd_ssi_common_probe,
+ .remove = rsnd_ssi_common_remove,
.init = rsnd_ssi_init,
.quit = rsnd_ssi_quit,
.start = rsnd_ssi_start,
@@ -818,23 +876,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
return ret;
}
-static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
-
- /* Do nothing for SSI parent mod */
- if (ssi_parent_mod == mod)
- return 0;
-
- /* PIO will request IRQ again */
- free_irq(ssi->irq, mod);
-
- return 0;
-}
-
static int rsnd_ssi_fallback(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -876,7 +917,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.name = SSI_NAME,
.dma_req = rsnd_ssi_dma_req,
.probe = rsnd_ssi_dma_probe,
- .remove = rsnd_ssi_dma_remove,
+ .remove = rsnd_ssi_common_remove,
.init = rsnd_ssi_init,
.quit = rsnd_ssi_quit,
.start = rsnd_ssi_start,
@@ -962,13 +1003,13 @@ static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
ssi = rsnd_mod_to_ssi(mod);
if (strstr(remote_ep->full_name, "hdmi0")) {
- ssi->flags |= RSND_SSI_HDMI0;
+ rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI0);
dev_dbg(dev, "%s[%d] connected to HDMI0\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
}
if (strstr(remote_ep->full_name, "hdmi1")) {
- ssi->flags |= RSND_SSI_HDMI1;
+ rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI1);
dev_dbg(dev, "%s[%d] connected to HDMI1\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
}
@@ -1001,7 +1042,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
+ return !!(rsnd_ssi_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE));
}
static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
@@ -1079,18 +1120,20 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
+ of_node_put(np);
goto rsnd_ssi_probe_done;
}
if (of_get_property(np, "shared-pin", NULL))
- ssi->flags |= RSND_SSI_CLK_PIN_SHARE;
+ rsnd_ssi_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
if (of_get_property(np, "no-busif", NULL))
- ssi->flags |= RSND_SSI_NO_BUSIF;
+ rsnd_ssi_flags_set(ssi, RSND_SSI_NO_BUSIF);
ssi->irq = irq_of_parse_and_map(np, 0);
if (!ssi->irq) {
ret = -EINVAL;
+ of_node_put(np);
goto rsnd_ssi_probe_done;
}
@@ -1101,8 +1144,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
rsnd_ssi_get_status, RSND_MOD_SSI, i);
- if (ret)
+ if (ret) {
+ of_node_put(np);
goto rsnd_ssi_probe_done;
+ }
i++;
}
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index bed2c9c0004b..4d948757d300 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -250,7 +250,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ssiu *ssiu;
- static struct rsnd_mod_ops *ops;
+ struct rsnd_mod_ops *ops;
int i, nr, ret;
/* same number to SSI */
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index 4a22aadac294..160502947da2 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -333,7 +333,7 @@ static void siu_dai_spbstop(struct siu_port *port_info)
/* API functions */
/* Playback and capture hardware properties are identical */
-static struct snd_pcm_hardware siu_dai_pcm_hw = {
+static const struct snd_pcm_hardware siu_dai_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED,
.formats = SNDRV_PCM_FMTBIT_S16,
.rates = SNDRV_PCM_RATE_8000_48000,
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 82902f56e82f..3118cb0ee3f2 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -593,7 +593,7 @@ static void siu_pcm_free(struct snd_pcm *pcm)
dev_dbg(pcm->card->dev, "%s\n", __func__);
}
-static struct snd_pcm_ops siu_pcm_ops = {
+static const struct snd_pcm_ops siu_pcm_ops = {
.open = siu_pcm_open,
.close = siu_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 206f36bf43e8..2cb8d3b55fbc 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -737,9 +737,6 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
}
/* check client and interface hw capabilities */
- snprintf(new_name, sizeof(new_name), "%s %s-%d",
- rtd->dai_link->stream_name, codec_dai->name, num);
-
if (codec_dai->driver->playback.channels_min)
playback = 1;
if (codec_dai->driver->capture.channels_min)
@@ -758,21 +755,18 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
return -EINVAL;
}
- if(playback)
+ if (playback)
direction = SND_COMPRESS_PLAYBACK;
else
direction = SND_COMPRESS_CAPTURE;
compr = kzalloc(sizeof(*compr), GFP_KERNEL);
- if (compr == NULL) {
- snd_printk(KERN_ERR "Cannot allocate compr\n");
+ if (!compr)
return -ENOMEM;
- }
compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
GFP_KERNEL);
- if (compr->ops == NULL) {
- dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
+ if (!compr->ops) {
ret = -ENOMEM;
goto compr_err;
}
@@ -797,19 +791,18 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
else if (rtd->dai_link->dpcm_capture)
be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
- } else
+ } else {
+ snprintf(new_name, sizeof(new_name), "%s %s-%d",
+ rtd->dai_link->stream_name, codec_dai->name, num);
+
memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
+ }
/* Add copy callback for not memory mapped DSPs */
if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
compr->ops->copy = soc_compr_copy;
mutex_init(&compr->lock);
-
- snprintf(new_name, sizeof(new_name), "%s %s-%d",
- rtd->dai_link->stream_name,
- rtd->codec_dai->name, num);
-
ret = snd_compress_new(rtd->card->snd_card, num, direction,
new_name, compr);
if (ret < 0) {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 921622a01944..e4ea5d4aa8d5 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -339,11 +339,12 @@ static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
static void soc_init_codec_debugfs(struct snd_soc_component *component)
{
struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+ struct dentry *debugfs_reg;
- codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
- codec->component.debugfs_root,
- codec, &codec_reg_fops);
- if (!codec->debugfs_reg)
+ debugfs_reg = debugfs_create_file("codec_reg", 0644,
+ codec->component.debugfs_root,
+ codec, &codec_reg_fops);
+ if (!debugfs_reg)
dev_warn(codec->dev,
"ASoC: Failed to create codec register debugfs file\n");
}
@@ -494,7 +495,7 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
static void snd_soc_debugfs_init(void)
{
snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
- if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
+ if (IS_ERR_OR_NULL(snd_soc_debugfs_root)) {
pr_warn("ASoC: Failed to create debugfs directory\n");
snd_soc_debugfs_root = NULL;
return;
@@ -550,6 +551,54 @@ static inline void snd_soc_debugfs_exit(void)
#endif
+static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_component *component)
+{
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_rtdcom_list *new_rtdcom;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ /* already connected */
+ if (rtdcom->component == component)
+ return 0;
+ }
+
+ new_rtdcom = kmalloc(sizeof(*new_rtdcom), GFP_KERNEL);
+ if (!new_rtdcom)
+ return -ENOMEM;
+
+ new_rtdcom->component = component;
+ INIT_LIST_HEAD(&new_rtdcom->list);
+
+ list_add_tail(&new_rtdcom->list, &rtd->component_list);
+
+ return 0;
+}
+
+static void snd_soc_rtdcom_del_all(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_rtdcom_list *rtdcom1, *rtdcom2;
+
+ for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2)
+ kfree(rtdcom1);
+
+ INIT_LIST_HEAD(&rtd->component_list);
+}
+
+struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
+ const char *driver_name)
+{
+ struct snd_soc_rtdcom_list *rtdcom;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ if ((rtdcom->component->driver->name == driver_name) ||
+ strcmp(rtdcom->component->driver->name, driver_name) == 0)
+ return rtdcom->component;
+ }
+
+ return NULL;
+}
+
struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
const char *dai_link, int stream)
{
@@ -574,6 +623,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
if (!rtd)
return NULL;
+ INIT_LIST_HEAD(&rtd->component_list);
rtd->card = card;
rtd->dai_link = dai_link;
rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) *
@@ -591,6 +641,7 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
{
if (rtd && rtd->codec_dais)
kfree(rtd->codec_dais);
+ snd_soc_rtdcom_del_all(rtd);
kfree(rtd);
}
@@ -949,7 +1000,7 @@ static struct snd_soc_component *soc_find_component(
/**
* snd_soc_find_dai - Find a registered DAI
*
- * @dlc: name of the DAI and optional component info to match
+ * @dlc: name of the DAI or the DAI driver and optional component info to match
*
* This function will search all registered components and their DAIs to
* find the DAI of the same name. The component's of_node and name
@@ -977,7 +1028,9 @@ struct snd_soc_dai *snd_soc_find_dai(
if (dlc->name && strcmp(component->name, dlc->name))
continue;
list_for_each_entry(dai, &component->dai_list, list) {
- if (dlc->dai_name && strcmp(dai->name, dlc->dai_name))
+ if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)
+ && (!dai->driver->name
+ || strcmp(dai->driver->name, dlc->dai_name)))
continue;
return dai;
@@ -1049,6 +1102,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai_link_component *codecs = dai_link->codecs;
struct snd_soc_dai_link_component cpu_dai_component;
+ struct snd_soc_component *component;
struct snd_soc_dai **codec_dais;
struct snd_soc_platform *platform;
struct device_node *platform_of_node;
@@ -1076,6 +1130,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
dai_link->cpu_dai_name);
goto _err_defer;
}
+ snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component);
rtd->num_codecs = dai_link->num_codecs;
@@ -1088,6 +1143,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
codecs[i].dai_name);
goto _err_defer;
}
+ snd_soc_rtdcom_add(rtd, codec_dais[i]->component);
}
/* Single codec links expect codec and codec_dai in runtime data */
@@ -1100,6 +1156,23 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
platform_name = "snd-soc-dummy";
/* find one from the set of registered platforms */
+ list_for_each_entry(component, &component_list, list) {
+ platform_of_node = component->dev->of_node;
+ if (!platform_of_node && component->dev->parent->of_node)
+ platform_of_node = component->dev->parent->of_node;
+
+ if (dai_link->platform_of_node) {
+ if (platform_of_node != dai_link->platform_of_node)
+ continue;
+ } else {
+ if (strcmp(component->name, platform_name))
+ continue;
+ }
+
+ snd_soc_rtdcom_add(rtd, component);
+ }
+
+ /* find one from the set of registered platforms */
list_for_each_entry(platform, &platform_list, list) {
platform_of_node = platform->dev->of_node;
if (!platform_of_node && platform->dev->parent->of_node)
@@ -1184,27 +1257,15 @@ static void soc_remove_link_dais(struct snd_soc_card *card,
static void soc_remove_link_components(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd, int order)
{
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_component *component;
- int i;
+ struct snd_soc_rtdcom_list *rtdcom;
- /* remove the platform */
- if (platform && platform->component.driver->remove_order == order)
- soc_remove_component(&platform->component);
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
- /* remove the CODEC-side CODEC */
- for (i = 0; i < rtd->num_codecs; i++) {
- component = rtd->codec_dais[i]->component;
if (component->driver->remove_order == order)
soc_remove_component(component);
}
-
- /* remove any CPU-side CODEC */
- if (cpu_dai) {
- if (cpu_dai->component->driver->remove_order == order)
- soc_remove_component(cpu_dai->component);
- }
}
static void soc_remove_dai_links(struct snd_soc_card *card)
@@ -1451,9 +1512,10 @@ static int soc_probe_component(struct snd_soc_card *card,
soc_init_component_debugfs(component);
- if (component->dapm_widgets) {
- ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets,
- component->num_dapm_widgets);
+ if (component->driver->dapm_widgets) {
+ ret = snd_soc_dapm_new_controls(dapm,
+ component->driver->dapm_widgets,
+ component->driver->num_dapm_widgets);
if (ret != 0) {
dev_err(component->dev,
@@ -1495,12 +1557,14 @@ static int soc_probe_component(struct snd_soc_card *card,
}
}
- if (component->controls)
- snd_soc_add_component_controls(component, component->controls,
- component->num_controls);
- if (component->dapm_routes)
- snd_soc_dapm_add_routes(dapm, component->dapm_routes,
- component->num_dapm_routes);
+ if (component->driver->controls)
+ snd_soc_add_component_controls(component,
+ component->driver->controls,
+ component->driver->num_controls);
+ if (component->driver->dapm_routes)
+ snd_soc_dapm_add_routes(dapm,
+ component->driver->dapm_routes,
+ component->driver->num_dapm_routes);
list_add(&dapm->list, &card->dapm_list);
list_add(&component->card_list, &card->component_dev_list);
@@ -1556,21 +1620,13 @@ static int soc_probe_link_components(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd,
int order)
{
- struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_component *component;
- int i, ret;
+ struct snd_soc_rtdcom_list *rtdcom;
+ int ret;
- /* probe the CPU-side component, if it is a CODEC */
- component = rtd->cpu_dai->component;
- if (component->driver->probe_order == order) {
- ret = soc_probe_component(card, component);
- if (ret < 0)
- return ret;
- }
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
- /* probe the CODEC-side components */
- for (i = 0; i < rtd->num_codecs; i++) {
- component = rtd->codec_dais[i]->component;
if (component->driver->probe_order == order) {
ret = soc_probe_component(card, component);
if (ret < 0)
@@ -1578,13 +1634,6 @@ static int soc_probe_link_components(struct snd_soc_card *card,
}
}
- /* probe the platform */
- if (platform->component.driver->probe_order == order) {
- ret = soc_probe_component(card, &platform->component);
- if (ret < 0)
- return ret;
- }
-
return 0;
}
@@ -2587,11 +2636,9 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
{
if (dai->driver && dai->driver->ops->set_sysclk)
return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
- else if (dai->codec && dai->codec->driver->set_sysclk)
- return dai->codec->driver->set_sysclk(dai->codec, clk_id, 0,
- freq, dir);
- else
- return -ENOTSUPP;
+
+ return snd_soc_component_set_sysclk(dai->component, clk_id, 0,
+ freq, dir);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
@@ -2617,6 +2664,32 @@ int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk);
/**
+ * snd_soc_component_set_sysclk - configure COMPONENT system or master clock.
+ * @component: COMPONENT
+ * @clk_id: DAI specific clock ID
+ * @source: Source for the clock
+ * @freq: new clock frequency in Hz
+ * @dir: new clock direction - input/output.
+ *
+ * Configures the CODEC master (MCLK) or system (SYSCLK) clocking.
+ */
+int snd_soc_component_set_sysclk(struct snd_soc_component *component, int clk_id,
+ int source, unsigned int freq, int dir)
+{
+ /* will be removed */
+ if (component->set_sysclk)
+ return component->set_sysclk(component, clk_id, source,
+ freq, dir);
+
+ if (component->driver->set_sysclk)
+ return component->driver->set_sysclk(component, clk_id, source,
+ freq, dir);
+
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk);
+
+/**
* snd_soc_dai_set_clkdiv - configure DAI clock dividers.
* @dai: DAI
* @div_id: DAI specific clock divider ID
@@ -2652,11 +2725,9 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
if (dai->driver && dai->driver->ops->set_pll)
return dai->driver->ops->set_pll(dai, pll_id, source,
freq_in, freq_out);
- else if (dai->codec && dai->codec->driver->set_pll)
- return dai->codec->driver->set_pll(dai->codec, pll_id, source,
- freq_in, freq_out);
- else
- return -EINVAL;
+
+ return snd_soc_component_set_pll(dai->component, pll_id, source,
+ freq_in, freq_out);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
@@ -2681,6 +2752,33 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
}
EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
+/*
+ * snd_soc_component_set_pll - configure component PLL.
+ * @component: COMPONENT
+ * @pll_id: DAI specific PLL ID
+ * @source: DAI specific source for the PLL
+ * @freq_in: PLL input clock frequency in Hz
+ * @freq_out: requested PLL output clock frequency in Hz
+ *
+ * Configures and enables PLL to generate output clock based on input clock.
+ */
+int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id,
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ /* will be removed */
+ if (component->set_pll)
+ return component->set_pll(component, pll_id, source,
+ freq_in, freq_out);
+
+ if (component->driver->set_pll)
+ return component->driver->set_pll(component, pll_id, source,
+ freq_in, freq_out);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_set_pll);
+
/**
* snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
* @dai: DAI
@@ -3171,10 +3269,11 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
component->remove = component->driver->remove;
component->suspend = component->driver->suspend;
component->resume = component->driver->resume;
- component->pcm_new = component->driver->pcm_new;
- component->pcm_free = component->driver->pcm_free;
+ component->set_sysclk = component->driver->set_sysclk;
+ component->set_pll = component->driver->set_pll;
+ component->set_jack = component->driver->set_jack;
- dapm = &component->dapm;
+ dapm = snd_soc_component_get_dapm(component);
dapm->dev = dev;
dapm->component = component;
dapm->bias_level = SND_SOC_BIAS_OFF;
@@ -3184,13 +3283,6 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
if (driver->stream_event)
dapm->stream_event = snd_soc_component_stream_event;
- component->controls = driver->controls;
- component->num_controls = driver->num_controls;
- component->dapm_widgets = driver->dapm_widgets;
- component->num_dapm_widgets = driver->num_dapm_widgets;
- component->dapm_routes = driver->dapm_routes;
- component->num_dapm_routes = driver->num_dapm_routes;
-
INIT_LIST_HEAD(&component->dai_list);
mutex_init(&component->io_mutex);
@@ -3282,67 +3374,79 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
}
int snd_soc_register_component(struct device *dev,
- const struct snd_soc_component_driver *cmpnt_drv,
+ const struct snd_soc_component_driver *component_driver,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
- struct snd_soc_component *cmpnt;
+ struct snd_soc_component *component;
int ret;
- cmpnt = kzalloc(sizeof(*cmpnt), GFP_KERNEL);
- if (!cmpnt) {
+ component = kzalloc(sizeof(*component), GFP_KERNEL);
+ if (!component) {
dev_err(dev, "ASoC: Failed to allocate memory\n");
return -ENOMEM;
}
- ret = snd_soc_component_initialize(cmpnt, cmpnt_drv, dev);
+ ret = snd_soc_component_initialize(component, component_driver, dev);
if (ret)
goto err_free;
- cmpnt->ignore_pmdown_time = true;
- cmpnt->registered_as_component = true;
+ component->ignore_pmdown_time = true;
+ component->registered_as_component = true;
- ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, true);
+ ret = snd_soc_register_dais(component, dai_drv, num_dai, true);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
goto err_cleanup;
}
- snd_soc_component_add(cmpnt);
+ snd_soc_component_add(component);
return 0;
err_cleanup:
- snd_soc_component_cleanup(cmpnt);
+ snd_soc_component_cleanup(component);
err_free:
- kfree(cmpnt);
+ kfree(component);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_component);
/**
- * snd_soc_unregister_component - Unregister a component from the ASoC core
+ * snd_soc_unregister_component - Unregister all related component
+ * from the ASoC core
*
* @dev: The device to unregister
*/
-void snd_soc_unregister_component(struct device *dev)
+static int __snd_soc_unregister_component(struct device *dev)
{
- struct snd_soc_component *cmpnt;
+ struct snd_soc_component *component;
+ int found = 0;
mutex_lock(&client_mutex);
- list_for_each_entry(cmpnt, &component_list, list) {
- if (dev == cmpnt->dev && cmpnt->registered_as_component)
- goto found;
+ list_for_each_entry(component, &component_list, list) {
+ if (dev != component->dev ||
+ !component->registered_as_component)
+ continue;
+
+ snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
+ snd_soc_component_del_unlocked(component);
+ found = 1;
+ break;
}
mutex_unlock(&client_mutex);
- return;
-found:
- snd_soc_tplg_component_remove(cmpnt, SND_SOC_TPLG_INDEX_ALL);
- snd_soc_component_del_unlocked(cmpnt);
- mutex_unlock(&client_mutex);
- snd_soc_component_cleanup(cmpnt);
- kfree(cmpnt);
+ if (found) {
+ snd_soc_component_cleanup(component);
+ kfree(component);
+ }
+
+ return found;
+}
+
+void snd_soc_unregister_component(struct device *dev)
+{
+ while (__snd_soc_unregister_component(dev));
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
@@ -3360,25 +3464,6 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component)
platform->driver->remove(platform);
}
-static int snd_soc_platform_drv_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_platform *platform = rtd->platform;
-
- if (platform->driver->pcm_new)
- return platform->driver->pcm_new(rtd);
- else
- return 0;
-}
-
-static void snd_soc_platform_drv_pcm_free(struct snd_pcm *pcm)
-{
- struct snd_soc_pcm_runtime *rtd = pcm->private_data;
- struct snd_soc_platform *platform = rtd->platform;
-
- if (platform->driver->pcm_free)
- platform->driver->pcm_free(pcm);
-}
-
/**
* snd_soc_add_platform - Add a platform to the ASoC core
* @dev: The parent device for the platform
@@ -3402,10 +3487,6 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
platform->component.probe = snd_soc_platform_drv_probe;
if (platform_drv->remove)
platform->component.remove = snd_soc_platform_drv_remove;
- if (platform_drv->pcm_new)
- platform->component.pcm_new = snd_soc_platform_drv_pcm_new;
- if (platform_drv->pcm_free)
- platform->component.pcm_free = snd_soc_platform_drv_pcm_free;
#ifdef CONFIG_DEBUG_FS
platform->component.debugfs_prefix = "platform";
@@ -3582,6 +3663,31 @@ static int snd_soc_codec_drv_read(struct snd_soc_component *component,
return 0;
}
+static int snd_soc_codec_set_sysclk_(struct snd_soc_component *component,
+ int clk_id, int source, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+ return snd_soc_codec_set_sysclk(codec, clk_id, source, freq, dir);
+}
+
+static int snd_soc_codec_set_pll_(struct snd_soc_component *component,
+ int pll_id, int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+ return snd_soc_codec_set_pll(codec, pll_id, source, freq_in, freq_out);
+}
+
+static int snd_soc_codec_set_jack_(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data)
+{
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+ return snd_soc_codec_set_jack(codec, jack, data);
+}
+
static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
@@ -3633,6 +3739,12 @@ int snd_soc_register_codec(struct device *dev,
codec->component.write = snd_soc_codec_drv_write;
if (codec_drv->read)
codec->component.read = snd_soc_codec_drv_read;
+ if (codec_drv->set_sysclk)
+ codec->component.set_sysclk = snd_soc_codec_set_sysclk_;
+ if (codec_drv->set_pll)
+ codec->component.set_pll = snd_soc_codec_set_pll_;
+ if (codec_drv->set_jack)
+ codec->component.set_jack = snd_soc_codec_set_jack_;
codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
dapm = snd_soc_codec_get_dapm(codec);
@@ -4113,6 +4225,8 @@ int snd_soc_get_dai_id(struct device_node *ep)
}
mutex_unlock(&client_mutex);
+ of_node_put(node);
+
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_get_dai_id);
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 7daf21fee355..99902ae1a2d9 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -22,6 +22,12 @@
#include <linux/suspend.h>
#include <trace/events/asoc.h>
+struct jack_gpio_tbl {
+ int count;
+ struct snd_soc_jack *jack;
+ struct snd_soc_jack_gpio *gpios;
+};
+
/**
* snd_soc_codec_set_jack - configure codec jack.
* @codec: CODEC
@@ -36,11 +42,33 @@ int snd_soc_codec_set_jack(struct snd_soc_codec *codec,
if (codec->driver->set_jack)
return codec->driver->set_jack(codec, jack, data);
else
- return -EINVAL;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(snd_soc_codec_set_jack);
/**
+ * snd_soc_component_set_jack - configure component jack.
+ * @component: COMPONENTs
+ * @jack: structure to use for the jack
+ * @data: can be used if codec driver need extra data for configuring jack
+ *
+ * Configures and enables jack detection function.
+ */
+int snd_soc_component_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data)
+{
+ /* will be removed */
+ if (component->set_jack)
+ return component->set_jack(component, jack, data);
+
+ if (component->driver->set_jack)
+ return component->driver->set_jack(component, jack, data);
+
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_set_jack);
+
+/**
* snd_soc_card_jack_new - Create a new jack
* @card: ASoC card
* @id: an identifying string for this jack
@@ -333,6 +361,28 @@ static int snd_soc_jack_pm_notifier(struct notifier_block *nb,
return NOTIFY_DONE;
}
+static void jack_free_gpios(struct snd_soc_jack *jack, int count,
+ struct snd_soc_jack_gpio *gpios)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ gpiod_unexport(gpios[i].desc);
+ unregister_pm_notifier(&gpios[i].pm_notifier);
+ free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
+ cancel_delayed_work_sync(&gpios[i].work);
+ gpiod_put(gpios[i].desc);
+ gpios[i].jack = NULL;
+ }
+}
+
+static void jack_devres_free_gpios(struct device *dev, void *res)
+{
+ struct jack_gpio_tbl *tbl = res;
+
+ jack_free_gpios(tbl->jack, tbl->count, tbl->gpios);
+}
+
/**
* snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack
*
@@ -347,6 +397,14 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios)
{
int i, ret;
+ struct jack_gpio_tbl *tbl;
+
+ tbl = devres_alloc(jack_devres_free_gpios, sizeof(*tbl), GFP_KERNEL);
+ if (!tbl)
+ return -ENOMEM;
+ tbl->jack = jack;
+ tbl->count = count;
+ tbl->gpios = gpios;
for (i = 0; i < count; i++) {
if (!gpios[i].name) {
@@ -424,12 +482,14 @@ got_gpio:
msecs_to_jiffies(gpios[i].debounce_time));
}
+ devres_add(jack->card->dev, tbl);
return 0;
err:
gpio_free(gpios[i].gpio);
undo:
- snd_soc_jack_free_gpios(jack, i, gpios);
+ jack_free_gpios(jack, i, gpios);
+ devres_free(tbl);
return ret;
}
@@ -471,16 +531,8 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpiods);
void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios)
{
- int i;
-
- for (i = 0; i < count; i++) {
- gpiod_unexport(gpios[i].desc);
- unregister_pm_notifier(&gpios[i].pm_notifier);
- free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
- cancel_delayed_work_sync(&gpios[i].work);
- gpiod_put(gpios[i].desc);
- gpios[i].jack = NULL;
- }
+ jack_free_gpios(jack, count, gpios);
+ devres_destroy(jack->card->dev, jack_devres_free_gpios, NULL, NULL);
}
EXPORT_SYMBOL_GPL(snd_soc_jack_free_gpios);
#endif /* CONFIG_GPIOLIB */
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index dcc5ece08668..94b88b897c3b 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -181,6 +181,10 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n",
be->dai_link->name, event, dir);
+ if ((event == SND_SOC_DAPM_STREAM_STOP) &&
+ (be->dpcm[dir].users >= 1))
+ continue;
+
snd_soc_dapm_stream_event(be, dir, event);
}
@@ -450,6 +454,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
const char *codec_dai_name = "multicodec";
@@ -458,10 +464,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
pinctrl_pm_select_default_state(cpu_dai->dev);
for (i = 0; i < rtd->num_codecs; i++)
pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev);
- pm_runtime_get_sync(cpu_dai->dev);
- for (i = 0; i < rtd->num_codecs; i++)
- pm_runtime_get_sync(rtd->codec_dais[i]->dev);
- pm_runtime_get_sync(platform->dev);
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ pm_runtime_get_sync(component->dev);
+ }
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -599,15 +607,13 @@ platform_err:
out:
mutex_unlock(&rtd->pcm_mutex);
- pm_runtime_mark_last_busy(platform->dev);
- pm_runtime_put_autosuspend(platform->dev);
- for (i = 0; i < rtd->num_codecs; i++) {
- pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
- pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
}
- pm_runtime_mark_last_busy(cpu_dai->dev);
- pm_runtime_put_autosuspend(cpu_dai->dev);
for (i = 0; i < rtd->num_codecs; i++) {
if (!rtd->codec_dais[i]->active)
pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -655,6 +661,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
int i;
@@ -711,17 +719,13 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
mutex_unlock(&rtd->pcm_mutex);
- pm_runtime_mark_last_busy(platform->dev);
- pm_runtime_put_autosuspend(platform->dev);
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
- for (i = 0; i < rtd->num_codecs; i++) {
- pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
- pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
}
- pm_runtime_mark_last_busy(cpu_dai->dev);
- pm_runtime_put_autosuspend(cpu_dai->dev);
-
for (i = 0; i < rtd->num_codecs; i++) {
if (!rtd->codec_dais[i]->active)
pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -2628,25 +2632,12 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
return ret;
}
-static void soc_pcm_free(struct snd_pcm *pcm)
-{
- struct snd_soc_pcm_runtime *rtd = pcm->private_data;
- struct snd_soc_component *component;
-
- list_for_each_entry(component, &rtd->card->component_dev_list,
- card_list) {
- if (component->pcm_free)
- component->pcm_free(pcm);
- }
-}
-
/* create a new pcm */
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
{
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_component *component;
struct snd_pcm *pcm;
char new_name[64];
int ret = 0, playback = 0, capture = 0;
@@ -2756,18 +2747,17 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
if (capture)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
- list_for_each_entry(component, &rtd->card->component_dev_list, card_list) {
- if (component->pcm_new) {
- ret = component->pcm_new(rtd);
- if (ret < 0) {
- dev_err(component->dev,
- "ASoC: pcm constructor failed: %d\n",
- ret);
- return ret;
- }
+ if (platform->driver->pcm_new) {
+ ret = platform->driver->pcm_new(rtd);
+ if (ret < 0) {
+ dev_err(platform->dev,
+ "ASoC: pcm constructor failed: %d\n",
+ ret);
+ return ret;
}
}
- pcm->private_free = soc_pcm_free;
+
+ pcm->private_free = platform->driver->pcm_free;
out:
dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
(rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
@@ -3010,8 +3000,7 @@ void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
return;
}
- rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444,
- rtd->debugfs_dpcm_root,
- rtd, &dpcm_state_fops);
+ debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
+ rtd, &dpcm_state_fops);
}
#endif
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 644d9a9ebfbc..e30aacbcfc29 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -284,7 +284,7 @@ static const struct snd_pcm_ops dummy_dma_ops = {
.ioctl = snd_pcm_lib_ioctl,
};
-static struct snd_soc_platform_driver dummy_platform = {
+static const struct snd_soc_platform_driver dummy_platform = {
.ops = &dummy_dma_ops,
};
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
index 977a078eb92f..78a6a360b4a6 100644
--- a/sound/soc/spear/spdif_in.c
+++ b/sound/soc/spear/spdif_in.c
@@ -151,7 +151,7 @@ static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
-static struct snd_soc_dai_ops spdif_in_dai_ops = {
+static const struct snd_soc_dai_ops spdif_in_dai_ops = {
.shutdown = spdif_in_shutdown,
.trigger = spdif_in_trigger,
.hw_params = spdif_in_hw_params,
@@ -216,15 +216,15 @@ static int spdif_in_probe(struct platform_device *pdev)
return -EINVAL;
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
- if (!host) {
- dev_warn(&pdev->dev, "kzalloc fail\n");
+ if (!host)
return -ENOMEM;
- }
host->io_base = io_base;
host->irq = platform_get_irq(pdev, 0);
- if (host->irq < 0)
- return -EINVAL;
+ if (host->irq < 0) {
+ dev_warn(&pdev->dev, "failed to get IRQ: %d\n", host->irq);
+ return host->irq;
+ }
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c
index 0a72d52d533e..58d5843811f9 100644
--- a/sound/soc/spear/spdif_out.c
+++ b/sound/soc/spear/spdif_out.c
@@ -282,10 +282,8 @@ static int spdif_out_probe(struct platform_device *pdev)
int ret;
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
- if (!host) {
- dev_warn(&pdev->dev, "kzalloc fail\n");
+ if (!host)
return -ENOMEM;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 8052629a89df..6d0bf78d114d 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -840,7 +840,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
}
/* Reset */
- rst = devm_reset_control_get(&pdev->dev, NULL);
+ rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (!IS_ERR(rst)) {
reset_control_assert(rst);
udelay(2);
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index f7713314913b..1258bef4dcb3 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
}
/* reset */
- rst = reset_control_get(&pdev->dev, NULL);
+ rst = reset_control_get_exclusive(&pdev->dev, NULL);
if (!IS_ERR(rst)) {
reset_control_assert(rst);
udelay(2);
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 4e4250bdb75a..84cc5678beba 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -930,7 +930,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
return ret;
}
- rst = devm_reset_control_get(&pdev->dev, NULL);
+ rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (!IS_ERR(rst)) {
reset_control_assert(rst);
udelay(2);
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 150069987c0c..baa9007464ed 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -762,7 +762,7 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
{ "Mic1", NULL, "VMIC" },
};
-static struct snd_soc_codec_driver sun4i_codec_codec = {
+static const struct snd_soc_codec_driver sun4i_codec_codec = {
.component_driver = {
.controls = sun4i_codec_controls,
.num_controls = ARRAY_SIZE(sun4i_codec_controls),
@@ -1068,7 +1068,7 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Right ADC", NULL, "Right ADC Mixer" },
};
-static struct snd_soc_codec_driver sun6i_codec_codec = {
+static const struct snd_soc_codec_driver sun6i_codec_codec = {
.component_driver = {
.controls = sun6i_codec_codec_widgets,
.num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets),
@@ -1096,7 +1096,7 @@ static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
};
-static struct snd_soc_codec_driver sun8i_a23_codec_codec = {
+static const struct snd_soc_codec_driver sun8i_a23_codec_codec = {
.component_driver = {
.controls = sun8i_a23_codec_codec_controls,
.num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
@@ -1171,9 +1171,8 @@ static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
{
struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
- if (scodec->gpio_pa)
- gpiod_set_value_cansleep(scodec->gpio_pa,
- !!SND_SOC_DAPM_EVENT_ON(event));
+ gpiod_set_value_cansleep(scodec->gpio_pa,
+ !!SND_SOC_DAPM_EVENT_ON(event));
return 0;
}
@@ -1574,7 +1573,8 @@ static int sun4i_codec_probe(struct platform_device *pdev)
}
if (quirks->has_reset) {
- scodec->rst = devm_reset_control_get(&pdev->dev, NULL);
+ scodec->rst = devm_reset_control_get_exclusive(&pdev->dev,
+ NULL);
if (IS_ERR(scodec->rst)) {
dev_err(&pdev->dev, "Failed to get reset control\n");
return PTR_ERR(scodec->rst);
@@ -1655,7 +1655,6 @@ static int sun4i_codec_probe(struct platform_device *pdev)
goto err_unregister_codec;
}
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, scodec);
ret = snd_soc_register_card(card);
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 3635bbc72cbc..04f92583a969 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -50,6 +50,8 @@
#define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
#define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0)
#define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
+#define SUN4I_I2S_FMT0_POLARITY_INVERTED (1)
+#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
#define SUN4I_I2S_FMT1_REG 0x08
#define SUN4I_I2S_FIFO_TX_REG 0x0c
@@ -82,7 +84,7 @@
#define SUN4I_I2S_TX_CNT_REG 0x2c
#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30
-#define SUN4I_I2S_TX_CHAN_SEL(num_chan) (((num_chan) - 1) << 0)
+#define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0)
#define SUN4I_I2S_TX_CHAN_MAP_REG 0x34
#define SUN4I_I2S_TX_CHAN_MAP(chan, sample) ((sample) << (chan << 2))
@@ -90,6 +92,83 @@
#define SUN4I_I2S_RX_CHAN_SEL_REG 0x38
#define SUN4I_I2S_RX_CHAN_MAP_REG 0x3c
+/* Defines required for sun8i-h3 support */
+#define SUN8I_I2S_CTRL_BCLK_OUT BIT(18)
+#define SUN8I_I2S_CTRL_LRCK_OUT BIT(17)
+
+#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8)
+#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
+
+#define SUN8I_I2S_INT_STA_REG 0x0c
+#define SUN8I_I2S_FIFO_TX_REG 0x20
+
+#define SUN8I_I2S_CHAN_CFG_REG 0x30
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(6, 4)
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) (chan - 1)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(2, 0)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1)
+
+#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
+#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
+#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 11)
+#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12)
+#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
+#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
+
+#define SUN8I_I2S_RX_CHAN_SEL_REG 0x54
+#define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
+
+/**
+ * struct sun4i_i2s_quirks - Differences between SoC variants.
+ *
+ * @has_reset: SoC needs reset deasserted.
+ * @has_slave_select_bit: SoC has a bit to enable slave mode.
+ * @has_fmt_set_lrck_period: SoC requires lrclk period to be set.
+ * @has_chcfg: tx and rx slot number need to be set.
+ * @has_chsel_tx_chen: SoC requires that the tx channels are enabled.
+ * @has_chsel_offset: SoC uses offset for selecting dai operational mode.
+ * @reg_offset_txdata: offset of the tx fifo.
+ * @sun4i_i2s_regmap: regmap config to use.
+ * @mclk_offset: Value by which mclkdiv needs to be adjusted.
+ * @bclk_offset: Value by which bclkdiv needs to be adjusted.
+ * @fmt_offset: Value by which wss and sr needs to be adjusted.
+ * @field_clkdiv_mclk_en: regmap field to enable mclk output.
+ * @field_fmt_wss: regmap field to set word select size.
+ * @field_fmt_sr: regmap field to set sample resolution.
+ * @field_fmt_bclk: regmap field to set clk polarity.
+ * @field_fmt_lrclk: regmap field to set frame polarity.
+ * @field_fmt_mode: regmap field to set the operational mode.
+ * @field_txchanmap: location of the tx channel mapping register.
+ * @field_rxchanmap: location of the rx channel mapping register.
+ * @field_txchansel: location of the tx channel select bit fields.
+ * @field_rxchansel: location of the rx channel select bit fields.
+ */
+struct sun4i_i2s_quirks {
+ bool has_reset;
+ bool has_slave_select_bit;
+ bool has_fmt_set_lrck_period;
+ bool has_chcfg;
+ bool has_chsel_tx_chen;
+ bool has_chsel_offset;
+ unsigned int reg_offset_txdata; /* TX FIFO */
+ const struct regmap_config *sun4i_i2s_regmap;
+ unsigned int mclk_offset;
+ unsigned int bclk_offset;
+ unsigned int fmt_offset;
+
+ /* Register fields for i2s */
+ struct reg_field field_clkdiv_mclk_en;
+ struct reg_field field_fmt_wss;
+ struct reg_field field_fmt_sr;
+ struct reg_field field_fmt_bclk;
+ struct reg_field field_fmt_lrclk;
+ struct reg_field field_fmt_mode;
+ struct reg_field field_txchanmap;
+ struct reg_field field_rxchanmap;
+ struct reg_field field_txchansel;
+ struct reg_field field_rxchansel;
+};
+
struct sun4i_i2s {
struct clk *bus_clk;
struct clk *mod_clk;
@@ -100,6 +179,20 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
+
+ /* Register fields for i2s */
+ struct regmap_field *field_clkdiv_mclk_en;
+ struct regmap_field *field_fmt_wss;
+ struct regmap_field *field_fmt_sr;
+ struct regmap_field *field_fmt_bclk;
+ struct regmap_field *field_fmt_lrclk;
+ struct regmap_field *field_fmt_mode;
+ struct regmap_field *field_txchanmap;
+ struct regmap_field *field_rxchanmap;
+ struct regmap_field *field_txchansel;
+ struct regmap_field *field_rxchansel;
+
+ const struct sun4i_i2s_quirks *variant;
};
struct sun4i_i2s_clk_div {
@@ -114,6 +207,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = {
{ .div = 8, .val = 3 },
{ .div = 12, .val = 4 },
{ .div = 16, .val = 5 },
+ /* TODO - extend divide ratio supported by newer SoCs */
};
static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
@@ -125,6 +219,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
{ .div = 12, .val = 5 },
{ .div = 16, .val = 6 },
{ .div = 24, .val = 7 },
+ /* TODO - extend divide ratio supported by newer SoCs */
};
static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
@@ -226,10 +321,21 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
if (mclk_div < 0)
return -EINVAL;
+ /* Adjust the clock division values if needed */
+ bclk_div += i2s->variant->bclk_offset;
+ mclk_div += i2s->variant->mclk_offset;
+
regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
- SUN4I_I2S_CLK_DIV_MCLK(mclk_div) |
- SUN4I_I2S_CLK_DIV_MCLK_EN);
+ SUN4I_I2S_CLK_DIV_MCLK(mclk_div));
+
+ regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
+
+ /* Set sync period */
+ if (i2s->variant->has_fmt_set_lrck_period)
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+ SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
+ SUN8I_I2S_FMT0_LRCK_PERIOD(32));
return 0;
}
@@ -239,12 +345,38 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- int sr, wss;
+ int sr, wss, channels;
u32 width;
- if (params_channels(params) != 2)
+ channels = params_channels(params);
+ if (channels != 2)
return -EINVAL;
+ if (i2s->variant->has_chcfg) {
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
+ }
+
+ /* Map the channels for playback and capture */
+ regmap_field_write(i2s->field_txchanmap, 0x76543210);
+ regmap_field_write(i2s->field_rxchanmap, 0x00003210);
+
+ /* Configure the channels */
+ regmap_field_write(i2s->field_txchansel,
+ SUN4I_I2S_CHAN_SEL(params_channels(params)));
+
+ regmap_field_write(i2s->field_rxchansel,
+ SUN4I_I2S_CHAN_SEL(params_channels(params)));
+
+ if (i2s->variant->has_chsel_tx_chen)
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+ SUN8I_I2S_TX_CHAN_EN_MASK,
+ SUN8I_I2S_TX_CHAN_EN(channels));
+
switch (params_physical_width(params)) {
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -264,9 +396,10 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
- SUN4I_I2S_FMT0_WSS_MASK | SUN4I_I2S_FMT0_SR_MASK,
- SUN4I_I2S_FMT0_WSS(wss) | SUN4I_I2S_FMT0_SR(sr));
+ regmap_field_write(i2s->field_fmt_wss,
+ wss + i2s->variant->fmt_offset);
+ regmap_field_write(i2s->field_fmt_sr,
+ sr + i2s->variant->fmt_offset);
return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
params_width(params));
@@ -276,11 +409,15 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
u32 val;
+ u32 offset = 0;
+ u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
+ u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
/* DAI Mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
val = SUN4I_I2S_FMT0_FMT_I2S;
+ offset = 1;
break;
case SND_SOC_DAIFMT_LEFT_J:
val = SUN4I_I2S_FMT0_FMT_LEFT_J;
@@ -292,59 +429,89 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
- SUN4I_I2S_FMT0_FMT_MASK,
- val);
+ if (i2s->variant->has_chsel_offset) {
+ /*
+ * offset being set indicates that we're connected to an i2s
+ * device, however offset is only used on the sun8i block and
+ * i2s shares the same setting with the LJ format. Increment
+ * val so that the bit to value to write is correct.
+ */
+ if (offset > 0)
+ val++;
+ /* blck offset determines whether i2s or LJ */
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK,
+ SUN8I_I2S_TX_CHAN_OFFSET(offset));
+ }
+
+ regmap_field_write(i2s->field_fmt_mode, val);
/* DAI clock polarity */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
/* Invert both clocks */
- val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
- SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+ bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
+ lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_IB_NF:
/* Invert bit clock */
- val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
- SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
+ bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_NB_IF:
/* Invert frame clock */
- val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED |
- SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL;
+ lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_NB_NF:
- /* Nothing to do for both normal cases */
- val = SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL |
- SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
break;
default:
return -EINVAL;
}
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
- SUN4I_I2S_FMT0_BCLK_POLARITY_MASK |
- SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK,
- val);
-
- /* DAI clock master masks */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- /* BCLK and LRCLK master */
- val = SUN4I_I2S_CTRL_MODE_MASTER;
- break;
- case SND_SOC_DAIFMT_CBM_CFM:
- /* BCLK and LRCLK slave */
- val = SUN4I_I2S_CTRL_MODE_SLAVE;
- break;
- default:
- return -EINVAL;
+ regmap_field_write(i2s->field_fmt_bclk, bclk_polarity);
+ regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
+
+ if (i2s->variant->has_slave_select_bit) {
+ /* DAI clock master masks */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* BCLK and LRCLK master */
+ val = SUN4I_I2S_CTRL_MODE_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* BCLK and LRCLK slave */
+ val = SUN4I_I2S_CTRL_MODE_SLAVE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN4I_I2S_CTRL_MODE_MASK,
+ val);
+ } else {
+ /*
+ * The newer i2s block does not have a slave select bit,
+ * instead the clk pins are configured as inputs.
+ */
+ /* DAI clock master masks */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* BCLK and LRCLK master */
+ val = SUN8I_I2S_CTRL_BCLK_OUT |
+ SUN8I_I2S_CTRL_LRCK_OUT;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* BCLK and LRCLK slave */
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN8I_I2S_CTRL_BCLK_OUT |
+ SUN8I_I2S_CTRL_LRCK_OUT,
+ val);
}
- regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
- SUN4I_I2S_CTRL_MODE_MASK,
- val);
-
/* Set significant bits in our FIFOs */
regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
@@ -459,21 +626,14 @@ static int sun4i_i2s_startup(struct snd_pcm_substream *substream,
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
/* Enable the whole hardware block */
- regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG,
- SUN4I_I2S_CTRL_GL_EN);
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
/* Enable the first output line */
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
SUN4I_I2S_CTRL_SDO_EN_MASK,
SUN4I_I2S_CTRL_SDO_EN(0));
- /* Enable the first two channels */
- regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
- SUN4I_I2S_TX_CHAN_SEL(2));
-
- /* Map them to the two first samples coming in */
- regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG,
- SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1));
return clk_prepare_enable(i2s->mod_clk);
}
@@ -490,7 +650,8 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream,
SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
/* Disable the whole hardware block */
- regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN4I_I2S_CTRL_GL_EN, 0);
}
static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -589,6 +750,27 @@ static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg)
}
}
+static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SUN8I_I2S_FIFO_TX_REG:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+ if (reg == SUN8I_I2S_INT_STA_REG)
+ return true;
+ if (reg == SUN8I_I2S_FIFO_TX_REG)
+ return false;
+
+ return sun4i_i2s_volatile_reg(dev, reg);
+}
+
static const struct reg_default sun4i_i2s_reg_defaults[] = {
{ SUN4I_I2S_CTRL_REG, 0x00000000 },
{ SUN4I_I2S_FMT0_REG, 0x0000000c },
@@ -602,6 +784,20 @@ static const struct reg_default sun4i_i2s_reg_defaults[] = {
{ SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 },
};
+static const struct reg_default sun8i_i2s_reg_defaults[] = {
+ { SUN4I_I2S_CTRL_REG, 0x00060000 },
+ { SUN4I_I2S_FMT0_REG, 0x00000033 },
+ { SUN4I_I2S_FMT1_REG, 0x00000030 },
+ { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
+ { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
+ { SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
+ { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_MAP_REG, 0x00000000 },
+ { SUN8I_I2S_RX_CHAN_SEL_REG, 0x00000000 },
+ { SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
+};
+
static const struct regmap_config sun4i_i2s_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -616,6 +812,19 @@ static const struct regmap_config sun4i_i2s_regmap_config = {
.volatile_reg = sun4i_i2s_volatile_reg,
};
+static const struct regmap_config sun8i_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN8I_I2S_RX_CHAN_MAP_REG,
+ .cache_type = REGCACHE_FLAT,
+ .reg_defaults = sun8i_i2s_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(sun8i_i2s_reg_defaults),
+ .writeable_reg = sun4i_i2s_wr_reg,
+ .readable_reg = sun8i_i2s_rd_reg,
+ .volatile_reg = sun8i_i2s_volatile_reg,
+};
+
static int sun4i_i2s_runtime_resume(struct device *dev)
{
struct sun4i_i2s *i2s = dev_get_drvdata(dev);
@@ -654,22 +863,129 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
return 0;
}
-struct sun4i_i2s_quirks {
- bool has_reset;
-};
-
static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
- .has_reset = false,
+ .has_reset = false,
+ .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG,
+ .sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
+ .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+ .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
+ .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
+ .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .has_slave_select_bit = true,
+ .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+ .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+ .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+ .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
+ .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
};
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
- .has_reset = true,
+ .has_reset = true,
+ .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG,
+ .sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
+ .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+ .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
+ .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
+ .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .has_slave_select_bit = true,
+ .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+ .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+ .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+ .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
+ .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+};
+
+static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
+ .has_reset = true,
+ .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
+ .sun4i_i2s_regmap = &sun8i_i2s_regmap_config,
+ .mclk_offset = 1,
+ .bclk_offset = 2,
+ .fmt_offset = 3,
+ .has_fmt_set_lrck_period = true,
+ .has_chcfg = true,
+ .has_chsel_tx_chen = true,
+ .has_chsel_offset = true,
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
+ .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
+ .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
+ .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
+ .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5),
+ .field_txchanmap = REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31),
+ .field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31),
+ .field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2),
+ .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2),
};
+static int sun4i_i2s_init_regmap_fields(struct device *dev,
+ struct sun4i_i2s *i2s)
+{
+ i2s->field_clkdiv_mclk_en =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_clkdiv_mclk_en);
+ if (IS_ERR(i2s->field_clkdiv_mclk_en))
+ return PTR_ERR(i2s->field_clkdiv_mclk_en);
+
+ i2s->field_fmt_wss =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_fmt_wss);
+ if (IS_ERR(i2s->field_fmt_wss))
+ return PTR_ERR(i2s->field_fmt_wss);
+
+ i2s->field_fmt_sr =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_fmt_sr);
+ if (IS_ERR(i2s->field_fmt_sr))
+ return PTR_ERR(i2s->field_fmt_sr);
+
+ i2s->field_fmt_bclk =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_fmt_bclk);
+ if (IS_ERR(i2s->field_fmt_bclk))
+ return PTR_ERR(i2s->field_fmt_bclk);
+
+ i2s->field_fmt_lrclk =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_fmt_lrclk);
+ if (IS_ERR(i2s->field_fmt_lrclk))
+ return PTR_ERR(i2s->field_fmt_lrclk);
+
+ i2s->field_fmt_mode =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_fmt_mode);
+ if (IS_ERR(i2s->field_fmt_mode))
+ return PTR_ERR(i2s->field_fmt_mode);
+
+ i2s->field_txchanmap =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_txchanmap);
+ if (IS_ERR(i2s->field_txchanmap))
+ return PTR_ERR(i2s->field_txchanmap);
+
+ i2s->field_rxchanmap =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_rxchanmap);
+ if (IS_ERR(i2s->field_rxchanmap))
+ return PTR_ERR(i2s->field_rxchanmap);
+
+ i2s->field_txchansel =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_txchansel);
+ if (IS_ERR(i2s->field_txchansel))
+ return PTR_ERR(i2s->field_txchansel);
+
+ i2s->field_rxchansel =
+ devm_regmap_field_alloc(dev, i2s->regmap,
+ i2s->variant->field_rxchansel);
+ return PTR_ERR_OR_ZERO(i2s->field_rxchansel);
+}
+
static int sun4i_i2s_probe(struct platform_device *pdev)
{
struct sun4i_i2s *i2s;
- const struct sun4i_i2s_quirks *quirks;
struct resource *res;
void __iomem *regs;
int irq, ret;
@@ -690,8 +1006,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
return irq;
}
- quirks = of_device_get_match_data(&pdev->dev);
- if (!quirks) {
+ i2s->variant = of_device_get_match_data(&pdev->dev);
+ if (!i2s->variant) {
dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
return -ENODEV;
}
@@ -703,7 +1019,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
- &sun4i_i2s_regmap_config);
+ i2s->variant->sun4i_i2s_regmap);
if (IS_ERR(i2s->regmap)) {
dev_err(&pdev->dev, "Regmap initialisation failed\n");
return PTR_ERR(i2s->regmap);
@@ -715,8 +1031,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
return PTR_ERR(i2s->mod_clk);
}
- if (quirks->has_reset) {
- i2s->rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (i2s->variant->has_reset) {
+ i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(i2s->rst)) {
dev_err(&pdev->dev, "Failed to get reset control\n");
return PTR_ERR(i2s->rst);
@@ -732,7 +1048,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
}
- i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
+ i2s->playback_dma_data.addr = res->start +
+ i2s->variant->reg_offset_txdata;
i2s->playback_dma_data.maxburst = 8;
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
@@ -759,6 +1076,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
goto err_suspend;
}
+ ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not initialise regmap fields\n");
+ goto err_suspend;
+ }
+
return 0;
err_suspend:
@@ -797,6 +1120,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
.compatible = "allwinner,sun6i-a31-i2s",
.data = &sun6i_a31_i2s_quirks,
},
+ {
+ .compatible = "allwinner,sun8i-h3-i2s",
+ .data = &sun8i_h3_i2s_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index eaefd07a5ed0..b4af4aabead1 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -458,11 +458,16 @@ static int sun4i_spdif_runtime_suspend(struct device *dev)
static int sun4i_spdif_runtime_resume(struct device *dev)
{
struct sun4i_spdif_dev *host = dev_get_drvdata(dev);
+ int ret;
- clk_prepare_enable(host->spdif_clk);
- clk_prepare_enable(host->apb_clk);
+ ret = clk_prepare_enable(host->spdif_clk);
+ if (ret)
+ return ret;
+ ret = clk_prepare_enable(host->apb_clk);
+ if (ret)
+ clk_disable_unprepare(host->spdif_clk);
- return 0;
+ return ret;
}
static int sun4i_spdif_probe(struct platform_device *pdev)
@@ -520,7 +525,8 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host);
if (quirks->has_reset) {
- host->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
+ host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
+ NULL);
if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 5723c3404f6b..abfb710df7cb 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -341,7 +341,7 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
"AIF1 Slot 0 Right"},
};
-static struct snd_soc_dai_ops sun8i_codec_dai_ops = {
+static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
.hw_params = sun8i_codec_hw_params,
.set_fmt = sun8i_set_fmt,
};
@@ -360,7 +360,7 @@ static struct snd_soc_dai_driver sun8i_codec_dai = {
.ops = &sun8i_codec_dai_ops,
};
-static struct snd_soc_codec_driver sun8i_soc_codec = {
+static const struct snd_soc_codec_driver sun8i_soc_codec = {
.component_driver = {
.dapm_widgets = sun8i_codec_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index efbe8d4c019e..6875fc39a575 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -9,8 +9,8 @@ config SND_SOC_TEGRA
Say Y or M here if you want support for SoC audio on Tegra.
config SND_SOC_TEGRA20_AC97
- tristate
- depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+ tristate "Tegra20 AC97 interface"
+ depends on SND_SOC_TEGRA
select SND_SOC_AC97_BUS
select SND_SOC_TEGRA20_DAS
help
@@ -19,16 +19,16 @@ config SND_SOC_TEGRA20_AC97
machine drivers to support below.
config SND_SOC_TEGRA20_DAS
- tristate
- depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+ tristate "Tegra20 DAS module"
+ depends on SND_SOC_TEGRA
help
Say Y or M if you want to add support for the Tegra20 DAS module.
You will also need to select the individual machine drivers to
support below.
config SND_SOC_TEGRA20_I2S
- tristate
- depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+ tristate "Tegra20 I2S interface"
+ depends on SND_SOC_TEGRA
select SND_SOC_TEGRA20_DAS
help
Say Y or M if you want to add support for codecs attached to the
@@ -36,8 +36,8 @@ config SND_SOC_TEGRA20_I2S
machine drivers to support below.
config SND_SOC_TEGRA20_SPDIF
- tristate
- depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+ tristate "Tegra20 SPDIF interface"
+ depends on SND_SOC_TEGRA
default m
help
Say Y or M if you want to add support for the Tegra20 SPDIF interface.
@@ -45,16 +45,16 @@ config SND_SOC_TEGRA20_SPDIF
below.
config SND_SOC_TEGRA30_AHUB
- tristate
- depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC
+ tristate "Tegra30 AHUB module"
+ depends on SND_SOC_TEGRA
help
- Say Y or M if you want to add support for the Tegra20 AHUB module.
+ Say Y or M if you want to add support for the Tegra30 AHUB module.
You will also need to select the individual machine drivers to
support below.
config SND_SOC_TEGRA30_I2S
- tristate
- depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC
+ tristate "Tegra30 I2S interface"
+ depends on SND_SOC_TEGRA
select SND_SOC_TEGRA30_AHUB
help
Say Y or M if you want to add support for codecs attached to the
@@ -64,8 +64,6 @@ config SND_SOC_TEGRA30_I2S
config SND_SOC_TEGRA_RT5640
tristate "SoC Audio support for Tegra boards using an RT5640 codec"
depends on SND_SOC_TEGRA && I2C && GPIOLIB
- select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
- select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
select SND_SOC_RT5640
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -74,8 +72,6 @@ config SND_SOC_TEGRA_RT5640
config SND_SOC_TEGRA_WM8753
tristate "SoC Audio support for Tegra boards using a WM8753 codec"
depends on SND_SOC_TEGRA && I2C && GPIOLIB
- select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
- select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
select SND_SOC_WM8753
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -84,8 +80,6 @@ config SND_SOC_TEGRA_WM8753
config SND_SOC_TEGRA_WM8903
tristate "SoC Audio support for Tegra boards using a WM8903 codec"
depends on SND_SOC_TEGRA && I2C && GPIOLIB
- select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
- select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
select SND_SOC_WM8903
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -94,7 +88,7 @@ config SND_SOC_TEGRA_WM8903
config SND_SOC_TEGRA_WM9712
tristate "SoC Audio support for Tegra boards using a WM9712 codec"
- depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC && GPIOLIB
+ depends on SND_SOC_TEGRA && GPIOLIB
select SND_SOC_TEGRA20_AC97
select SND_SOC_WM9712
help
@@ -104,7 +98,6 @@ config SND_SOC_TEGRA_WM9712
config SND_SOC_TEGRA_TRIMSLICE
tristate "SoC Audio support for TrimSlice board"
depends on SND_SOC_TEGRA && I2C
- select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
select SND_SOC_TLV320AIC23_I2C
help
Say Y or M here if you want to add support for SoC audio on the
@@ -113,7 +106,6 @@ config SND_SOC_TEGRA_TRIMSLICE
config SND_SOC_TEGRA_ALC5632
tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
depends on SND_SOC_TEGRA && I2C && GPIOLIB
- select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
select SND_SOC_ALC5632
help
Say Y or M here if you want to add support for SoC audio on the
@@ -122,8 +114,6 @@ config SND_SOC_TEGRA_ALC5632
config SND_SOC_TEGRA_MAX98090
tristate "SoC Audio support for Tegra boards using a MAX98090 codec"
depends on SND_SOC_TEGRA && I2C && GPIOLIB
- select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
- select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
select SND_SOC_MAX98090
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -132,8 +122,6 @@ config SND_SOC_TEGRA_MAX98090
config SND_SOC_TEGRA_RT5677
tristate "SoC Audio support for Tegra boards using a RT5677 codec"
depends on SND_SOC_TEGRA && I2C && GPIOLIB
- select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
- select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
select SND_SOC_RT5677
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -142,8 +130,6 @@ config SND_SOC_TEGRA_RT5677
config SND_SOC_TEGRA_SGTL5000
tristate "SoC Audio support for Tegra boards using a SGTL5000 codec"
depends on SND_SOC_TEGRA && I2C && GPIOLIB
- select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
- select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
select SND_SOC_SGTL5000
help
Say Y or M here if you want to add support for SoC audio on Tegra
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 8c10ae7982ba..43679aeeb12b 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -544,8 +544,8 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
soc_data->mod_list_mask))
continue;
- rst = reset_control_get(&pdev->dev,
- configlink_mods[i].rst_name);
+ rst = reset_control_get_exclusive(&pdev->dev,
+ configlink_mods[i].rst_name);
if (IS_ERR(rst)) {
dev_err(&pdev->dev, "Can't get reset %s\n",
configlink_mods[i].rst_name);
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index b2b279c96029..0b176ea24914 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -275,7 +275,7 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai)
return 0;
}
-static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
+static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
.set_fmt = tegra30_i2s_set_fmt,
.hw_params = tegra30_i2s_hw_params,
.trigger = tegra30_i2s_trigger,
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index 0509902512cc..5197d6b18cb6 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -124,18 +124,6 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int tegra_alc5632_card_remove(struct snd_soc_card *card)
-{
- struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
-
- if (gpio_is_valid(machine->gpio_hp_det)) {
- snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1,
- &tegra_alc5632_hp_jack_gpio);
- }
-
- return 0;
-}
-
static struct snd_soc_dai_link tegra_alc5632_dai = {
.name = "ALC5632",
.stream_name = "ALC5632 PCM",
@@ -150,7 +138,6 @@ static struct snd_soc_dai_link tegra_alc5632_dai = {
static struct snd_soc_card snd_soc_tegra_alc5632 = {
.name = "tegra-alc5632",
.owner = THIS_MODULE,
- .remove = tegra_alc5632_card_remove,
.dai_link = &tegra_alc5632_dai,
.num_links = 1,
.controls = tegra_alc5632_controls,
@@ -173,7 +160,6 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, alc5632);
alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
index c34a54d6e812..cf142e2c7bd7 100644
--- a/sound/soc/tegra/tegra_max98090.c
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -176,23 +176,6 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int tegra_max98090_card_remove(struct snd_soc_card *card)
-{
- struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
-
- if (gpio_is_valid(machine->gpio_hp_det)) {
- snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
- &tegra_max98090_hp_jack_gpio);
- }
-
- if (gpio_is_valid(machine->gpio_mic_det)) {
- snd_soc_jack_free_gpios(&tegra_max98090_mic_jack, 1,
- &tegra_max98090_mic_jack_gpio);
- }
-
- return 0;
-}
-
static struct snd_soc_dai_link tegra_max98090_dai = {
.name = "max98090",
.stream_name = "max98090 PCM",
@@ -206,7 +189,6 @@ static struct snd_soc_dai_link tegra_max98090_dai = {
static struct snd_soc_card snd_soc_tegra_max98090 = {
.name = "tegra-max98090",
.owner = THIS_MODULE,
- .remove = tegra_max98090_card_remove,
.dai_link = &tegra_max98090_dai,
.num_links = 1,
.controls = tegra_max98090_controls,
@@ -229,7 +211,6 @@ static int tegra_max98090_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index 93a356802345..fc81b48aa9d6 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -126,18 +126,6 @@ static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int tegra_rt5640_card_remove(struct snd_soc_card *card)
-{
- struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
-
- if (gpio_is_valid(machine->gpio_hp_det)) {
- snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1,
- &tegra_rt5640_hp_jack_gpio);
- }
-
- return 0;
-}
-
static struct snd_soc_dai_link tegra_rt5640_dai = {
.name = "RT5640",
.stream_name = "RT5640 PCM",
@@ -151,7 +139,6 @@ static struct snd_soc_dai_link tegra_rt5640_dai = {
static struct snd_soc_card snd_soc_tegra_rt5640 = {
.name = "tegra-rt5640",
.owner = THIS_MODULE,
- .remove = tegra_rt5640_card_remove,
.dai_link = &tegra_rt5640_dai,
.num_links = 1,
.controls = tegra_rt5640_controls,
@@ -174,7 +161,6 @@ static int tegra_rt5640_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
machine->gpio_hp_det = of_get_named_gpio_flags(
diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c
index ebf58d0e0f10..0e4805c7b4ca 100644
--- a/sound/soc/tegra/tegra_rt5677.c
+++ b/sound/soc/tegra/tegra_rt5677.c
@@ -169,23 +169,6 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int tegra_rt5677_card_remove(struct snd_soc_card *card)
-{
- struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
-
- if (gpio_is_valid(machine->gpio_hp_det)) {
- snd_soc_jack_free_gpios(&tegra_rt5677_hp_jack, 1,
- &tegra_rt5677_hp_jack_gpio);
- }
-
- if (gpio_is_valid(machine->gpio_mic_present)) {
- snd_soc_jack_free_gpios(&tegra_rt5677_mic_jack, 1,
- &tegra_rt5677_mic_jack_gpio);
- }
-
- return 0;
-}
-
static struct snd_soc_dai_link tegra_rt5677_dai = {
.name = "RT5677",
.stream_name = "RT5677 PCM",
@@ -199,7 +182,6 @@ static struct snd_soc_dai_link tegra_rt5677_dai = {
static struct snd_soc_card snd_soc_tegra_rt5677 = {
.name = "tegra-rt5677",
.owner = THIS_MODULE,
- .remove = tegra_rt5677_card_remove,
.dai_link = &tegra_rt5677_dai,
.num_links = 1,
.controls = tegra_rt5677_controls,
@@ -222,7 +204,6 @@ static int tegra_rt5677_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c
index 6dda01f69983..45a4aa9d2a47 100644
--- a/sound/soc/tegra/tegra_sgtl5000.c
+++ b/sound/soc/tegra/tegra_sgtl5000.c
@@ -124,7 +124,6 @@ static int tegra_sgtl5000_driver_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
ret = snd_soc_of_parse_card_name(card, "nvidia,model");
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index d0ab0026a4cd..23a810e3bacc 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -132,7 +132,6 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
ret = snd_soc_of_parse_card_name(card, "nvidia,model");
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index dbfb49298ae8..18bdae59a4df 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -203,12 +203,6 @@ static int tegra_wm8903_remove(struct snd_soc_card *card)
snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_codec *codec = codec_dai->codec;
- struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-
- if (gpio_is_valid(machine->gpio_hp_det)) {
- snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1,
- &tegra_wm8903_hp_jack_gpio);
- }
wm8903_mic_detect(codec, NULL, 0, 0);
@@ -252,7 +246,6 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
machine->gpio_spkr_en = of_get_named_gpio(np, "nvidia,spkr-en-gpios",
diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c
index c9cd22432627..864a3345972e 100644
--- a/sound/soc/tegra/tegra_wm9712.c
+++ b/sound/soc/tegra/tegra_wm9712.c
@@ -81,7 +81,6 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
machine->codec = platform_device_alloc("wm9712-codec", -1);
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index c9dcad9bb931..99bcdd979eb2 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -127,7 +127,6 @@ static int tegra_snd_trimslice_probe(struct platform_device *pdev)
return -ENOMEM;
card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, trimslice);
trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(np,
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index 7912bf09dc4d..a2bb68fea5a3 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -271,7 +271,7 @@ static int txx9aclc_pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-static struct snd_pcm_ops txx9aclc_pcm_ops = {
+static const struct snd_pcm_ops txx9aclc_pcm_ops = {
.open = txx9aclc_pcm_open,
.close = txx9aclc_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -403,7 +403,7 @@ static int txx9aclc_pcm_remove(struct snd_soc_platform *platform)
return 0;
}
-static struct snd_soc_platform_driver txx9aclc_soc_platform = {
+static const struct snd_soc_platform_driver txx9aclc_soc_platform = {
.probe = txx9aclc_pcm_probe,
.remove = txx9aclc_pcm_remove,
.ops = &txx9aclc_pcm_ops,
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index b50f68a439ce..070a6880980e 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -33,6 +33,7 @@ static struct snd_soc_dai_link mop500_dai_links[] = {
.stream_name = "ab8500_0",
.cpu_dai_name = "ux500-msp-i2s.1",
.codec_dai_name = "ab8500-codec-dai.0",
+ .platform_name = "ux500-msp-i2s.1",
.codec_name = "ab8500-codec.0",
.init = mop500_ab8500_machine_init,
.ops = mop500_ab8500_ops,
@@ -42,6 +43,7 @@ static struct snd_soc_dai_link mop500_dai_links[] = {
.stream_name = "ab8500_1",
.cpu_dai_name = "ux500-msp-i2s.3",
.codec_dai_name = "ab8500-codec-dai.1",
+ .platform_name = "ux500-msp-i2s.3",
.codec_name = "ab8500-codec.0",
.init = NULL,
.ops = mop500_ab8500_ops,
@@ -85,6 +87,8 @@ static int mop500_of_probe(struct platform_device *pdev,
for (i = 0; i < 2; i++) {
mop500_dai_links[i].cpu_of_node = msp_np[i];
mop500_dai_links[i].cpu_dai_name = NULL;
+ mop500_dai_links[i].platform_of_node = msp_np[i];
+ mop500_dai_links[i].platform_name = NULL;
mop500_dai_links[i].codec_of_node = codec_np;
mop500_dai_links[i].codec_name = NULL;
}
@@ -111,7 +115,6 @@ static int mop500_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "%s: Card %s: Set platform drvdata.\n",
__func__, mop500_card.name);
- platform_set_drvdata(pdev, &mop500_card);
snd_soc_card_set_drvdata(&mop500_card, NULL);
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index ec5152aa3f6e..625b72a5facd 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -707,7 +707,7 @@ static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-static struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
+static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
{
.set_sysclk = ux500_msp_dai_set_dai_sysclk,
.set_fmt = ux500_msp_dai_set_dai_fmt,
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 082736c539bc..e630813c5008 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -542,6 +542,8 @@ int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
if (size < sizeof(scale))
return -ENOMEM;
+ if (cval->min_mute)
+ scale[0] = SNDRV_CTL_TLVT_DB_MINMAX_MUTE;
scale[2] = cval->dBmin;
scale[3] = cval->dBmax;
if (copy_to_user(_tlv, scale, sizeof(scale)))
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 3417ef347e40..2b4b067646ab 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -64,6 +64,7 @@ struct usb_mixer_elem_info {
int cached;
int cache_val[MAX_CHANNELS];
u8 initialized;
+ u8 min_mute;
void *private_data;
};
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index e3d1dec48ee4..e1e7ce9ab217 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -1878,6 +1878,12 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
if (unitid == 7 && cval->control == UAC_FU_VOLUME)
snd_dragonfly_quirk_db_scale(mixer, cval, kctl);
break;
+ /* lowest playback value is muted on C-Media devices */
+ case USB_ID(0x0d8c, 0x000c):
+ case USB_ID(0x0d8c, 0x0014):
+ if (strstr(kctl->id.name, "Playback"))
+ cval->min_mute = 1;
+ break;
}
}
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index d7b0b0a3a2db..5d2a63248b1d 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1142,6 +1142,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */
case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
+ case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */
case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */
@@ -1308,10 +1309,13 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
&& (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(20);
- /* Zoom R16/24 needs a tiny delay here, otherwise requests like
- * get/set frequency return as failed despite actually succeeding.
+ /* Zoom R16/24, Logitech H650e, Jabra 550a needs a tiny delay here,
+ * otherwise requests like get/set frequency return as failed despite
+ * actually succeeding.
*/
- if (chip->usb_id == USB_ID(0x1686, 0x00dd) &&
+ if ((chip->usb_id == USB_ID(0x1686, 0x00dd) ||
+ chip->usb_id == USB_ID(0x046d, 0x0a46) ||
+ chip->usb_id == USB_ID(0x0b0e, 0x0349)) &&
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(1);
}
@@ -1374,6 +1378,10 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
}
}
break;
+ case USB_ID(0x16d0, 0x0a23):
+ if (fp->altsetting == 2)
+ return SNDRV_PCM_FMTBIT_DSD_U32_BE;
+ break;
default:
break;