Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: codecs: Add msm8916-wcd digital codec

msm8916-wcd codec is found in Qualcomm msm8916 and apq8016 processors.
This codec IP is split in to two parts(Digital & Analog).
Analog part is integrated in to PMIC PM8916 and the digital part is
integrated into Application processor. Data transfer between Analog and
Digital Die is done via a internal bus called PDM.

This patch adds support to Digital part of the Codec which is integrated
into Application Processor.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Srinivas Kandagatla and committed by
Mark Brown
150db8c5 585e881e

+948
+20
Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt
··· 1 + msm8916 digital audio CODEC 2 + 3 + ## Bindings for codec core in lpass: 4 + 5 + Required properties 6 + - compatible = "qcom,msm8916-wcd-digital-codec"; 7 + - reg: address space for lpass codec. 8 + - clocks: Handle to mclk and ahbclk 9 + - clock-names: should be "mclk", "ahbix-clk". 10 + 11 + Example: 12 + 13 + audio-codec@771c000{ 14 + compatible = "qcom,msm8916-wcd-digital-codec"; 15 + reg = <0x0771c000 0x400>; 16 + clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>, 17 + <&gcc GCC_CODEC_DIGCODEC_CLK>; 18 + clock-names = "ahbix-clk", "mclk"; 19 + #sound-dai-cells = <1>; 20 + };
+3
sound/soc/codecs/Kconfig
··· 585 585 tristate "Qualcomm MSM8916 WCD Analog Codec" 586 586 depends on SPMI || COMPILE_TEST 587 587 588 + config SND_SOC_MSM8916_WCD_DIGITAL 589 + tristate "Qualcomm MSM8916 WCD DIGITAL Codec" 590 + 588 591 config SND_SOC_PCM1681 589 592 tristate "Texas Instruments PCM1681 CODEC" 590 593 depends on I2C
+2
sound/soc/codecs/Makefile
··· 87 87 snd-soc-mc13783-objs := mc13783.o 88 88 snd-soc-ml26124-objs := ml26124.o 89 89 snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o 90 + snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o 90 91 snd-soc-nau8810-objs := nau8810.o 91 92 snd-soc-nau8825-objs := nau8825.o 92 93 snd-soc-hdmi-codec-objs := hdmi-codec.o ··· 312 311 obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o 313 312 obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o 314 313 obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o 314 + obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o 315 315 obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o 316 316 obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o 317 317 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
+923
sound/soc/codecs/msm8916-wcd-digital.c
··· 1 + /* Copyright (c) 2016, The Linux Foundation. All rights reserved. 2 + * 3 + * This program is free software; you can redistribute it and/or modify 4 + * it under the terms of the GNU General Public License version 2 and 5 + * only version 2 as published by the Free Software Foundation. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + */ 12 + 13 + #include <linux/module.h> 14 + #include <linux/err.h> 15 + #include <linux/kernel.h> 16 + #include <linux/delay.h> 17 + #include <linux/types.h> 18 + #include <linux/clk.h> 19 + #include <linux/of.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/regmap.h> 22 + #include <linux/mfd/syscon.h> 23 + #include <sound/soc.h> 24 + #include <sound/pcm.h> 25 + #include <sound/pcm_params.h> 26 + #include <sound/tlv.h> 27 + 28 + #define LPASS_CDC_CLK_RX_RESET_CTL (0x000) 29 + #define LPASS_CDC_CLK_TX_RESET_B1_CTL (0x004) 30 + #define CLK_RX_RESET_B1_CTL_TX1_RESET_MASK BIT(0) 31 + #define CLK_RX_RESET_B1_CTL_TX2_RESET_MASK BIT(1) 32 + #define LPASS_CDC_CLK_DMIC_B1_CTL (0x008) 33 + #define DMIC_B1_CTL_DMIC0_CLK_SEL_MASK GENMASK(3, 1) 34 + #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV2 (0x0 << 1) 35 + #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3 (0x1 << 1) 36 + #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV4 (0x2 << 1) 37 + #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV6 (0x3 << 1) 38 + #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV16 (0x4 << 1) 39 + #define DMIC_B1_CTL_DMIC0_CLK_EN_MASK BIT(0) 40 + #define DMIC_B1_CTL_DMIC0_CLK_EN_ENABLE BIT(0) 41 + 42 + #define LPASS_CDC_CLK_RX_I2S_CTL (0x00C) 43 + #define RX_I2S_CTL_RX_I2S_MODE_MASK BIT(5) 44 + #define RX_I2S_CTL_RX_I2S_MODE_16 BIT(5) 45 + #define RX_I2S_CTL_RX_I2S_MODE_32 0 46 + #define RX_I2S_CTL_RX_I2S_FS_RATE_MASK GENMASK(2, 0) 47 + #define RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ 0x0 48 + #define RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ 0x1 49 + #define RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ 0x2 50 + #define RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ 0x3 51 + #define RX_I2S_CTL_RX_I2S_FS_RATE_F_96_KHZ 0x4 52 + #define RX_I2S_CTL_RX_I2S_FS_RATE_F_192_KHZ 0x5 53 + #define LPASS_CDC_CLK_TX_I2S_CTL (0x010) 54 + #define TX_I2S_CTL_TX_I2S_MODE_MASK BIT(5) 55 + #define TX_I2S_CTL_TX_I2S_MODE_16 BIT(5) 56 + #define TX_I2S_CTL_TX_I2S_MODE_32 0 57 + #define TX_I2S_CTL_TX_I2S_FS_RATE_MASK GENMASK(2, 0) 58 + #define TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ 0x0 59 + #define TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ 0x1 60 + #define TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ 0x2 61 + #define TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ 0x3 62 + #define TX_I2S_CTL_TX_I2S_FS_RATE_F_96_KHZ 0x4 63 + #define TX_I2S_CTL_TX_I2S_FS_RATE_F_192_KHZ 0x5 64 + 65 + #define LPASS_CDC_CLK_OTHR_RESET_B1_CTL (0x014) 66 + #define LPASS_CDC_CLK_TX_CLK_EN_B1_CTL (0x018) 67 + #define LPASS_CDC_CLK_OTHR_CTL (0x01C) 68 + #define LPASS_CDC_CLK_RX_B1_CTL (0x020) 69 + #define LPASS_CDC_CLK_MCLK_CTL (0x024) 70 + #define MCLK_CTL_MCLK_EN_MASK BIT(0) 71 + #define MCLK_CTL_MCLK_EN_ENABLE BIT(0) 72 + #define MCLK_CTL_MCLK_EN_DISABLE 0 73 + #define LPASS_CDC_CLK_PDM_CTL (0x028) 74 + #define LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK BIT(0) 75 + #define LPASS_CDC_CLK_PDM_CTL_PDM_EN BIT(0) 76 + #define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK BIT(1) 77 + #define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB BIT(1) 78 + #define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_PDM_CLK 0 79 + 80 + #define LPASS_CDC_CLK_SD_CTL (0x02C) 81 + #define LPASS_CDC_RX1_B1_CTL (0x040) 82 + #define LPASS_CDC_RX2_B1_CTL (0x060) 83 + #define LPASS_CDC_RX3_B1_CTL (0x080) 84 + #define LPASS_CDC_RX1_B2_CTL (0x044) 85 + #define LPASS_CDC_RX2_B2_CTL (0x064) 86 + #define LPASS_CDC_RX3_B2_CTL (0x084) 87 + #define LPASS_CDC_RX1_B3_CTL (0x048) 88 + #define LPASS_CDC_RX2_B3_CTL (0x068) 89 + #define LPASS_CDC_RX3_B3_CTL (0x088) 90 + #define LPASS_CDC_RX1_B4_CTL (0x04C) 91 + #define LPASS_CDC_RX2_B4_CTL (0x06C) 92 + #define LPASS_CDC_RX3_B4_CTL (0x08C) 93 + #define LPASS_CDC_RX1_B5_CTL (0x050) 94 + #define LPASS_CDC_RX2_B5_CTL (0x070) 95 + #define LPASS_CDC_RX3_B5_CTL (0x090) 96 + #define LPASS_CDC_RX1_B6_CTL (0x054) 97 + #define RXn_B6_CTL_MUTE_MASK BIT(0) 98 + #define RXn_B6_CTL_MUTE_ENABLE BIT(0) 99 + #define RXn_B6_CTL_MUTE_DISABLE 0 100 + #define LPASS_CDC_RX2_B6_CTL (0x074) 101 + #define LPASS_CDC_RX3_B6_CTL (0x094) 102 + #define LPASS_CDC_RX1_VOL_CTL_B1_CTL (0x058) 103 + #define LPASS_CDC_RX2_VOL_CTL_B1_CTL (0x078) 104 + #define LPASS_CDC_RX3_VOL_CTL_B1_CTL (0x098) 105 + #define LPASS_CDC_RX1_VOL_CTL_B2_CTL (0x05C) 106 + #define LPASS_CDC_RX2_VOL_CTL_B2_CTL (0x07C) 107 + #define LPASS_CDC_RX3_VOL_CTL_B2_CTL (0x09C) 108 + #define LPASS_CDC_TOP_GAIN_UPDATE (0x0A0) 109 + #define LPASS_CDC_TOP_CTL (0x0A4) 110 + #define TOP_CTL_DIG_MCLK_FREQ_MASK BIT(0) 111 + #define TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ 0 112 + #define TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ BIT(0) 113 + 114 + #define LPASS_CDC_DEBUG_DESER1_CTL (0x0E0) 115 + #define LPASS_CDC_DEBUG_DESER2_CTL (0x0E4) 116 + #define LPASS_CDC_DEBUG_B1_CTL_CFG (0x0E8) 117 + #define LPASS_CDC_DEBUG_B2_CTL_CFG (0x0EC) 118 + #define LPASS_CDC_DEBUG_B3_CTL_CFG (0x0F0) 119 + #define LPASS_CDC_IIR1_GAIN_B1_CTL (0x100) 120 + #define LPASS_CDC_IIR2_GAIN_B1_CTL (0x140) 121 + #define LPASS_CDC_IIR1_GAIN_B2_CTL (0x104) 122 + #define LPASS_CDC_IIR2_GAIN_B2_CTL (0x144) 123 + #define LPASS_CDC_IIR1_GAIN_B3_CTL (0x108) 124 + #define LPASS_CDC_IIR2_GAIN_B3_CTL (0x148) 125 + #define LPASS_CDC_IIR1_GAIN_B4_CTL (0x10C) 126 + #define LPASS_CDC_IIR2_GAIN_B4_CTL (0x14C) 127 + #define LPASS_CDC_IIR1_GAIN_B5_CTL (0x110) 128 + #define LPASS_CDC_IIR2_GAIN_B5_CTL (0x150) 129 + #define LPASS_CDC_IIR1_GAIN_B6_CTL (0x114) 130 + #define LPASS_CDC_IIR2_GAIN_B6_CTL (0x154) 131 + #define LPASS_CDC_IIR1_GAIN_B7_CTL (0x118) 132 + #define LPASS_CDC_IIR2_GAIN_B7_CTL (0x158) 133 + #define LPASS_CDC_IIR1_GAIN_B8_CTL (0x11C) 134 + #define LPASS_CDC_IIR2_GAIN_B8_CTL (0x15C) 135 + #define LPASS_CDC_IIR1_CTL (0x120) 136 + #define LPASS_CDC_IIR2_CTL (0x160) 137 + #define LPASS_CDC_IIR1_GAIN_TIMER_CTL (0x124) 138 + #define LPASS_CDC_IIR2_GAIN_TIMER_CTL (0x164) 139 + #define LPASS_CDC_IIR1_COEF_B1_CTL (0x128) 140 + #define LPASS_CDC_IIR2_COEF_B1_CTL (0x168) 141 + #define LPASS_CDC_IIR1_COEF_B2_CTL (0x12C) 142 + #define LPASS_CDC_IIR2_COEF_B2_CTL (0x16C) 143 + #define LPASS_CDC_CONN_RX1_B1_CTL (0x180) 144 + #define LPASS_CDC_CONN_RX1_B2_CTL (0x184) 145 + #define LPASS_CDC_CONN_RX1_B3_CTL (0x188) 146 + #define LPASS_CDC_CONN_RX2_B1_CTL (0x18C) 147 + #define LPASS_CDC_CONN_RX2_B2_CTL (0x190) 148 + #define LPASS_CDC_CONN_RX2_B3_CTL (0x194) 149 + #define LPASS_CDC_CONN_RX3_B1_CTL (0x198) 150 + #define LPASS_CDC_CONN_RX3_B2_CTL (0x19C) 151 + #define LPASS_CDC_CONN_TX_B1_CTL (0x1A0) 152 + #define LPASS_CDC_CONN_EQ1_B1_CTL (0x1A8) 153 + #define LPASS_CDC_CONN_EQ1_B2_CTL (0x1AC) 154 + #define LPASS_CDC_CONN_EQ1_B3_CTL (0x1B0) 155 + #define LPASS_CDC_CONN_EQ1_B4_CTL (0x1B4) 156 + #define LPASS_CDC_CONN_EQ2_B1_CTL (0x1B8) 157 + #define LPASS_CDC_CONN_EQ2_B2_CTL (0x1BC) 158 + #define LPASS_CDC_CONN_EQ2_B3_CTL (0x1C0) 159 + #define LPASS_CDC_CONN_EQ2_B4_CTL (0x1C4) 160 + #define LPASS_CDC_CONN_TX_I2S_SD1_CTL (0x1C8) 161 + #define LPASS_CDC_TX1_VOL_CTL_TIMER (0x280) 162 + #define LPASS_CDC_TX2_VOL_CTL_TIMER (0x2A0) 163 + #define LPASS_CDC_TX1_VOL_CTL_GAIN (0x284) 164 + #define LPASS_CDC_TX2_VOL_CTL_GAIN (0x2A4) 165 + #define LPASS_CDC_TX1_VOL_CTL_CFG (0x288) 166 + #define TX_VOL_CTL_CFG_MUTE_EN_MASK BIT(0) 167 + #define TX_VOL_CTL_CFG_MUTE_EN_ENABLE BIT(0) 168 + 169 + #define LPASS_CDC_TX2_VOL_CTL_CFG (0x2A8) 170 + #define LPASS_CDC_TX1_MUX_CTL (0x28C) 171 + #define TX_MUX_CTL_CUT_OFF_FREQ_MASK GENMASK(5, 4) 172 + #define TX_MUX_CTL_CUT_OFF_FREQ_SHIFT 4 173 + #define TX_MUX_CTL_CF_NEG_3DB_4HZ (0x0 << 4) 174 + #define TX_MUX_CTL_CF_NEG_3DB_75HZ (0x1 << 4) 175 + #define TX_MUX_CTL_CF_NEG_3DB_150HZ (0x2 << 4) 176 + #define TX_MUX_CTL_HPF_BP_SEL_MASK BIT(3) 177 + #define TX_MUX_CTL_HPF_BP_SEL_BYPASS BIT(3) 178 + #define TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS 0 179 + 180 + #define LPASS_CDC_TX2_MUX_CTL (0x2AC) 181 + #define LPASS_CDC_TX1_CLK_FS_CTL (0x290) 182 + #define LPASS_CDC_TX2_CLK_FS_CTL (0x2B0) 183 + #define LPASS_CDC_TX1_DMIC_CTL (0x294) 184 + #define LPASS_CDC_TX2_DMIC_CTL (0x2B4) 185 + #define TXN_DMIC_CTL_CLK_SEL_MASK GENMASK(2, 0) 186 + #define TXN_DMIC_CTL_CLK_SEL_DIV2 0x0 187 + #define TXN_DMIC_CTL_CLK_SEL_DIV3 0x1 188 + #define TXN_DMIC_CTL_CLK_SEL_DIV4 0x2 189 + #define TXN_DMIC_CTL_CLK_SEL_DIV6 0x3 190 + #define TXN_DMIC_CTL_CLK_SEL_DIV16 0x4 191 + 192 + #define MSM8916_WCD_DIGITAL_RATES (SNDRV_PCM_RATE_8000 | \ 193 + SNDRV_PCM_RATE_16000 | \ 194 + SNDRV_PCM_RATE_32000 | \ 195 + SNDRV_PCM_RATE_48000) 196 + #define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 197 + SNDRV_PCM_FMTBIT_S24_LE) 198 + 199 + struct msm8916_wcd_digital_priv { 200 + struct clk *ahbclk, *mclk; 201 + }; 202 + 203 + static const unsigned long rx_gain_reg[] = { 204 + LPASS_CDC_RX1_VOL_CTL_B2_CTL, 205 + LPASS_CDC_RX2_VOL_CTL_B2_CTL, 206 + LPASS_CDC_RX3_VOL_CTL_B2_CTL, 207 + }; 208 + 209 + static const unsigned long tx_gain_reg[] = { 210 + LPASS_CDC_TX1_VOL_CTL_GAIN, 211 + LPASS_CDC_TX2_VOL_CTL_GAIN, 212 + }; 213 + 214 + static const char *const rx_mix1_text[] = { 215 + "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3" 216 + }; 217 + 218 + static const char *const dec_mux_text[] = { 219 + "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2" 220 + }; 221 + static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" }; 222 + static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; 223 + 224 + /* RX1 MIX1 */ 225 + static const struct soc_enum rx_mix1_inp_enum[] = { 226 + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text), 227 + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text), 228 + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text), 229 + }; 230 + 231 + /* RX1 MIX2 */ 232 + static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( 233 + LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text); 234 + 235 + /* RX2 MIX1 */ 236 + static const struct soc_enum rx2_mix1_inp_enum[] = { 237 + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), 238 + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text), 239 + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), 240 + }; 241 + 242 + /* RX2 MIX2 */ 243 + static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( 244 + LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text); 245 + 246 + /* RX3 MIX1 */ 247 + static const struct soc_enum rx3_mix1_inp_enum[] = { 248 + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), 249 + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text), 250 + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), 251 + }; 252 + 253 + /* DEC */ 254 + static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE( 255 + LPASS_CDC_CONN_TX_B1_CTL, 0, 6, dec_mux_text); 256 + static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE( 257 + LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text); 258 + 259 + /* RDAC2 MUX */ 260 + static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM( 261 + "DEC1 MUX Mux", dec1_mux_enum); 262 + static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM( 263 + "DEC2 MUX Mux", dec2_mux_enum); 264 + static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM( 265 + "RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]); 266 + static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM( 267 + "RX1 MIX1 INP2 Mux", rx_mix1_inp_enum[1]); 268 + static const struct snd_kcontrol_new rx_mix1_inp3_mux = SOC_DAPM_ENUM( 269 + "RX1 MIX1 INP3 Mux", rx_mix1_inp_enum[2]); 270 + static const struct snd_kcontrol_new rx2_mix1_inp1_mux = SOC_DAPM_ENUM( 271 + "RX2 MIX1 INP1 Mux", rx2_mix1_inp_enum[0]); 272 + static const struct snd_kcontrol_new rx2_mix1_inp2_mux = SOC_DAPM_ENUM( 273 + "RX2 MIX1 INP2 Mux", rx2_mix1_inp_enum[1]); 274 + static const struct snd_kcontrol_new rx2_mix1_inp3_mux = SOC_DAPM_ENUM( 275 + "RX2 MIX1 INP3 Mux", rx2_mix1_inp_enum[2]); 276 + static const struct snd_kcontrol_new rx3_mix1_inp1_mux = SOC_DAPM_ENUM( 277 + "RX3 MIX1 INP1 Mux", rx3_mix1_inp_enum[0]); 278 + static const struct snd_kcontrol_new rx3_mix1_inp2_mux = SOC_DAPM_ENUM( 279 + "RX3 MIX1 INP2 Mux", rx3_mix1_inp_enum[1]); 280 + static const struct snd_kcontrol_new rx3_mix1_inp3_mux = SOC_DAPM_ENUM( 281 + "RX3 MIX1 INP3 Mux", rx3_mix1_inp_enum[2]); 282 + 283 + /* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */ 284 + static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0); 285 + 286 + /* Cutoff Freq for High Pass Filter at -3dB */ 287 + static const char * const hpf_cutoff_text[] = { 288 + "4Hz", "75Hz", "150Hz", 289 + }; 290 + 291 + static SOC_ENUM_SINGLE_DECL(tx1_hpf_cutoff_enum, LPASS_CDC_TX1_MUX_CTL, 4, 292 + hpf_cutoff_text); 293 + static SOC_ENUM_SINGLE_DECL(tx2_hpf_cutoff_enum, LPASS_CDC_TX2_MUX_CTL, 4, 294 + hpf_cutoff_text); 295 + 296 + /* cut off for dc blocker inside rx chain */ 297 + static const char * const dc_blocker_cutoff_text[] = { 298 + "4Hz", "75Hz", "150Hz", 299 + }; 300 + 301 + static SOC_ENUM_SINGLE_DECL(rx1_dcb_cutoff_enum, LPASS_CDC_RX1_B4_CTL, 0, 302 + dc_blocker_cutoff_text); 303 + static SOC_ENUM_SINGLE_DECL(rx2_dcb_cutoff_enum, LPASS_CDC_RX2_B4_CTL, 0, 304 + dc_blocker_cutoff_text); 305 + static SOC_ENUM_SINGLE_DECL(rx3_dcb_cutoff_enum, LPASS_CDC_RX3_B4_CTL, 0, 306 + dc_blocker_cutoff_text); 307 + 308 + static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { 309 + SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL, 310 + -128, 127, digital_gain), 311 + SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL, 312 + -128, 127, digital_gain), 313 + SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL, 314 + -128, 127, digital_gain), 315 + SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN, 316 + -128, 127, digital_gain), 317 + SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN, 318 + -128, 127, digital_gain), 319 + SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum), 320 + SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum), 321 + SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0), 322 + SOC_SINGLE("TX2 HPF Switch", LPASS_CDC_TX2_MUX_CTL, 3, 1, 0), 323 + SOC_ENUM("RX1 DCB Cutoff", rx1_dcb_cutoff_enum), 324 + SOC_ENUM("RX2 DCB Cutoff", rx2_dcb_cutoff_enum), 325 + SOC_ENUM("RX3 DCB Cutoff", rx3_dcb_cutoff_enum), 326 + SOC_SINGLE("RX1 DCB Switch", LPASS_CDC_RX1_B5_CTL, 2, 1, 0), 327 + SOC_SINGLE("RX2 DCB Switch", LPASS_CDC_RX2_B5_CTL, 2, 1, 0), 328 + SOC_SINGLE("RX3 DCB Switch", LPASS_CDC_RX3_B5_CTL, 2, 1, 0), 329 + SOC_SINGLE("RX1 Mute Switch", LPASS_CDC_RX1_B6_CTL, 0, 1, 0), 330 + SOC_SINGLE("RX2 Mute Switch", LPASS_CDC_RX2_B6_CTL, 0, 1, 0), 331 + SOC_SINGLE("RX3 Mute Switch", LPASS_CDC_RX3_B6_CTL, 0, 1, 0), 332 + }; 333 + 334 + static int msm8916_wcd_digital_enable_interpolator( 335 + struct snd_soc_dapm_widget *w, 336 + struct snd_kcontrol *kcontrol, 337 + int event) 338 + { 339 + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 340 + 341 + switch (event) { 342 + case SND_SOC_DAPM_POST_PMU: 343 + /* apply the digital gain after the interpolator is enabled */ 344 + usleep_range(10000, 10100); 345 + snd_soc_write(codec, rx_gain_reg[w->shift], 346 + snd_soc_read(codec, rx_gain_reg[w->shift])); 347 + break; 348 + } 349 + return 0; 350 + } 351 + 352 + static int msm8916_wcd_digital_enable_dec(struct snd_soc_dapm_widget *w, 353 + struct snd_kcontrol *kcontrol, 354 + int event) 355 + { 356 + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 357 + unsigned int decimator = w->shift + 1; 358 + u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg; 359 + u8 dec_hpf_cut_of_freq; 360 + 361 + dec_reset_reg = LPASS_CDC_CLK_TX_RESET_B1_CTL; 362 + tx_vol_ctl_reg = LPASS_CDC_TX1_VOL_CTL_CFG + 32 * (decimator - 1); 363 + tx_mux_ctl_reg = LPASS_CDC_TX1_MUX_CTL + 32 * (decimator - 1); 364 + 365 + switch (event) { 366 + case SND_SOC_DAPM_PRE_PMU: 367 + /* Enable TX digital mute */ 368 + snd_soc_update_bits(codec, tx_vol_ctl_reg, 369 + TX_VOL_CTL_CFG_MUTE_EN_MASK, 370 + TX_VOL_CTL_CFG_MUTE_EN_ENABLE); 371 + dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg) & 372 + TX_MUX_CTL_CUT_OFF_FREQ_MASK; 373 + dec_hpf_cut_of_freq >>= TX_MUX_CTL_CUT_OFF_FREQ_SHIFT; 374 + if (dec_hpf_cut_of_freq != TX_MUX_CTL_CF_NEG_3DB_150HZ) { 375 + /* set cut of freq to CF_MIN_3DB_150HZ (0x1) */ 376 + snd_soc_update_bits(codec, tx_mux_ctl_reg, 377 + TX_MUX_CTL_CUT_OFF_FREQ_MASK, 378 + TX_MUX_CTL_CF_NEG_3DB_150HZ); 379 + } 380 + break; 381 + case SND_SOC_DAPM_POST_PMU: 382 + /* enable HPF */ 383 + snd_soc_update_bits(codec, tx_mux_ctl_reg, 384 + TX_MUX_CTL_HPF_BP_SEL_MASK, 385 + TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS); 386 + /* apply the digital gain after the decimator is enabled */ 387 + snd_soc_write(codec, tx_gain_reg[w->shift], 388 + snd_soc_read(codec, tx_gain_reg[w->shift])); 389 + snd_soc_update_bits(codec, tx_vol_ctl_reg, 390 + TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); 391 + break; 392 + case SND_SOC_DAPM_PRE_PMD: 393 + snd_soc_update_bits(codec, tx_vol_ctl_reg, 394 + TX_VOL_CTL_CFG_MUTE_EN_MASK, 395 + TX_VOL_CTL_CFG_MUTE_EN_ENABLE); 396 + snd_soc_update_bits(codec, tx_mux_ctl_reg, 397 + TX_MUX_CTL_HPF_BP_SEL_MASK, 398 + TX_MUX_CTL_HPF_BP_SEL_BYPASS); 399 + break; 400 + case SND_SOC_DAPM_POST_PMD: 401 + snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 402 + 1 << w->shift); 403 + snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0); 404 + snd_soc_update_bits(codec, tx_mux_ctl_reg, 405 + TX_MUX_CTL_HPF_BP_SEL_MASK, 406 + TX_MUX_CTL_HPF_BP_SEL_BYPASS); 407 + snd_soc_update_bits(codec, tx_vol_ctl_reg, 408 + TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); 409 + break; 410 + } 411 + 412 + return 0; 413 + } 414 + 415 + static int msm8916_wcd_digital_enable_dmic(struct snd_soc_dapm_widget *w, 416 + struct snd_kcontrol *kcontrol, 417 + int event) 418 + { 419 + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 420 + unsigned int dmic; 421 + int ret; 422 + /* get dmic number out of widget name */ 423 + char *dmic_num = strpbrk(w->name, "12"); 424 + 425 + if (dmic_num == NULL) { 426 + dev_err(codec->dev, "Invalid DMIC\n"); 427 + return -EINVAL; 428 + } 429 + ret = kstrtouint(dmic_num, 10, &dmic); 430 + if (ret < 0 || dmic > 2) { 431 + dev_err(codec->dev, "Invalid DMIC line on the codec\n"); 432 + return -EINVAL; 433 + } 434 + 435 + switch (event) { 436 + case SND_SOC_DAPM_PRE_PMU: 437 + snd_soc_update_bits(codec, LPASS_CDC_CLK_DMIC_B1_CTL, 438 + DMIC_B1_CTL_DMIC0_CLK_SEL_MASK, 439 + DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3); 440 + switch (dmic) { 441 + case 1: 442 + snd_soc_update_bits(codec, LPASS_CDC_TX1_DMIC_CTL, 443 + TXN_DMIC_CTL_CLK_SEL_MASK, 444 + TXN_DMIC_CTL_CLK_SEL_DIV3); 445 + break; 446 + case 2: 447 + snd_soc_update_bits(codec, LPASS_CDC_TX2_DMIC_CTL, 448 + TXN_DMIC_CTL_CLK_SEL_MASK, 449 + TXN_DMIC_CTL_CLK_SEL_DIV3); 450 + break; 451 + } 452 + break; 453 + } 454 + 455 + return 0; 456 + } 457 + 458 + static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = { 459 + /*RX stuff */ 460 + SND_SOC_DAPM_AIF_IN("I2S RX1", NULL, 0, SND_SOC_NOPM, 0, 0), 461 + SND_SOC_DAPM_AIF_IN("I2S RX2", NULL, 0, SND_SOC_NOPM, 0, 0), 462 + SND_SOC_DAPM_AIF_IN("I2S RX3", NULL, 0, SND_SOC_NOPM, 0, 0), 463 + 464 + SND_SOC_DAPM_OUTPUT("PDM_RX1"), 465 + SND_SOC_DAPM_OUTPUT("PDM_RX2"), 466 + SND_SOC_DAPM_OUTPUT("PDM_RX3"), 467 + 468 + SND_SOC_DAPM_INPUT("LPASS_PDM_TX"), 469 + 470 + SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), 471 + SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), 472 + SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), 473 + 474 + /* Interpolator */ 475 + SND_SOC_DAPM_MIXER_E("RX1 INT", LPASS_CDC_CLK_RX_B1_CTL, 0, 0, NULL, 476 + 0, msm8916_wcd_digital_enable_interpolator, 477 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 478 + SND_SOC_DAPM_MIXER_E("RX2 INT", LPASS_CDC_CLK_RX_B1_CTL, 1, 0, NULL, 479 + 0, msm8916_wcd_digital_enable_interpolator, 480 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 481 + SND_SOC_DAPM_MIXER_E("RX3 INT", LPASS_CDC_CLK_RX_B1_CTL, 2, 0, NULL, 482 + 0, msm8916_wcd_digital_enable_interpolator, 483 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 484 + SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0, 485 + &rx_mix1_inp1_mux), 486 + SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0, 487 + &rx_mix1_inp2_mux), 488 + SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0, 489 + &rx_mix1_inp3_mux), 490 + SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0, 491 + &rx2_mix1_inp1_mux), 492 + SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0, 493 + &rx2_mix1_inp2_mux), 494 + SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0, 495 + &rx2_mix1_inp3_mux), 496 + SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0, 497 + &rx3_mix1_inp1_mux), 498 + SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0, 499 + &rx3_mix1_inp2_mux), 500 + SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0, 501 + &rx3_mix1_inp3_mux), 502 + 503 + /* TX */ 504 + SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), 505 + SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), 506 + SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), 507 + 508 + SND_SOC_DAPM_MUX_E("DEC1 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0, 509 + &dec1_mux, msm8916_wcd_digital_enable_dec, 510 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 511 + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 512 + SND_SOC_DAPM_MUX_E("DEC2 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0, 513 + &dec2_mux, msm8916_wcd_digital_enable_dec, 514 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 515 + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 516 + SND_SOC_DAPM_AIF_OUT("I2S TX1", NULL, 0, SND_SOC_NOPM, 0, 0), 517 + SND_SOC_DAPM_AIF_OUT("I2S TX2", NULL, 0, SND_SOC_NOPM, 0, 0), 518 + SND_SOC_DAPM_AIF_OUT("I2S TX3", NULL, 0, SND_SOC_NOPM, 0, 0), 519 + 520 + /* Digital Mic Inputs */ 521 + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, 522 + msm8916_wcd_digital_enable_dmic, 523 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 524 + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, 525 + msm8916_wcd_digital_enable_dmic, 526 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 527 + SND_SOC_DAPM_SUPPLY("DMIC_CLK", LPASS_CDC_CLK_DMIC_B1_CTL, 0, 0, 528 + NULL, 0), 529 + SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", LPASS_CDC_CLK_RX_I2S_CTL, 530 + 4, 0, NULL, 0), 531 + SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", LPASS_CDC_CLK_TX_I2S_CTL, 4, 0, 532 + NULL, 0), 533 + 534 + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, NULL, 0), 535 + SND_SOC_DAPM_SUPPLY("PDM_CLK", LPASS_CDC_CLK_PDM_CTL, 0, 0, NULL, 0), 536 + /* Connectivity Clock */ 537 + SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0, 538 + NULL, 0), 539 + 540 + }; 541 + 542 + static int msm8916_wcd_digital_parse_dt(struct platform_device *pdev, 543 + struct msm8916_wcd_digital_priv *priv) 544 + { 545 + struct device *dev = &pdev->dev; 546 + 547 + priv->ahbclk = devm_clk_get(dev, "ahbix-clk"); 548 + if (IS_ERR(priv->ahbclk)) { 549 + dev_err(dev, "failed to get ahbix clk\n"); 550 + return PTR_ERR(priv->ahbclk); 551 + } 552 + 553 + priv->mclk = devm_clk_get(dev, "mclk"); 554 + if (IS_ERR(priv->mclk)) { 555 + dev_err(dev, "failed to get mclk\n"); 556 + return PTR_ERR(priv->mclk); 557 + } 558 + 559 + return 0; 560 + } 561 + 562 + static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec) 563 + { 564 + struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(codec->dev); 565 + 566 + snd_soc_codec_set_drvdata(codec, priv); 567 + 568 + return 0; 569 + } 570 + 571 + static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream, 572 + struct snd_pcm_hw_params *params, 573 + struct snd_soc_dai *dai) 574 + { 575 + u8 tx_fs_rate; 576 + u8 rx_fs_rate; 577 + 578 + switch (params_rate(params)) { 579 + case 8000: 580 + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ; 581 + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ; 582 + break; 583 + case 16000: 584 + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ; 585 + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ; 586 + break; 587 + case 32000: 588 + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ; 589 + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ; 590 + break; 591 + case 48000: 592 + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ; 593 + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ; 594 + break; 595 + default: 596 + dev_err(dai->codec->dev, "Invalid sampling rate %d\n", 597 + params_rate(params)); 598 + return -EINVAL; 599 + } 600 + 601 + switch (substream->stream) { 602 + case SNDRV_PCM_STREAM_CAPTURE: 603 + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, 604 + TX_I2S_CTL_TX_I2S_FS_RATE_MASK, tx_fs_rate); 605 + break; 606 + case SNDRV_PCM_STREAM_PLAYBACK: 607 + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, 608 + RX_I2S_CTL_RX_I2S_FS_RATE_MASK, rx_fs_rate); 609 + break; 610 + default: 611 + return -EINVAL; 612 + } 613 + 614 + switch (params_format(params)) { 615 + case SNDRV_PCM_FORMAT_S16_LE: 616 + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, 617 + TX_I2S_CTL_TX_I2S_MODE_MASK, 618 + TX_I2S_CTL_TX_I2S_MODE_16); 619 + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, 620 + RX_I2S_CTL_RX_I2S_MODE_MASK, 621 + RX_I2S_CTL_RX_I2S_MODE_16); 622 + break; 623 + case SNDRV_PCM_FORMAT_S24_LE: 624 + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, 625 + TX_I2S_CTL_TX_I2S_MODE_MASK, 626 + TX_I2S_CTL_TX_I2S_MODE_32); 627 + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, 628 + RX_I2S_CTL_RX_I2S_MODE_MASK, 629 + RX_I2S_CTL_RX_I2S_MODE_32); 630 + break; 631 + default: 632 + dev_err(dai->dev, "%s: wrong format selected\n", __func__); 633 + return -EINVAL; 634 + } 635 + 636 + return 0; 637 + } 638 + 639 + static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = { 640 + 641 + {"I2S RX1", NULL, "AIF1 Playback"}, 642 + {"I2S RX2", NULL, "AIF1 Playback"}, 643 + {"I2S RX3", NULL, "AIF1 Playback"}, 644 + 645 + {"AIF1 Capture", NULL, "I2S TX1"}, 646 + {"AIF1 Capture", NULL, "I2S TX2"}, 647 + {"AIF1 Capture", NULL, "I2S TX3"}, 648 + 649 + /* Decimator Inputs */ 650 + {"DEC1 MUX", "DMIC1", "DMIC1"}, 651 + {"DEC1 MUX", "DMIC2", "DMIC2"}, 652 + {"DEC1 MUX", "ADC1", "ADC1"}, 653 + {"DEC1 MUX", "ADC2", "ADC2"}, 654 + {"DEC1 MUX", "ADC3", "ADC3"}, 655 + {"DEC1 MUX", NULL, "CDC_CONN"}, 656 + 657 + {"DEC2 MUX", "DMIC1", "DMIC1"}, 658 + {"DEC2 MUX", "DMIC2", "DMIC2"}, 659 + {"DEC2 MUX", "ADC1", "ADC1"}, 660 + {"DEC2 MUX", "ADC2", "ADC2"}, 661 + {"DEC2 MUX", "ADC3", "ADC3"}, 662 + {"DEC2 MUX", NULL, "CDC_CONN"}, 663 + 664 + {"DMIC1", NULL, "DMIC_CLK"}, 665 + {"DMIC2", NULL, "DMIC_CLK"}, 666 + 667 + {"I2S TX1", NULL, "DEC1 MUX"}, 668 + {"I2S TX2", NULL, "DEC2 MUX"}, 669 + 670 + {"I2S TX1", NULL, "TX_I2S_CLK"}, 671 + {"I2S TX2", NULL, "TX_I2S_CLK"}, 672 + 673 + {"TX_I2S_CLK", NULL, "MCLK"}, 674 + {"TX_I2S_CLK", NULL, "PDM_CLK"}, 675 + 676 + {"ADC1", NULL, "LPASS_PDM_TX"}, 677 + {"ADC2", NULL, "LPASS_PDM_TX"}, 678 + {"ADC3", NULL, "LPASS_PDM_TX"}, 679 + 680 + {"I2S RX1", NULL, "RX_I2S_CLK"}, 681 + {"I2S RX2", NULL, "RX_I2S_CLK"}, 682 + {"I2S RX3", NULL, "RX_I2S_CLK"}, 683 + 684 + {"RX_I2S_CLK", NULL, "PDM_CLK"}, 685 + {"RX_I2S_CLK", NULL, "MCLK"}, 686 + {"RX_I2S_CLK", NULL, "CDC_CONN"}, 687 + 688 + /* RX1 PATH.. */ 689 + {"PDM_RX1", NULL, "RX1 INT"}, 690 + {"RX1 INT", NULL, "RX1 MIX1"}, 691 + 692 + {"RX1 MIX1", NULL, "RX1 MIX1 INP1"}, 693 + {"RX1 MIX1", NULL, "RX1 MIX1 INP2"}, 694 + {"RX1 MIX1", NULL, "RX1 MIX1 INP3"}, 695 + 696 + {"RX1 MIX1 INP1", "RX1", "I2S RX1"}, 697 + {"RX1 MIX1 INP1", "RX2", "I2S RX2"}, 698 + {"RX1 MIX1 INP1", "RX3", "I2S RX3"}, 699 + 700 + {"RX1 MIX1 INP2", "RX1", "I2S RX1"}, 701 + {"RX1 MIX1 INP2", "RX2", "I2S RX2"}, 702 + {"RX1 MIX1 INP2", "RX3", "I2S RX3"}, 703 + 704 + {"RX1 MIX1 INP3", "RX1", "I2S RX1"}, 705 + {"RX1 MIX1 INP3", "RX2", "I2S RX2"}, 706 + {"RX1 MIX1 INP3", "RX3", "I2S RX3"}, 707 + 708 + /* RX2 PATH */ 709 + {"PDM_RX2", NULL, "RX2 INT"}, 710 + {"RX2 INT", NULL, "RX2 MIX1"}, 711 + 712 + {"RX2 MIX1", NULL, "RX2 MIX1 INP1"}, 713 + {"RX2 MIX1", NULL, "RX2 MIX1 INP2"}, 714 + {"RX2 MIX1", NULL, "RX2 MIX1 INP3"}, 715 + 716 + {"RX2 MIX1 INP1", "RX1", "I2S RX1"}, 717 + {"RX2 MIX1 INP1", "RX2", "I2S RX2"}, 718 + {"RX2 MIX1 INP1", "RX3", "I2S RX3"}, 719 + 720 + {"RX2 MIX1 INP2", "RX1", "I2S RX1"}, 721 + {"RX2 MIX1 INP2", "RX2", "I2S RX2"}, 722 + {"RX2 MIX1 INP2", "RX3", "I2S RX3"}, 723 + 724 + {"RX2 MIX1 INP3", "RX1", "I2S RX1"}, 725 + {"RX2 MIX1 INP3", "RX2", "I2S RX2"}, 726 + {"RX2 MIX1 INP3", "RX3", "I2S RX3"}, 727 + 728 + /* RX3 PATH */ 729 + {"PDM_RX3", NULL, "RX3 INT"}, 730 + {"RX3 INT", NULL, "RX3 MIX1"}, 731 + 732 + {"RX3 MIX1", NULL, "RX3 MIX1 INP1"}, 733 + {"RX3 MIX1", NULL, "RX3 MIX1 INP2"}, 734 + {"RX3 MIX1", NULL, "RX3 MIX1 INP3"}, 735 + 736 + {"RX3 MIX1 INP1", "RX1", "I2S RX1"}, 737 + {"RX3 MIX1 INP1", "RX2", "I2S RX2"}, 738 + {"RX3 MIX1 INP1", "RX3", "I2S RX3"}, 739 + 740 + {"RX3 MIX1 INP2", "RX1", "I2S RX1"}, 741 + {"RX3 MIX1 INP2", "RX2", "I2S RX2"}, 742 + {"RX3 MIX1 INP2", "RX3", "I2S RX3"}, 743 + 744 + {"RX3 MIX1 INP3", "RX1", "I2S RX1"}, 745 + {"RX3 MIX1 INP3", "RX2", "I2S RX2"}, 746 + {"RX3 MIX1 INP3", "RX3", "I2S RX3"}, 747 + 748 + }; 749 + 750 + static int msm8916_wcd_digital_startup(struct snd_pcm_substream *substream, 751 + struct snd_soc_dai *dai) 752 + { 753 + struct snd_soc_codec *codec = dai->codec; 754 + struct msm8916_wcd_digital_priv *msm8916_wcd; 755 + unsigned long mclk_rate; 756 + 757 + msm8916_wcd = snd_soc_codec_get_drvdata(codec); 758 + snd_soc_update_bits(codec, LPASS_CDC_CLK_MCLK_CTL, 759 + MCLK_CTL_MCLK_EN_MASK, 760 + MCLK_CTL_MCLK_EN_ENABLE); 761 + snd_soc_update_bits(codec, LPASS_CDC_CLK_PDM_CTL, 762 + LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 763 + LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB); 764 + 765 + mclk_rate = clk_get_rate(msm8916_wcd->mclk); 766 + switch (mclk_rate) { 767 + case 12288000: 768 + snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, 769 + TOP_CTL_DIG_MCLK_FREQ_MASK, 770 + TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ); 771 + break; 772 + case 9600000: 773 + snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, 774 + TOP_CTL_DIG_MCLK_FREQ_MASK, 775 + TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ); 776 + break; 777 + default: 778 + dev_err(codec->dev, "Invalid mclk rate %ld\n", mclk_rate); 779 + break; 780 + } 781 + return 0; 782 + } 783 + 784 + static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream, 785 + struct snd_soc_dai *dai) 786 + { 787 + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_PDM_CTL, 788 + LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0); 789 + } 790 + 791 + static struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = { 792 + .startup = msm8916_wcd_digital_startup, 793 + .shutdown = msm8916_wcd_digital_shutdown, 794 + .hw_params = msm8916_wcd_digital_hw_params, 795 + }; 796 + 797 + static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = { 798 + [0] = { 799 + .name = "msm8916_wcd_digital_i2s_rx1", 800 + .id = 0, 801 + .playback = { 802 + .stream_name = "AIF1 Playback", 803 + .rates = MSM8916_WCD_DIGITAL_RATES, 804 + .formats = MSM8916_WCD_DIGITAL_FORMATS, 805 + .channels_min = 1, 806 + .channels_max = 3, 807 + }, 808 + .ops = &msm8916_wcd_digital_dai_ops, 809 + }, 810 + [1] = { 811 + .name = "msm8916_wcd_digital_i2s_tx1", 812 + .id = 1, 813 + .capture = { 814 + .stream_name = "AIF1 Capture", 815 + .rates = MSM8916_WCD_DIGITAL_RATES, 816 + .formats = MSM8916_WCD_DIGITAL_FORMATS, 817 + .channels_min = 1, 818 + .channels_max = 4, 819 + }, 820 + .ops = &msm8916_wcd_digital_dai_ops, 821 + }, 822 + }; 823 + 824 + static struct snd_soc_codec_driver msm8916_wcd_digital = { 825 + .probe = msm8916_wcd_digital_codec_probe, 826 + .component_driver = { 827 + .controls = msm8916_wcd_digital_snd_controls, 828 + .num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls), 829 + .dapm_widgets = msm8916_wcd_digital_dapm_widgets, 830 + .num_dapm_widgets = 831 + ARRAY_SIZE(msm8916_wcd_digital_dapm_widgets), 832 + .dapm_routes = msm8916_wcd_digital_audio_map, 833 + .num_dapm_routes = ARRAY_SIZE(msm8916_wcd_digital_audio_map), 834 + }, 835 + }; 836 + 837 + static const struct regmap_config msm8916_codec_regmap_config = { 838 + .reg_bits = 32, 839 + .reg_stride = 4, 840 + .val_bits = 32, 841 + .max_register = LPASS_CDC_TX2_DMIC_CTL, 842 + .cache_type = REGCACHE_FLAT, 843 + }; 844 + 845 + static int msm8916_wcd_digital_probe(struct platform_device *pdev) 846 + { 847 + struct msm8916_wcd_digital_priv *priv; 848 + struct device *dev = &pdev->dev; 849 + void __iomem *base; 850 + struct resource *mem_res; 851 + struct regmap *digital_map; 852 + int ret; 853 + 854 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 855 + if (!priv) 856 + return -ENOMEM; 857 + 858 + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 859 + base = devm_ioremap_resource(&pdev->dev, mem_res); 860 + if (IS_ERR(base)) 861 + return PTR_ERR(base); 862 + 863 + digital_map = 864 + devm_regmap_init_mmio(&pdev->dev, base, 865 + &msm8916_codec_regmap_config); 866 + if (IS_ERR(digital_map)) 867 + return PTR_ERR(digital_map); 868 + 869 + ret = msm8916_wcd_digital_parse_dt(pdev, priv); 870 + if (ret < 0) 871 + return ret; 872 + 873 + ret = clk_prepare_enable(priv->ahbclk); 874 + if (ret < 0) { 875 + dev_err(dev, "failed to enable ahbclk %d\n", ret); 876 + return ret; 877 + } 878 + 879 + ret = clk_prepare_enable(priv->mclk); 880 + if (ret < 0) { 881 + dev_err(dev, "failed to enable mclk %d\n", ret); 882 + return ret; 883 + } 884 + 885 + dev_set_drvdata(dev, priv); 886 + 887 + return snd_soc_register_codec(dev, &msm8916_wcd_digital, 888 + msm8916_wcd_digital_dai, 889 + ARRAY_SIZE(msm8916_wcd_digital_dai)); 890 + } 891 + 892 + static int msm8916_wcd_digital_remove(struct platform_device *pdev) 893 + { 894 + struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(&pdev->dev); 895 + 896 + snd_soc_unregister_codec(&pdev->dev); 897 + clk_disable_unprepare(priv->mclk); 898 + clk_disable_unprepare(priv->ahbclk); 899 + 900 + return 0; 901 + } 902 + 903 + static const struct of_device_id msm8916_wcd_digital_match_table[] = { 904 + { .compatible = "qcom,msm8916-wcd-digital-codec" }, 905 + { } 906 + }; 907 + 908 + MODULE_DEVICE_TABLE(of, msm8916_wcd_digital_match_table); 909 + 910 + static struct platform_driver msm8916_wcd_digital_driver = { 911 + .driver = { 912 + .name = "msm8916-wcd-digital-codec", 913 + .of_match_table = msm8916_wcd_digital_match_table, 914 + }, 915 + .probe = msm8916_wcd_digital_probe, 916 + .remove = msm8916_wcd_digital_remove, 917 + }; 918 + 919 + module_platform_driver(msm8916_wcd_digital_driver); 920 + 921 + MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>"); 922 + MODULE_DESCRIPTION("MSM8916 WCD Digital Codec driver"); 923 + MODULE_LICENSE("GPL v2");