diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-02-09 10:54:50 +0300 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-02-09 10:54:50 +0300 |
commit | d1612c80edaab7ac9170cb2fc86b538ab2e5a741 (patch) | |
tree | 759755d5abef02f23a42f5056aaac84de694d5ad | |
parent | d34890cf4113397625a6629d71749fa638a7a734 (diff) | |
parent | f4c2e9bcb0be4ee1c8722853e4faaaf6a9423d72 (diff) | |
download | linux-d1612c80edaab7ac9170cb2fc86b538ab2e5a741.tar.xz |
Merge tag 'asoc-v3.20-3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next
ASoC: Final updates for v3.20
A few more updates for v3.20 that have accumilated over the second half
of last week. One new (relatively simple) driver for the Maxim
max98357a and some other driver specific fixes and enhancements. I did
apply a few patches that haven't been in -next just now before sending
this, all fixes except for one simple device ID addition patch.
27 files changed, 775 insertions, 596 deletions
diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt new file mode 100644 index 000000000000..b41433386e2f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt @@ -0,0 +1,23 @@ +Ingenic JZ4740 I2S controller + +Required properties: +- compatible : "ingenic,jz4740-i2s" +- reg : I2S registers location and length +- clocks : AIC and I2S PLL clock specifiers. +- clock-names: "aic" and "i2s" +- dmas: DMA controller phandle and DMA request line for I2S Tx and Rx channels +- dma-names: Must be "tx" and "rx" + +Example: + +i2s: i2s@10020000 { + compatible = "ingenic,jz4740-i2s"; + reg = <0x10020000 0x94>; + + clocks = <&cgu JZ4740_CLK_AIC>, <&cgu JZ4740_CLK_I2SPLL>; + clock-names = "aic", "i2s"; + + dmas = <&dma 2>, <&dma 3>; + dma-names = "tx", "rx"; + +}; diff --git a/Documentation/devicetree/bindings/sound/max98357a.txt b/Documentation/devicetree/bindings/sound/max98357a.txt new file mode 100644 index 000000000000..a7a149a236e5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98357a.txt @@ -0,0 +1,14 @@ +Maxim MAX98357A audio DAC + +This node models the Maxim MAX98357A DAC. + +Required properties: +- compatible : "maxim,max98357a" +- sdmode-gpios : GPIO specifier for the GPIO -> DAC SDMODE pin + +Example: + +max98357a { + compatible = "maxim,max98357a"; + sdmode-gpios = <&qcom_pinmux 25 0>; +}; diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index b8168f1f8139..cb6001085f1a 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -61,9 +61,12 @@ reg = <0x03830000 0x100>; clocks = <&clock_audss EXYNOS_I2S_BUS>; clock-names = "iis"; + #clock-cells = <1>; + clock-output-names = "i2s_cdclk0"; dmas = <&pdma0 12>, <&pdma0 11>, <&pdma0 10>; dma-names = "tx", "rx", "tx-sec"; samsung,idma-addr = <0x03000000>; + #sound-dai-cells = <1>; status = "disabled"; }; @@ -368,22 +371,28 @@ }; i2s1: i2s@13960000 { - compatible = "samsung,s5pv210-i2s"; + compatible = "samsung,s3c6410-i2s"; reg = <0x13960000 0x100>; clocks = <&clock CLK_I2S1>; clock-names = "iis"; + #clock-cells = <1>; + clock-output-names = "i2s_cdclk1"; dmas = <&pdma1 12>, <&pdma1 11>; dma-names = "tx", "rx"; + #sound-dai-cells = <1>; status = "disabled"; }; i2s2: i2s@13970000 { - compatible = "samsung,s5pv210-i2s"; + compatible = "samsung,s3c6410-i2s"; reg = <0x13970000 0x100>; clocks = <&clock CLK_I2S2>; clock-names = "iis"; + #clock-cells = <1>; + clock-output-names = "i2s_cdclk2"; dmas = <&pdma0 14>, <&pdma0 13>; dma-names = "tx", "rx"; + #sound-dai-cells = <1>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 3fbf588682b9..abd63366298a 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -7,6 +7,7 @@ * published by the Free Software Foundation. */ +#include <dt-bindings/sound/samsung-i2s.h> #include <dt-bindings/input/input.h> #include "exynos4412.dtsi" @@ -37,14 +38,13 @@ pinctrl-names = "default"; status = "okay"; clocks = <&clock_audss EXYNOS_I2S_BUS>, - <&clock_audss EXYNOS_DOUT_AUD_BUS>; - clock-names = "iis", "i2s_opclk0"; + <&clock_audss EXYNOS_DOUT_AUD_BUS>, + <&clock_audss EXYNOS_SCLK_I2S>; + clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; }; sound: sound { - compatible = "samsung,odroidx2-audio"; - samsung,i2s-controller = <&i2s0>; - samsung,audio-codec = <&max98090>; + compatible = "simple-audio-card"; assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>, <&clock_audss EXYNOS_MOUT_I2S>, <&clock_audss EXYNOS_DOUT_SRP>, @@ -55,6 +55,20 @@ <0>, <192000000>, <19200000>; + + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&link0_codec>; + simple-audio-card,frame-master = <&link0_codec>; + + simple-audio-card,cpu { + sound-dai = <&i2s0 0>; + system-clock-frequency = <19200000>; + }; + + link0_codec: simple-audio-card,codec { + sound-dai = <&max98090>; + clocks = <&i2s0 CLK_I2S_CDCLK>; + }; }; mmc@12550000 { @@ -373,6 +387,9 @@ reg = <0x10>; interrupt-parent = <&gpx0>; interrupts = <0 0>; + clocks = <&i2s0 CLK_I2S_CDCLK>; + clock-names = "mclk"; + #sound-dai-cells = <0>; }; }; diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts index c8a64be55d07..44684e57ead1 100644 --- a/arch/arm/boot/dts/exynos4412-odroidu3.dts +++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts @@ -49,9 +49,11 @@ }; &sound { - compatible = "samsung,odroidu3-audio"; - samsung,model = "Odroid-U3"; - samsung,audio-routing = + simple-audio-card,name = "Odroid-U3"; + simple-audio-card,widgets = + "Headphone", "Headphone Jack", + "Speakers", "Speakers"; + simple-audio-card,routing = "Headphone Jack", "HPL", "Headphone Jack", "HPR", "Headphone Jack", "MICBIAS", diff --git a/arch/arm/boot/dts/exynos4412-odroidx2.dts b/arch/arm/boot/dts/exynos4412-odroidx2.dts index 96b43f4497cc..6e33678562ae 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx2.dts +++ b/arch/arm/boot/dts/exynos4412-odroidx2.dts @@ -23,8 +23,12 @@ }; &sound { - samsung,model = "Odroid-X2"; - samsung,audio-routing = + simple-audio-card,name = "Odroid-X2"; + simple-audio-card,widgets = + "Headphone", "Headphone Jack", + "Microphone", "Mic Jack", + "Microphone", "DMIC"; + simple-audio-card,routing = "Headphone Jack", "HPL", "Headphone Jack", "HPR", "IN1", "Mic Jack", diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3190eed43c38..064e6c18e109 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98088 if I2C select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C + select SND_SOC_MAX98357A select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C select SND_SOC_MAX9877 if I2C @@ -456,6 +457,9 @@ config SND_SOC_MAX98090 config SND_SOC_MAX98095 tristate +config SND_SOC_MAX98357A + tristate + config SND_SOC_MAX9850 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bbdfd1e1c182..69b8666d187a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -64,6 +64,7 @@ snd-soc-max9768-objs := max9768.o snd-soc-max98088-objs := max98088.o snd-soc-max98090-objs := max98090.o snd-soc-max98095-objs := max98095.o +snd-soc-max98357a-objs := max98357a.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o @@ -245,6 +246,7 @@ obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o 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_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c new file mode 100644 index 000000000000..1806333ea29e --- /dev/null +++ b/sound/soc/codecs/max98357a.c @@ -0,0 +1,138 @@ +/* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + * + * max98357a.c -- MAX98357A ALSA SoC Codec driver + */ + +#include <linux/module.h> +#include <linux/gpio.h> +#include <sound/soc.h> + +#define DRV_NAME "max98357a" + +static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + gpiod_set_value(sdmode, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + gpiod_set_value(sdmode, 0); + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = { + SND_SOC_DAPM_DAC("SDMode", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("Speaker"), +}; + +static const struct snd_soc_dapm_route max98357a_dapm_routes[] = { + {"Speaker", NULL, "SDMode"}, +}; + +static int max98357a_codec_probe(struct snd_soc_codec *codec) +{ + struct gpio_desc *sdmode; + + sdmode = devm_gpiod_get(codec->dev, "sdmode"); + if (IS_ERR(sdmode)) { + dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n", + __func__, PTR_ERR(sdmode)); + return PTR_ERR(sdmode); + } + gpiod_direction_output(sdmode, 0); + snd_soc_codec_set_drvdata(codec, sdmode); + + return 0; +} + +static struct snd_soc_codec_driver max98357a_codec_driver = { + .probe = max98357a_codec_probe, + .dapm_widgets = max98357a_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98357a_dapm_widgets), + .dapm_routes = max98357a_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes), +}; + +static struct snd_soc_dai_ops max98357a_dai_ops = { + .trigger = max98357a_daiops_trigger, +}; + +static struct snd_soc_dai_driver max98357a_dai_driver = { + .name = DRV_NAME, + .playback = { + .stream_name = DRV_NAME "-playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &max98357a_dai_ops, +}; + +static int max98357a_platform_probe(struct platform_device *pdev) +{ + int ret; + + ret = snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver, + &max98357a_dai_driver, 1); + if (ret) + dev_err(&pdev->dev, "%s() error registering codec driver: %d\n", + __func__, ret); + + return ret; +} + +static int max98357a_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id max98357a_device_id[] = { + { .compatible = "maxim," DRV_NAME, }, + {} +}; +MODULE_DEVICE_TABLE(of, max98357a_device_id); +#endif + +static struct platform_driver max98357a_platform_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(max98357a_device_id), + }, + .probe = max98357a_platform_probe, + .remove = max98357a_platform_remove, +}; +module_platform_driver(max98357a_platform_driver); + +MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 8104d2285602..f374840a5a7c 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -34,6 +34,7 @@ #include "rt286.h" #define RT286_VENDOR_ID 0x10ec0286 +#define RT288_VENDOR_ID 0x10ec0288 struct rt286_priv { struct regmap *regmap; @@ -305,6 +306,8 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) *hp = false; *mic = false; + if (!rt286->codec) + return -EINVAL; if (rt286->pdata.cbj_en) { regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); *hp = buf & 0x80000000; @@ -1169,6 +1172,7 @@ static const struct regmap_config rt286_regmap = { static const struct i2c_device_id rt286_i2c_id[] = { {"rt286", 0}, + {"rt288", 0}, {} }; MODULE_DEVICE_TABLE(i2c, rt286_i2c_id); @@ -1189,6 +1193,17 @@ static struct dmi_system_id force_combo_jack_table[] = { { } }; +static struct dmi_system_id dmi_dell_dino[] = { + { + .ident = "Dell Dino", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_BOARD_NAME, "0144P8") + } + }, + { } +}; + static int rt286_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1211,7 +1226,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c, regmap_read(rt286->regmap, RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret); - if (ret != RT286_VENDOR_ID) { + if (ret != RT286_VENDOR_ID && ret != RT288_VENDOR_ID) { dev_err(&i2c->dev, "Device with ID register %x is not rt286\n", ret); return -ENODEV; @@ -1224,7 +1239,8 @@ static int rt286_i2c_probe(struct i2c_client *i2c, if (pdata) rt286->pdata = *pdata; - if (dmi_check_system(force_combo_jack_table)) + if (dmi_check_system(force_combo_jack_table) || + dmi_check_system(dmi_dell_dino)) rt286->pdata.cbj_en = true; regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); @@ -1263,6 +1279,17 @@ static int rt286_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); + if (dmi_check_system(dmi_dell_dino)) { + regmap_update_bits(rt286->regmap, + RT286_SET_GPIO_MASK, 0x40, 0x40); + regmap_update_bits(rt286->regmap, + RT286_SET_GPIO_DIRECTION, 0x40, 0x40); + regmap_update_bits(rt286->regmap, + RT286_SET_GPIO_DATA, 0x40, 0x40); + regmap_update_bits(rt286->regmap, + RT286_GPIO_CTRL, 0xc, 0x8); + } + if (rt286->i2c->irq) { ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286); diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h index b539b7320a79..7130edb152ef 100644 --- a/sound/soc/codecs/rt286.h +++ b/sound/soc/codecs/rt286.h @@ -117,6 +117,12 @@ VERB_CMD(AC_VERB_SET_COEF_INDEX, RT286_VENDOR_REGISTERS, 0) #define RT286_PROC_COEF\ VERB_CMD(AC_VERB_SET_PROC_COEF, RT286_VENDOR_REGISTERS, 0) +#define RT286_SET_GPIO_MASK\ + VERB_CMD(AC_VERB_SET_GPIO_MASK, RT286_AUDIO_FUNCTION_GROUP, 0) +#define RT286_SET_GPIO_DIRECTION\ + VERB_CMD(AC_VERB_SET_GPIO_DIRECTION, RT286_AUDIO_FUNCTION_GROUP, 0) +#define RT286_SET_GPIO_DATA\ + VERB_CMD(AC_VERB_SET_GPIO_DATA, RT286_AUDIO_FUNCTION_GROUP, 0) /* Index registers */ #define RT286_A_BIAS_CTRL1 0x01 @@ -131,6 +137,7 @@ #define RT286_POWER_CTRL3 0x0f #define RT286_MIC1_DET_CTRL 0x19 #define RT286_MISC_CTRL1 0x20 +#define RT286_GPIO_CTRL 0x29 #define RT286_IRQ_CTRL 0x33 #define RT286_PLL_CTRL1 0x49 #define RT286_CBJ_CTRL1 0x4f diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 3e16a889a806..c9a4c5be083b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -615,6 +615,87 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source, } +/** + * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5645 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + unsigned int asrc2_mask = 0; + unsigned int asrc2_value = 0; + unsigned int asrc3_mask = 0; + unsigned int asrc3_value = 0; + + switch (clk_src) { + case RT5645_CLK_SEL_SYS: + case RT5645_CLK_SEL_I2S1_ASRC: + case RT5645_CLK_SEL_I2S2_ASRC: + case RT5645_CLK_SEL_SYS2: + break; + + default: + return -EINVAL; + } + + if (filter_mask & RT5645_DA_STEREO_FILTER) { + asrc2_mask |= RT5645_DA_STO_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_DA_STO_CLK_SEL_MASK) + | (clk_src << RT5645_DA_STO_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_DA_MONO_L_FILTER) { + asrc2_mask |= RT5645_DA_MONOL_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_DA_MONOL_CLK_SEL_MASK) + | (clk_src << RT5645_DA_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_DA_MONO_R_FILTER) { + asrc2_mask |= RT5645_DA_MONOR_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_DA_MONOR_CLK_SEL_MASK) + | (clk_src << RT5645_DA_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_AD_STEREO_FILTER) { + asrc2_mask |= RT5645_AD_STO1_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5645_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_AD_MONO_L_FILTER) { + asrc3_mask |= RT5645_AD_MONOL_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5645_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5645_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_AD_MONO_R_FILTER) { + asrc3_mask |= RT5645_AD_MONOR_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5645_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5645_AD_MONOR_CLK_SEL_SFT); + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5645_ASRC_2, + asrc2_mask, asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5645_ASRC_3, + asrc3_mask, asrc3_value); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5645_sel_asrc_clk_src); + /* Digital Mixer */ static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 74542310d3f0..dbfd98c22f4d 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -1120,50 +1120,27 @@ #define RT5645_DMIC_2_M_NOR (0x0 << 8) #define RT5645_DMIC_2_M_ASYN (0x1 << 8) +/* ASRC clock source selection (0x84, 0x85) */ +#define RT5645_CLK_SEL_SYS (0x0) +#define RT5645_CLK_SEL_I2S1_ASRC (0x1) +#define RT5645_CLK_SEL_I2S2_ASRC (0x2) +#define RT5645_CLK_SEL_SYS2 (0x5) + /* ASRC Control 2 (0x84) */ -#define RT5645_MDA_L_M_MASK (0x1 << 15) -#define RT5645_MDA_L_M_SFT 15 -#define RT5645_MDA_L_M_NOR (0x0 << 15) -#define RT5645_MDA_L_M_ASYN (0x1 << 15) -#define RT5645_MDA_R_M_MASK (0x1 << 14) -#define RT5645_MDA_R_M_SFT 14 -#define RT5645_MDA_R_M_NOR (0x0 << 14) -#define RT5645_MDA_R_M_ASYN (0x1 << 14) -#define RT5645_MAD_L_M_MASK (0x1 << 13) -#define RT5645_MAD_L_M_SFT 13 -#define RT5645_MAD_L_M_NOR (0x0 << 13) -#define RT5645_MAD_L_M_ASYN (0x1 << 13) -#define RT5645_MAD_R_M_MASK (0x1 << 12) -#define RT5645_MAD_R_M_SFT 12 -#define RT5645_MAD_R_M_NOR (0x0 << 12) -#define RT5645_MAD_R_M_ASYN (0x1 << 12) -#define RT5645_ADC_M_MASK (0x1 << 11) -#define RT5645_ADC_M_SFT 11 -#define RT5645_ADC_M_NOR (0x0 << 11) -#define RT5645_ADC_M_ASYN (0x1 << 11) -#define RT5645_STO_DAC_M_MASK (0x1 << 5) -#define RT5645_STO_DAC_M_SFT 5 -#define RT5645_STO_DAC_M_NOR (0x0 << 5) -#define RT5645_STO_DAC_M_ASYN (0x1 << 5) -#define RT5645_I2S1_R_D_MASK (0x1 << 4) -#define RT5645_I2S1_R_D_SFT 4 -#define RT5645_I2S1_R_D_DIS (0x0 << 4) -#define RT5645_I2S1_R_D_EN (0x1 << 4) -#define RT5645_I2S2_R_D_MASK (0x1 << 3) -#define RT5645_I2S2_R_D_SFT 3 -#define RT5645_I2S2_R_D_DIS (0x0 << 3) -#define RT5645_I2S2_R_D_EN (0x1 << 3) -#define RT5645_PRE_SCLK_MASK (0x3) -#define RT5645_PRE_SCLK_SFT 0 -#define RT5645_PRE_SCLK_512 (0x0) -#define RT5645_PRE_SCLK_1024 (0x1) -#define RT5645_PRE_SCLK_2048 (0x2) +#define RT5645_DA_STO_CLK_SEL_MASK (0xf << 12) +#define RT5645_DA_STO_CLK_SEL_SFT 12 +#define RT5645_DA_MONOL_CLK_SEL_MASK (0xf << 8) +#define RT5645_DA_MONOL_CLK_SEL_SFT 8 +#define RT5645_DA_MONOR_CLK_SEL_MASK (0xf << 4) +#define RT5645_DA_MONOR_CLK_SEL_SFT 4 +#define RT5645_AD_STO1_CLK_SEL_MASK (0xf << 0) +#define RT5645_AD_STO1_CLK_SEL_SFT 0 /* ASRC Control 3 (0x85) */ -#define RT5645_I2S1_RATE_MASK (0xf << 12) -#define RT5645_I2S1_RATE_SFT 12 -#define RT5645_I2S2_RATE_MASK (0xf << 8) -#define RT5645_I2S2_RATE_SFT 8 +#define RT5645_AD_MONOL_CLK_SEL_MASK (0xf << 4) +#define RT5645_AD_MONOL_CLK_SEL_SFT 4 +#define RT5645_AD_MONOR_CLK_SEL_MASK (0xf << 0) +#define RT5645_AD_MONOR_CLK_SEL_SFT 0 /* ASRC Control 4 (0x89) */ #define RT5645_I2S1_PD_MASK (0x7 << 12) @@ -2189,6 +2166,19 @@ enum { CODEC_TYPE_RT5650, }; +/* filter mask */ +enum { + RT5645_DA_STEREO_FILTER = 0x1, + RT5645_DA_MONO_L_FILTER = (0x1 << 1), + RT5645_DA_MONO_R_FILTER = (0x1 << 2), + RT5645_AD_STEREO_FILTER = (0x1 << 3), + RT5645_AD_MONO_L_FILTER = (0x1 << 4), + RT5645_AD_MONO_R_FILTER = (0x1 << 5), +}; + +int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + struct rt5645_priv { struct snd_soc_codec *codec; struct rt5645_platform_data pdata; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 7b3d6b5992f1..e1a4a45c57e2 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2616,6 +2616,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = { static const struct regmap_config rt5670_regmap = { .reg_bits = 8, .val_bits = 16, + .use_single_rw = true, .max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) * RT5670_PR_SPACING), .volatile_reg = rt5670_volatile_register, diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index c0813f546d1f..ee03dbdda235 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -110,3 +110,14 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH platforms with RT5672 audio codec. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_RT5645_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645 codec" + depends on X86_INTEL_LPSS + select SND_SOC_RT5645 + select SND_SST_MFLD_PLATFORM + select SND_SST_IPC_ACPI + help + This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell + platforms with RT5645 audio codec. + If unsure select "N". diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index e928ec385300..a8e53c45c6b6 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -28,6 +28,7 @@ snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o +snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o @@ -35,6 +36,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o # DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c new file mode 100644 index 000000000000..bd29617a9ab9 --- /dev/null +++ b/sound/soc/intel/cht_bsw_rt5645.c @@ -0,0 +1,326 @@ +/* + * cht-bsw-rt5645.c - ASoc Machine driver for Intel Cherryview-based platforms + * Cherrytrail and Braswell, with RT5645 codec. + * + * Copyright (C) 2015 Intel Corp + * Author: Fang, Yang A <yang.a.fang@intel.com> + * N,Harshapriya <harshapriya.n@intel.com> + * This file is modified from cht_bsw_rt5672.c + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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/platform_device.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include "../codecs/rt5645.h" +#include "sst-atom-controls.h" + +#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI "rt5645-aif1" + +struct cht_mc_private { + struct snd_soc_jack hp_jack; + struct snd_soc_jack mic_jack; +}; + +static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) +{ + int i; + + for (i = 0; i < card->num_rtd; i++) { + struct snd_soc_pcm_runtime *rtd; + + rtd = card->rtd + i; + if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, + strlen(CHT_CODEC_DAI))) + return rtd->codec_dai; + } + return NULL; +} + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = cht_get_codec_dai(card); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); + return -EIO; + } + + if (!SND_SOC_DAPM_EVENT_OFF(event)) + return 0; + + /* Set codec sysclk source to its internal clock because codec PLL will + * be off when idle and MCLK will also be off by ACPI when codec is + * runtime suspended. Codec needs clock for jack detection and button + * press. + */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route cht_audio_map[] = { + {"IN1P", NULL, "Headset Mic"}, + {"IN1N", NULL, "Headset Mic"}, + {"DMIC L1", NULL, "Int Mic"}, + {"DMIC R1", NULL, "Int Mic"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"Ext Spk", NULL, "SPOL"}, + {"Ext Spk", NULL, "SPOR"}, + {"AIF1 Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx" }, + {"codec_in1", NULL, "ssp2 Rx" }, + {"ssp2 Rx", NULL, "AIF1 Capture"}, + {"Headphone", NULL, "Platform Clock"}, + {"Headset Mic", NULL, "Platform Clock"}, + {"Int Mic", NULL, "Platform Clock"}, + {"Ext Spk", NULL, "Platform Clock"}, +}; + +static const struct snd_kcontrol_new cht_mc_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Ext Spk"), +}; + +static int cht_aif1_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 *codec_dai = rtd->codec_dai; + int ret; + + /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK, + CHT_PLAT_CLK_3_HZ, params_rate(params) * 512); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1, + params_rate(params) * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } + + return 0; +} + +static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_codec *codec = runtime->codec; + struct snd_soc_dai *codec_dai = runtime->codec_dai; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); + + /* Select clk_i2s1_asrc as ASRC clock source */ + rt5645_sel_asrc_clk_src(codec, + RT5645_DA_STEREO_FILTER | + RT5645_DA_MONO_L_FILTER | + RT5645_DA_MONO_R_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + + /* 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) { + dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret); + return ret; + } + + ret = snd_soc_jack_new(codec, "Headphone Jack", + SND_JACK_HEADPHONE, + &ctx->hp_jack); + if (ret) { + dev_err(runtime->dev, "HP jack creation failed %d\n", ret); + return ret; + } + + ret = snd_soc_jack_new(codec, "Mic Jack", + SND_JACK_MICROPHONE, + &ctx->mic_jack); + if (ret) { + dev_err(runtime->dev, "Mic jack creation failed %d\n", ret); + return ret; + } + + rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack); + + return ret; +} + +static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP2 to 24-bit */ + snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - + SNDRV_PCM_HW_PARAM_FIRST_MASK], + SNDRV_PCM_FORMAT_S24_LE); + return 0; +} + +static unsigned int rates_48000[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_48000 = { + .count = ARRAY_SIZE(rates_48000), + .list = rates_48000, +}; + +static int cht_aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_48000); +} + +static struct snd_soc_ops cht_aif1_ops = { + .startup = cht_aif1_startup, +}; + +static struct snd_soc_ops cht_be_ssp2_ops = { + .hw_params = cht_aif1_hw_params, +}; + +static struct snd_soc_dai_link cht_dailink[] = { + [MERR_DPCM_AUDIO] = { + .name = "Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "media-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &cht_aif1_ops, + }, + [MERR_DPCM_COMPR] = { + .name = "Compressed Port", + .stream_name = "Compress", + .cpu_dai_name = "compress-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + }, + /* CODEC<->CODEC link */ + /* back ends */ + { + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5645-aif1", + .codec_name = "i2c-10EC5645:00", + .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .init = cht_codec_init, + .be_hw_params_fixup = cht_codec_fixup, + .ignore_suspend = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &cht_be_ssp2_ops, + }, +}; + +/* SoC card */ +static struct snd_soc_card snd_soc_card_cht = { + .name = "chtrt5645", + .dai_link = cht_dailink, + .num_links = ARRAY_SIZE(cht_dailink), + .dapm_widgets = cht_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), + .dapm_routes = cht_audio_map, + .num_dapm_routes = ARRAY_SIZE(cht_audio_map), + .controls = cht_mc_controls, + .num_controls = ARRAY_SIZE(cht_mc_controls), +}; + +static int snd_cht_mc_probe(struct platform_device *pdev) +{ + int ret_val = 0; + struct cht_mc_private *drv; + + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); + if (!drv) + return -ENOMEM; + + snd_soc_card_cht.dev = &pdev->dev; + snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); + if (ret_val) { + dev_err(&pdev->dev, + "snd_soc_register_card failed %d\n", ret_val); + return ret_val; + } + platform_set_drvdata(pdev, &snd_soc_card_cht); + return ret_val; +} + +static struct platform_driver snd_cht_mc_driver = { + .driver = { + .name = "cht-bsw-rt5645", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_cht_mc_probe, +}; + +module_platform_driver(snd_cht_mc_driver) + +MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver"); +MODULE_AUTHOR("Fang, Yang A,N,Harshapriya"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-rt5645"); diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index a282179a3064..0ab1309ef274 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -338,12 +338,6 @@ static inline u32 msg_get_stage_type(u32 msg) return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; } -static inline u32 msg_set_stage_type(u32 msg, u32 type) -{ - return (msg & ~IPC_STG_TYPE_MASK) + - (type << IPC_STG_TYPE_SHIFT); -} - static inline u32 msg_get_stream_id(u32 msg) { return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT; @@ -970,45 +964,6 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw, } /* Mixer Controls */ -int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, - u32 stage_id, u32 channel) -{ - int ret; - - ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel, - &stream->mute_volume[channel]); - if (ret < 0) - return ret; - - ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0); - if (ret < 0) { - dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", - stream->reply.stream_hw_id, channel); - return ret; - } - - stream->mute[channel] = 1; - return 0; -} - -int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, - u32 stage_id, u32 channel) - -{ - int ret; - - stream->mute[channel] = 0; - ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, - stream->mute_volume[channel]); - if (ret < 0) { - dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", - stream->reply.stream_hw_id, channel); - return ret; - } - - return 0; -} - int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume) { @@ -1022,17 +977,6 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream return 0; } -int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u64 curve_duration, - enum sst_hsw_volume_curve curve) -{ - /* curve duration in steps of 100ns */ - stream->vol_req.curve_duration = curve_duration; - stream->vol_req.curve_type = curve; - - return 0; -} - /* stream volume */ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume) @@ -1084,42 +1028,6 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, return 0; } -int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel) -{ - int ret; - - ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel, - &hsw->mute_volume[channel]); - if (ret < 0) - return ret; - - ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0); - if (ret < 0) { - dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", - channel); - return ret; - } - - hsw->mute[channel] = 1; - return 0; -} - -int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel) -{ - int ret; - - ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, - hsw->mixer_info.volume_register_address[channel]); - if (ret < 0) { - dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", - channel); - return ret; - } - - hsw->mute[channel] = 0; - return 0; -} - int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 *volume) { @@ -1133,16 +1041,6 @@ int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, return 0; } -int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, - u64 curve_duration, enum sst_hsw_volume_curve curve) -{ - /* curve duration in steps of 100ns */ - hsw->curve_duration = curve_duration; - hsw->curve_type = curve; - - return 0; -} - /* global mixer volume */ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 volume) @@ -1451,48 +1349,6 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) /* Stream Information - these calls could be inline but we want the IPC ABI to be opaque to client PCM drivers to cope with any future ABI changes */ -int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, - struct sst_hsw_stream *stream) -{ - return stream->reply.stream_hw_id; -} - -int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, - struct sst_hsw_stream *stream) -{ - return stream->reply.mixer_hw_id; -} - -u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream) -{ - return stream->reply.read_position_register_address; -} - -u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream) -{ - return stream->reply.presentation_position_register_address; -} - -u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 channel) -{ - if (channel >= 2) - return 0; - - return stream->reply.peak_meter_register_address[channel]; -} - -u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 channel) -{ - if (channel >= 2) - return 0; - - return stream->reply.volume_register_address[channel]; -} - int sst_hsw_mixer_get_info(struct sst_hsw *hsw) { struct sst_hsw_ipc_stream_info_reply *reply; @@ -1630,30 +1486,6 @@ u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, return ppos; } -int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 stage_id, u32 position) -{ - u32 header; - int ret; - - trace_stream_write_position(stream->reply.stream_hw_id, position); - - header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | - IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); - header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); - header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT); - header |= (stage_id << IPC_STG_ID_SHIFT); - stream->wpos.position = position; - - ret = ipc_tx_message_nowait(hsw, header, &stream->wpos, - sizeof(stream->wpos)); - if (ret < 0) - dev_err(hsw->dev, "error: stream %d set position %d failed\n", - stream->reply.stream_hw_id, position); - - return ret; -} - /* physical BE config */ int sst_hsw_device_set_config(struct sst_hsw *hsw, enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 138e894ab413..c1ad901342f2 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -376,32 +376,17 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw, u32 create_channel_map(enum sst_hsw_channel_config config); /* Stream Mixer Controls - */ -int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, - u32 stage_id, u32 channel); -int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, - u32 stage_id, u32 channel); - int sst_hsw_stream_set_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume); int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume); -int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u64 curve_duration, - enum sst_hsw_volume_curve curve); - /* Global Mixer Controls - */ -int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel); -int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel); - int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 volume); int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 *volume); -int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, - u64 curve_duration, enum sst_hsw_volume_curve curve); - /* Stream API */ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data), @@ -440,18 +425,6 @@ int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 offset, u32 size); int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 offset, u32 size); -int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, - struct sst_hsw_stream *stream); -int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, - struct sst_hsw_stream *stream); -u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream); -u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream); -u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 channel); -u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 channel); int sst_hsw_mixer_get_info(struct sst_hsw *hsw); /* Stream ALSA trigger operations */ @@ -466,8 +439,6 @@ int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 *position); int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 *position); -int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 stage_id, u32 position); u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, struct sst_hsw_stream *stream); u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, @@ -481,8 +452,6 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, /* DX Config */ int sst_hsw_dx_set_state(struct sst_hsw *hsw, enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx); -int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, - u32 *offset, u32 *size, u32 *source); /* init */ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index ad7f4a51e138..78fa01be57f2 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -119,8 +119,9 @@ struct hsw_pcm_data { }; enum hsw_pm_state { - HSW_PM_STATE_D3 = 0, - HSW_PM_STATE_D0 = 1, + HSW_PM_STATE_D0 = 0, + HSW_PM_STATE_RTD3 = 1, + HSW_PM_STATE_D3 = 2, }; /* private data for the driver */ @@ -1035,12 +1036,12 @@ static int hsw_pcm_runtime_suspend(struct device *dev) struct hsw_priv_data *pdata = dev_get_drvdata(dev); struct sst_hsw *hsw = pdata->hsw; - if (pdata->pm_state == HSW_PM_STATE_D3) + if (pdata->pm_state >= HSW_PM_STATE_RTD3) return 0; sst_hsw_dsp_runtime_suspend(hsw); sst_hsw_dsp_runtime_sleep(hsw); - pdata->pm_state = HSW_PM_STATE_D3; + pdata->pm_state = HSW_PM_STATE_RTD3; return 0; } @@ -1051,7 +1052,7 @@ static int hsw_pcm_runtime_resume(struct device *dev) struct sst_hsw *hsw = pdata->hsw; int ret; - if (pdata->pm_state == HSW_PM_STATE_D0) + if (pdata->pm_state != HSW_PM_STATE_RTD3) return 0; ret = sst_hsw_dsp_load(hsw); @@ -1091,7 +1092,7 @@ static void hsw_pcm_complete(struct device *dev) struct hsw_pcm_data *pcm_data; int i, err; - if (pdata->pm_state == HSW_PM_STATE_D0) + if (pdata->pm_state != HSW_PM_STATE_D3) return; err = sst_hsw_dsp_load(hsw); @@ -1139,41 +1140,42 @@ static int hsw_pcm_prepare(struct device *dev) if (pdata->pm_state == HSW_PM_STATE_D3) return 0; - /* suspend all active streams */ - for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; + else if (pdata->pm_state == HSW_PM_STATE_D0) { + /* suspend all active streams */ + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; + + if (!pcm_data->substream) + continue; + dev_dbg(dev, "suspending pcm %d\n", i); + snd_pcm_suspend_all(pcm_data->hsw_pcm); + + /* We need to wait until the DSP FW stops the streams */ + msleep(2); + } - if (!pcm_data->substream) - continue; - dev_dbg(dev, "suspending pcm %d\n", i); - snd_pcm_suspend_all(pcm_data->hsw_pcm); + /* preserve persistent memory */ + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; + + if (!pcm_data->substream) + continue; - /* We need to wait until the DSP FW stops the streams */ - msleep(2); + dev_dbg(dev, "saving context pcm %d\n", i); + err = sst_module_runtime_save(pcm_data->runtime, + &pcm_data->context); + if (err < 0) + dev_err(dev, "failed to save context for PCM %d\n", i); + } + /* enter D3 state and stall */ + sst_hsw_dsp_runtime_suspend(hsw); + /* put the DSP to sleep */ + sst_hsw_dsp_runtime_sleep(hsw); } snd_soc_suspend(pdata->soc_card->dev); snd_soc_poweroff(pdata->soc_card->dev); - /* enter D3 state and stall */ - sst_hsw_dsp_runtime_suspend(hsw); - - /* preserve persistent memory */ - for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; - - if (!pcm_data->substream) - continue; - - dev_dbg(dev, "saving context pcm %d\n", i); - err = sst_module_runtime_save(pcm_data->runtime, - &pcm_data->context); - if (err < 0) - dev_err(dev, "failed to save context for PCM %d\n", i); - } - - /* put the DSP to sleep */ - sst_hsw_dsp_runtime_sleep(hsw); pdata->pm_state = HSW_PM_STATE_D3; return 0; diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h index 7f4bbfcbc6f5..562bc483d6b7 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/sst/sst.h @@ -58,6 +58,7 @@ enum sst_algo_ops { #define SST_BLOCK_TIMEOUT 1000 #define FW_SIGNATURE_SIZE 4 +#define FW_NAME_SIZE 32 /* stream states */ enum sst_stream_states { @@ -426,7 +427,7 @@ struct intel_sst_drv { * Holder for firmware name. Due to async call it needs to be * persistent till worker thread gets called */ - char firmware_name[20]; + char firmware_name[FW_NAME_SIZE]; }; /* misc definitions */ diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index 43bc1c4b9207..b782dfdcdbba 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c @@ -47,7 +47,7 @@ struct sst_machines { char board[32]; char machine[32]; void (*machine_quirk)(void); - char firmware[32]; + char firmware[FW_NAME_SIZE]; struct sst_platform_info *pdata; }; @@ -350,9 +350,9 @@ static struct sst_machines sst_acpi_bytcr[] = { /* Cherryview-based platforms: CherryTrail and Braswell */ static struct sst_machines sst_acpi_chv[] = { - {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "fw_sst_22a8.bin", + {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin", &chv_platform_data }, - {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "fw_sst_22a8.bin", + {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", &chv_platform_data }, {}, }; diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index d3d45c6f064f..07f77815a586 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -14,6 +14,8 @@ #include <linux/init.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -83,6 +85,8 @@ #define JZ_AIC_I2S_STATUS_BUSY BIT(2) #define JZ_AIC_CLK_DIV_MASK 0xf +#define I2SDIV_DV_SHIFT 8 +#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT) struct jz4740_i2s { struct resource *mem; @@ -237,10 +241,14 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, { struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int sample_size; - uint32_t ctrl; + uint32_t ctrl, div_reg; + int div; ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); + div_reg = jz4740_i2s_read(i2s, JZ_REG_AIC_CLK_DIV); + div = clk_get_rate(i2s->clk_i2s) / (64 * params_rate(params)); + switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: sample_size = 0; @@ -264,7 +272,10 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; } + div_reg &= ~I2SDIV_DV_MASK; + div_reg |= (div - 1) << I2SDIV_DV_SHIFT; jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); + jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg); return 0; } @@ -415,6 +426,13 @@ static const struct snd_soc_component_driver jz4740_i2s_component = { .name = "jz4740-i2s", }; +#ifdef CONFIG_OF +static const struct of_device_id jz4740_of_matches[] = { + { .compatible = "ingenic,jz4740-i2s" }, + { /* sentinel */ } +}; +#endif + static int jz4740_i2s_dev_probe(struct platform_device *pdev) { struct jz4740_i2s *i2s; @@ -455,6 +473,7 @@ static struct platform_driver jz4740_i2s_driver = { .probe = jz4740_i2s_dev_probe, .driver = { .name = "jz4740-i2s", + .of_match_table = of_match_ptr(jz4740_of_matches) }, }; diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index e817a2f43ea8..3cebf6ca03df 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -146,17 +146,6 @@ config SND_SOC_SMARTQ select SND_SAMSUNG_I2S select SND_SOC_WM8750 -config SND_SOC_GONI_AQUILA_WM8994 - tristate "SoC I2S Audio support for AQUILA/GONI - WM8994" - depends on SND_SOC_SAMSUNG && (MACH_GONI || MACH_AQUILA) - depends on I2C=y - select SND_SAMSUNG_I2S - select MFD_WM8994 - select SND_SOC_WM8994 - help - Say Y if you want to add support for SoC audio on goni or aquila - with the WM8994. - config SND_SOC_SAMSUNG_SMDK_SPDIF tristate "SoC S/PDIF Audio support for SMDK" depends on SND_SOC_SAMSUNG diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 31e3dba7e3b5..052fe71be518 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -35,7 +35,6 @@ snd-soc-smdk-wm8994-objs := smdk_wm8994.o snd-soc-snow-objs := snow.o snd-soc-smdk-wm9713-objs := smdk_wm9713.o snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o -snd-soc-goni-wm8994-objs := goni_wm8994.o snd-soc-smdk-spdif-objs := smdk_spdif.o snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o @@ -63,7 +62,6 @@ obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o -obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c deleted file mode 100644 index fad56b9e7369..000000000000 --- a/sound/soc/samsung/goni_wm8994.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * goni_wm8994.c - * - * Copyright (C) 2010 Samsung Electronics Co.Ltd - * Author: Chanwoo Choi <cw00.choi@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <linux/module.h> -#include <sound/soc.h> -#include <sound/jack.h> - -#include <asm/mach-types.h> -#include <mach/gpio-samsung.h> - -#include "../codecs/wm8994.h" - -#define MACHINE_NAME 0 -#define CPU_VOICE_DAI 1 - -static const char *aquila_str[] = { - [MACHINE_NAME] = "aquila", - [CPU_VOICE_DAI] = "aquila-voice-dai", -}; - -static struct snd_soc_card goni; -static struct platform_device *goni_snd_device; - -/* 3.5 pie jack */ -static struct snd_soc_jack jack; - -/* 3.5 pie jack detection DAPM pins */ -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, { - .pin = "Headset Stereophone", - .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL | - SND_JACK_AVOUT, - }, -}; - -/* 3.5 pie jack detection gpios */ -static struct snd_soc_jack_gpio jack_gpios[] = { - { - .gpio = S5PV210_GPH0(6), - .name = "DET_3.5", - .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_AVOUT, - .debounce_time = 200, - }, -}; - -static const struct snd_soc_dapm_widget goni_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Ext Left Spk", NULL), - SND_SOC_DAPM_SPK("Ext Right Spk", NULL), - SND_SOC_DAPM_SPK("Ext Rcv", NULL), - SND_SOC_DAPM_HP("Headset Stereophone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Main Mic", NULL), - SND_SOC_DAPM_MIC("2nd Mic", NULL), - SND_SOC_DAPM_LINE("Radio In", NULL), -}; - -static const struct snd_soc_dapm_route goni_dapm_routes[] = { - {"Ext Left Spk", NULL, "SPKOUTLP"}, - {"Ext Left Spk", NULL, "SPKOUTLN"}, - - {"Ext Right Spk", NULL, "SPKOUTRP"}, - {"Ext Right Spk", NULL, "SPKOUTRN"}, - - {"Ext Rcv", NULL, "HPOUT2N"}, - {"Ext Rcv", NULL, "HPOUT2P"}, - - {"Headset Stereophone", NULL, "HPOUT1L"}, - {"Headset Stereophone", NULL, "HPOUT1R"}, - - {"IN1RN", NULL, "Headset Mic"}, - {"IN1RP", NULL, "Headset Mic"}, - - {"IN1RN", NULL, "2nd Mic"}, - {"IN1RP", NULL, "2nd Mic"}, - - {"IN1LN", NULL, "Main Mic"}, - {"IN1LP", NULL, "Main Mic"}, - - {"IN2LN", NULL, "Radio In"}, - {"IN2RN", NULL, "Radio In"}, -}; - -static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; - - /* set endpoints to not connected */ - snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN"); - snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); - snd_soc_dapm_nc_pin(dapm, "LINEOUT1N"); - snd_soc_dapm_nc_pin(dapm, "LINEOUT1P"); - snd_soc_dapm_nc_pin(dapm, "LINEOUT2N"); - snd_soc_dapm_nc_pin(dapm, "LINEOUT2P"); - - if (machine_is_aquila()) { - snd_soc_dapm_nc_pin(dapm, "SPKOUTRN"); - snd_soc_dapm_nc_pin(dapm, "SPKOUTRP"); - } - - /* Headset jack detection */ - ret = snd_soc_jack_new(codec, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT, - &jack); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins); - if (ret) - return ret; - - ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios); - if (ret) - return ret; - - return 0; -} - -static int goni_hifi_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 *codec_dai = rtd->codec_dai; - unsigned int pll_out = 24000000; - int ret = 0; - - /* set the codec FLL */ - ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out, - params_rate(params) * 256); - if (ret < 0) - return ret; - - /* set the codec system clock */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, - params_rate(params) * 256, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops goni_hifi_ops = { - .hw_params = goni_hifi_hw_params, -}; - -static int goni_voice_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 *codec_dai = rtd->codec_dai; - unsigned int pll_out = 24000000; - int ret = 0; - - if (params_rate(params) != 8000) - return -EINVAL; - - /* set the codec FLL */ - ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out, - params_rate(params) * 256); - if (ret < 0) - return ret; - - /* set the codec system clock */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2, - params_rate(params) * 256, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_dai_driver voice_dai = { - .name = "goni-voice-dai", - .id = 0, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, -}; - -static const struct snd_soc_component_driver voice_component = { - .name = "goni-voice", -}; - -static struct snd_soc_ops goni_voice_ops = { - .hw_params = goni_voice_hw_params, -}; - -static struct snd_soc_dai_link goni_dai[] = { -{ - .name = "WM8994", - .stream_name = "WM8994 HiFi", - .cpu_dai_name = "samsung-i2s.0", - .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-i2s.0", - .codec_name = "wm8994-codec.0-001a", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, - .init = goni_wm8994_init, - .ops = &goni_hifi_ops, -}, { - .name = "WM8994 Voice", - .stream_name = "Voice", - .cpu_dai_name = "goni-voice-dai", - .codec_dai_name = "wm8994-aif2", - .codec_name = "wm8994-codec.0-001a", - .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_IB_IF | - SND_SOC_DAIFMT_CBM_CFM, - .ops = &goni_voice_ops, -}, -}; - -static struct snd_soc_card goni = { - .name = "goni", - .owner = THIS_MODULE, - .dai_link = goni_dai, - .num_links = ARRAY_SIZE(goni_dai), - - .dapm_widgets = goni_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(goni_dapm_widgets), - .dapm_routes = goni_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(goni_dapm_routes), -}; - -static int __init goni_init(void) -{ - int ret; - - if (machine_is_aquila()) { - voice_dai.name = aquila_str[CPU_VOICE_DAI]; - goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI]; - goni.name = aquila_str[MACHINE_NAME]; - } else if (!machine_is_goni()) - return -ENODEV; - - goni_snd_device = platform_device_alloc("soc-audio", -1); - if (!goni_snd_device) - return -ENOMEM; - - /* register voice DAI here */ - ret = devm_snd_soc_register_component(&goni_snd_device->dev, - &voice_component, &voice_dai, 1); - if (ret) { - platform_device_put(goni_snd_device); - return ret; - } - - platform_set_drvdata(goni_snd_device, &goni); - ret = platform_device_add(goni_snd_device); - - if (ret) - platform_device_put(goni_snd_device); - - return ret; -} - -static void __exit goni_exit(void) -{ - platform_device_unregister(goni_snd_device); -} - -module_init(goni_init); -module_exit(goni_exit); - -/* Module information */ -MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)"); -MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d94434d6138e..30579ca5bacb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2419,8 +2419,8 @@ int snd_soc_unregister_card(struct snd_soc_card *card) card->instantiated = false; snd_soc_dapm_shutdown(card); soc_cleanup_card_resources(card); + dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); } - dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); return 0; } |