| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | // TLV320ADCX140 Sound driver |
| 3 | // Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/ |
| 4 | |
| 5 | #include <linux/module.h> |
| 6 | #include <linux/moduleparam.h> |
| 7 | #include <linux/init.h> |
| 8 | #include <linux/delay.h> |
| 9 | #include <linux/pm.h> |
| 10 | #include <linux/i2c.h> |
| 11 | #include <linux/gpio/consumer.h> |
| 12 | #include <linux/regulator/consumer.h> |
| 13 | #include <linux/acpi.h> |
| 14 | #include <linux/of.h> |
| 15 | #include <linux/slab.h> |
| 16 | #include <sound/core.h> |
| 17 | #include <sound/pcm.h> |
| 18 | #include <sound/pcm_params.h> |
| 19 | #include <sound/soc.h> |
| 20 | #include <sound/initval.h> |
| 21 | #include <sound/tlv.h> |
| 22 | |
| 23 | #include "tlv320adcx140.h" |
| 24 | |
| 25 | struct adcx140_priv { |
| 26 | struct snd_soc_component *component; |
| 27 | struct regulator *supply_areg; |
| 28 | struct gpio_desc *gpio_reset; |
| 29 | struct regmap *regmap; |
| 30 | struct device *dev; |
| 31 | |
| 32 | bool micbias_vg; |
| 33 | bool phase_calib_on; |
| 34 | |
| 35 | unsigned int dai_fmt; |
| 36 | unsigned int slot_width; |
| 37 | }; |
| 38 | |
| 39 | static const char * const gpo_config_names[] = { |
| 40 | "ti,gpo-config-1" , |
| 41 | "ti,gpo-config-2" , |
| 42 | "ti,gpo-config-3" , |
| 43 | "ti,gpo-config-4" , |
| 44 | }; |
| 45 | |
| 46 | static const struct reg_default adcx140_reg_defaults[] = { |
| 47 | { ADCX140_PAGE_SELECT, 0x00 }, |
| 48 | { ADCX140_SW_RESET, 0x00 }, |
| 49 | { ADCX140_SLEEP_CFG, 0x00 }, |
| 50 | { ADCX140_SHDN_CFG, 0x05 }, |
| 51 | { ADCX140_ASI_CFG0, 0x30 }, |
| 52 | { ADCX140_ASI_CFG1, 0x00 }, |
| 53 | { ADCX140_ASI_CFG2, 0x00 }, |
| 54 | { ADCX140_ASI_CH1, 0x00 }, |
| 55 | { ADCX140_ASI_CH2, 0x01 }, |
| 56 | { ADCX140_ASI_CH3, 0x02 }, |
| 57 | { ADCX140_ASI_CH4, 0x03 }, |
| 58 | { ADCX140_ASI_CH5, 0x04 }, |
| 59 | { ADCX140_ASI_CH6, 0x05 }, |
| 60 | { ADCX140_ASI_CH7, 0x06 }, |
| 61 | { ADCX140_ASI_CH8, 0x07 }, |
| 62 | { ADCX140_MST_CFG0, 0x02 }, |
| 63 | { ADCX140_MST_CFG1, 0x48 }, |
| 64 | { ADCX140_ASI_STS, 0xff }, |
| 65 | { ADCX140_CLK_SRC, 0x10 }, |
| 66 | { ADCX140_PDMCLK_CFG, 0x40 }, |
| 67 | { ADCX140_PDM_CFG, 0x00 }, |
| 68 | { ADCX140_GPIO_CFG0, 0x22 }, |
| 69 | { ADCX140_GPO_CFG0, 0x00 }, |
| 70 | { ADCX140_GPO_CFG1, 0x00 }, |
| 71 | { ADCX140_GPO_CFG2, 0x00 }, |
| 72 | { ADCX140_GPO_CFG3, 0x00 }, |
| 73 | { ADCX140_GPO_VAL, 0x00 }, |
| 74 | { ADCX140_GPIO_MON, 0x00 }, |
| 75 | { ADCX140_GPI_CFG0, 0x00 }, |
| 76 | { ADCX140_GPI_CFG1, 0x00 }, |
| 77 | { ADCX140_GPI_MON, 0x00 }, |
| 78 | { ADCX140_INT_CFG, 0x00 }, |
| 79 | { ADCX140_INT_MASK0, 0xff }, |
| 80 | { ADCX140_INT_LTCH0, 0x00 }, |
| 81 | { ADCX140_BIAS_CFG, 0x00 }, |
| 82 | { ADCX140_CH1_CFG0, 0x00 }, |
| 83 | { ADCX140_CH1_CFG1, 0x00 }, |
| 84 | { ADCX140_CH1_CFG2, 0xc9 }, |
| 85 | { ADCX140_CH1_CFG3, 0x80 }, |
| 86 | { ADCX140_CH1_CFG4, 0x00 }, |
| 87 | { ADCX140_CH2_CFG0, 0x00 }, |
| 88 | { ADCX140_CH2_CFG1, 0x00 }, |
| 89 | { ADCX140_CH2_CFG2, 0xc9 }, |
| 90 | { ADCX140_CH2_CFG3, 0x80 }, |
| 91 | { ADCX140_CH2_CFG4, 0x00 }, |
| 92 | { ADCX140_CH3_CFG0, 0x00 }, |
| 93 | { ADCX140_CH3_CFG1, 0x00 }, |
| 94 | { ADCX140_CH3_CFG2, 0xc9 }, |
| 95 | { ADCX140_CH3_CFG3, 0x80 }, |
| 96 | { ADCX140_CH3_CFG4, 0x00 }, |
| 97 | { ADCX140_CH4_CFG0, 0x00 }, |
| 98 | { ADCX140_CH4_CFG1, 0x00 }, |
| 99 | { ADCX140_CH4_CFG2, 0xc9 }, |
| 100 | { ADCX140_CH4_CFG3, 0x80 }, |
| 101 | { ADCX140_CH4_CFG4, 0x00 }, |
| 102 | { ADCX140_CH5_CFG2, 0xc9 }, |
| 103 | { ADCX140_CH5_CFG3, 0x80 }, |
| 104 | { ADCX140_CH5_CFG4, 0x00 }, |
| 105 | { ADCX140_CH6_CFG2, 0xc9 }, |
| 106 | { ADCX140_CH6_CFG3, 0x80 }, |
| 107 | { ADCX140_CH6_CFG4, 0x00 }, |
| 108 | { ADCX140_CH7_CFG2, 0xc9 }, |
| 109 | { ADCX140_CH7_CFG3, 0x80 }, |
| 110 | { ADCX140_CH7_CFG4, 0x00 }, |
| 111 | { ADCX140_CH8_CFG2, 0xc9 }, |
| 112 | { ADCX140_CH8_CFG3, 0x80 }, |
| 113 | { ADCX140_CH8_CFG4, 0x00 }, |
| 114 | { ADCX140_DSP_CFG0, 0x01 }, |
| 115 | { ADCX140_DSP_CFG1, 0x40 }, |
| 116 | { ADCX140_DRE_CFG0, 0x7b }, |
| 117 | { ADCX140_AGC_CFG0, 0xe7 }, |
| 118 | { ADCX140_IN_CH_EN, 0xf0 }, |
| 119 | { ADCX140_ASI_OUT_CH_EN, 0x00 }, |
| 120 | { ADCX140_PWR_CFG, 0x00 }, |
| 121 | { ADCX140_DEV_STS0, 0x00 }, |
| 122 | { ADCX140_DEV_STS1, 0x80 }, |
| 123 | }; |
| 124 | |
| 125 | static const struct regmap_range_cfg adcx140_ranges[] = { |
| 126 | { |
| 127 | .range_min = 0, |
| 128 | .range_max = 12 * 128, |
| 129 | .selector_reg = ADCX140_PAGE_SELECT, |
| 130 | .selector_mask = 0xff, |
| 131 | .selector_shift = 0, |
| 132 | .window_start = 0, |
| 133 | .window_len = 128, |
| 134 | }, |
| 135 | }; |
| 136 | |
| 137 | static bool adcx140_volatile(struct device *dev, unsigned int reg) |
| 138 | { |
| 139 | switch (reg) { |
| 140 | case ADCX140_SW_RESET: |
| 141 | case ADCX140_DEV_STS0: |
| 142 | case ADCX140_DEV_STS1: |
| 143 | case ADCX140_ASI_STS: |
| 144 | return true; |
| 145 | default: |
| 146 | return false; |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | static const struct regmap_config adcx140_i2c_regmap = { |
| 151 | .reg_bits = 8, |
| 152 | .val_bits = 8, |
| 153 | .reg_defaults = adcx140_reg_defaults, |
| 154 | .num_reg_defaults = ARRAY_SIZE(adcx140_reg_defaults), |
| 155 | .cache_type = REGCACHE_FLAT, |
| 156 | .ranges = adcx140_ranges, |
| 157 | .num_ranges = ARRAY_SIZE(adcx140_ranges), |
| 158 | .max_register = 12 * 128, |
| 159 | .volatile_reg = adcx140_volatile, |
| 160 | }; |
| 161 | |
| 162 | /* Digital Volume control. From -100 to 27 dB in 0.5 dB steps */ |
| 163 | static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10050, 50, 0); |
| 164 | |
| 165 | /* ADC gain. From 0 to 42 dB in 1 dB steps */ |
| 166 | static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 100, 0); |
| 167 | |
| 168 | /* DRE Level. From -12 dB to -66 dB in 1 dB steps */ |
| 169 | static DECLARE_TLV_DB_SCALE(dre_thresh_tlv, -6600, 100, 0); |
| 170 | /* DRE Max Gain. From 2 dB to 26 dB in 2 dB steps */ |
| 171 | static DECLARE_TLV_DB_SCALE(dre_gain_tlv, 200, 200, 0); |
| 172 | |
| 173 | /* AGC Level. From -6 dB to -36 dB in 2 dB steps */ |
| 174 | static DECLARE_TLV_DB_SCALE(agc_thresh_tlv, -3600, 200, 0); |
| 175 | /* AGC Max Gain. From 3 dB to 42 dB in 3 dB steps */ |
| 176 | static DECLARE_TLV_DB_SCALE(agc_gain_tlv, 300, 300, 0); |
| 177 | |
| 178 | static const char * const decimation_filter_text[] = { |
| 179 | "Linear Phase" , "Low Latency" , "Ultra-low Latency" |
| 180 | }; |
| 181 | |
| 182 | static SOC_ENUM_SINGLE_DECL(decimation_filter_enum, ADCX140_DSP_CFG0, 4, |
| 183 | decimation_filter_text); |
| 184 | |
| 185 | static const struct snd_kcontrol_new decimation_filter_controls[] = { |
| 186 | SOC_DAPM_ENUM("Decimation Filter" , decimation_filter_enum), |
| 187 | }; |
| 188 | |
| 189 | static const char * const pdmclk_text[] = { |
| 190 | "2.8224 MHz" , "1.4112 MHz" , "705.6 kHz" , "5.6448 MHz" |
| 191 | }; |
| 192 | |
| 193 | static SOC_ENUM_SINGLE_DECL(pdmclk_select_enum, ADCX140_PDMCLK_CFG, 0, |
| 194 | pdmclk_text); |
| 195 | |
| 196 | static const struct snd_kcontrol_new pdmclk_div_controls[] = { |
| 197 | SOC_DAPM_ENUM("PDM Clk Divider Select" , pdmclk_select_enum), |
| 198 | }; |
| 199 | |
| 200 | static const char * const resistor_text[] = { |
| 201 | "2.5 kOhm" , "10 kOhm" , "20 kOhm" |
| 202 | }; |
| 203 | |
| 204 | static SOC_ENUM_SINGLE_DECL(in1_resistor_enum, ADCX140_CH1_CFG0, 2, |
| 205 | resistor_text); |
| 206 | static SOC_ENUM_SINGLE_DECL(in2_resistor_enum, ADCX140_CH2_CFG0, 2, |
| 207 | resistor_text); |
| 208 | static SOC_ENUM_SINGLE_DECL(in3_resistor_enum, ADCX140_CH3_CFG0, 2, |
| 209 | resistor_text); |
| 210 | static SOC_ENUM_SINGLE_DECL(in4_resistor_enum, ADCX140_CH4_CFG0, 2, |
| 211 | resistor_text); |
| 212 | |
| 213 | static const struct snd_kcontrol_new in1_resistor_controls[] = { |
| 214 | SOC_DAPM_ENUM("CH1 Resistor Select" , in1_resistor_enum), |
| 215 | }; |
| 216 | static const struct snd_kcontrol_new in2_resistor_controls[] = { |
| 217 | SOC_DAPM_ENUM("CH2 Resistor Select" , in2_resistor_enum), |
| 218 | }; |
| 219 | static const struct snd_kcontrol_new in3_resistor_controls[] = { |
| 220 | SOC_DAPM_ENUM("CH3 Resistor Select" , in3_resistor_enum), |
| 221 | }; |
| 222 | static const struct snd_kcontrol_new in4_resistor_controls[] = { |
| 223 | SOC_DAPM_ENUM("CH4 Resistor Select" , in4_resistor_enum), |
| 224 | }; |
| 225 | |
| 226 | /* Analog/Digital Selection */ |
| 227 | static const char * const adcx140_mic_sel_text[] = {"Analog" , "Line In" , "Digital" }; |
| 228 | static const char * const adcx140_analog_sel_text[] = {"Analog" , "Line In" }; |
| 229 | |
| 230 | static SOC_ENUM_SINGLE_DECL(adcx140_mic1p_enum, |
| 231 | ADCX140_CH1_CFG0, 5, |
| 232 | adcx140_mic_sel_text); |
| 233 | |
| 234 | static const struct snd_kcontrol_new adcx140_dapm_mic1p_control = |
| 235 | SOC_DAPM_ENUM("MIC1P MUX" , adcx140_mic1p_enum); |
| 236 | |
| 237 | static SOC_ENUM_SINGLE_DECL(adcx140_mic1_analog_enum, |
| 238 | ADCX140_CH1_CFG0, 7, |
| 239 | adcx140_analog_sel_text); |
| 240 | |
| 241 | static const struct snd_kcontrol_new adcx140_dapm_mic1_analog_control = |
| 242 | SOC_DAPM_ENUM("MIC1 Analog MUX" , adcx140_mic1_analog_enum); |
| 243 | |
| 244 | static SOC_ENUM_SINGLE_DECL(adcx140_mic1m_enum, |
| 245 | ADCX140_CH1_CFG0, 5, |
| 246 | adcx140_mic_sel_text); |
| 247 | |
| 248 | static const struct snd_kcontrol_new adcx140_dapm_mic1m_control = |
| 249 | SOC_DAPM_ENUM("MIC1M MUX" , adcx140_mic1m_enum); |
| 250 | |
| 251 | static SOC_ENUM_SINGLE_DECL(adcx140_mic2p_enum, |
| 252 | ADCX140_CH2_CFG0, 5, |
| 253 | adcx140_mic_sel_text); |
| 254 | |
| 255 | static const struct snd_kcontrol_new adcx140_dapm_mic2p_control = |
| 256 | SOC_DAPM_ENUM("MIC2P MUX" , adcx140_mic2p_enum); |
| 257 | |
| 258 | static SOC_ENUM_SINGLE_DECL(adcx140_mic2_analog_enum, |
| 259 | ADCX140_CH2_CFG0, 7, |
| 260 | adcx140_analog_sel_text); |
| 261 | |
| 262 | static const struct snd_kcontrol_new adcx140_dapm_mic2_analog_control = |
| 263 | SOC_DAPM_ENUM("MIC2 Analog MUX" , adcx140_mic2_analog_enum); |
| 264 | |
| 265 | static SOC_ENUM_SINGLE_DECL(adcx140_mic2m_enum, |
| 266 | ADCX140_CH2_CFG0, 5, |
| 267 | adcx140_mic_sel_text); |
| 268 | |
| 269 | static const struct snd_kcontrol_new adcx140_dapm_mic2m_control = |
| 270 | SOC_DAPM_ENUM("MIC2M MUX" , adcx140_mic2m_enum); |
| 271 | |
| 272 | static SOC_ENUM_SINGLE_DECL(adcx140_mic3p_enum, |
| 273 | ADCX140_CH3_CFG0, 5, |
| 274 | adcx140_mic_sel_text); |
| 275 | |
| 276 | static const struct snd_kcontrol_new adcx140_dapm_mic3p_control = |
| 277 | SOC_DAPM_ENUM("MIC3P MUX" , adcx140_mic3p_enum); |
| 278 | |
| 279 | static SOC_ENUM_SINGLE_DECL(adcx140_mic3_analog_enum, |
| 280 | ADCX140_CH3_CFG0, 7, |
| 281 | adcx140_analog_sel_text); |
| 282 | |
| 283 | static const struct snd_kcontrol_new adcx140_dapm_mic3_analog_control = |
| 284 | SOC_DAPM_ENUM("MIC3 Analog MUX" , adcx140_mic3_analog_enum); |
| 285 | |
| 286 | static SOC_ENUM_SINGLE_DECL(adcx140_mic3m_enum, |
| 287 | ADCX140_CH3_CFG0, 5, |
| 288 | adcx140_mic_sel_text); |
| 289 | |
| 290 | static const struct snd_kcontrol_new adcx140_dapm_mic3m_control = |
| 291 | SOC_DAPM_ENUM("MIC3M MUX" , adcx140_mic3m_enum); |
| 292 | |
| 293 | static SOC_ENUM_SINGLE_DECL(adcx140_mic4p_enum, |
| 294 | ADCX140_CH4_CFG0, 5, |
| 295 | adcx140_mic_sel_text); |
| 296 | |
| 297 | static const struct snd_kcontrol_new adcx140_dapm_mic4p_control = |
| 298 | SOC_DAPM_ENUM("MIC4P MUX" , adcx140_mic4p_enum); |
| 299 | |
| 300 | static SOC_ENUM_SINGLE_DECL(adcx140_mic4_analog_enum, |
| 301 | ADCX140_CH4_CFG0, 7, |
| 302 | adcx140_analog_sel_text); |
| 303 | |
| 304 | static const struct snd_kcontrol_new adcx140_dapm_mic4_analog_control = |
| 305 | SOC_DAPM_ENUM("MIC4 Analog MUX" , adcx140_mic4_analog_enum); |
| 306 | |
| 307 | static SOC_ENUM_SINGLE_DECL(adcx140_mic4m_enum, |
| 308 | ADCX140_CH4_CFG0, 5, |
| 309 | adcx140_mic_sel_text); |
| 310 | |
| 311 | static const struct snd_kcontrol_new adcx140_dapm_mic4m_control = |
| 312 | SOC_DAPM_ENUM("MIC4M MUX" , adcx140_mic4m_enum); |
| 313 | |
| 314 | static const struct snd_kcontrol_new adcx140_dapm_ch1_en_switch = |
| 315 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 7, 1, 0); |
| 316 | static const struct snd_kcontrol_new adcx140_dapm_ch2_en_switch = |
| 317 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 6, 1, 0); |
| 318 | static const struct snd_kcontrol_new adcx140_dapm_ch3_en_switch = |
| 319 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 5, 1, 0); |
| 320 | static const struct snd_kcontrol_new adcx140_dapm_ch4_en_switch = |
| 321 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 4, 1, 0); |
| 322 | static const struct snd_kcontrol_new adcx140_dapm_ch5_en_switch = |
| 323 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 3, 1, 0); |
| 324 | static const struct snd_kcontrol_new adcx140_dapm_ch6_en_switch = |
| 325 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 2, 1, 0); |
| 326 | static const struct snd_kcontrol_new adcx140_dapm_ch7_en_switch = |
| 327 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 1, 1, 0); |
| 328 | static const struct snd_kcontrol_new adcx140_dapm_ch8_en_switch = |
| 329 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 0, 1, 0); |
| 330 | |
| 331 | static const struct snd_kcontrol_new adcx140_dapm_ch1_dre_en_switch = |
| 332 | SOC_DAPM_SINGLE("Switch" , ADCX140_CH1_CFG0, 0, 1, 0); |
| 333 | static const struct snd_kcontrol_new adcx140_dapm_ch2_dre_en_switch = |
| 334 | SOC_DAPM_SINGLE("Switch" , ADCX140_CH2_CFG0, 0, 1, 0); |
| 335 | static const struct snd_kcontrol_new adcx140_dapm_ch3_dre_en_switch = |
| 336 | SOC_DAPM_SINGLE("Switch" , ADCX140_CH3_CFG0, 0, 1, 0); |
| 337 | static const struct snd_kcontrol_new adcx140_dapm_ch4_dre_en_switch = |
| 338 | SOC_DAPM_SINGLE("Switch" , ADCX140_CH4_CFG0, 0, 1, 0); |
| 339 | |
| 340 | static const struct snd_kcontrol_new adcx140_dapm_dre_en_switch = |
| 341 | SOC_DAPM_SINGLE("Switch" , ADCX140_DSP_CFG1, 3, 1, 0); |
| 342 | |
| 343 | /* Output Mixer */ |
| 344 | static const struct snd_kcontrol_new adcx140_output_mixer_controls[] = { |
| 345 | SOC_DAPM_SINGLE("Digital CH1 Switch" , 0, 0, 0, 0), |
| 346 | SOC_DAPM_SINGLE("Digital CH2 Switch" , 0, 0, 0, 0), |
| 347 | SOC_DAPM_SINGLE("Digital CH3 Switch" , 0, 0, 0, 0), |
| 348 | SOC_DAPM_SINGLE("Digital CH4 Switch" , 0, 0, 0, 0), |
| 349 | }; |
| 350 | |
| 351 | static const struct snd_soc_dapm_widget adcx140_dapm_widgets[] = { |
| 352 | /* Analog Differential Inputs */ |
| 353 | SND_SOC_DAPM_INPUT("MIC1P" ), |
| 354 | SND_SOC_DAPM_INPUT("MIC1M" ), |
| 355 | SND_SOC_DAPM_INPUT("MIC2P" ), |
| 356 | SND_SOC_DAPM_INPUT("MIC2M" ), |
| 357 | SND_SOC_DAPM_INPUT("MIC3P" ), |
| 358 | SND_SOC_DAPM_INPUT("MIC3M" ), |
| 359 | SND_SOC_DAPM_INPUT("MIC4P" ), |
| 360 | SND_SOC_DAPM_INPUT("MIC4M" ), |
| 361 | |
| 362 | SND_SOC_DAPM_OUTPUT("CH1_OUT" ), |
| 363 | SND_SOC_DAPM_OUTPUT("CH2_OUT" ), |
| 364 | SND_SOC_DAPM_OUTPUT("CH3_OUT" ), |
| 365 | SND_SOC_DAPM_OUTPUT("CH4_OUT" ), |
| 366 | SND_SOC_DAPM_OUTPUT("CH5_OUT" ), |
| 367 | SND_SOC_DAPM_OUTPUT("CH6_OUT" ), |
| 368 | SND_SOC_DAPM_OUTPUT("CH7_OUT" ), |
| 369 | SND_SOC_DAPM_OUTPUT("CH8_OUT" ), |
| 370 | |
| 371 | SND_SOC_DAPM_MIXER("Output Mixer" , SND_SOC_NOPM, 0, 0, |
| 372 | &adcx140_output_mixer_controls[0], |
| 373 | ARRAY_SIZE(adcx140_output_mixer_controls)), |
| 374 | |
| 375 | /* Input Selection to MIC_PGA */ |
| 376 | SND_SOC_DAPM_MUX("MIC1P Input Mux" , SND_SOC_NOPM, 0, 0, |
| 377 | &adcx140_dapm_mic1p_control), |
| 378 | SND_SOC_DAPM_MUX("MIC2P Input Mux" , SND_SOC_NOPM, 0, 0, |
| 379 | &adcx140_dapm_mic2p_control), |
| 380 | SND_SOC_DAPM_MUX("MIC3P Input Mux" , SND_SOC_NOPM, 0, 0, |
| 381 | &adcx140_dapm_mic3p_control), |
| 382 | SND_SOC_DAPM_MUX("MIC4P Input Mux" , SND_SOC_NOPM, 0, 0, |
| 383 | &adcx140_dapm_mic4p_control), |
| 384 | |
| 385 | /* Input Selection to MIC_PGA */ |
| 386 | SND_SOC_DAPM_MUX("MIC1 Analog Mux" , SND_SOC_NOPM, 0, 0, |
| 387 | &adcx140_dapm_mic1_analog_control), |
| 388 | SND_SOC_DAPM_MUX("MIC2 Analog Mux" , SND_SOC_NOPM, 0, 0, |
| 389 | &adcx140_dapm_mic2_analog_control), |
| 390 | SND_SOC_DAPM_MUX("MIC3 Analog Mux" , SND_SOC_NOPM, 0, 0, |
| 391 | &adcx140_dapm_mic3_analog_control), |
| 392 | SND_SOC_DAPM_MUX("MIC4 Analog Mux" , SND_SOC_NOPM, 0, 0, |
| 393 | &adcx140_dapm_mic4_analog_control), |
| 394 | |
| 395 | SND_SOC_DAPM_MUX("MIC1M Input Mux" , SND_SOC_NOPM, 0, 0, |
| 396 | &adcx140_dapm_mic1m_control), |
| 397 | SND_SOC_DAPM_MUX("MIC2M Input Mux" , SND_SOC_NOPM, 0, 0, |
| 398 | &adcx140_dapm_mic2m_control), |
| 399 | SND_SOC_DAPM_MUX("MIC3M Input Mux" , SND_SOC_NOPM, 0, 0, |
| 400 | &adcx140_dapm_mic3m_control), |
| 401 | SND_SOC_DAPM_MUX("MIC4M Input Mux" , SND_SOC_NOPM, 0, 0, |
| 402 | &adcx140_dapm_mic4m_control), |
| 403 | |
| 404 | SND_SOC_DAPM_PGA("MIC_GAIN_CTL_CH1" , SND_SOC_NOPM, 0, 0, NULL, 0), |
| 405 | SND_SOC_DAPM_PGA("MIC_GAIN_CTL_CH2" , SND_SOC_NOPM, 0, 0, NULL, 0), |
| 406 | SND_SOC_DAPM_PGA("MIC_GAIN_CTL_CH3" , SND_SOC_NOPM, 0, 0, NULL, 0), |
| 407 | SND_SOC_DAPM_PGA("MIC_GAIN_CTL_CH4" , SND_SOC_NOPM, 0, 0, NULL, 0), |
| 408 | |
| 409 | SND_SOC_DAPM_ADC("CH1_ADC" , "CH1 Capture" , ADCX140_IN_CH_EN, 7, 0), |
| 410 | SND_SOC_DAPM_ADC("CH2_ADC" , "CH2 Capture" , ADCX140_IN_CH_EN, 6, 0), |
| 411 | SND_SOC_DAPM_ADC("CH3_ADC" , "CH3 Capture" , ADCX140_IN_CH_EN, 5, 0), |
| 412 | SND_SOC_DAPM_ADC("CH4_ADC" , "CH4 Capture" , ADCX140_IN_CH_EN, 4, 0), |
| 413 | |
| 414 | SND_SOC_DAPM_ADC("CH1_DIG" , "CH1 Capture" , ADCX140_IN_CH_EN, 7, 0), |
| 415 | SND_SOC_DAPM_ADC("CH2_DIG" , "CH2 Capture" , ADCX140_IN_CH_EN, 6, 0), |
| 416 | SND_SOC_DAPM_ADC("CH3_DIG" , "CH3 Capture" , ADCX140_IN_CH_EN, 5, 0), |
| 417 | SND_SOC_DAPM_ADC("CH4_DIG" , "CH4 Capture" , ADCX140_IN_CH_EN, 4, 0), |
| 418 | SND_SOC_DAPM_ADC("CH5_DIG" , "CH5 Capture" , ADCX140_IN_CH_EN, 3, 0), |
| 419 | SND_SOC_DAPM_ADC("CH6_DIG" , "CH6 Capture" , ADCX140_IN_CH_EN, 2, 0), |
| 420 | SND_SOC_DAPM_ADC("CH7_DIG" , "CH7 Capture" , ADCX140_IN_CH_EN, 1, 0), |
| 421 | SND_SOC_DAPM_ADC("CH8_DIG" , "CH8 Capture" , ADCX140_IN_CH_EN, 0, 0), |
| 422 | |
| 423 | |
| 424 | SND_SOC_DAPM_SWITCH("CH1_ASI_EN" , SND_SOC_NOPM, 0, 0, |
| 425 | &adcx140_dapm_ch1_en_switch), |
| 426 | SND_SOC_DAPM_SWITCH("CH2_ASI_EN" , SND_SOC_NOPM, 0, 0, |
| 427 | &adcx140_dapm_ch2_en_switch), |
| 428 | SND_SOC_DAPM_SWITCH("CH3_ASI_EN" , SND_SOC_NOPM, 0, 0, |
| 429 | &adcx140_dapm_ch3_en_switch), |
| 430 | SND_SOC_DAPM_SWITCH("CH4_ASI_EN" , SND_SOC_NOPM, 0, 0, |
| 431 | &adcx140_dapm_ch4_en_switch), |
| 432 | |
| 433 | SND_SOC_DAPM_SWITCH("CH5_ASI_EN" , SND_SOC_NOPM, 0, 0, |
| 434 | &adcx140_dapm_ch5_en_switch), |
| 435 | SND_SOC_DAPM_SWITCH("CH6_ASI_EN" , SND_SOC_NOPM, 0, 0, |
| 436 | &adcx140_dapm_ch6_en_switch), |
| 437 | SND_SOC_DAPM_SWITCH("CH7_ASI_EN" , SND_SOC_NOPM, 0, 0, |
| 438 | &adcx140_dapm_ch7_en_switch), |
| 439 | SND_SOC_DAPM_SWITCH("CH8_ASI_EN" , SND_SOC_NOPM, 0, 0, |
| 440 | &adcx140_dapm_ch8_en_switch), |
| 441 | |
| 442 | SND_SOC_DAPM_SWITCH("DRE_ENABLE" , SND_SOC_NOPM, 0, 0, |
| 443 | &adcx140_dapm_dre_en_switch), |
| 444 | |
| 445 | SND_SOC_DAPM_SWITCH("CH1_DRE_EN" , SND_SOC_NOPM, 0, 0, |
| 446 | &adcx140_dapm_ch1_dre_en_switch), |
| 447 | SND_SOC_DAPM_SWITCH("CH2_DRE_EN" , SND_SOC_NOPM, 0, 0, |
| 448 | &adcx140_dapm_ch2_dre_en_switch), |
| 449 | SND_SOC_DAPM_SWITCH("CH3_DRE_EN" , SND_SOC_NOPM, 0, 0, |
| 450 | &adcx140_dapm_ch3_dre_en_switch), |
| 451 | SND_SOC_DAPM_SWITCH("CH4_DRE_EN" , SND_SOC_NOPM, 0, 0, |
| 452 | &adcx140_dapm_ch4_dre_en_switch), |
| 453 | |
| 454 | SND_SOC_DAPM_MUX("IN1 Analog Mic Resistor" , SND_SOC_NOPM, 0, 0, |
| 455 | in1_resistor_controls), |
| 456 | SND_SOC_DAPM_MUX("IN2 Analog Mic Resistor" , SND_SOC_NOPM, 0, 0, |
| 457 | in2_resistor_controls), |
| 458 | SND_SOC_DAPM_MUX("IN3 Analog Mic Resistor" , SND_SOC_NOPM, 0, 0, |
| 459 | in3_resistor_controls), |
| 460 | SND_SOC_DAPM_MUX("IN4 Analog Mic Resistor" , SND_SOC_NOPM, 0, 0, |
| 461 | in4_resistor_controls), |
| 462 | |
| 463 | SND_SOC_DAPM_MUX("PDM Clk Div Select" , SND_SOC_NOPM, 0, 0, |
| 464 | pdmclk_div_controls), |
| 465 | |
| 466 | SND_SOC_DAPM_MUX("Decimation Filter" , SND_SOC_NOPM, 0, 0, |
| 467 | decimation_filter_controls), |
| 468 | }; |
| 469 | |
| 470 | static const struct snd_soc_dapm_route adcx140_audio_map[] = { |
| 471 | /* Outputs */ |
| 472 | {"CH1_OUT" , NULL, "Output Mixer" }, |
| 473 | {"CH2_OUT" , NULL, "Output Mixer" }, |
| 474 | {"CH3_OUT" , NULL, "Output Mixer" }, |
| 475 | {"CH4_OUT" , NULL, "Output Mixer" }, |
| 476 | |
| 477 | {"CH1_ASI_EN" , "Switch" , "CH1_ADC" }, |
| 478 | {"CH2_ASI_EN" , "Switch" , "CH2_ADC" }, |
| 479 | {"CH3_ASI_EN" , "Switch" , "CH3_ADC" }, |
| 480 | {"CH4_ASI_EN" , "Switch" , "CH4_ADC" }, |
| 481 | |
| 482 | {"CH1_ASI_EN" , "Switch" , "CH1_DIG" }, |
| 483 | {"CH2_ASI_EN" , "Switch" , "CH2_DIG" }, |
| 484 | {"CH3_ASI_EN" , "Switch" , "CH3_DIG" }, |
| 485 | {"CH4_ASI_EN" , "Switch" , "CH4_DIG" }, |
| 486 | {"CH5_ASI_EN" , "Switch" , "CH5_DIG" }, |
| 487 | {"CH6_ASI_EN" , "Switch" , "CH6_DIG" }, |
| 488 | {"CH7_ASI_EN" , "Switch" , "CH7_DIG" }, |
| 489 | {"CH8_ASI_EN" , "Switch" , "CH8_DIG" }, |
| 490 | |
| 491 | {"CH5_ASI_EN" , "Switch" , "CH5_OUT" }, |
| 492 | {"CH6_ASI_EN" , "Switch" , "CH6_OUT" }, |
| 493 | {"CH7_ASI_EN" , "Switch" , "CH7_OUT" }, |
| 494 | {"CH8_ASI_EN" , "Switch" , "CH8_OUT" }, |
| 495 | |
| 496 | {"Decimation Filter" , "Linear Phase" , "DRE_ENABLE" }, |
| 497 | {"Decimation Filter" , "Low Latency" , "DRE_ENABLE" }, |
| 498 | {"Decimation Filter" , "Ultra-low Latency" , "DRE_ENABLE" }, |
| 499 | |
| 500 | {"DRE_ENABLE" , "Switch" , "CH1_DRE_EN" }, |
| 501 | {"DRE_ENABLE" , "Switch" , "CH2_DRE_EN" }, |
| 502 | {"DRE_ENABLE" , "Switch" , "CH3_DRE_EN" }, |
| 503 | {"DRE_ENABLE" , "Switch" , "CH4_DRE_EN" }, |
| 504 | |
| 505 | {"CH1_DRE_EN" , "Switch" , "CH1_ADC" }, |
| 506 | {"CH2_DRE_EN" , "Switch" , "CH2_ADC" }, |
| 507 | {"CH3_DRE_EN" , "Switch" , "CH3_ADC" }, |
| 508 | {"CH4_DRE_EN" , "Switch" , "CH4_ADC" }, |
| 509 | |
| 510 | /* Mic input */ |
| 511 | {"CH1_ADC" , NULL, "MIC_GAIN_CTL_CH1" }, |
| 512 | {"CH2_ADC" , NULL, "MIC_GAIN_CTL_CH2" }, |
| 513 | {"CH3_ADC" , NULL, "MIC_GAIN_CTL_CH3" }, |
| 514 | {"CH4_ADC" , NULL, "MIC_GAIN_CTL_CH4" }, |
| 515 | |
| 516 | {"MIC_GAIN_CTL_CH1" , NULL, "IN1 Analog Mic Resistor" }, |
| 517 | {"MIC_GAIN_CTL_CH1" , NULL, "IN1 Analog Mic Resistor" }, |
| 518 | {"MIC_GAIN_CTL_CH2" , NULL, "IN2 Analog Mic Resistor" }, |
| 519 | {"MIC_GAIN_CTL_CH2" , NULL, "IN2 Analog Mic Resistor" }, |
| 520 | {"MIC_GAIN_CTL_CH3" , NULL, "IN3 Analog Mic Resistor" }, |
| 521 | {"MIC_GAIN_CTL_CH3" , NULL, "IN3 Analog Mic Resistor" }, |
| 522 | {"MIC_GAIN_CTL_CH4" , NULL, "IN4 Analog Mic Resistor" }, |
| 523 | {"MIC_GAIN_CTL_CH4" , NULL, "IN4 Analog Mic Resistor" }, |
| 524 | |
| 525 | {"IN1 Analog Mic Resistor" , "2.5 kOhm" , "MIC1P Input Mux" }, |
| 526 | {"IN1 Analog Mic Resistor" , "10 kOhm" , "MIC1P Input Mux" }, |
| 527 | {"IN1 Analog Mic Resistor" , "20 kOhm" , "MIC1P Input Mux" }, |
| 528 | |
| 529 | {"IN1 Analog Mic Resistor" , "2.5 kOhm" , "MIC1M Input Mux" }, |
| 530 | {"IN1 Analog Mic Resistor" , "10 kOhm" , "MIC1M Input Mux" }, |
| 531 | {"IN1 Analog Mic Resistor" , "20 kOhm" , "MIC1M Input Mux" }, |
| 532 | |
| 533 | {"IN2 Analog Mic Resistor" , "2.5 kOhm" , "MIC2P Input Mux" }, |
| 534 | {"IN2 Analog Mic Resistor" , "10 kOhm" , "MIC2P Input Mux" }, |
| 535 | {"IN2 Analog Mic Resistor" , "20 kOhm" , "MIC2P Input Mux" }, |
| 536 | |
| 537 | {"IN2 Analog Mic Resistor" , "2.5 kOhm" , "MIC2M Input Mux" }, |
| 538 | {"IN2 Analog Mic Resistor" , "10 kOhm" , "MIC2M Input Mux" }, |
| 539 | {"IN2 Analog Mic Resistor" , "20 kOhm" , "MIC2M Input Mux" }, |
| 540 | |
| 541 | {"IN3 Analog Mic Resistor" , "2.5 kOhm" , "MIC3P Input Mux" }, |
| 542 | {"IN3 Analog Mic Resistor" , "10 kOhm" , "MIC3P Input Mux" }, |
| 543 | {"IN3 Analog Mic Resistor" , "20 kOhm" , "MIC3P Input Mux" }, |
| 544 | |
| 545 | {"IN3 Analog Mic Resistor" , "2.5 kOhm" , "MIC3M Input Mux" }, |
| 546 | {"IN3 Analog Mic Resistor" , "10 kOhm" , "MIC3M Input Mux" }, |
| 547 | {"IN3 Analog Mic Resistor" , "20 kOhm" , "MIC3M Input Mux" }, |
| 548 | |
| 549 | {"IN4 Analog Mic Resistor" , "2.5 kOhm" , "MIC4P Input Mux" }, |
| 550 | {"IN4 Analog Mic Resistor" , "10 kOhm" , "MIC4P Input Mux" }, |
| 551 | {"IN4 Analog Mic Resistor" , "20 kOhm" , "MIC4P Input Mux" }, |
| 552 | |
| 553 | {"IN4 Analog Mic Resistor" , "2.5 kOhm" , "MIC4M Input Mux" }, |
| 554 | {"IN4 Analog Mic Resistor" , "10 kOhm" , "MIC4M Input Mux" }, |
| 555 | {"IN4 Analog Mic Resistor" , "20 kOhm" , "MIC4M Input Mux" }, |
| 556 | |
| 557 | {"PDM Clk Div Select" , "2.8224 MHz" , "MIC1P Input Mux" }, |
| 558 | {"PDM Clk Div Select" , "1.4112 MHz" , "MIC1P Input Mux" }, |
| 559 | {"PDM Clk Div Select" , "705.6 kHz" , "MIC1P Input Mux" }, |
| 560 | {"PDM Clk Div Select" , "5.6448 MHz" , "MIC1P Input Mux" }, |
| 561 | |
| 562 | {"MIC1P Input Mux" , NULL, "CH1_DIG" }, |
| 563 | {"MIC1M Input Mux" , NULL, "CH2_DIG" }, |
| 564 | {"MIC2P Input Mux" , NULL, "CH3_DIG" }, |
| 565 | {"MIC2M Input Mux" , NULL, "CH4_DIG" }, |
| 566 | {"MIC3P Input Mux" , NULL, "CH5_DIG" }, |
| 567 | {"MIC3M Input Mux" , NULL, "CH6_DIG" }, |
| 568 | {"MIC4P Input Mux" , NULL, "CH7_DIG" }, |
| 569 | {"MIC4M Input Mux" , NULL, "CH8_DIG" }, |
| 570 | |
| 571 | {"MIC1 Analog Mux" , "Line In" , "MIC1P" }, |
| 572 | {"MIC2 Analog Mux" , "Line In" , "MIC2P" }, |
| 573 | {"MIC3 Analog Mux" , "Line In" , "MIC3P" }, |
| 574 | {"MIC4 Analog Mux" , "Line In" , "MIC4P" }, |
| 575 | |
| 576 | {"MIC1P Input Mux" , "Analog" , "MIC1P" }, |
| 577 | {"MIC1M Input Mux" , "Analog" , "MIC1M" }, |
| 578 | {"MIC2P Input Mux" , "Analog" , "MIC2P" }, |
| 579 | {"MIC2M Input Mux" , "Analog" , "MIC2M" }, |
| 580 | {"MIC3P Input Mux" , "Analog" , "MIC3P" }, |
| 581 | {"MIC3M Input Mux" , "Analog" , "MIC3M" }, |
| 582 | {"MIC4P Input Mux" , "Analog" , "MIC4P" }, |
| 583 | {"MIC4M Input Mux" , "Analog" , "MIC4M" }, |
| 584 | |
| 585 | {"MIC1P Input Mux" , "Digital" , "MIC1P" }, |
| 586 | {"MIC1M Input Mux" , "Digital" , "MIC1M" }, |
| 587 | {"MIC2P Input Mux" , "Digital" , "MIC2P" }, |
| 588 | {"MIC2M Input Mux" , "Digital" , "MIC2M" }, |
| 589 | {"MIC3P Input Mux" , "Digital" , "MIC3P" }, |
| 590 | {"MIC3M Input Mux" , "Digital" , "MIC3M" }, |
| 591 | {"MIC4P Input Mux" , "Digital" , "MIC4P" }, |
| 592 | {"MIC4M Input Mux" , "Digital" , "MIC4M" }, |
| 593 | }; |
| 594 | |
| 595 | #define ADCX140_PHASE_CALIB_SWITCH(xname) {\ |
| 596 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
| 597 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
| 598 | .info = adcx140_phase_calib_info, \ |
| 599 | .get = adcx140_phase_calib_get, \ |
| 600 | .put = adcx140_phase_calib_put} |
| 601 | |
| 602 | static int adcx140_phase_calib_info(struct snd_kcontrol *kcontrol, |
| 603 | struct snd_ctl_elem_info *uinfo) |
| 604 | { |
| 605 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
| 606 | uinfo->count = 1; |
| 607 | uinfo->value.integer.min = 0; |
| 608 | uinfo->value.integer.max = 1; |
| 609 | return 0; |
| 610 | } |
| 611 | |
| 612 | static int adcx140_phase_calib_get(struct snd_kcontrol *kcontrol, |
| 613 | struct snd_ctl_elem_value *value) |
| 614 | { |
| 615 | struct snd_soc_component *codec = |
| 616 | snd_soc_kcontrol_component(kcontrol); |
| 617 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: codec); |
| 618 | |
| 619 | value->value.integer.value[0] = adcx140->phase_calib_on ? 1 : 0; |
| 620 | |
| 621 | |
| 622 | return 0; |
| 623 | } |
| 624 | |
| 625 | static int adcx140_phase_calib_put(struct snd_kcontrol *kcontrol, |
| 626 | struct snd_ctl_elem_value *value) |
| 627 | { |
| 628 | struct snd_soc_component *codec |
| 629 | = snd_soc_kcontrol_component(kcontrol); |
| 630 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: codec); |
| 631 | |
| 632 | bool v = value->value.integer.value[0] ? true : false; |
| 633 | |
| 634 | if (adcx140->phase_calib_on != v) { |
| 635 | adcx140->phase_calib_on = v; |
| 636 | return 1; |
| 637 | } |
| 638 | return 0; |
| 639 | } |
| 640 | |
| 641 | static const struct snd_kcontrol_new adcx140_snd_controls[] = { |
| 642 | SOC_SINGLE_TLV("Analog CH1 Mic Gain Volume" , ADCX140_CH1_CFG1, 2, 42, 0, |
| 643 | adc_tlv), |
| 644 | SOC_SINGLE_TLV("Analog CH2 Mic Gain Volume" , ADCX140_CH2_CFG1, 2, 42, 0, |
| 645 | adc_tlv), |
| 646 | SOC_SINGLE_TLV("Analog CH3 Mic Gain Volume" , ADCX140_CH3_CFG1, 2, 42, 0, |
| 647 | adc_tlv), |
| 648 | SOC_SINGLE_TLV("Analog CH4 Mic Gain Volume" , ADCX140_CH4_CFG1, 2, 42, 0, |
| 649 | adc_tlv), |
| 650 | |
| 651 | SOC_SINGLE_TLV("DRE Threshold" , ADCX140_DRE_CFG0, 4, 9, 0, |
| 652 | dre_thresh_tlv), |
| 653 | SOC_SINGLE_TLV("DRE Max Gain" , ADCX140_DRE_CFG0, 0, 12, 0, |
| 654 | dre_gain_tlv), |
| 655 | |
| 656 | SOC_SINGLE_TLV("AGC Threshold" , ADCX140_AGC_CFG0, 4, 15, 0, |
| 657 | agc_thresh_tlv), |
| 658 | SOC_SINGLE_TLV("AGC Max Gain" , ADCX140_AGC_CFG0, 0, 13, 0, |
| 659 | agc_gain_tlv), |
| 660 | |
| 661 | SOC_SINGLE_TLV("Digital CH1 Out Volume" , ADCX140_CH1_CFG2, |
| 662 | 0, 0xff, 0, dig_vol_tlv), |
| 663 | SOC_SINGLE_TLV("Digital CH2 Out Volume" , ADCX140_CH2_CFG2, |
| 664 | 0, 0xff, 0, dig_vol_tlv), |
| 665 | SOC_SINGLE_TLV("Digital CH3 Out Volume" , ADCX140_CH3_CFG2, |
| 666 | 0, 0xff, 0, dig_vol_tlv), |
| 667 | SOC_SINGLE_TLV("Digital CH4 Out Volume" , ADCX140_CH4_CFG2, |
| 668 | 0, 0xff, 0, dig_vol_tlv), |
| 669 | SOC_SINGLE_TLV("Digital CH5 Out Volume" , ADCX140_CH5_CFG2, |
| 670 | 0, 0xff, 0, dig_vol_tlv), |
| 671 | SOC_SINGLE_TLV("Digital CH6 Out Volume" , ADCX140_CH6_CFG2, |
| 672 | 0, 0xff, 0, dig_vol_tlv), |
| 673 | SOC_SINGLE_TLV("Digital CH7 Out Volume" , ADCX140_CH7_CFG2, |
| 674 | 0, 0xff, 0, dig_vol_tlv), |
| 675 | SOC_SINGLE_TLV("Digital CH8 Out Volume" , ADCX140_CH8_CFG2, |
| 676 | 0, 0xff, 0, dig_vol_tlv), |
| 677 | ADCX140_PHASE_CALIB_SWITCH("Phase Calibration Switch" ), |
| 678 | }; |
| 679 | |
| 680 | static int adcx140_reset(struct adcx140_priv *adcx140) |
| 681 | { |
| 682 | int ret = 0; |
| 683 | |
| 684 | if (adcx140->gpio_reset) { |
| 685 | gpiod_direction_output(desc: adcx140->gpio_reset, value: 0); |
| 686 | /* 8.4.1: wait for hw shutdown (25ms) + >= 1ms */ |
| 687 | usleep_range(min: 30000, max: 100000); |
| 688 | gpiod_direction_output(desc: adcx140->gpio_reset, value: 1); |
| 689 | } else { |
| 690 | ret = regmap_write(map: adcx140->regmap, ADCX140_SW_RESET, |
| 691 | ADCX140_RESET); |
| 692 | } |
| 693 | |
| 694 | /* 8.4.2: wait >= 10 ms after entering sleep mode. */ |
| 695 | usleep_range(min: 10000, max: 100000); |
| 696 | |
| 697 | return ret; |
| 698 | } |
| 699 | |
| 700 | static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) |
| 701 | { |
| 702 | int pwr_ctrl = 0; |
| 703 | int ret = 0; |
| 704 | struct snd_soc_component *component = adcx140->component; |
| 705 | |
| 706 | if (power_state) |
| 707 | pwr_ctrl = ADCX140_PWR_CFG_ADC_PDZ | ADCX140_PWR_CFG_PLL_PDZ; |
| 708 | |
| 709 | if (adcx140->micbias_vg && power_state) |
| 710 | pwr_ctrl |= ADCX140_PWR_CFG_BIAS_PDZ; |
| 711 | |
| 712 | if (pwr_ctrl) { |
| 713 | ret = regmap_write(map: adcx140->regmap, ADCX140_PHASE_CALIB, |
| 714 | val: adcx140->phase_calib_on ? 0x00 : 0x40); |
| 715 | if (ret) |
| 716 | dev_err(component->dev, "%s: register write error %d\n" , |
| 717 | __func__, ret); |
| 718 | } |
| 719 | |
| 720 | regmap_update_bits(map: adcx140->regmap, ADCX140_PWR_CFG, |
| 721 | ADCX140_PWR_CTRL_MSK, val: pwr_ctrl); |
| 722 | } |
| 723 | |
| 724 | static int adcx140_hw_params(struct snd_pcm_substream *substream, |
| 725 | struct snd_pcm_hw_params *params, |
| 726 | struct snd_soc_dai *dai) |
| 727 | { |
| 728 | struct snd_soc_component *component = dai->component; |
| 729 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
| 730 | u8 data = 0; |
| 731 | |
| 732 | switch (params_width(p: params)) { |
| 733 | case 16: |
| 734 | data = ADCX140_16_BIT_WORD; |
| 735 | break; |
| 736 | case 20: |
| 737 | data = ADCX140_20_BIT_WORD; |
| 738 | break; |
| 739 | case 24: |
| 740 | data = ADCX140_24_BIT_WORD; |
| 741 | break; |
| 742 | case 32: |
| 743 | data = ADCX140_32_BIT_WORD; |
| 744 | break; |
| 745 | default: |
| 746 | dev_err(component->dev, "%s: Unsupported width %d\n" , |
| 747 | __func__, params_width(params)); |
| 748 | return -EINVAL; |
| 749 | } |
| 750 | |
| 751 | adcx140_pwr_ctrl(adcx140, power_state: false); |
| 752 | |
| 753 | snd_soc_component_update_bits(component, ADCX140_ASI_CFG0, |
| 754 | ADCX140_WORD_LEN_MSK, val: data); |
| 755 | |
| 756 | adcx140_pwr_ctrl(adcx140, power_state: true); |
| 757 | |
| 758 | return 0; |
| 759 | } |
| 760 | |
| 761 | static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 762 | unsigned int fmt) |
| 763 | { |
| 764 | struct snd_soc_component *component = codec_dai->component; |
| 765 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
| 766 | u8 iface_reg1 = 0; |
| 767 | u8 iface_reg2 = 0; |
| 768 | int offset = 0; |
| 769 | bool inverted_bclk = false; |
| 770 | |
| 771 | /* set master/slave audio interface */ |
| 772 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
| 773 | case SND_SOC_DAIFMT_CBP_CFP: |
| 774 | iface_reg2 |= ADCX140_BCLK_FSYNC_MASTER; |
| 775 | break; |
| 776 | case SND_SOC_DAIFMT_CBC_CFC: |
| 777 | break; |
| 778 | default: |
| 779 | dev_err(component->dev, "Invalid DAI clock provider\n" ); |
| 780 | return -EINVAL; |
| 781 | } |
| 782 | |
| 783 | /* interface format */ |
| 784 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
| 785 | case SND_SOC_DAIFMT_I2S: |
| 786 | iface_reg1 |= ADCX140_I2S_MODE_BIT; |
| 787 | break; |
| 788 | case SND_SOC_DAIFMT_LEFT_J: |
| 789 | iface_reg1 |= ADCX140_LEFT_JUST_BIT; |
| 790 | break; |
| 791 | case SND_SOC_DAIFMT_DSP_A: |
| 792 | offset = 1; |
| 793 | inverted_bclk = true; |
| 794 | break; |
| 795 | case SND_SOC_DAIFMT_DSP_B: |
| 796 | inverted_bclk = true; |
| 797 | break; |
| 798 | default: |
| 799 | dev_err(component->dev, "Invalid DAI interface format\n" ); |
| 800 | return -EINVAL; |
| 801 | } |
| 802 | |
| 803 | /* signal polarity */ |
| 804 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
| 805 | case SND_SOC_DAIFMT_IB_NF: |
| 806 | case SND_SOC_DAIFMT_IB_IF: |
| 807 | inverted_bclk = !inverted_bclk; |
| 808 | break; |
| 809 | case SND_SOC_DAIFMT_NB_IF: |
| 810 | iface_reg1 |= ADCX140_FSYNCINV_BIT; |
| 811 | break; |
| 812 | case SND_SOC_DAIFMT_NB_NF: |
| 813 | break; |
| 814 | default: |
| 815 | dev_err(component->dev, "Invalid DAI clock signal polarity\n" ); |
| 816 | return -EINVAL; |
| 817 | } |
| 818 | |
| 819 | if (inverted_bclk) |
| 820 | iface_reg1 |= ADCX140_BCLKINV_BIT; |
| 821 | |
| 822 | adcx140->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; |
| 823 | |
| 824 | adcx140_pwr_ctrl(adcx140, power_state: false); |
| 825 | |
| 826 | snd_soc_component_update_bits(component, ADCX140_ASI_CFG0, |
| 827 | ADCX140_FSYNCINV_BIT | |
| 828 | ADCX140_BCLKINV_BIT | |
| 829 | ADCX140_ASI_FORMAT_MSK, |
| 830 | val: iface_reg1); |
| 831 | snd_soc_component_update_bits(component, ADCX140_MST_CFG0, |
| 832 | ADCX140_BCLK_FSYNC_MASTER, val: iface_reg2); |
| 833 | |
| 834 | /* Configure data offset */ |
| 835 | snd_soc_component_update_bits(component, ADCX140_ASI_CFG1, |
| 836 | ADCX140_TX_OFFSET_MASK, val: offset); |
| 837 | |
| 838 | adcx140_pwr_ctrl(adcx140, power_state: true); |
| 839 | |
| 840 | return 0; |
| 841 | } |
| 842 | |
| 843 | static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, |
| 844 | unsigned int tx_mask, unsigned int rx_mask, |
| 845 | int slots, int slot_width) |
| 846 | { |
| 847 | struct snd_soc_component *component = codec_dai->component; |
| 848 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
| 849 | |
| 850 | /* |
| 851 | * The chip itself supports arbitrary masks, but the driver currently |
| 852 | * only supports adjacent slots beginning at the first slot. |
| 853 | */ |
| 854 | if (tx_mask != GENMASK(__fls(tx_mask), 0)) { |
| 855 | dev_err(component->dev, "Only lower adjacent slots are supported\n" ); |
| 856 | return -EINVAL; |
| 857 | } |
| 858 | |
| 859 | switch (slot_width) { |
| 860 | case 16: |
| 861 | case 20: |
| 862 | case 24: |
| 863 | case 32: |
| 864 | break; |
| 865 | default: |
| 866 | dev_err(component->dev, "Unsupported slot width %d\n" , slot_width); |
| 867 | return -EINVAL; |
| 868 | } |
| 869 | |
| 870 | adcx140->slot_width = slot_width; |
| 871 | |
| 872 | return 0; |
| 873 | } |
| 874 | |
| 875 | static const struct snd_soc_dai_ops adcx140_dai_ops = { |
| 876 | .hw_params = adcx140_hw_params, |
| 877 | .set_fmt = adcx140_set_dai_fmt, |
| 878 | .set_tdm_slot = adcx140_set_dai_tdm_slot, |
| 879 | }; |
| 880 | |
| 881 | static int adcx140_configure_gpo(struct adcx140_priv *adcx140) |
| 882 | { |
| 883 | u32 gpo_outputs[ADCX140_NUM_GPOS]; |
| 884 | u32 gpo_output_val = 0; |
| 885 | int ret; |
| 886 | int i; |
| 887 | |
| 888 | for (i = 0; i < ADCX140_NUM_GPOS; i++) { |
| 889 | ret = device_property_read_u32_array(dev: adcx140->dev, |
| 890 | propname: gpo_config_names[i], |
| 891 | val: gpo_outputs, |
| 892 | ADCX140_NUM_GPO_CFGS); |
| 893 | if (ret) |
| 894 | continue; |
| 895 | |
| 896 | if (gpo_outputs[0] > ADCX140_GPO_CFG_MAX) { |
| 897 | dev_err(adcx140->dev, "GPO%d config out of range\n" , i + 1); |
| 898 | return -EINVAL; |
| 899 | } |
| 900 | |
| 901 | if (gpo_outputs[1] > ADCX140_GPO_DRV_MAX) { |
| 902 | dev_err(adcx140->dev, "GPO%d drive out of range\n" , i + 1); |
| 903 | return -EINVAL; |
| 904 | } |
| 905 | |
| 906 | gpo_output_val = gpo_outputs[0] << ADCX140_GPO_SHIFT | |
| 907 | gpo_outputs[1]; |
| 908 | ret = regmap_write(map: adcx140->regmap, ADCX140_GPO_CFG0 + i, |
| 909 | val: gpo_output_val); |
| 910 | if (ret) |
| 911 | return ret; |
| 912 | } |
| 913 | |
| 914 | return 0; |
| 915 | |
| 916 | } |
| 917 | |
| 918 | static int adcx140_configure_gpio(struct adcx140_priv *adcx140) |
| 919 | { |
| 920 | int gpio_count = 0; |
| 921 | u32 gpio_outputs[ADCX140_NUM_GPIO_CFGS]; |
| 922 | u32 gpio_output_val = 0; |
| 923 | int ret; |
| 924 | |
| 925 | gpio_count = device_property_count_u32(dev: adcx140->dev, |
| 926 | propname: "ti,gpio-config" ); |
| 927 | if (gpio_count <= 0) |
| 928 | return 0; |
| 929 | |
| 930 | if (gpio_count != ADCX140_NUM_GPIO_CFGS) |
| 931 | return -EINVAL; |
| 932 | |
| 933 | ret = device_property_read_u32_array(dev: adcx140->dev, propname: "ti,gpio-config" , |
| 934 | val: gpio_outputs, nval: gpio_count); |
| 935 | if (ret) |
| 936 | return ret; |
| 937 | |
| 938 | if (gpio_outputs[0] > ADCX140_GPIO_CFG_MAX) { |
| 939 | dev_err(adcx140->dev, "GPIO config out of range\n" ); |
| 940 | return -EINVAL; |
| 941 | } |
| 942 | |
| 943 | if (gpio_outputs[1] > ADCX140_GPIO_DRV_MAX) { |
| 944 | dev_err(adcx140->dev, "GPIO drive out of range\n" ); |
| 945 | return -EINVAL; |
| 946 | } |
| 947 | |
| 948 | gpio_output_val = gpio_outputs[0] << ADCX140_GPIO_SHIFT |
| 949 | | gpio_outputs[1]; |
| 950 | |
| 951 | return regmap_write(map: adcx140->regmap, ADCX140_GPIO_CFG0, val: gpio_output_val); |
| 952 | } |
| 953 | |
| 954 | static int adcx140_codec_probe(struct snd_soc_component *component) |
| 955 | { |
| 956 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
| 957 | int sleep_cfg_val = ADCX140_WAKE_DEV; |
| 958 | u32 bias_source; |
| 959 | u32 vref_source; |
| 960 | u8 bias_cfg; |
| 961 | int pdm_count; |
| 962 | u32 pdm_edges[ADCX140_NUM_PDM_EDGES]; |
| 963 | u32 pdm_edge_val = 0; |
| 964 | int gpi_count; |
| 965 | u32 gpi_inputs[ADCX140_NUM_GPI_PINS]; |
| 966 | u32 gpi_input_val = 0; |
| 967 | int i; |
| 968 | int ret; |
| 969 | bool tx_high_z; |
| 970 | |
| 971 | ret = device_property_read_u32(dev: adcx140->dev, propname: "ti,mic-bias-source" , |
| 972 | val: &bias_source); |
| 973 | if (ret || bias_source > ADCX140_MIC_BIAS_VAL_AVDD) { |
| 974 | bias_source = ADCX140_MIC_BIAS_VAL_VREF; |
| 975 | adcx140->micbias_vg = false; |
| 976 | } else { |
| 977 | adcx140->micbias_vg = true; |
| 978 | } |
| 979 | |
| 980 | ret = device_property_read_u32(dev: adcx140->dev, propname: "ti,vref-source" , |
| 981 | val: &vref_source); |
| 982 | if (ret) |
| 983 | vref_source = ADCX140_MIC_BIAS_VREF_275V; |
| 984 | |
| 985 | if (vref_source > ADCX140_MIC_BIAS_VREF_1375V) { |
| 986 | dev_err(adcx140->dev, "Mic Bias source value is invalid\n" ); |
| 987 | return -EINVAL; |
| 988 | } |
| 989 | |
| 990 | bias_cfg = bias_source << ADCX140_MIC_BIAS_SHIFT | vref_source; |
| 991 | |
| 992 | ret = adcx140_reset(adcx140); |
| 993 | if (ret) |
| 994 | goto out; |
| 995 | |
| 996 | if (adcx140->supply_areg == NULL) |
| 997 | sleep_cfg_val |= ADCX140_AREG_INTERNAL; |
| 998 | |
| 999 | ret = regmap_write(map: adcx140->regmap, ADCX140_SLEEP_CFG, val: sleep_cfg_val); |
| 1000 | if (ret) { |
| 1001 | dev_err(adcx140->dev, "setting sleep config failed %d\n" , ret); |
| 1002 | goto out; |
| 1003 | } |
| 1004 | |
| 1005 | /* 8.4.3: Wait >= 1ms after entering active mode. */ |
| 1006 | usleep_range(min: 1000, max: 100000); |
| 1007 | |
| 1008 | pdm_count = device_property_count_u32(dev: adcx140->dev, |
| 1009 | propname: "ti,pdm-edge-select" ); |
| 1010 | if (pdm_count <= ADCX140_NUM_PDM_EDGES && pdm_count > 0) { |
| 1011 | ret = device_property_read_u32_array(dev: adcx140->dev, |
| 1012 | propname: "ti,pdm-edge-select" , |
| 1013 | val: pdm_edges, nval: pdm_count); |
| 1014 | if (ret) |
| 1015 | return ret; |
| 1016 | |
| 1017 | for (i = 0; i < pdm_count; i++) |
| 1018 | pdm_edge_val |= pdm_edges[i] << (ADCX140_PDM_EDGE_SHIFT - i); |
| 1019 | |
| 1020 | ret = regmap_write(map: adcx140->regmap, ADCX140_PDM_CFG, |
| 1021 | val: pdm_edge_val); |
| 1022 | if (ret) |
| 1023 | return ret; |
| 1024 | } |
| 1025 | |
| 1026 | gpi_count = device_property_count_u32(dev: adcx140->dev, propname: "ti,gpi-config" ); |
| 1027 | if (gpi_count <= ADCX140_NUM_GPI_PINS && gpi_count > 0) { |
| 1028 | ret = device_property_read_u32_array(dev: adcx140->dev, |
| 1029 | propname: "ti,gpi-config" , |
| 1030 | val: gpi_inputs, nval: gpi_count); |
| 1031 | if (ret) |
| 1032 | return ret; |
| 1033 | |
| 1034 | gpi_input_val = gpi_inputs[ADCX140_GPI1_INDEX] << ADCX140_GPI_SHIFT | |
| 1035 | gpi_inputs[ADCX140_GPI2_INDEX]; |
| 1036 | |
| 1037 | ret = regmap_write(map: adcx140->regmap, ADCX140_GPI_CFG0, |
| 1038 | val: gpi_input_val); |
| 1039 | if (ret) |
| 1040 | return ret; |
| 1041 | |
| 1042 | gpi_input_val = gpi_inputs[ADCX140_GPI3_INDEX] << ADCX140_GPI_SHIFT | |
| 1043 | gpi_inputs[ADCX140_GPI4_INDEX]; |
| 1044 | |
| 1045 | ret = regmap_write(map: adcx140->regmap, ADCX140_GPI_CFG1, |
| 1046 | val: gpi_input_val); |
| 1047 | if (ret) |
| 1048 | return ret; |
| 1049 | } |
| 1050 | |
| 1051 | ret = adcx140_configure_gpio(adcx140); |
| 1052 | if (ret) |
| 1053 | return ret; |
| 1054 | |
| 1055 | ret = adcx140_configure_gpo(adcx140); |
| 1056 | if (ret) |
| 1057 | goto out; |
| 1058 | |
| 1059 | ret = regmap_update_bits(map: adcx140->regmap, ADCX140_BIAS_CFG, |
| 1060 | ADCX140_MIC_BIAS_VAL_MSK | |
| 1061 | ADCX140_MIC_BIAS_VREF_MSK, val: bias_cfg); |
| 1062 | if (ret) |
| 1063 | dev_err(adcx140->dev, "setting MIC bias failed %d\n" , ret); |
| 1064 | |
| 1065 | tx_high_z = device_property_read_bool(dev: adcx140->dev, propname: "ti,asi-tx-drive" ); |
| 1066 | if (tx_high_z) { |
| 1067 | ret = regmap_update_bits(map: adcx140->regmap, ADCX140_ASI_CFG0, |
| 1068 | ADCX140_TX_FILL, ADCX140_TX_FILL); |
| 1069 | if (ret) { |
| 1070 | dev_err(adcx140->dev, "Setting Tx drive failed %d\n" , ret); |
| 1071 | goto out; |
| 1072 | } |
| 1073 | } |
| 1074 | |
| 1075 | adcx140_pwr_ctrl(adcx140, power_state: true); |
| 1076 | out: |
| 1077 | return ret; |
| 1078 | } |
| 1079 | |
| 1080 | static int adcx140_set_bias_level(struct snd_soc_component *component, |
| 1081 | enum snd_soc_bias_level level) |
| 1082 | { |
| 1083 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
| 1084 | |
| 1085 | switch (level) { |
| 1086 | case SND_SOC_BIAS_ON: |
| 1087 | case SND_SOC_BIAS_PREPARE: |
| 1088 | case SND_SOC_BIAS_STANDBY: |
| 1089 | adcx140_pwr_ctrl(adcx140, power_state: true); |
| 1090 | break; |
| 1091 | case SND_SOC_BIAS_OFF: |
| 1092 | adcx140_pwr_ctrl(adcx140, power_state: false); |
| 1093 | break; |
| 1094 | } |
| 1095 | |
| 1096 | return 0; |
| 1097 | } |
| 1098 | |
| 1099 | static const struct snd_soc_component_driver soc_codec_driver_adcx140 = { |
| 1100 | .probe = adcx140_codec_probe, |
| 1101 | .set_bias_level = adcx140_set_bias_level, |
| 1102 | .controls = adcx140_snd_controls, |
| 1103 | .num_controls = ARRAY_SIZE(adcx140_snd_controls), |
| 1104 | .dapm_widgets = adcx140_dapm_widgets, |
| 1105 | .num_dapm_widgets = ARRAY_SIZE(adcx140_dapm_widgets), |
| 1106 | .dapm_routes = adcx140_audio_map, |
| 1107 | .num_dapm_routes = ARRAY_SIZE(adcx140_audio_map), |
| 1108 | .suspend_bias_off = 1, |
| 1109 | .idle_bias_on = 0, |
| 1110 | .use_pmdown_time = 1, |
| 1111 | .endianness = 1, |
| 1112 | }; |
| 1113 | |
| 1114 | static struct snd_soc_dai_driver adcx140_dai_driver[] = { |
| 1115 | { |
| 1116 | .name = "tlv320adcx140-codec" , |
| 1117 | .capture = { |
| 1118 | .stream_name = "Capture" , |
| 1119 | .channels_min = 2, |
| 1120 | .channels_max = ADCX140_MAX_CHANNELS, |
| 1121 | .rates = ADCX140_RATES, |
| 1122 | .formats = ADCX140_FORMATS, |
| 1123 | }, |
| 1124 | .ops = &adcx140_dai_ops, |
| 1125 | .symmetric_rate = 1, |
| 1126 | } |
| 1127 | }; |
| 1128 | |
| 1129 | #ifdef CONFIG_OF |
| 1130 | static const struct of_device_id tlv320adcx140_of_match[] = { |
| 1131 | { .compatible = "ti,tlv320adc3140" }, |
| 1132 | { .compatible = "ti,tlv320adc5140" }, |
| 1133 | { .compatible = "ti,tlv320adc6140" }, |
| 1134 | {}, |
| 1135 | }; |
| 1136 | MODULE_DEVICE_TABLE(of, tlv320adcx140_of_match); |
| 1137 | #endif |
| 1138 | |
| 1139 | static void adcx140_disable_regulator(void *arg) |
| 1140 | { |
| 1141 | struct adcx140_priv *adcx140 = arg; |
| 1142 | |
| 1143 | regulator_disable(regulator: adcx140->supply_areg); |
| 1144 | } |
| 1145 | |
| 1146 | static int adcx140_i2c_probe(struct i2c_client *i2c) |
| 1147 | { |
| 1148 | struct adcx140_priv *adcx140; |
| 1149 | int ret; |
| 1150 | |
| 1151 | adcx140 = devm_kzalloc(dev: &i2c->dev, size: sizeof(*adcx140), GFP_KERNEL); |
| 1152 | if (!adcx140) |
| 1153 | return -ENOMEM; |
| 1154 | |
| 1155 | adcx140->phase_calib_on = false; |
| 1156 | adcx140->dev = &i2c->dev; |
| 1157 | |
| 1158 | adcx140->gpio_reset = devm_gpiod_get_optional(dev: adcx140->dev, |
| 1159 | con_id: "reset" , flags: GPIOD_OUT_LOW); |
| 1160 | if (IS_ERR(ptr: adcx140->gpio_reset)) |
| 1161 | dev_info(&i2c->dev, "Reset GPIO not defined\n" ); |
| 1162 | |
| 1163 | adcx140->supply_areg = devm_regulator_get_optional(dev: adcx140->dev, |
| 1164 | id: "areg" ); |
| 1165 | if (IS_ERR(ptr: adcx140->supply_areg)) { |
| 1166 | if (PTR_ERR(ptr: adcx140->supply_areg) == -EPROBE_DEFER) |
| 1167 | return -EPROBE_DEFER; |
| 1168 | |
| 1169 | adcx140->supply_areg = NULL; |
| 1170 | } else { |
| 1171 | ret = regulator_enable(regulator: adcx140->supply_areg); |
| 1172 | if (ret) { |
| 1173 | dev_err(adcx140->dev, "Failed to enable areg\n" ); |
| 1174 | return ret; |
| 1175 | } |
| 1176 | |
| 1177 | ret = devm_add_action_or_reset(&i2c->dev, adcx140_disable_regulator, adcx140); |
| 1178 | if (ret) |
| 1179 | return ret; |
| 1180 | } |
| 1181 | |
| 1182 | adcx140->regmap = devm_regmap_init_i2c(i2c, &adcx140_i2c_regmap); |
| 1183 | if (IS_ERR(ptr: adcx140->regmap)) { |
| 1184 | ret = PTR_ERR(ptr: adcx140->regmap); |
| 1185 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n" , |
| 1186 | ret); |
| 1187 | return ret; |
| 1188 | } |
| 1189 | |
| 1190 | i2c_set_clientdata(client: i2c, data: adcx140); |
| 1191 | |
| 1192 | return devm_snd_soc_register_component(dev: &i2c->dev, |
| 1193 | component_driver: &soc_codec_driver_adcx140, |
| 1194 | dai_drv: adcx140_dai_driver, num_dai: 1); |
| 1195 | } |
| 1196 | |
| 1197 | static const struct i2c_device_id adcx140_i2c_id[] = { |
| 1198 | { "tlv320adc3140" , 0 }, |
| 1199 | { "tlv320adc5140" , 1 }, |
| 1200 | { "tlv320adc6140" , 2 }, |
| 1201 | {} |
| 1202 | }; |
| 1203 | MODULE_DEVICE_TABLE(i2c, adcx140_i2c_id); |
| 1204 | |
| 1205 | static struct i2c_driver adcx140_i2c_driver = { |
| 1206 | .driver = { |
| 1207 | .name = "tlv320adcx140-codec" , |
| 1208 | .of_match_table = of_match_ptr(tlv320adcx140_of_match), |
| 1209 | }, |
| 1210 | .probe = adcx140_i2c_probe, |
| 1211 | .id_table = adcx140_i2c_id, |
| 1212 | }; |
| 1213 | module_i2c_driver(adcx140_i2c_driver); |
| 1214 | |
| 1215 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>" ); |
| 1216 | MODULE_DESCRIPTION("ASoC TLV320ADCX140 CODEC Driver" ); |
| 1217 | MODULE_LICENSE("GPL v2" ); |
| 1218 | |