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

ASoC: nau8540: new codec driver

Add codec driver of NAU85L40

Signed-off-by: John Hsu <KCHSU0@nuvoton.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

John Hsu and committed by
Mark Brown
c1644e3d 7ce7d89f

+1080
+16
Documentation/devicetree/bindings/sound/nau8540.txt
··· 1 + NAU85L40 audio CODEC 2 + 3 + This device supports I2C only. 4 + 5 + Required properties: 6 + 7 + - compatible : "nuvoton,nau8540" 8 + 9 + - reg : the I2C address of the device. 10 + 11 + Example: 12 + 13 + codec: nau8540@1c { 14 + compatible = "nuvoton,nau8540"; 15 + reg = <0x1c>; 16 + };
+5
sound/soc/codecs/Kconfig
··· 95 95 select SND_SOC_MAX9877 if I2C 96 96 select SND_SOC_MC13783 if MFD_MC13XXX 97 97 select SND_SOC_ML26124 if I2C 98 + select SND_SOC_NAU8540 if I2C 98 99 select SND_SOC_NAU8810 if I2C 99 100 select SND_SOC_NAU8825 if I2C 100 101 select SND_SOC_HDMI_CODEC ··· 1105 1104 1106 1105 config SND_SOC_ML26124 1107 1106 tristate 1107 + 1108 + config SND_SOC_NAU8540 1109 + tristate "Nuvoton Technology Corporation NAU85L40 CODEC" 1110 + depends on I2C 1108 1111 1109 1112 config SND_SOC_NAU8810 1110 1113 tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
+2
sound/soc/codecs/Makefile
··· 90 90 snd-soc-ml26124-objs := ml26124.o 91 91 snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o 92 92 snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o 93 + snd-soc-nau8540-objs := nau8540.o 93 94 snd-soc-nau8810-objs := nau8810.o 94 95 snd-soc-nau8825-objs := nau8825.o 95 96 snd-soc-hdmi-codec-objs := hdmi-codec.o ··· 319 318 obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o 320 319 obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o 321 320 obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o 321 + obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o 322 322 obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o 323 323 obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o 324 324 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
+835
sound/soc/codecs/nau8540.c
··· 1 + /* 2 + * NAU85L40 ALSA SoC audio driver 3 + * 4 + * Copyright 2016 Nuvoton Technology Corp. 5 + * Author: John Hsu <KCHSU0@nuvoton.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + 12 + #include <linux/module.h> 13 + #include <linux/moduleparam.h> 14 + #include <linux/init.h> 15 + #include <linux/delay.h> 16 + #include <linux/pm.h> 17 + #include <linux/i2c.h> 18 + #include <linux/regmap.h> 19 + #include <linux/regulator/consumer.h> 20 + #include <linux/spi/spi.h> 21 + #include <linux/slab.h> 22 + #include <linux/of_device.h> 23 + #include <sound/core.h> 24 + #include <sound/pcm.h> 25 + #include <sound/pcm_params.h> 26 + #include <sound/soc.h> 27 + #include <sound/soc-dapm.h> 28 + #include <sound/initval.h> 29 + #include <sound/tlv.h> 30 + #include "nau8540.h" 31 + 32 + 33 + #define NAU_FREF_MAX 13500000 34 + #define NAU_FVCO_MAX 100000000 35 + #define NAU_FVCO_MIN 90000000 36 + 37 + /* the maximum frequency of CLK_ADC */ 38 + #define CLK_ADC_MAX 6144000 39 + 40 + /* scaling for mclk from sysclk_src output */ 41 + static const struct nau8540_fll_attr mclk_src_scaling[] = { 42 + { 1, 0x0 }, 43 + { 2, 0x2 }, 44 + { 4, 0x3 }, 45 + { 8, 0x4 }, 46 + { 16, 0x5 }, 47 + { 32, 0x6 }, 48 + { 3, 0x7 }, 49 + { 6, 0xa }, 50 + { 12, 0xb }, 51 + { 24, 0xc }, 52 + }; 53 + 54 + /* ratio for input clk freq */ 55 + static const struct nau8540_fll_attr fll_ratio[] = { 56 + { 512000, 0x01 }, 57 + { 256000, 0x02 }, 58 + { 128000, 0x04 }, 59 + { 64000, 0x08 }, 60 + { 32000, 0x10 }, 61 + { 8000, 0x20 }, 62 + { 4000, 0x40 }, 63 + }; 64 + 65 + static const struct nau8540_fll_attr fll_pre_scalar[] = { 66 + { 1, 0x0 }, 67 + { 2, 0x1 }, 68 + { 4, 0x2 }, 69 + { 8, 0x3 }, 70 + }; 71 + 72 + /* over sampling rate */ 73 + static const struct nau8540_osr_attr osr_adc_sel[] = { 74 + { 32, 3 }, /* OSR 32, SRC 1/8 */ 75 + { 64, 2 }, /* OSR 64, SRC 1/4 */ 76 + { 128, 1 }, /* OSR 128, SRC 1/2 */ 77 + { 256, 0 }, /* OSR 256, SRC 1 */ 78 + }; 79 + 80 + static const struct reg_default nau8540_reg_defaults[] = { 81 + {NAU8540_REG_POWER_MANAGEMENT, 0x0000}, 82 + {NAU8540_REG_CLOCK_CTRL, 0x0000}, 83 + {NAU8540_REG_CLOCK_SRC, 0x0000}, 84 + {NAU8540_REG_FLL1, 0x0001}, 85 + {NAU8540_REG_FLL2, 0x3126}, 86 + {NAU8540_REG_FLL3, 0x0008}, 87 + {NAU8540_REG_FLL4, 0x0010}, 88 + {NAU8540_REG_FLL5, 0xC000}, 89 + {NAU8540_REG_FLL6, 0x6000}, 90 + {NAU8540_REG_FLL_VCO_RSV, 0xF13C}, 91 + {NAU8540_REG_PCM_CTRL0, 0x000B}, 92 + {NAU8540_REG_PCM_CTRL1, 0x3010}, 93 + {NAU8540_REG_PCM_CTRL2, 0x0800}, 94 + {NAU8540_REG_PCM_CTRL3, 0x0000}, 95 + {NAU8540_REG_PCM_CTRL4, 0x000F}, 96 + {NAU8540_REG_ALC_CONTROL_1, 0x0000}, 97 + {NAU8540_REG_ALC_CONTROL_2, 0x700B}, 98 + {NAU8540_REG_ALC_CONTROL_3, 0x0022}, 99 + {NAU8540_REG_ALC_CONTROL_4, 0x1010}, 100 + {NAU8540_REG_ALC_CONTROL_5, 0x1010}, 101 + {NAU8540_REG_NOTCH_FIL1_CH1, 0x0000}, 102 + {NAU8540_REG_NOTCH_FIL2_CH1, 0x0000}, 103 + {NAU8540_REG_NOTCH_FIL1_CH2, 0x0000}, 104 + {NAU8540_REG_NOTCH_FIL2_CH2, 0x0000}, 105 + {NAU8540_REG_NOTCH_FIL1_CH3, 0x0000}, 106 + {NAU8540_REG_NOTCH_FIL2_CH3, 0x0000}, 107 + {NAU8540_REG_NOTCH_FIL1_CH4, 0x0000}, 108 + {NAU8540_REG_NOTCH_FIL2_CH4, 0x0000}, 109 + {NAU8540_REG_HPF_FILTER_CH12, 0x0000}, 110 + {NAU8540_REG_HPF_FILTER_CH34, 0x0000}, 111 + {NAU8540_REG_ADC_SAMPLE_RATE, 0x0002}, 112 + {NAU8540_REG_DIGITAL_GAIN_CH1, 0x0400}, 113 + {NAU8540_REG_DIGITAL_GAIN_CH2, 0x0400}, 114 + {NAU8540_REG_DIGITAL_GAIN_CH3, 0x0400}, 115 + {NAU8540_REG_DIGITAL_GAIN_CH4, 0x0400}, 116 + {NAU8540_REG_DIGITAL_MUX, 0x00E4}, 117 + {NAU8540_REG_GPIO_CTRL, 0x0000}, 118 + {NAU8540_REG_MISC_CTRL, 0x0000}, 119 + {NAU8540_REG_I2C_CTRL, 0xEFFF}, 120 + {NAU8540_REG_VMID_CTRL, 0x0000}, 121 + {NAU8540_REG_MUTE, 0x0000}, 122 + {NAU8540_REG_ANALOG_ADC1, 0x0011}, 123 + {NAU8540_REG_ANALOG_ADC2, 0x0020}, 124 + {NAU8540_REG_ANALOG_PWR, 0x0000}, 125 + {NAU8540_REG_MIC_BIAS, 0x0004}, 126 + {NAU8540_REG_REFERENCE, 0x0000}, 127 + {NAU8540_REG_FEPGA1, 0x0000}, 128 + {NAU8540_REG_FEPGA2, 0x0000}, 129 + {NAU8540_REG_FEPGA3, 0x0101}, 130 + {NAU8540_REG_FEPGA4, 0x0101}, 131 + {NAU8540_REG_PWR, 0x0000}, 132 + }; 133 + 134 + static bool nau8540_readable_reg(struct device *dev, unsigned int reg) 135 + { 136 + switch (reg) { 137 + case NAU8540_REG_POWER_MANAGEMENT ... NAU8540_REG_FLL_VCO_RSV: 138 + case NAU8540_REG_PCM_CTRL0 ... NAU8540_REG_PCM_CTRL4: 139 + case NAU8540_REG_ALC_CONTROL_1 ... NAU8540_REG_ALC_CONTROL_5: 140 + case NAU8540_REG_ALC_GAIN_CH12 ... NAU8540_REG_ADC_SAMPLE_RATE: 141 + case NAU8540_REG_DIGITAL_GAIN_CH1 ... NAU8540_REG_DIGITAL_MUX: 142 + case NAU8540_REG_P2P_CH1 ... NAU8540_REG_I2C_CTRL: 143 + case NAU8540_REG_I2C_DEVICE_ID: 144 + case NAU8540_REG_VMID_CTRL ... NAU8540_REG_MUTE: 145 + case NAU8540_REG_ANALOG_ADC1 ... NAU8540_REG_PWR: 146 + return true; 147 + default: 148 + return false; 149 + } 150 + 151 + } 152 + 153 + static bool nau8540_writeable_reg(struct device *dev, unsigned int reg) 154 + { 155 + switch (reg) { 156 + case NAU8540_REG_SW_RESET ... NAU8540_REG_FLL_VCO_RSV: 157 + case NAU8540_REG_PCM_CTRL0 ... NAU8540_REG_PCM_CTRL4: 158 + case NAU8540_REG_ALC_CONTROL_1 ... NAU8540_REG_ALC_CONTROL_5: 159 + case NAU8540_REG_NOTCH_FIL1_CH1 ... NAU8540_REG_ADC_SAMPLE_RATE: 160 + case NAU8540_REG_DIGITAL_GAIN_CH1 ... NAU8540_REG_DIGITAL_MUX: 161 + case NAU8540_REG_GPIO_CTRL ... NAU8540_REG_I2C_CTRL: 162 + case NAU8540_REG_RST: 163 + case NAU8540_REG_VMID_CTRL ... NAU8540_REG_MUTE: 164 + case NAU8540_REG_ANALOG_ADC1 ... NAU8540_REG_PWR: 165 + return true; 166 + default: 167 + return false; 168 + } 169 + } 170 + 171 + static bool nau8540_volatile_reg(struct device *dev, unsigned int reg) 172 + { 173 + switch (reg) { 174 + case NAU8540_REG_SW_RESET: 175 + case NAU8540_REG_ALC_GAIN_CH12 ... NAU8540_REG_ALC_STATUS: 176 + case NAU8540_REG_P2P_CH1 ... NAU8540_REG_PEAK_CH4: 177 + case NAU8540_REG_I2C_DEVICE_ID: 178 + case NAU8540_REG_RST: 179 + return true; 180 + default: 181 + return false; 182 + } 183 + } 184 + 185 + 186 + static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -12800, 3600); 187 + static const DECLARE_TLV_DB_MINMAX(fepga_gain_tlv, -100, 3600); 188 + 189 + static const struct snd_kcontrol_new nau8540_snd_controls[] = { 190 + SOC_SINGLE_TLV("Mic1 Volume", NAU8540_REG_DIGITAL_GAIN_CH1, 191 + 0, 0x520, 0, adc_vol_tlv), 192 + SOC_SINGLE_TLV("Mic2 Volume", NAU8540_REG_DIGITAL_GAIN_CH2, 193 + 0, 0x520, 0, adc_vol_tlv), 194 + SOC_SINGLE_TLV("Mic3 Volume", NAU8540_REG_DIGITAL_GAIN_CH3, 195 + 0, 0x520, 0, adc_vol_tlv), 196 + SOC_SINGLE_TLV("Mic4 Volume", NAU8540_REG_DIGITAL_GAIN_CH4, 197 + 0, 0x520, 0, adc_vol_tlv), 198 + 199 + SOC_SINGLE_TLV("Frontend PGA1 Volume", NAU8540_REG_FEPGA3, 200 + 0, 0x25, 0, fepga_gain_tlv), 201 + SOC_SINGLE_TLV("Frontend PGA2 Volume", NAU8540_REG_FEPGA3, 202 + 8, 0x25, 0, fepga_gain_tlv), 203 + SOC_SINGLE_TLV("Frontend PGA3 Volume", NAU8540_REG_FEPGA4, 204 + 0, 0x25, 0, fepga_gain_tlv), 205 + SOC_SINGLE_TLV("Frontend PGA4 Volume", NAU8540_REG_FEPGA4, 206 + 8, 0x25, 0, fepga_gain_tlv), 207 + }; 208 + 209 + static const char * const adc_channel[] = { 210 + "ADC channel 1", "ADC channel 2", "ADC channel 3", "ADC channel 4" 211 + }; 212 + static SOC_ENUM_SINGLE_DECL( 213 + digital_ch4_enum, NAU8540_REG_DIGITAL_MUX, 6, adc_channel); 214 + 215 + static const struct snd_kcontrol_new digital_ch4_mux = 216 + SOC_DAPM_ENUM("Digital CH4 Select", digital_ch4_enum); 217 + 218 + static SOC_ENUM_SINGLE_DECL( 219 + digital_ch3_enum, NAU8540_REG_DIGITAL_MUX, 4, adc_channel); 220 + 221 + static const struct snd_kcontrol_new digital_ch3_mux = 222 + SOC_DAPM_ENUM("Digital CH3 Select", digital_ch3_enum); 223 + 224 + static SOC_ENUM_SINGLE_DECL( 225 + digital_ch2_enum, NAU8540_REG_DIGITAL_MUX, 2, adc_channel); 226 + 227 + static const struct snd_kcontrol_new digital_ch2_mux = 228 + SOC_DAPM_ENUM("Digital CH2 Select", digital_ch2_enum); 229 + 230 + static SOC_ENUM_SINGLE_DECL( 231 + digital_ch1_enum, NAU8540_REG_DIGITAL_MUX, 0, adc_channel); 232 + 233 + static const struct snd_kcontrol_new digital_ch1_mux = 234 + SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum); 235 + 236 + static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = { 237 + SND_SOC_DAPM_SUPPLY("MICBIAS2", NAU8540_REG_MIC_BIAS, 11, 0, NULL, 0), 238 + SND_SOC_DAPM_SUPPLY("MICBIAS1", NAU8540_REG_MIC_BIAS, 10, 0, NULL, 0), 239 + 240 + SND_SOC_DAPM_INPUT("MIC1"), 241 + SND_SOC_DAPM_INPUT("MIC2"), 242 + SND_SOC_DAPM_INPUT("MIC3"), 243 + SND_SOC_DAPM_INPUT("MIC4"), 244 + 245 + SND_SOC_DAPM_PGA("Frontend PGA1", NAU8540_REG_PWR, 12, 0, NULL, 0), 246 + SND_SOC_DAPM_PGA("Frontend PGA2", NAU8540_REG_PWR, 13, 0, NULL, 0), 247 + SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0), 248 + SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0), 249 + 250 + SND_SOC_DAPM_ADC("ADC1", NULL, 251 + NAU8540_REG_POWER_MANAGEMENT, 0, 0), 252 + SND_SOC_DAPM_ADC("ADC2", NULL, 253 + NAU8540_REG_POWER_MANAGEMENT, 1, 0), 254 + SND_SOC_DAPM_ADC("ADC3", NULL, 255 + NAU8540_REG_POWER_MANAGEMENT, 2, 0), 256 + SND_SOC_DAPM_ADC("ADC4", NULL, 257 + NAU8540_REG_POWER_MANAGEMENT, 3, 0), 258 + 259 + SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0), 260 + SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0), 261 + SND_SOC_DAPM_PGA("ADC CH3", NAU8540_REG_ANALOG_PWR, 2, 0, NULL, 0), 262 + SND_SOC_DAPM_PGA("ADC CH4", NAU8540_REG_ANALOG_PWR, 3, 0, NULL, 0), 263 + 264 + SND_SOC_DAPM_MUX("Digital CH4 Mux", 265 + SND_SOC_NOPM, 0, 0, &digital_ch4_mux), 266 + SND_SOC_DAPM_MUX("Digital CH3 Mux", 267 + SND_SOC_NOPM, 0, 0, &digital_ch3_mux), 268 + SND_SOC_DAPM_MUX("Digital CH2 Mux", 269 + SND_SOC_NOPM, 0, 0, &digital_ch2_mux), 270 + SND_SOC_DAPM_MUX("Digital CH1 Mux", 271 + SND_SOC_NOPM, 0, 0, &digital_ch1_mux), 272 + 273 + SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0), 274 + }; 275 + 276 + static const struct snd_soc_dapm_route nau8540_dapm_routes[] = { 277 + {"Frontend PGA1", NULL, "MIC1"}, 278 + {"Frontend PGA2", NULL, "MIC2"}, 279 + {"Frontend PGA3", NULL, "MIC3"}, 280 + {"Frontend PGA4", NULL, "MIC4"}, 281 + 282 + {"ADC1", NULL, "Frontend PGA1"}, 283 + {"ADC2", NULL, "Frontend PGA2"}, 284 + {"ADC3", NULL, "Frontend PGA3"}, 285 + {"ADC4", NULL, "Frontend PGA4"}, 286 + 287 + {"ADC CH1", NULL, "ADC1"}, 288 + {"ADC CH2", NULL, "ADC2"}, 289 + {"ADC CH3", NULL, "ADC3"}, 290 + {"ADC CH4", NULL, "ADC4"}, 291 + 292 + {"ADC1", NULL, "MICBIAS1"}, 293 + {"ADC2", NULL, "MICBIAS1"}, 294 + {"ADC3", NULL, "MICBIAS2"}, 295 + {"ADC4", NULL, "MICBIAS2"}, 296 + 297 + {"Digital CH1 Mux", "ADC channel 1", "ADC CH1"}, 298 + {"Digital CH1 Mux", "ADC channel 2", "ADC CH2"}, 299 + {"Digital CH1 Mux", "ADC channel 3", "ADC CH3"}, 300 + {"Digital CH1 Mux", "ADC channel 4", "ADC CH4"}, 301 + 302 + {"Digital CH2 Mux", "ADC channel 1", "ADC CH1"}, 303 + {"Digital CH2 Mux", "ADC channel 2", "ADC CH2"}, 304 + {"Digital CH2 Mux", "ADC channel 3", "ADC CH3"}, 305 + {"Digital CH2 Mux", "ADC channel 4", "ADC CH4"}, 306 + 307 + {"Digital CH3 Mux", "ADC channel 1", "ADC CH1"}, 308 + {"Digital CH3 Mux", "ADC channel 2", "ADC CH2"}, 309 + {"Digital CH3 Mux", "ADC channel 3", "ADC CH3"}, 310 + {"Digital CH3 Mux", "ADC channel 4", "ADC CH4"}, 311 + 312 + {"Digital CH4 Mux", "ADC channel 1", "ADC CH1"}, 313 + {"Digital CH4 Mux", "ADC channel 2", "ADC CH2"}, 314 + {"Digital CH4 Mux", "ADC channel 3", "ADC CH3"}, 315 + {"Digital CH4 Mux", "ADC channel 4", "ADC CH4"}, 316 + 317 + {"AIFTX", NULL, "Digital CH1 Mux"}, 318 + {"AIFTX", NULL, "Digital CH2 Mux"}, 319 + {"AIFTX", NULL, "Digital CH3 Mux"}, 320 + {"AIFTX", NULL, "Digital CH4 Mux"}, 321 + }; 322 + 323 + static int nau8540_clock_check(struct nau8540 *nau8540, int rate, int osr) 324 + { 325 + int osrate; 326 + 327 + if (osr >= ARRAY_SIZE(osr_adc_sel)) 328 + return -EINVAL; 329 + osrate = osr_adc_sel[osr].osr; 330 + 331 + if (rate * osr > CLK_ADC_MAX) { 332 + dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n"); 333 + return -EINVAL; 334 + } 335 + 336 + return 0; 337 + } 338 + 339 + static int nau8540_hw_params(struct snd_pcm_substream *substream, 340 + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 341 + { 342 + struct snd_soc_codec *codec = dai->codec; 343 + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); 344 + unsigned int val_len = 0, osr; 345 + 346 + /* CLK_ADC = OSR * FS 347 + * ADC clock frequency is defined as Over Sampling Rate (OSR) 348 + * multiplied by the audio sample rate (Fs). Note that the OSR and Fs 349 + * values must be selected such that the maximum frequency is less 350 + * than 6.144 MHz. 351 + */ 352 + regmap_read(nau8540->regmap, NAU8540_REG_ADC_SAMPLE_RATE, &osr); 353 + osr &= NAU8540_ADC_OSR_MASK; 354 + if (nau8540_clock_check(nau8540, params_rate(params), osr)) 355 + return -EINVAL; 356 + regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC, 357 + NAU8540_CLK_ADC_SRC_MASK, 358 + osr_adc_sel[osr].clk_src << NAU8540_CLK_ADC_SRC_SFT); 359 + 360 + switch (params_width(params)) { 361 + case 16: 362 + val_len |= NAU8540_I2S_DL_16; 363 + break; 364 + case 20: 365 + val_len |= NAU8540_I2S_DL_20; 366 + break; 367 + case 24: 368 + val_len |= NAU8540_I2S_DL_24; 369 + break; 370 + case 32: 371 + val_len |= NAU8540_I2S_DL_32; 372 + break; 373 + default: 374 + return -EINVAL; 375 + } 376 + 377 + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL0, 378 + NAU8540_I2S_DL_MASK, val_len); 379 + 380 + return 0; 381 + } 382 + 383 + static int nau8540_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 384 + { 385 + struct snd_soc_codec *codec = dai->codec; 386 + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); 387 + unsigned int ctrl1_val = 0, ctrl2_val = 0; 388 + 389 + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 390 + case SND_SOC_DAIFMT_CBM_CFM: 391 + ctrl2_val |= NAU8540_I2S_MS_MASTER; 392 + break; 393 + case SND_SOC_DAIFMT_CBS_CFS: 394 + break; 395 + default: 396 + return -EINVAL; 397 + } 398 + 399 + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 400 + case SND_SOC_DAIFMT_NB_NF: 401 + break; 402 + case SND_SOC_DAIFMT_IB_NF: 403 + ctrl1_val |= NAU8540_I2S_BP_INV; 404 + break; 405 + default: 406 + return -EINVAL; 407 + } 408 + 409 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 410 + case SND_SOC_DAIFMT_I2S: 411 + ctrl1_val |= NAU8540_I2S_DF_I2S; 412 + break; 413 + case SND_SOC_DAIFMT_LEFT_J: 414 + ctrl1_val |= NAU8540_I2S_DF_LEFT; 415 + break; 416 + case SND_SOC_DAIFMT_RIGHT_J: 417 + ctrl1_val |= NAU8540_I2S_DF_RIGTH; 418 + break; 419 + case SND_SOC_DAIFMT_DSP_A: 420 + ctrl1_val |= NAU8540_I2S_DF_PCM_AB; 421 + break; 422 + case SND_SOC_DAIFMT_DSP_B: 423 + ctrl1_val |= NAU8540_I2S_DF_PCM_AB; 424 + ctrl1_val |= NAU8540_I2S_PCMB_EN; 425 + break; 426 + default: 427 + return -EINVAL; 428 + } 429 + 430 + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL0, 431 + NAU8540_I2S_DL_MASK | NAU8540_I2S_DF_MASK | 432 + NAU8540_I2S_BP_INV | NAU8540_I2S_PCMB_EN, ctrl1_val); 433 + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1, 434 + NAU8540_I2S_MS_MASK | NAU8540_I2S_DO12_OE, ctrl2_val); 435 + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2, 436 + NAU8540_I2S_DO34_OE, 0); 437 + 438 + return 0; 439 + } 440 + 441 + /** 442 + * nau8540_set_tdm_slot - configure DAI TX TDM. 443 + * @dai: DAI 444 + * @tx_mask: bitmask representing active TX slots. Ex. 445 + * 0xf for normal 4 channel TDM. 446 + * 0xf0 for shifted 4 channel TDM 447 + * @rx_mask: no used. 448 + * @slots: Number of slots in use. 449 + * @slot_width: Width in bits for each slot. 450 + * 451 + * Configures a DAI for TDM operation. Only support 4 slots TDM. 452 + */ 453 + static int nau8540_set_tdm_slot(struct snd_soc_dai *dai, 454 + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) 455 + { 456 + struct snd_soc_codec *codec = dai->codec; 457 + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); 458 + unsigned int ctrl2_val = 0, ctrl4_val = 0; 459 + 460 + if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf))) 461 + return -EINVAL; 462 + 463 + ctrl4_val |= (NAU8540_TDM_MODE | NAU8540_TDM_OFFSET_EN); 464 + if (tx_mask & 0xf0) { 465 + ctrl2_val = 4 * slot_width; 466 + ctrl4_val |= (tx_mask >> 4); 467 + } else { 468 + ctrl4_val |= tx_mask; 469 + } 470 + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL4, 471 + NAU8540_TDM_MODE | NAU8540_TDM_OFFSET_EN | 472 + NAU8540_TDM_TX_MASK, ctrl4_val); 473 + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1, 474 + NAU8540_I2S_DO12_OE, NAU8540_I2S_DO12_OE); 475 + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2, 476 + NAU8540_I2S_DO34_OE | NAU8540_I2S_TSLOT_L_MASK, 477 + NAU8540_I2S_DO34_OE | ctrl2_val); 478 + 479 + return 0; 480 + } 481 + 482 + 483 + static const struct snd_soc_dai_ops nau8540_dai_ops = { 484 + .hw_params = nau8540_hw_params, 485 + .set_fmt = nau8540_set_fmt, 486 + .set_tdm_slot = nau8540_set_tdm_slot, 487 + }; 488 + 489 + #define NAU8540_RATES SNDRV_PCM_RATE_8000_48000 490 + #define NAU8540_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ 491 + | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) 492 + 493 + static struct snd_soc_dai_driver nau8540_dai = { 494 + .name = "nau8540-hifi", 495 + .capture = { 496 + .stream_name = "Capture", 497 + .channels_min = 1, 498 + .channels_max = 4, 499 + .rates = NAU8540_RATES, 500 + .formats = NAU8540_FORMATS, 501 + }, 502 + .ops = &nau8540_dai_ops, 503 + }; 504 + 505 + /** 506 + * nau8540_calc_fll_param - Calculate FLL parameters. 507 + * @fll_in: external clock provided to codec. 508 + * @fs: sampling rate. 509 + * @fll_param: Pointer to structure of FLL parameters. 510 + * 511 + * Calculate FLL parameters to configure codec. 512 + * 513 + * Returns 0 for success or negative error code. 514 + */ 515 + static int nau8540_calc_fll_param(unsigned int fll_in, 516 + unsigned int fs, struct nau8540_fll *fll_param) 517 + { 518 + u64 fvco, fvco_max; 519 + unsigned int fref, i, fvco_sel; 520 + 521 + /* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing 522 + * freq_in by 1, 2, 4, or 8 using FLL pre-scalar. 523 + * FREF = freq_in / NAU8540_FLL_REF_DIV_MASK 524 + */ 525 + for (i = 0; i < ARRAY_SIZE(fll_pre_scalar); i++) { 526 + fref = fll_in / fll_pre_scalar[i].param; 527 + if (fref <= NAU_FREF_MAX) 528 + break; 529 + } 530 + if (i == ARRAY_SIZE(fll_pre_scalar)) 531 + return -EINVAL; 532 + fll_param->clk_ref_div = fll_pre_scalar[i].val; 533 + 534 + /* Choose the FLL ratio based on FREF */ 535 + for (i = 0; i < ARRAY_SIZE(fll_ratio); i++) { 536 + if (fref >= fll_ratio[i].param) 537 + break; 538 + } 539 + if (i == ARRAY_SIZE(fll_ratio)) 540 + return -EINVAL; 541 + fll_param->ratio = fll_ratio[i].val; 542 + 543 + /* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs. 544 + * FDCO must be within the 90MHz - 124MHz or the FFL cannot be 545 + * guaranteed across the full range of operation. 546 + * FDCO = freq_out * 2 * mclk_src_scaling 547 + */ 548 + fvco_max = 0; 549 + fvco_sel = ARRAY_SIZE(mclk_src_scaling); 550 + for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) { 551 + fvco = 256 * fs * 2 * mclk_src_scaling[i].param; 552 + if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX && 553 + fvco_max < fvco) { 554 + fvco_max = fvco; 555 + fvco_sel = i; 556 + } 557 + } 558 + if (ARRAY_SIZE(mclk_src_scaling) == fvco_sel) 559 + return -EINVAL; 560 + fll_param->mclk_src = mclk_src_scaling[fvco_sel].val; 561 + 562 + /* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional 563 + * input based on FDCO, FREF and FLL ratio. 564 + */ 565 + fvco = div_u64(fvco_max << 16, fref * fll_param->ratio); 566 + fll_param->fll_int = (fvco >> 16) & 0x3FF; 567 + fll_param->fll_frac = fvco & 0xFFFF; 568 + return 0; 569 + } 570 + 571 + static void nau8540_fll_apply(struct regmap *regmap, 572 + struct nau8540_fll *fll_param) 573 + { 574 + regmap_update_bits(regmap, NAU8540_REG_CLOCK_SRC, 575 + NAU8540_CLK_SRC_MASK | NAU8540_CLK_MCLK_SRC_MASK, 576 + NAU8540_CLK_SRC_MCLK | fll_param->mclk_src); 577 + regmap_update_bits(regmap, NAU8540_REG_FLL1, 578 + NAU8540_FLL_RATIO_MASK, fll_param->ratio); 579 + /* FLL 16-bit fractional input */ 580 + regmap_write(regmap, NAU8540_REG_FLL2, fll_param->fll_frac); 581 + /* FLL 10-bit integer input */ 582 + regmap_update_bits(regmap, NAU8540_REG_FLL3, 583 + NAU8540_FLL_INTEGER_MASK, fll_param->fll_int); 584 + /* FLL pre-scaler */ 585 + regmap_update_bits(regmap, NAU8540_REG_FLL4, 586 + NAU8540_FLL_REF_DIV_MASK, 587 + fll_param->clk_ref_div << NAU8540_FLL_REF_DIV_SFT); 588 + regmap_update_bits(regmap, NAU8540_REG_FLL5, 589 + NAU8540_FLL_CLK_SW_MASK, NAU8540_FLL_CLK_SW_REF); 590 + regmap_update_bits(regmap, 591 + NAU8540_REG_FLL6, NAU8540_DCO_EN, 0); 592 + if (fll_param->fll_frac) { 593 + regmap_update_bits(regmap, NAU8540_REG_FLL5, 594 + NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN | 595 + NAU8540_FLL_FTR_SW_MASK, 596 + NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN | 597 + NAU8540_FLL_FTR_SW_FILTER); 598 + regmap_update_bits(regmap, NAU8540_REG_FLL6, 599 + NAU8540_SDM_EN, NAU8540_SDM_EN); 600 + } else { 601 + regmap_update_bits(regmap, NAU8540_REG_FLL5, 602 + NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN | 603 + NAU8540_FLL_FTR_SW_MASK, NAU8540_FLL_FTR_SW_ACCU); 604 + regmap_update_bits(regmap, 605 + NAU8540_REG_FLL6, NAU8540_SDM_EN, 0); 606 + } 607 + } 608 + 609 + /* freq_out must be 256*Fs in order to achieve the best performance */ 610 + static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source, 611 + unsigned int freq_in, unsigned int freq_out) 612 + { 613 + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); 614 + struct nau8540_fll fll_param; 615 + int ret, fs; 616 + 617 + switch (pll_id) { 618 + case NAU8540_CLK_FLL_MCLK: 619 + regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3, 620 + NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_MCLK); 621 + break; 622 + 623 + case NAU8540_CLK_FLL_BLK: 624 + regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3, 625 + NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_BLK); 626 + break; 627 + 628 + case NAU8540_CLK_FLL_FS: 629 + regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3, 630 + NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_FS); 631 + break; 632 + 633 + default: 634 + dev_err(nau8540->dev, "Invalid clock id (%d)\n", pll_id); 635 + return -EINVAL; 636 + } 637 + dev_dbg(nau8540->dev, "Sysclk is %dHz and clock id is %d\n", 638 + freq_out, pll_id); 639 + 640 + fs = freq_out / 256; 641 + ret = nau8540_calc_fll_param(freq_in, fs, &fll_param); 642 + if (ret < 0) { 643 + dev_err(nau8540->dev, "Unsupported input clock %d\n", freq_in); 644 + return ret; 645 + } 646 + dev_dbg(nau8540->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n", 647 + fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac, 648 + fll_param.fll_int, fll_param.clk_ref_div); 649 + 650 + nau8540_fll_apply(nau8540->regmap, &fll_param); 651 + mdelay(2); 652 + regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC, 653 + NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_VCO); 654 + 655 + return 0; 656 + } 657 + 658 + static int nau8540_set_sysclk(struct snd_soc_codec *codec, 659 + int clk_id, int source, unsigned int freq, int dir) 660 + { 661 + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); 662 + 663 + switch (clk_id) { 664 + case NAU8540_CLK_DIS: 665 + case NAU8540_CLK_MCLK: 666 + regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC, 667 + NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_MCLK); 668 + regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL6, 669 + NAU8540_DCO_EN, 0); 670 + break; 671 + 672 + case NAU8540_CLK_INTERNAL: 673 + regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL6, 674 + NAU8540_DCO_EN, NAU8540_DCO_EN); 675 + regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC, 676 + NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_VCO); 677 + break; 678 + 679 + default: 680 + dev_err(nau8540->dev, "Invalid clock id (%d)\n", clk_id); 681 + return -EINVAL; 682 + } 683 + 684 + dev_dbg(nau8540->dev, "Sysclk is %dHz and clock id is %d\n", 685 + freq, clk_id); 686 + 687 + return 0; 688 + } 689 + 690 + static void nau8540_reset_chip(struct regmap *regmap) 691 + { 692 + regmap_write(regmap, NAU8540_REG_SW_RESET, 0x00); 693 + regmap_write(regmap, NAU8540_REG_SW_RESET, 0x00); 694 + } 695 + 696 + static void nau8540_init_regs(struct nau8540 *nau8540) 697 + { 698 + struct regmap *regmap = nau8540->regmap; 699 + 700 + /* Enable Bias/VMID/VMID Tieoff */ 701 + regmap_update_bits(regmap, NAU8540_REG_VMID_CTRL, 702 + NAU8540_VMID_EN | NAU8540_VMID_SEL_MASK, 703 + NAU8540_VMID_EN | (0x2 << NAU8540_VMID_SEL_SFT)); 704 + regmap_update_bits(regmap, NAU8540_REG_REFERENCE, 705 + NAU8540_PRECHARGE_DIS | NAU8540_GLOBAL_BIAS_EN, 706 + NAU8540_PRECHARGE_DIS | NAU8540_GLOBAL_BIAS_EN); 707 + mdelay(2); 708 + regmap_update_bits(regmap, NAU8540_REG_MIC_BIAS, 709 + NAU8540_PU_PRE, NAU8540_PU_PRE); 710 + regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL, 711 + NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN, 712 + NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN); 713 + /* ADC OSR selection, CLK_ADC = Fs * OSR */ 714 + regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE, 715 + NAU8540_ADC_OSR_MASK, NAU8540_ADC_OSR_64); 716 + } 717 + 718 + static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec) 719 + { 720 + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); 721 + 722 + regcache_cache_only(nau8540->regmap, true); 723 + regcache_mark_dirty(nau8540->regmap); 724 + 725 + return 0; 726 + } 727 + 728 + static int __maybe_unused nau8540_resume(struct snd_soc_codec *codec) 729 + { 730 + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); 731 + 732 + regcache_cache_only(nau8540->regmap, false); 733 + regcache_sync(nau8540->regmap); 734 + 735 + return 0; 736 + } 737 + 738 + static struct snd_soc_codec_driver nau8540_codec_driver = { 739 + .set_sysclk = nau8540_set_sysclk, 740 + .set_pll = nau8540_set_pll, 741 + .suspend = nau8540_suspend, 742 + .resume = nau8540_resume, 743 + .suspend_bias_off = true, 744 + 745 + .component_driver = { 746 + .controls = nau8540_snd_controls, 747 + .num_controls = ARRAY_SIZE(nau8540_snd_controls), 748 + .dapm_widgets = nau8540_dapm_widgets, 749 + .num_dapm_widgets = ARRAY_SIZE(nau8540_dapm_widgets), 750 + .dapm_routes = nau8540_dapm_routes, 751 + .num_dapm_routes = ARRAY_SIZE(nau8540_dapm_routes), 752 + }, 753 + }; 754 + 755 + static const struct regmap_config nau8540_regmap_config = { 756 + .val_bits = 16, 757 + .reg_bits = 16, 758 + 759 + .max_register = NAU8540_REG_MAX, 760 + .readable_reg = nau8540_readable_reg, 761 + .writeable_reg = nau8540_writeable_reg, 762 + .volatile_reg = nau8540_volatile_reg, 763 + 764 + .cache_type = REGCACHE_RBTREE, 765 + .reg_defaults = nau8540_reg_defaults, 766 + .num_reg_defaults = ARRAY_SIZE(nau8540_reg_defaults), 767 + }; 768 + 769 + static int nau8540_i2c_probe(struct i2c_client *i2c, 770 + const struct i2c_device_id *id) 771 + { 772 + struct device *dev = &i2c->dev; 773 + struct nau8540 *nau8540 = dev_get_platdata(dev); 774 + int ret, value; 775 + 776 + if (!nau8540) { 777 + nau8540 = devm_kzalloc(dev, sizeof(*nau8540), GFP_KERNEL); 778 + if (!nau8540) 779 + return -ENOMEM; 780 + } 781 + i2c_set_clientdata(i2c, nau8540); 782 + 783 + nau8540->regmap = devm_regmap_init_i2c(i2c, &nau8540_regmap_config); 784 + if (IS_ERR(nau8540->regmap)) 785 + return PTR_ERR(nau8540->regmap); 786 + ret = regmap_read(nau8540->regmap, NAU8540_REG_I2C_DEVICE_ID, &value); 787 + if (ret < 0) { 788 + dev_err(dev, "Failed to read device id from the NAU85L40: %d\n", 789 + ret); 790 + return ret; 791 + } 792 + 793 + nau8540->dev = dev; 794 + nau8540_reset_chip(nau8540->regmap); 795 + nau8540_init_regs(nau8540); 796 + 797 + return snd_soc_register_codec(dev, 798 + &nau8540_codec_driver, &nau8540_dai, 1); 799 + } 800 + 801 + static int nau8540_i2c_remove(struct i2c_client *client) 802 + { 803 + snd_soc_unregister_codec(&client->dev); 804 + return 0; 805 + } 806 + 807 + 808 + static const struct i2c_device_id nau8540_i2c_ids[] = { 809 + { "nau8540", 0 }, 810 + { } 811 + }; 812 + MODULE_DEVICE_TABLE(i2c, nau8540_i2c_ids); 813 + 814 + #ifdef CONFIG_OF 815 + static const struct of_device_id nau8540_of_ids[] = { 816 + { .compatible = "nuvoton,nau8540", }, 817 + {} 818 + }; 819 + MODULE_DEVICE_TABLE(of, nau8540_of_ids); 820 + #endif 821 + 822 + static struct i2c_driver nau8540_i2c_driver = { 823 + .driver = { 824 + .name = "nau8540", 825 + .of_match_table = of_match_ptr(nau8540_of_ids), 826 + }, 827 + .probe = nau8540_i2c_probe, 828 + .remove = nau8540_i2c_remove, 829 + .id_table = nau8540_i2c_ids, 830 + }; 831 + module_i2c_driver(nau8540_i2c_driver); 832 + 833 + MODULE_DESCRIPTION("ASoC NAU85L40 driver"); 834 + MODULE_AUTHOR("John Hsu <KCHSU0@nuvoton.com>"); 835 + MODULE_LICENSE("GPL v2");
+222
sound/soc/codecs/nau8540.h
··· 1 + /* 2 + * NAU85L40 ALSA SoC audio driver 3 + * 4 + * Copyright 2016 Nuvoton Technology Corp. 5 + * Author: John Hsu <KCHSU0@nuvoton.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + 12 + #ifndef __NAU8540_H__ 13 + #define __NAU8540_H__ 14 + 15 + #define NAU8540_REG_SW_RESET 0x00 16 + #define NAU8540_REG_POWER_MANAGEMENT 0x01 17 + #define NAU8540_REG_CLOCK_CTRL 0x02 18 + #define NAU8540_REG_CLOCK_SRC 0x03 19 + #define NAU8540_REG_FLL1 0x04 20 + #define NAU8540_REG_FLL2 0x05 21 + #define NAU8540_REG_FLL3 0x06 22 + #define NAU8540_REG_FLL4 0x07 23 + #define NAU8540_REG_FLL5 0x08 24 + #define NAU8540_REG_FLL6 0x09 25 + #define NAU8540_REG_FLL_VCO_RSV 0x0A 26 + #define NAU8540_REG_PCM_CTRL0 0x10 27 + #define NAU8540_REG_PCM_CTRL1 0x11 28 + #define NAU8540_REG_PCM_CTRL2 0x12 29 + #define NAU8540_REG_PCM_CTRL3 0x13 30 + #define NAU8540_REG_PCM_CTRL4 0x14 31 + #define NAU8540_REG_ALC_CONTROL_1 0x20 32 + #define NAU8540_REG_ALC_CONTROL_2 0x21 33 + #define NAU8540_REG_ALC_CONTROL_3 0x22 34 + #define NAU8540_REG_ALC_CONTROL_4 0x23 35 + #define NAU8540_REG_ALC_CONTROL_5 0x24 36 + #define NAU8540_REG_ALC_GAIN_CH12 0x2D 37 + #define NAU8540_REG_ALC_GAIN_CH34 0x2E 38 + #define NAU8540_REG_ALC_STATUS 0x2F 39 + #define NAU8540_REG_NOTCH_FIL1_CH1 0x30 40 + #define NAU8540_REG_NOTCH_FIL2_CH1 0x31 41 + #define NAU8540_REG_NOTCH_FIL1_CH2 0x32 42 + #define NAU8540_REG_NOTCH_FIL2_CH2 0x33 43 + #define NAU8540_REG_NOTCH_FIL1_CH3 0x34 44 + #define NAU8540_REG_NOTCH_FIL2_CH3 0x35 45 + #define NAU8540_REG_NOTCH_FIL1_CH4 0x36 46 + #define NAU8540_REG_NOTCH_FIL2_CH4 0x37 47 + #define NAU8540_REG_HPF_FILTER_CH12 0x38 48 + #define NAU8540_REG_HPF_FILTER_CH34 0x39 49 + #define NAU8540_REG_ADC_SAMPLE_RATE 0x3A 50 + #define NAU8540_REG_DIGITAL_GAIN_CH1 0x40 51 + #define NAU8540_REG_DIGITAL_GAIN_CH2 0x41 52 + #define NAU8540_REG_DIGITAL_GAIN_CH3 0x42 53 + #define NAU8540_REG_DIGITAL_GAIN_CH4 0x43 54 + #define NAU8540_REG_DIGITAL_MUX 0x44 55 + #define NAU8540_REG_P2P_CH1 0x48 56 + #define NAU8540_REG_P2P_CH2 0x49 57 + #define NAU8540_REG_P2P_CH3 0x4A 58 + #define NAU8540_REG_P2P_CH4 0x4B 59 + #define NAU8540_REG_PEAK_CH1 0x4C 60 + #define NAU8540_REG_PEAK_CH2 0x4D 61 + #define NAU8540_REG_PEAK_CH3 0x4E 62 + #define NAU8540_REG_PEAK_CH4 0x4F 63 + #define NAU8540_REG_GPIO_CTRL 0x50 64 + #define NAU8540_REG_MISC_CTRL 0x51 65 + #define NAU8540_REG_I2C_CTRL 0x52 66 + #define NAU8540_REG_I2C_DEVICE_ID 0x58 67 + #define NAU8540_REG_RST 0x5A 68 + #define NAU8540_REG_VMID_CTRL 0x60 69 + #define NAU8540_REG_MUTE 0x61 70 + #define NAU8540_REG_ANALOG_ADC1 0x64 71 + #define NAU8540_REG_ANALOG_ADC2 0x65 72 + #define NAU8540_REG_ANALOG_PWR 0x66 73 + #define NAU8540_REG_MIC_BIAS 0x67 74 + #define NAU8540_REG_REFERENCE 0x68 75 + #define NAU8540_REG_FEPGA1 0x69 76 + #define NAU8540_REG_FEPGA2 0x6A 77 + #define NAU8540_REG_FEPGA3 0x6B 78 + #define NAU8540_REG_FEPGA4 0x6C 79 + #define NAU8540_REG_PWR 0x6D 80 + #define NAU8540_REG_MAX NAU8540_REG_PWR 81 + 82 + 83 + /* POWER_MANAGEMENT (0x01) */ 84 + #define NAU8540_ADC4_EN (0x1 << 3) 85 + #define NAU8540_ADC3_EN (0x1 << 2) 86 + #define NAU8540_ADC2_EN (0x1 << 1) 87 + #define NAU8540_ADC1_EN 0x1 88 + 89 + /* CLOCK_CTRL (0x02) */ 90 + #define NAU8540_CLK_ADC_EN (0x1 << 15) 91 + #define NAU8540_CLK_I2S_EN (0x1 << 1) 92 + 93 + /* CLOCK_SRC (0x03) */ 94 + #define NAU8540_CLK_SRC_SFT 15 95 + #define NAU8540_CLK_SRC_MASK (1 << NAU8540_CLK_SRC_SFT) 96 + #define NAU8540_CLK_SRC_VCO (1 << NAU8540_CLK_SRC_SFT) 97 + #define NAU8540_CLK_SRC_MCLK (0 << NAU8540_CLK_SRC_SFT) 98 + #define NAU8540_CLK_ADC_SRC_SFT 6 99 + #define NAU8540_CLK_ADC_SRC_MASK (0x3 << NAU8540_CLK_ADC_SRC_SFT) 100 + #define NAU8540_CLK_MCLK_SRC_MASK 0xf 101 + 102 + /* FLL1 (0x04) */ 103 + #define NAU8540_FLL_RATIO_MASK 0x7f 104 + 105 + /* FLL3 (0x06) */ 106 + #define NAU8540_FLL_CLK_SRC_SFT 10 107 + #define NAU8540_FLL_CLK_SRC_MASK (0x3 << NAU8540_FLL_CLK_SRC_SFT) 108 + #define NAU8540_FLL_CLK_SRC_MCLK (0 << NAU8540_FLL_CLK_SRC_SFT) 109 + #define NAU8540_FLL_CLK_SRC_BLK (0x2 << NAU8540_FLL_CLK_SRC_SFT) 110 + #define NAU8540_FLL_CLK_SRC_FS (0x3 << NAU8540_FLL_CLK_SRC_SFT) 111 + #define NAU8540_FLL_INTEGER_MASK 0x3ff 112 + 113 + /* FLL4 (0x07) */ 114 + #define NAU8540_FLL_REF_DIV_SFT 10 115 + #define NAU8540_FLL_REF_DIV_MASK (0x3 << NAU8540_FLL_REF_DIV_SFT) 116 + 117 + /* FLL5 (0x08) */ 118 + #define NAU8540_FLL_PDB_DAC_EN (0x1 << 15) 119 + #define NAU8540_FLL_LOOP_FTR_EN (0x1 << 14) 120 + #define NAU8540_FLL_CLK_SW_MASK (0x1 << 13) 121 + #define NAU8540_FLL_CLK_SW_N2 (0x1 << 13) 122 + #define NAU8540_FLL_CLK_SW_REF (0x0 << 13) 123 + #define NAU8540_FLL_FTR_SW_MASK (0x1 << 12) 124 + #define NAU8540_FLL_FTR_SW_ACCU (0x1 << 12) 125 + #define NAU8540_FLL_FTR_SW_FILTER (0x0 << 12) 126 + 127 + /* FLL6 (0x9) */ 128 + #define NAU8540_DCO_EN (0x1 << 15) 129 + #define NAU8540_SDM_EN (0x1 << 14) 130 + 131 + /* PCM_CTRL0 (0x10) */ 132 + #define NAU8540_I2S_BP_SFT 7 133 + #define NAU8540_I2S_BP_INV (0x1 << NAU8540_I2S_BP_SFT) 134 + #define NAU8540_I2S_PCMB_SFT 6 135 + #define NAU8540_I2S_PCMB_EN (0x1 << NAU8540_I2S_PCMB_SFT) 136 + #define NAU8540_I2S_DL_SFT 2 137 + #define NAU8540_I2S_DL_MASK (0x3 << NAU8540_I2S_DL_SFT) 138 + #define NAU8540_I2S_DL_16 (0 << NAU8540_I2S_DL_SFT) 139 + #define NAU8540_I2S_DL_20 (0x1 << NAU8540_I2S_DL_SFT) 140 + #define NAU8540_I2S_DL_24 (0x2 << NAU8540_I2S_DL_SFT) 141 + #define NAU8540_I2S_DL_32 (0x3 << NAU8540_I2S_DL_SFT) 142 + #define NAU8540_I2S_DF_MASK 0x3 143 + #define NAU8540_I2S_DF_RIGTH 0 144 + #define NAU8540_I2S_DF_LEFT 0x1 145 + #define NAU8540_I2S_DF_I2S 0x2 146 + #define NAU8540_I2S_DF_PCM_AB 0x3 147 + 148 + /* PCM_CTRL1 (0x11) */ 149 + #define NAU8540_I2S_LRC_DIV_SFT 12 150 + #define NAU8540_I2S_LRC_DIV_MASK (0x3 << NAU8540_I2S_LRC_DIV_SFT) 151 + #define NAU8540_I2S_DO12_OE (0x1 << 4) 152 + #define NAU8540_I2S_MS_SFT 3 153 + #define NAU8540_I2S_MS_MASK (0x1 << NAU8540_I2S_MS_SFT) 154 + #define NAU8540_I2S_MS_MASTER (0x1 << NAU8540_I2S_MS_SFT) 155 + #define NAU8540_I2S_MS_SLAVE (0x0 << NAU8540_I2S_MS_SFT) 156 + #define NAU8540_I2S_BLK_DIV_MASK 0x7 157 + 158 + /* PCM_CTRL1 (0x12) */ 159 + #define NAU8540_I2S_DO34_OE (0x1 << 11) 160 + #define NAU8540_I2S_TSLOT_L_MASK 0x3ff 161 + 162 + /* PCM_CTRL4 (0x14) */ 163 + #define NAU8540_TDM_MODE (0x1 << 15) 164 + #define NAU8540_TDM_OFFSET_EN (0x1 << 14) 165 + #define NAU8540_TDM_TX_MASK 0xf 166 + 167 + /* ADC_SAMPLE_RATE (0x3A) */ 168 + #define NAU8540_ADC_OSR_MASK 0x3 169 + #define NAU8540_ADC_OSR_256 0x3 170 + #define NAU8540_ADC_OSR_128 0x2 171 + #define NAU8540_ADC_OSR_64 0x1 172 + #define NAU8540_ADC_OSR_32 0x0 173 + 174 + /* VMID_CTRL (0x60) */ 175 + #define NAU8540_VMID_EN (1 << 6) 176 + #define NAU8540_VMID_SEL_SFT 4 177 + #define NAU8540_VMID_SEL_MASK (0x3 << NAU8540_VMID_SEL_SFT) 178 + 179 + /* MIC_BIAS (0x67) */ 180 + #define NAU8540_PU_PRE (0x1 << 8) 181 + 182 + /* REFERENCE (0x68) */ 183 + #define NAU8540_PRECHARGE_DIS (0x1 << 13) 184 + #define NAU8540_GLOBAL_BIAS_EN (0x1 << 12) 185 + 186 + 187 + /* System Clock Source */ 188 + enum { 189 + NAU8540_CLK_DIS, 190 + NAU8540_CLK_MCLK, 191 + NAU8540_CLK_INTERNAL, 192 + NAU8540_CLK_FLL_MCLK, 193 + NAU8540_CLK_FLL_BLK, 194 + NAU8540_CLK_FLL_FS, 195 + }; 196 + 197 + struct nau8540 { 198 + struct device *dev; 199 + struct regmap *regmap; 200 + }; 201 + 202 + struct nau8540_fll { 203 + int mclk_src; 204 + int ratio; 205 + int fll_frac; 206 + int fll_int; 207 + int clk_ref_div; 208 + }; 209 + 210 + struct nau8540_fll_attr { 211 + unsigned int param; 212 + unsigned int val; 213 + }; 214 + 215 + /* over sampling rate */ 216 + struct nau8540_osr_attr { 217 + unsigned int osr; 218 + unsigned int clk_src; 219 + }; 220 + 221 + 222 + #endif /* __NAU8540_H__ */