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

ASoC: nau8822: new codec driver

Add driver for NAU88C22.

Signed-off-by: David Lin <CTLIN0@nuvoton.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

David Lin and committed by
Mark Brown
1e3cb6c3 a85227da

+1363
+16
Documentation/devicetree/bindings/sound/nau8822.txt
··· 1 + NAU8822 audio CODEC 2 + 3 + This device supports I2C only. 4 + 5 + Required properties: 6 + 7 + - compatible : "nuvoton,nau8822" 8 + 9 + - reg : the I2C address of the device. 10 + 11 + Example: 12 + 13 + codec: nau8822@1a { 14 + compatible = "nuvoton,nau8822"; 15 + reg = <0x1a>; 16 + };
+5
sound/soc/codecs/Kconfig
··· 110 110 select SND_SOC_MT6351 if MTK_PMIC_WRAP 111 111 select SND_SOC_NAU8540 if I2C 112 112 select SND_SOC_NAU8810 if I2C 113 + select SND_SOC_NAU8822 if I2C 113 114 select SND_SOC_NAU8824 if I2C 114 115 select SND_SOC_NAU8825 if I2C 115 116 select SND_SOC_HDMI_CODEC ··· 1325 1324 1326 1325 config SND_SOC_NAU8810 1327 1326 tristate "Nuvoton Technology Corporation NAU88C10 CODEC" 1327 + depends on I2C 1328 + 1329 + config SND_SOC_NAU8822 1330 + tristate "Nuvoton Technology Corporation NAU88C22 CODEC" 1328 1331 depends on I2C 1329 1332 1330 1333 config SND_SOC_NAU8824
+2
sound/soc/codecs/Makefile
··· 107 107 snd-soc-mt6351-objs := mt6351.o 108 108 snd-soc-nau8540-objs := nau8540.o 109 109 snd-soc-nau8810-objs := nau8810.o 110 + snd-soc-nau8822-objs := nau8822.o 110 111 snd-soc-nau8824-objs := nau8824.o 111 112 snd-soc-nau8825-objs := nau8825.o 112 113 snd-soc-hdmi-codec-objs := hdmi-codec.o ··· 372 371 obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o 373 372 obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o 374 373 obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o 374 + obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o 375 375 obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o 376 376 obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o 377 377 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
+1136
sound/soc/codecs/nau8822.c
··· 1 + /* 2 + * nau8822.c -- NAU8822 ALSA Soc Audio Codec driver 3 + * 4 + * Copyright 2017 Nuvoton Technology Corp. 5 + * 6 + * Author: David Lin <ctlin0@nuvoton.com> 7 + * Co-author: John Hsu <kchsu0@nuvoton.com> 8 + * Co-author: Seven Li <wtli@nuvoton.com> 9 + * 10 + * Based on WM8974.c 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License version 2 as 14 + * published by the Free Software Foundation. 15 + */ 16 + 17 + #include <linux/module.h> 18 + #include <linux/moduleparam.h> 19 + #include <linux/kernel.h> 20 + #include <linux/init.h> 21 + #include <linux/delay.h> 22 + #include <linux/pm.h> 23 + #include <linux/i2c.h> 24 + #include <linux/regmap.h> 25 + #include <linux/slab.h> 26 + #include <sound/core.h> 27 + #include <sound/pcm.h> 28 + #include <sound/pcm_params.h> 29 + #include <sound/soc.h> 30 + #include <sound/initval.h> 31 + #include <sound/tlv.h> 32 + #include <asm/div64.h> 33 + #include "nau8822.h" 34 + 35 + #define NAU_PLL_FREQ_MAX 100000000 36 + #define NAU_PLL_FREQ_MIN 90000000 37 + #define NAU_PLL_REF_MAX 33000000 38 + #define NAU_PLL_REF_MIN 8000000 39 + #define NAU_PLL_OPTOP_MIN 6 40 + 41 + static const int nau8822_mclk_scaler[] = { 10, 15, 20, 30, 40, 60, 80, 120 }; 42 + 43 + static const struct reg_default nau8822_reg_defaults[] = { 44 + { NAU8822_REG_POWER_MANAGEMENT_1, 0x0000 }, 45 + { NAU8822_REG_POWER_MANAGEMENT_2, 0x0000 }, 46 + { NAU8822_REG_POWER_MANAGEMENT_3, 0x0000 }, 47 + { NAU8822_REG_AUDIO_INTERFACE, 0x0050 }, 48 + { NAU8822_REG_COMPANDING_CONTROL, 0x0000 }, 49 + { NAU8822_REG_CLOCKING, 0x0140 }, 50 + { NAU8822_REG_ADDITIONAL_CONTROL, 0x0000 }, 51 + { NAU8822_REG_GPIO_CONTROL, 0x0000 }, 52 + { NAU8822_REG_JACK_DETECT_CONTROL_1, 0x0000 }, 53 + { NAU8822_REG_DAC_CONTROL, 0x0000 }, 54 + { NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, 0x00ff }, 55 + { NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, 0x00ff }, 56 + { NAU8822_REG_JACK_DETECT_CONTROL_2, 0x0000 }, 57 + { NAU8822_REG_ADC_CONTROL, 0x0100 }, 58 + { NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, 0x00ff }, 59 + { NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, 0x00ff }, 60 + { NAU8822_REG_EQ1, 0x012c }, 61 + { NAU8822_REG_EQ2, 0x002c }, 62 + { NAU8822_REG_EQ3, 0x002c }, 63 + { NAU8822_REG_EQ4, 0x002c }, 64 + { NAU8822_REG_EQ5, 0x002c }, 65 + { NAU8822_REG_DAC_LIMITER_1, 0x0032 }, 66 + { NAU8822_REG_DAC_LIMITER_2, 0x0000 }, 67 + { NAU8822_REG_NOTCH_FILTER_1, 0x0000 }, 68 + { NAU8822_REG_NOTCH_FILTER_2, 0x0000 }, 69 + { NAU8822_REG_NOTCH_FILTER_3, 0x0000 }, 70 + { NAU8822_REG_NOTCH_FILTER_4, 0x0000 }, 71 + { NAU8822_REG_ALC_CONTROL_1, 0x0038 }, 72 + { NAU8822_REG_ALC_CONTROL_2, 0x000b }, 73 + { NAU8822_REG_ALC_CONTROL_3, 0x0032 }, 74 + { NAU8822_REG_NOISE_GATE, 0x0010 }, 75 + { NAU8822_REG_PLL_N, 0x0008 }, 76 + { NAU8822_REG_PLL_K1, 0x000c }, 77 + { NAU8822_REG_PLL_K2, 0x0093 }, 78 + { NAU8822_REG_PLL_K3, 0x00e9 }, 79 + { NAU8822_REG_3D_CONTROL, 0x0000 }, 80 + { NAU8822_REG_RIGHT_SPEAKER_CONTROL, 0x0000 }, 81 + { NAU8822_REG_INPUT_CONTROL, 0x0033 }, 82 + { NAU8822_REG_LEFT_INP_PGA_CONTROL, 0x0010 }, 83 + { NAU8822_REG_RIGHT_INP_PGA_CONTROL, 0x0010 }, 84 + { NAU8822_REG_LEFT_ADC_BOOST_CONTROL, 0x0100 }, 85 + { NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 0x0100 }, 86 + { NAU8822_REG_OUTPUT_CONTROL, 0x0002 }, 87 + { NAU8822_REG_LEFT_MIXER_CONTROL, 0x0001 }, 88 + { NAU8822_REG_RIGHT_MIXER_CONTROL, 0x0001 }, 89 + { NAU8822_REG_LHP_VOLUME, 0x0039 }, 90 + { NAU8822_REG_RHP_VOLUME, 0x0039 }, 91 + { NAU8822_REG_LSPKOUT_VOLUME, 0x0039 }, 92 + { NAU8822_REG_RSPKOUT_VOLUME, 0x0039 }, 93 + { NAU8822_REG_AUX2_MIXER, 0x0001 }, 94 + { NAU8822_REG_AUX1_MIXER, 0x0001 }, 95 + { NAU8822_REG_POWER_MANAGEMENT_4, 0x0000 }, 96 + { NAU8822_REG_LEFT_TIME_SLOT, 0x0000 }, 97 + { NAU8822_REG_MISC, 0x0020 }, 98 + { NAU8822_REG_RIGHT_TIME_SLOT, 0x0000 }, 99 + { NAU8822_REG_DEVICE_REVISION, 0x007f }, 100 + { NAU8822_REG_DEVICE_ID, 0x001a }, 101 + { NAU8822_REG_DAC_DITHER, 0x0114 }, 102 + { NAU8822_REG_ALC_ENHANCE_1, 0x0000 }, 103 + { NAU8822_REG_ALC_ENHANCE_2, 0x0000 }, 104 + { NAU8822_REG_192KHZ_SAMPLING, 0x0008 }, 105 + { NAU8822_REG_MISC_CONTROL, 0x0000 }, 106 + { NAU8822_REG_INPUT_TIEOFF, 0x0000 }, 107 + { NAU8822_REG_POWER_REDUCTION, 0x0000 }, 108 + { NAU8822_REG_AGC_PEAK2PEAK, 0x0000 }, 109 + { NAU8822_REG_AGC_PEAK_DETECT, 0x0000 }, 110 + { NAU8822_REG_AUTOMUTE_CONTROL, 0x0000 }, 111 + { NAU8822_REG_OUTPUT_TIEOFF, 0x0000 }, 112 + }; 113 + 114 + static bool nau8822_readable_reg(struct device *dev, unsigned int reg) 115 + { 116 + switch (reg) { 117 + case NAU8822_REG_RESET ... NAU8822_REG_JACK_DETECT_CONTROL_1: 118 + case NAU8822_REG_DAC_CONTROL ... NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME: 119 + case NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME: 120 + case NAU8822_REG_EQ1 ... NAU8822_REG_EQ5: 121 + case NAU8822_REG_DAC_LIMITER_1 ... NAU8822_REG_DAC_LIMITER_2: 122 + case NAU8822_REG_NOTCH_FILTER_1 ... NAU8822_REG_NOTCH_FILTER_4: 123 + case NAU8822_REG_ALC_CONTROL_1 ...NAU8822_REG_PLL_K3: 124 + case NAU8822_REG_3D_CONTROL: 125 + case NAU8822_REG_RIGHT_SPEAKER_CONTROL: 126 + case NAU8822_REG_INPUT_CONTROL ... NAU8822_REG_LEFT_ADC_BOOST_CONTROL: 127 + case NAU8822_REG_RIGHT_ADC_BOOST_CONTROL ... NAU8822_REG_AUX1_MIXER: 128 + case NAU8822_REG_POWER_MANAGEMENT_4 ... NAU8822_REG_DEVICE_ID: 129 + case NAU8822_REG_DAC_DITHER: 130 + case NAU8822_REG_ALC_ENHANCE_1 ... NAU8822_REG_MISC_CONTROL: 131 + case NAU8822_REG_INPUT_TIEOFF ... NAU8822_REG_OUTPUT_TIEOFF: 132 + return true; 133 + default: 134 + return false; 135 + } 136 + } 137 + 138 + static bool nau8822_writeable_reg(struct device *dev, unsigned int reg) 139 + { 140 + switch (reg) { 141 + case NAU8822_REG_RESET ... NAU8822_REG_JACK_DETECT_CONTROL_1: 142 + case NAU8822_REG_DAC_CONTROL ... NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME: 143 + case NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME: 144 + case NAU8822_REG_EQ1 ... NAU8822_REG_EQ5: 145 + case NAU8822_REG_DAC_LIMITER_1 ... NAU8822_REG_DAC_LIMITER_2: 146 + case NAU8822_REG_NOTCH_FILTER_1 ... NAU8822_REG_NOTCH_FILTER_4: 147 + case NAU8822_REG_ALC_CONTROL_1 ...NAU8822_REG_PLL_K3: 148 + case NAU8822_REG_3D_CONTROL: 149 + case NAU8822_REG_RIGHT_SPEAKER_CONTROL: 150 + case NAU8822_REG_INPUT_CONTROL ... NAU8822_REG_LEFT_ADC_BOOST_CONTROL: 151 + case NAU8822_REG_RIGHT_ADC_BOOST_CONTROL ... NAU8822_REG_AUX1_MIXER: 152 + case NAU8822_REG_POWER_MANAGEMENT_4 ... NAU8822_REG_DEVICE_ID: 153 + case NAU8822_REG_DAC_DITHER: 154 + case NAU8822_REG_ALC_ENHANCE_1 ... NAU8822_REG_MISC_CONTROL: 155 + case NAU8822_REG_INPUT_TIEOFF ... NAU8822_REG_OUTPUT_TIEOFF: 156 + return true; 157 + default: 158 + return false; 159 + } 160 + } 161 + 162 + static bool nau8822_volatile(struct device *dev, unsigned int reg) 163 + { 164 + switch (reg) { 165 + case NAU8822_REG_RESET: 166 + case NAU8822_REG_DEVICE_REVISION: 167 + case NAU8822_REG_DEVICE_ID: 168 + case NAU8822_REG_AGC_PEAK2PEAK: 169 + case NAU8822_REG_AGC_PEAK_DETECT: 170 + case NAU8822_REG_AUTOMUTE_CONTROL: 171 + return true; 172 + default: 173 + return false; 174 + } 175 + } 176 + 177 + /* The EQ parameters get function is to get the 5 band equalizer control. 178 + * The regmap raw read can't work here because regmap doesn't provide 179 + * value format for value width of 9 bits. Therefore, the driver reads data 180 + * from cache and makes value format according to the endianness of 181 + * bytes type control element. 182 + */ 183 + static int nau8822_eq_get(struct snd_kcontrol *kcontrol, 184 + struct snd_ctl_elem_value *ucontrol) 185 + { 186 + struct snd_soc_component *component = 187 + snd_soc_kcontrol_component(kcontrol); 188 + struct soc_bytes_ext *params = (void *)kcontrol->private_value; 189 + int i, reg; 190 + u16 reg_val, *val; 191 + 192 + val = (u16 *)ucontrol->value.bytes.data; 193 + reg = NAU8822_REG_EQ1; 194 + for (i = 0; i < params->max / sizeof(u16); i++) { 195 + reg_val = snd_soc_component_read32(component, reg + i); 196 + /* conversion of 16-bit integers between native CPU format 197 + * and big endian format 198 + */ 199 + reg_val = cpu_to_be16(reg_val); 200 + memcpy(val + i, &reg_val, sizeof(reg_val)); 201 + } 202 + 203 + return 0; 204 + } 205 + 206 + /* The EQ parameters put function is to make configuration of 5 band equalizer 207 + * control. These configuration includes central frequency, equalizer gain, 208 + * cut-off frequency, bandwidth control, and equalizer path. 209 + * The regmap raw write can't work here because regmap doesn't provide 210 + * register and value format for register with address 7 bits and value 9 bits. 211 + * Therefore, the driver makes value format according to the endianness of 212 + * bytes type control element and writes data to codec. 213 + */ 214 + static int nau8822_eq_put(struct snd_kcontrol *kcontrol, 215 + struct snd_ctl_elem_value *ucontrol) 216 + { 217 + struct snd_soc_component *component = 218 + snd_soc_kcontrol_component(kcontrol); 219 + struct soc_bytes_ext *params = (void *)kcontrol->private_value; 220 + void *data; 221 + u16 *val, value; 222 + int i, reg, ret; 223 + 224 + data = kmemdup(ucontrol->value.bytes.data, 225 + params->max, GFP_KERNEL | GFP_DMA); 226 + if (!data) 227 + return -ENOMEM; 228 + 229 + val = (u16 *)data; 230 + reg = NAU8822_REG_EQ1; 231 + for (i = 0; i < params->max / sizeof(u16); i++) { 232 + /* conversion of 16-bit integers between native CPU format 233 + * and big endian format 234 + */ 235 + value = be16_to_cpu(*(val + i)); 236 + ret = snd_soc_component_write(component, reg + i, value); 237 + if (ret) { 238 + dev_err(component->dev, 239 + "EQ configuration fail, register: %x ret: %d\n", 240 + reg + i, ret); 241 + kfree(data); 242 + return ret; 243 + } 244 + } 245 + kfree(data); 246 + 247 + return 0; 248 + } 249 + 250 + static const char * const nau8822_companding[] = { 251 + "Off", "NC", "u-law", "A-law"}; 252 + 253 + static const struct soc_enum nau8822_companding_adc_enum = 254 + SOC_ENUM_SINGLE(NAU8822_REG_COMPANDING_CONTROL, NAU8822_ADCCM_SFT, 255 + ARRAY_SIZE(nau8822_companding), nau8822_companding); 256 + 257 + static const struct soc_enum nau8822_companding_dac_enum = 258 + SOC_ENUM_SINGLE(NAU8822_REG_COMPANDING_CONTROL, NAU8822_DACCM_SFT, 259 + ARRAY_SIZE(nau8822_companding), nau8822_companding); 260 + 261 + static const char * const nau8822_eqmode[] = {"Capture", "Playback"}; 262 + 263 + static const struct soc_enum nau8822_eqmode_enum = 264 + SOC_ENUM_SINGLE(NAU8822_REG_EQ1, NAU8822_EQM_SFT, 265 + ARRAY_SIZE(nau8822_eqmode), nau8822_eqmode); 266 + 267 + static const char * const nau8822_alc1[] = {"Off", "Right", "Left", "Both"}; 268 + static const char * const nau8822_alc3[] = {"Normal", "Limiter"}; 269 + 270 + static const struct soc_enum nau8822_alc_enable_enum = 271 + SOC_ENUM_SINGLE(NAU8822_REG_ALC_CONTROL_1, NAU8822_ALCEN_SFT, 272 + ARRAY_SIZE(nau8822_alc1), nau8822_alc1); 273 + 274 + static const struct soc_enum nau8822_alc_mode_enum = 275 + SOC_ENUM_SINGLE(NAU8822_REG_ALC_CONTROL_3, NAU8822_ALCM_SFT, 276 + ARRAY_SIZE(nau8822_alc3), nau8822_alc3); 277 + 278 + static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); 279 + static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); 280 + static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); 281 + static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); 282 + static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1); 283 + static const DECLARE_TLV_DB_SCALE(limiter_tlv, 0, 100, 0); 284 + 285 + static const struct snd_kcontrol_new nau8822_snd_controls[] = { 286 + SOC_ENUM("ADC Companding", nau8822_companding_adc_enum), 287 + SOC_ENUM("DAC Companding", nau8822_companding_dac_enum), 288 + 289 + SOC_ENUM("EQ Function", nau8822_eqmode_enum), 290 + SND_SOC_BYTES_EXT("EQ Parameters", 10, 291 + nau8822_eq_get, nau8822_eq_put), 292 + 293 + SOC_DOUBLE("DAC Inversion Switch", 294 + NAU8822_REG_DAC_CONTROL, 0, 1, 1, 0), 295 + SOC_DOUBLE_R_TLV("PCM Volume", 296 + NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, 297 + NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, 0, 255, 0, digital_tlv), 298 + 299 + SOC_SINGLE("High Pass Filter Switch", 300 + NAU8822_REG_ADC_CONTROL, 8, 1, 0), 301 + SOC_SINGLE("High Pass Cut Off", 302 + NAU8822_REG_ADC_CONTROL, 4, 7, 0), 303 + 304 + SOC_DOUBLE("ADC Inversion Switch", 305 + NAU8822_REG_ADC_CONTROL, 0, 1, 1, 0), 306 + SOC_DOUBLE_R_TLV("ADC Volume", 307 + NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, 308 + NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, 0, 255, 0, digital_tlv), 309 + 310 + SOC_SINGLE("DAC Limiter Switch", 311 + NAU8822_REG_DAC_LIMITER_1, 8, 1, 0), 312 + SOC_SINGLE("DAC Limiter Decay", 313 + NAU8822_REG_DAC_LIMITER_1, 4, 15, 0), 314 + SOC_SINGLE("DAC Limiter Attack", 315 + NAU8822_REG_DAC_LIMITER_1, 0, 15, 0), 316 + SOC_SINGLE("DAC Limiter Threshold", 317 + NAU8822_REG_DAC_LIMITER_2, 4, 7, 0), 318 + SOC_SINGLE_TLV("DAC Limiter Volume", 319 + NAU8822_REG_DAC_LIMITER_2, 0, 12, 0, limiter_tlv), 320 + 321 + SOC_ENUM("ALC Mode", nau8822_alc_mode_enum), 322 + SOC_ENUM("ALC Enable Switch", nau8822_alc_enable_enum), 323 + SOC_SINGLE("ALC Min Gain", 324 + NAU8822_REG_ALC_CONTROL_1, 0, 7, 0), 325 + SOC_SINGLE("ALC Max Gain", 326 + NAU8822_REG_ALC_CONTROL_1, 3, 7, 0), 327 + SOC_SINGLE("ALC Hold", 328 + NAU8822_REG_ALC_CONTROL_2, 4, 10, 0), 329 + SOC_SINGLE("ALC Target", 330 + NAU8822_REG_ALC_CONTROL_2, 0, 15, 0), 331 + SOC_SINGLE("ALC Decay", 332 + NAU8822_REG_ALC_CONTROL_3, 4, 10, 0), 333 + SOC_SINGLE("ALC Attack", 334 + NAU8822_REG_ALC_CONTROL_3, 0, 10, 0), 335 + SOC_SINGLE("ALC Noise Gate Switch", 336 + NAU8822_REG_NOISE_GATE, 3, 1, 0), 337 + SOC_SINGLE("ALC Noise Gate Threshold", 338 + NAU8822_REG_NOISE_GATE, 0, 7, 0), 339 + 340 + SOC_DOUBLE_R("PGA ZC Switch", 341 + NAU8822_REG_LEFT_INP_PGA_CONTROL, 342 + NAU8822_REG_RIGHT_INP_PGA_CONTROL, 343 + 7, 1, 0), 344 + SOC_DOUBLE_R_TLV("PGA Volume", 345 + NAU8822_REG_LEFT_INP_PGA_CONTROL, 346 + NAU8822_REG_RIGHT_INP_PGA_CONTROL, 0, 63, 0, inpga_tlv), 347 + 348 + SOC_DOUBLE_R("Headphone ZC Switch", 349 + NAU8822_REG_LHP_VOLUME, 350 + NAU8822_REG_RHP_VOLUME, 7, 1, 0), 351 + SOC_DOUBLE_R("Headphone Playback Switch", 352 + NAU8822_REG_LHP_VOLUME, 353 + NAU8822_REG_RHP_VOLUME, 6, 1, 1), 354 + SOC_DOUBLE_R_TLV("Headphone Volume", 355 + NAU8822_REG_LHP_VOLUME, 356 + NAU8822_REG_RHP_VOLUME, 0, 63, 0, spk_tlv), 357 + 358 + SOC_DOUBLE_R("Speaker ZC Switch", 359 + NAU8822_REG_LSPKOUT_VOLUME, 360 + NAU8822_REG_RSPKOUT_VOLUME, 7, 1, 0), 361 + SOC_DOUBLE_R("Speaker Playback Switch", 362 + NAU8822_REG_LSPKOUT_VOLUME, 363 + NAU8822_REG_RSPKOUT_VOLUME, 6, 1, 1), 364 + SOC_DOUBLE_R_TLV("Speaker Volume", 365 + NAU8822_REG_LSPKOUT_VOLUME, 366 + NAU8822_REG_RSPKOUT_VOLUME, 0, 63, 0, spk_tlv), 367 + 368 + SOC_DOUBLE_R("AUXOUT Playback Switch", 369 + NAU8822_REG_AUX2_MIXER, 370 + NAU8822_REG_AUX1_MIXER, 6, 1, 1), 371 + 372 + SOC_DOUBLE_R_TLV("PGA Boost Volume", 373 + NAU8822_REG_LEFT_ADC_BOOST_CONTROL, 374 + NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 8, 1, 0, pga_boost_tlv), 375 + SOC_DOUBLE_R_TLV("L2/R2 Boost Volume", 376 + NAU8822_REG_LEFT_ADC_BOOST_CONTROL, 377 + NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 4, 7, 0, boost_tlv), 378 + SOC_DOUBLE_R_TLV("Aux Boost Volume", 379 + NAU8822_REG_LEFT_ADC_BOOST_CONTROL, 380 + NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 0, 7, 0, boost_tlv), 381 + 382 + SOC_SINGLE("DAC 128x Oversampling Switch", 383 + NAU8822_REG_DAC_CONTROL, 5, 1, 0), 384 + SOC_SINGLE("ADC 128x Oversampling Switch", 385 + NAU8822_REG_ADC_CONTROL, 5, 1, 0), 386 + }; 387 + 388 + /* LMAIN and RMAIN Mixer */ 389 + static const struct snd_kcontrol_new nau8822_left_out_mixer[] = { 390 + SOC_DAPM_SINGLE("LINMIX Switch", 391 + NAU8822_REG_LEFT_MIXER_CONTROL, 1, 1, 0), 392 + SOC_DAPM_SINGLE("LAUX Switch", 393 + NAU8822_REG_LEFT_MIXER_CONTROL, 5, 1, 0), 394 + SOC_DAPM_SINGLE("LDAC Switch", 395 + NAU8822_REG_LEFT_MIXER_CONTROL, 0, 1, 0), 396 + SOC_DAPM_SINGLE("RDAC Switch", 397 + NAU8822_REG_OUTPUT_CONTROL, 5, 1, 0), 398 + }; 399 + 400 + static const struct snd_kcontrol_new nau8822_right_out_mixer[] = { 401 + SOC_DAPM_SINGLE("RINMIX Switch", 402 + NAU8822_REG_RIGHT_MIXER_CONTROL, 1, 1, 0), 403 + SOC_DAPM_SINGLE("RAUX Switch", 404 + NAU8822_REG_RIGHT_MIXER_CONTROL, 5, 1, 0), 405 + SOC_DAPM_SINGLE("RDAC Switch", 406 + NAU8822_REG_RIGHT_MIXER_CONTROL, 0, 1, 0), 407 + SOC_DAPM_SINGLE("LDAC Switch", 408 + NAU8822_REG_OUTPUT_CONTROL, 6, 1, 0), 409 + }; 410 + 411 + /* AUX1 and AUX2 Mixer */ 412 + static const struct snd_kcontrol_new nau8822_auxout1_mixer[] = { 413 + SOC_DAPM_SINGLE("RDAC Switch", NAU8822_REG_AUX1_MIXER, 0, 1, 0), 414 + SOC_DAPM_SINGLE("RMIX Switch", NAU8822_REG_AUX1_MIXER, 1, 1, 0), 415 + SOC_DAPM_SINGLE("RINMIX Switch", NAU8822_REG_AUX1_MIXER, 2, 1, 0), 416 + SOC_DAPM_SINGLE("LDAC Switch", NAU8822_REG_AUX1_MIXER, 3, 1, 0), 417 + SOC_DAPM_SINGLE("LMIX Switch", NAU8822_REG_AUX1_MIXER, 4, 1, 0), 418 + }; 419 + 420 + static const struct snd_kcontrol_new nau8822_auxout2_mixer[] = { 421 + SOC_DAPM_SINGLE("LDAC Switch", NAU8822_REG_AUX2_MIXER, 0, 1, 0), 422 + SOC_DAPM_SINGLE("LMIX Switch", NAU8822_REG_AUX2_MIXER, 1, 1, 0), 423 + SOC_DAPM_SINGLE("LINMIX Switch", NAU8822_REG_AUX2_MIXER, 2, 1, 0), 424 + SOC_DAPM_SINGLE("AUX1MIX Output Switch", 425 + NAU8822_REG_AUX2_MIXER, 3, 1, 0), 426 + }; 427 + 428 + /* Input PGA */ 429 + static const struct snd_kcontrol_new nau8822_left_input_mixer[] = { 430 + SOC_DAPM_SINGLE("L2 Switch", NAU8822_REG_INPUT_CONTROL, 2, 1, 0), 431 + SOC_DAPM_SINGLE("MicN Switch", NAU8822_REG_INPUT_CONTROL, 1, 1, 0), 432 + SOC_DAPM_SINGLE("MicP Switch", NAU8822_REG_INPUT_CONTROL, 0, 1, 0), 433 + }; 434 + static const struct snd_kcontrol_new nau8822_right_input_mixer[] = { 435 + SOC_DAPM_SINGLE("R2 Switch", NAU8822_REG_INPUT_CONTROL, 6, 1, 0), 436 + SOC_DAPM_SINGLE("MicN Switch", NAU8822_REG_INPUT_CONTROL, 5, 1, 0), 437 + SOC_DAPM_SINGLE("MicP Switch", NAU8822_REG_INPUT_CONTROL, 4, 1, 0), 438 + }; 439 + 440 + /* Loopback Switch */ 441 + static const struct snd_kcontrol_new nau8822_loopback = 442 + SOC_DAPM_SINGLE("Switch", NAU8822_REG_COMPANDING_CONTROL, 443 + NAU8822_ADDAP_SFT, 1, 0); 444 + 445 + static int check_mclk_select_pll(struct snd_soc_dapm_widget *source, 446 + struct snd_soc_dapm_widget *sink) 447 + { 448 + struct snd_soc_component *component = 449 + snd_soc_dapm_to_component(source->dapm); 450 + unsigned int value; 451 + 452 + value = snd_soc_component_read32(component, NAU8822_REG_CLOCKING); 453 + 454 + return (value & NAU8822_CLKM_MASK); 455 + } 456 + 457 + static const struct snd_soc_dapm_widget nau8822_dapm_widgets[] = { 458 + SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", 459 + NAU8822_REG_POWER_MANAGEMENT_3, 0, 0), 460 + SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", 461 + NAU8822_REG_POWER_MANAGEMENT_3, 1, 0), 462 + SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", 463 + NAU8822_REG_POWER_MANAGEMENT_2, 0, 0), 464 + SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", 465 + NAU8822_REG_POWER_MANAGEMENT_2, 1, 0), 466 + 467 + SOC_MIXER_ARRAY("Left Output Mixer", 468 + NAU8822_REG_POWER_MANAGEMENT_3, 2, 0, nau8822_left_out_mixer), 469 + SOC_MIXER_ARRAY("Right Output Mixer", 470 + NAU8822_REG_POWER_MANAGEMENT_3, 3, 0, nau8822_right_out_mixer), 471 + SOC_MIXER_ARRAY("AUX1 Output Mixer", 472 + NAU8822_REG_POWER_MANAGEMENT_1, 7, 0, nau8822_auxout1_mixer), 473 + SOC_MIXER_ARRAY("AUX2 Output Mixer", 474 + NAU8822_REG_POWER_MANAGEMENT_1, 6, 0, nau8822_auxout2_mixer), 475 + 476 + SOC_MIXER_ARRAY("Left Input Mixer", 477 + NAU8822_REG_POWER_MANAGEMENT_2, 478 + 2, 0, nau8822_left_input_mixer), 479 + SOC_MIXER_ARRAY("Right Input Mixer", 480 + NAU8822_REG_POWER_MANAGEMENT_2, 481 + 3, 0, nau8822_right_input_mixer), 482 + 483 + SND_SOC_DAPM_PGA("Left Boost Mixer", 484 + NAU8822_REG_POWER_MANAGEMENT_2, 4, 0, NULL, 0), 485 + SND_SOC_DAPM_PGA("Right Boost Mixer", 486 + NAU8822_REG_POWER_MANAGEMENT_2, 5, 0, NULL, 0), 487 + 488 + SND_SOC_DAPM_PGA("Left Capture PGA", 489 + NAU8822_REG_LEFT_INP_PGA_CONTROL, 6, 1, NULL, 0), 490 + SND_SOC_DAPM_PGA("Right Capture PGA", 491 + NAU8822_REG_RIGHT_INP_PGA_CONTROL, 6, 1, NULL, 0), 492 + 493 + SND_SOC_DAPM_PGA("Left Headphone Out", 494 + NAU8822_REG_POWER_MANAGEMENT_2, 7, 0, NULL, 0), 495 + SND_SOC_DAPM_PGA("Right Headphone Out", 496 + NAU8822_REG_POWER_MANAGEMENT_2, 8, 0, NULL, 0), 497 + 498 + SND_SOC_DAPM_PGA("Left Speaker Out", 499 + NAU8822_REG_POWER_MANAGEMENT_3, 6, 0, NULL, 0), 500 + SND_SOC_DAPM_PGA("Right Speaker Out", 501 + NAU8822_REG_POWER_MANAGEMENT_3, 5, 0, NULL, 0), 502 + 503 + SND_SOC_DAPM_PGA("AUX1 Out", 504 + NAU8822_REG_POWER_MANAGEMENT_3, 8, 0, NULL, 0), 505 + SND_SOC_DAPM_PGA("AUX2 Out", 506 + NAU8822_REG_POWER_MANAGEMENT_3, 7, 0, NULL, 0), 507 + 508 + SND_SOC_DAPM_SUPPLY("Mic Bias", 509 + NAU8822_REG_POWER_MANAGEMENT_1, 4, 0, NULL, 0), 510 + SND_SOC_DAPM_SUPPLY("PLL", 511 + NAU8822_REG_POWER_MANAGEMENT_1, 5, 0, NULL, 0), 512 + 513 + SND_SOC_DAPM_SWITCH("Digital Loopback", SND_SOC_NOPM, 0, 0, 514 + &nau8822_loopback), 515 + 516 + SND_SOC_DAPM_INPUT("LMICN"), 517 + SND_SOC_DAPM_INPUT("LMICP"), 518 + SND_SOC_DAPM_INPUT("RMICN"), 519 + SND_SOC_DAPM_INPUT("RMICP"), 520 + SND_SOC_DAPM_INPUT("LAUX"), 521 + SND_SOC_DAPM_INPUT("RAUX"), 522 + SND_SOC_DAPM_INPUT("L2"), 523 + SND_SOC_DAPM_INPUT("R2"), 524 + SND_SOC_DAPM_OUTPUT("LHP"), 525 + SND_SOC_DAPM_OUTPUT("RHP"), 526 + SND_SOC_DAPM_OUTPUT("LSPK"), 527 + SND_SOC_DAPM_OUTPUT("RSPK"), 528 + SND_SOC_DAPM_OUTPUT("AUXOUT1"), 529 + SND_SOC_DAPM_OUTPUT("AUXOUT2"), 530 + }; 531 + 532 + static const struct snd_soc_dapm_route nau8822_dapm_routes[] = { 533 + {"Right DAC", NULL, "PLL", check_mclk_select_pll}, 534 + {"Left DAC", NULL, "PLL", check_mclk_select_pll}, 535 + 536 + /* LMAIN and RMAIN Mixer */ 537 + {"Right Output Mixer", "LDAC Switch", "Left DAC"}, 538 + {"Right Output Mixer", "RDAC Switch", "Right DAC"}, 539 + {"Right Output Mixer", "RAUX Switch", "RAUX"}, 540 + {"Right Output Mixer", "RINMIX Switch", "Right Boost Mixer"}, 541 + 542 + {"Left Output Mixer", "LDAC Switch", "Left DAC"}, 543 + {"Left Output Mixer", "RDAC Switch", "Right DAC"}, 544 + {"Left Output Mixer", "LAUX Switch", "LAUX"}, 545 + {"Left Output Mixer", "LINMIX Switch", "Left Boost Mixer"}, 546 + 547 + /* AUX1 and AUX2 Mixer */ 548 + {"AUX1 Output Mixer", "RDAC Switch", "Right DAC"}, 549 + {"AUX1 Output Mixer", "RMIX Switch", "Right Output Mixer"}, 550 + {"AUX1 Output Mixer", "RINMIX Switch", "Right Boost Mixer"}, 551 + {"AUX1 Output Mixer", "LDAC Switch", "Left DAC"}, 552 + {"AUX1 Output Mixer", "LMIX Switch", "Left Output Mixer"}, 553 + 554 + {"AUX2 Output Mixer", "LDAC Switch", "Left DAC"}, 555 + {"AUX2 Output Mixer", "LMIX Switch", "Left Output Mixer"}, 556 + {"AUX2 Output Mixer", "LINMIX Switch", "Left Boost Mixer"}, 557 + {"AUX2 Output Mixer", "AUX1MIX Output Switch", "AUX1 Output Mixer"}, 558 + 559 + /* Outputs */ 560 + {"Right Headphone Out", NULL, "Right Output Mixer"}, 561 + {"RHP", NULL, "Right Headphone Out"}, 562 + 563 + {"Left Headphone Out", NULL, "Left Output Mixer"}, 564 + {"LHP", NULL, "Left Headphone Out"}, 565 + 566 + {"Right Speaker Out", NULL, "Right Output Mixer"}, 567 + {"RSPK", NULL, "Right Speaker Out"}, 568 + 569 + {"Left Speaker Out", NULL, "Left Output Mixer"}, 570 + {"LSPK", NULL, "Left Speaker Out"}, 571 + 572 + {"AUX1 Out", NULL, "AUX1 Output Mixer"}, 573 + {"AUX2 Out", NULL, "AUX2 Output Mixer"}, 574 + {"AUXOUT1", NULL, "AUX1 Out"}, 575 + {"AUXOUT2", NULL, "AUX2 Out"}, 576 + 577 + /* Boost Mixer */ 578 + {"Right ADC", NULL, "PLL", check_mclk_select_pll}, 579 + {"Left ADC", NULL, "PLL", check_mclk_select_pll}, 580 + 581 + {"Right ADC", NULL, "Right Boost Mixer"}, 582 + 583 + {"Right Boost Mixer", NULL, "RAUX"}, 584 + {"Right Boost Mixer", NULL, "Right Capture PGA"}, 585 + {"Right Boost Mixer", NULL, "R2"}, 586 + 587 + {"Left ADC", NULL, "Left Boost Mixer"}, 588 + 589 + {"Left Boost Mixer", NULL, "LAUX"}, 590 + {"Left Boost Mixer", NULL, "Left Capture PGA"}, 591 + {"Left Boost Mixer", NULL, "L2"}, 592 + 593 + /* Input PGA */ 594 + {"Right Capture PGA", NULL, "Right Input Mixer"}, 595 + {"Left Capture PGA", NULL, "Left Input Mixer"}, 596 + 597 + /* Enable Microphone Power */ 598 + {"Right Capture PGA", NULL, "Mic Bias"}, 599 + {"Left Capture PGA", NULL, "Mic Bias"}, 600 + 601 + {"Right Input Mixer", "R2 Switch", "R2"}, 602 + {"Right Input Mixer", "MicN Switch", "RMICN"}, 603 + {"Right Input Mixer", "MicP Switch", "RMICP"}, 604 + 605 + {"Left Input Mixer", "L2 Switch", "L2"}, 606 + {"Left Input Mixer", "MicN Switch", "LMICN"}, 607 + {"Left Input Mixer", "MicP Switch", "LMICP"}, 608 + 609 + /* Digital Loopback */ 610 + {"Digital Loopback", "Switch", "Left ADC"}, 611 + {"Digital Loopback", "Switch", "Right ADC"}, 612 + {"Left DAC", NULL, "Digital Loopback"}, 613 + {"Right DAC", NULL, "Digital Loopback"}, 614 + }; 615 + 616 + static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, 617 + unsigned int freq, int dir) 618 + { 619 + struct snd_soc_component *component = dai->component; 620 + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); 621 + 622 + nau8822->div_id = clk_id; 623 + nau8822->sysclk = freq; 624 + dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq, 625 + clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK"); 626 + 627 + return 0; 628 + } 629 + 630 + static int nau8822_calc_pll(unsigned int pll_in, unsigned int fs, 631 + struct nau8822_pll *pll_param) 632 + { 633 + u64 f2, f2_max, pll_ratio; 634 + int i, scal_sel; 635 + 636 + if (pll_in > NAU_PLL_REF_MAX || pll_in < NAU_PLL_REF_MIN) 637 + return -EINVAL; 638 + f2_max = 0; 639 + scal_sel = ARRAY_SIZE(nau8822_mclk_scaler); 640 + 641 + for (i = 0; i < scal_sel; i++) { 642 + f2 = 256 * fs * 4 * nau8822_mclk_scaler[i] / 10; 643 + if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX && 644 + f2_max < f2) { 645 + f2_max = f2; 646 + scal_sel = i; 647 + } 648 + } 649 + 650 + if (ARRAY_SIZE(nau8822_mclk_scaler) == scal_sel) 651 + return -EINVAL; 652 + pll_param->mclk_scaler = scal_sel; 653 + f2 = f2_max; 654 + 655 + /* Calculate the PLL 4-bit integer input and the PLL 24-bit fractional 656 + * input; round up the 24+4bit. 657 + */ 658 + pll_ratio = div_u64(f2 << 28, pll_in); 659 + pll_param->pre_factor = 0; 660 + if (((pll_ratio >> 28) & 0xF) < NAU_PLL_OPTOP_MIN) { 661 + pll_ratio <<= 1; 662 + pll_param->pre_factor = 1; 663 + } 664 + pll_param->pll_int = (pll_ratio >> 28) & 0xF; 665 + pll_param->pll_frac = ((pll_ratio & 0xFFFFFFF) >> 4); 666 + 667 + return 0; 668 + } 669 + 670 + static int nau8822_config_clkdiv(struct snd_soc_dai *dai, int div, int rate) 671 + { 672 + struct snd_soc_component *component = dai->component; 673 + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); 674 + struct nau8822_pll *pll = &nau8822->pll; 675 + int i, sclk, imclk; 676 + 677 + switch (nau8822->div_id) { 678 + case NAU8822_CLK_MCLK: 679 + /* Configure the master clock prescaler div to make system 680 + * clock to approximate the internal master clock (IMCLK); 681 + * and large or equal to IMCLK. 682 + */ 683 + div = 0; 684 + imclk = rate * 256; 685 + for (i = 1; i < ARRAY_SIZE(nau8822_mclk_scaler); i++) { 686 + sclk = (nau8822->sysclk * 10) / nau8822_mclk_scaler[i]; 687 + if (sclk < imclk) 688 + break; 689 + div = i; 690 + } 691 + dev_dbg(component->dev, "master clock prescaler %x for fs %d\n", 692 + div, rate); 693 + 694 + /* master clock from MCLK and disable PLL */ 695 + snd_soc_component_update_bits(component, 696 + NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, 697 + (div << NAU8822_MCLKSEL_SFT)); 698 + snd_soc_component_update_bits(component, 699 + NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, 700 + NAU8822_CLKM_MCLK); 701 + break; 702 + 703 + case NAU8822_CLK_PLL: 704 + /* master clock from PLL and enable PLL */ 705 + if (pll->mclk_scaler != div) { 706 + dev_err(component->dev, 707 + "master clock prescaler not meet PLL parameters\n"); 708 + return -EINVAL; 709 + } 710 + snd_soc_component_update_bits(component, 711 + NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, 712 + (div << NAU8822_MCLKSEL_SFT)); 713 + snd_soc_component_update_bits(component, 714 + NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, 715 + NAU8822_CLKM_PLL); 716 + break; 717 + 718 + default: 719 + return -EINVAL; 720 + } 721 + 722 + return 0; 723 + } 724 + 725 + static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, 726 + unsigned int freq_in, unsigned int freq_out) 727 + { 728 + struct snd_soc_component *component = dai->component; 729 + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); 730 + struct nau8822_pll *pll_param = &nau8822->pll; 731 + int ret, fs; 732 + 733 + fs = freq_out / 256; 734 + 735 + ret = nau8822_calc_pll(freq_in, fs, pll_param); 736 + if (ret < 0) { 737 + dev_err(component->dev, "Unsupported input clock %d\n", 738 + freq_in); 739 + return ret; 740 + } 741 + 742 + dev_info(component->dev, 743 + "pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n", 744 + pll_param->pll_int, pll_param->pll_frac, 745 + pll_param->mclk_scaler, pll_param->pre_factor); 746 + 747 + snd_soc_component_update_bits(component, 748 + NAU8822_REG_PLL_N, NAU8822_PLLMCLK_DIV2 | NAU8822_PLLN_MASK, 749 + (pll_param->pre_factor ? NAU8822_PLLMCLK_DIV2 : 0) | 750 + pll_param->pll_int); 751 + snd_soc_component_write(component, 752 + NAU8822_REG_PLL_K1, (pll_param->pll_frac >> NAU8822_PLLK1_SFT) & 753 + NAU8822_PLLK1_MASK); 754 + snd_soc_component_write(component, 755 + NAU8822_REG_PLL_K2, (pll_param->pll_frac >> NAU8822_PLLK2_SFT) & 756 + NAU8822_PLLK2_MASK); 757 + snd_soc_component_write(component, 758 + NAU8822_REG_PLL_K3, pll_param->pll_frac & NAU8822_PLLK3_MASK); 759 + snd_soc_component_update_bits(component, 760 + NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, 761 + pll_param->mclk_scaler << NAU8822_MCLKSEL_SFT); 762 + snd_soc_component_update_bits(component, 763 + NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, NAU8822_CLKM_PLL); 764 + 765 + return 0; 766 + } 767 + 768 + static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) 769 + { 770 + struct snd_soc_component *component = dai->component; 771 + u16 ctrl1_val = 0, ctrl2_val = 0; 772 + 773 + dev_dbg(component->dev, "%s\n", __func__); 774 + 775 + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 776 + case SND_SOC_DAIFMT_CBM_CFM: 777 + ctrl2_val |= 1; 778 + break; 779 + case SND_SOC_DAIFMT_CBS_CFS: 780 + ctrl2_val &= ~1; 781 + break; 782 + default: 783 + return -EINVAL; 784 + } 785 + 786 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 787 + case SND_SOC_DAIFMT_I2S: 788 + ctrl1_val |= 0x10; 789 + break; 790 + case SND_SOC_DAIFMT_RIGHT_J: 791 + break; 792 + case SND_SOC_DAIFMT_LEFT_J: 793 + ctrl1_val |= 0x8; 794 + break; 795 + case SND_SOC_DAIFMT_DSP_A: 796 + ctrl1_val |= 0x18; 797 + break; 798 + default: 799 + return -EINVAL; 800 + } 801 + 802 + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 803 + case SND_SOC_DAIFMT_NB_NF: 804 + break; 805 + case SND_SOC_DAIFMT_IB_IF: 806 + ctrl1_val |= 0x180; 807 + break; 808 + case SND_SOC_DAIFMT_IB_NF: 809 + ctrl1_val |= 0x100; 810 + break; 811 + case SND_SOC_DAIFMT_NB_IF: 812 + ctrl1_val |= 0x80; 813 + break; 814 + default: 815 + return -EINVAL; 816 + } 817 + 818 + snd_soc_component_update_bits(component, 819 + NAU8822_REG_AUDIO_INTERFACE, 820 + NAU8822_AIFMT_MASK | NAU8822_LRP_MASK | NAU8822_BCLKP_MASK, 821 + ctrl1_val); 822 + snd_soc_component_update_bits(component, 823 + NAU8822_REG_CLOCKING, NAU8822_CLKIOEN_MASK, ctrl2_val); 824 + 825 + return 0; 826 + } 827 + 828 + static int nau8822_hw_params(struct snd_pcm_substream *substream, 829 + struct snd_pcm_hw_params *params, 830 + struct snd_soc_dai *dai) 831 + { 832 + struct snd_soc_component *component = dai->component; 833 + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); 834 + int val_len = 0, val_rate = 0; 835 + 836 + switch (params_format(params)) { 837 + case SNDRV_PCM_FORMAT_S16_LE: 838 + break; 839 + case SNDRV_PCM_FORMAT_S20_3LE: 840 + val_len |= NAU8822_WLEN_20; 841 + break; 842 + case SNDRV_PCM_FORMAT_S24_LE: 843 + val_len |= NAU8822_WLEN_24; 844 + break; 845 + case SNDRV_PCM_FORMAT_S32_LE: 846 + val_len |= NAU8822_WLEN_32; 847 + break; 848 + default: 849 + return -EINVAL; 850 + } 851 + 852 + switch (params_rate(params)) { 853 + case 8000: 854 + val_rate |= NAU8822_SMPLR_8K; 855 + break; 856 + case 11025: 857 + val_rate |= NAU8822_SMPLR_12K; 858 + break; 859 + case 16000: 860 + val_rate |= NAU8822_SMPLR_16K; 861 + break; 862 + case 22050: 863 + val_rate |= NAU8822_SMPLR_24K; 864 + break; 865 + case 32000: 866 + val_rate |= NAU8822_SMPLR_32K; 867 + break; 868 + case 44100: 869 + case 48000: 870 + break; 871 + default: 872 + return -EINVAL; 873 + } 874 + 875 + snd_soc_component_update_bits(component, 876 + NAU8822_REG_AUDIO_INTERFACE, NAU8822_WLEN_MASK, val_len); 877 + snd_soc_component_update_bits(component, 878 + NAU8822_REG_ADDITIONAL_CONTROL, NAU8822_SMPLR_MASK, val_rate); 879 + 880 + /* If the master clock is from MCLK, provide the runtime FS for driver 881 + * to get the master clock prescaler configuration. 882 + */ 883 + if (nau8822->div_id == NAU8822_CLK_MCLK) 884 + nau8822_config_clkdiv(dai, 0, params_rate(params)); 885 + 886 + return 0; 887 + } 888 + 889 + static int nau8822_mute(struct snd_soc_dai *dai, int mute) 890 + { 891 + struct snd_soc_component *component = dai->component; 892 + 893 + dev_dbg(component->dev, "%s: %d\n", __func__, mute); 894 + 895 + if (mute) 896 + snd_soc_component_update_bits(component, 897 + NAU8822_REG_DAC_CONTROL, 0x40, 0x40); 898 + else 899 + snd_soc_component_update_bits(component, 900 + NAU8822_REG_DAC_CONTROL, 0x40, 0); 901 + 902 + return 0; 903 + } 904 + 905 + static int nau8822_set_bias_level(struct snd_soc_component *component, 906 + enum snd_soc_bias_level level) 907 + { 908 + switch (level) { 909 + case SND_SOC_BIAS_ON: 910 + case SND_SOC_BIAS_PREPARE: 911 + snd_soc_component_update_bits(component, 912 + NAU8822_REG_POWER_MANAGEMENT_1, 913 + NAU8822_REFIMP_MASK, NAU8822_REFIMP_80K); 914 + break; 915 + 916 + case SND_SOC_BIAS_STANDBY: 917 + snd_soc_component_update_bits(component, 918 + NAU8822_REG_POWER_MANAGEMENT_1, 919 + NAU8822_IOBUF_EN | NAU8822_ABIAS_EN, 920 + NAU8822_IOBUF_EN | NAU8822_ABIAS_EN); 921 + 922 + if (snd_soc_component_get_bias_level(component) == 923 + SND_SOC_BIAS_OFF) { 924 + snd_soc_component_update_bits(component, 925 + NAU8822_REG_POWER_MANAGEMENT_1, 926 + NAU8822_REFIMP_MASK, NAU8822_REFIMP_3K); 927 + mdelay(100); 928 + } 929 + snd_soc_component_update_bits(component, 930 + NAU8822_REG_POWER_MANAGEMENT_1, 931 + NAU8822_REFIMP_MASK, NAU8822_REFIMP_300K); 932 + break; 933 + 934 + case SND_SOC_BIAS_OFF: 935 + snd_soc_component_write(component, 936 + NAU8822_REG_POWER_MANAGEMENT_1, 0); 937 + snd_soc_component_write(component, 938 + NAU8822_REG_POWER_MANAGEMENT_2, 0); 939 + snd_soc_component_write(component, 940 + NAU8822_REG_POWER_MANAGEMENT_3, 0); 941 + break; 942 + } 943 + 944 + dev_dbg(component->dev, "%s: %d\n", __func__, level); 945 + 946 + return 0; 947 + } 948 + 949 + #define NAU8822_RATES (SNDRV_PCM_RATE_8000_48000) 950 + 951 + #define NAU8822_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ 952 + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 953 + 954 + static const struct snd_soc_dai_ops nau8822_dai_ops = { 955 + .hw_params = nau8822_hw_params, 956 + .digital_mute = nau8822_mute, 957 + .set_fmt = nau8822_set_dai_fmt, 958 + .set_sysclk = nau8822_set_dai_sysclk, 959 + .set_pll = nau8822_set_pll, 960 + }; 961 + 962 + static struct snd_soc_dai_driver nau8822_dai = { 963 + .name = "nau8822-hifi", 964 + .playback = { 965 + .stream_name = "Playback", 966 + .channels_min = 1, 967 + .channels_max = 2, 968 + .rates = NAU8822_RATES, 969 + .formats = NAU8822_FORMATS, 970 + }, 971 + .capture = { 972 + .stream_name = "Capture", 973 + .channels_min = 1, 974 + .channels_max = 2, 975 + .rates = NAU8822_RATES, 976 + .formats = NAU8822_FORMATS, 977 + }, 978 + .ops = &nau8822_dai_ops, 979 + .symmetric_rates = 1, 980 + }; 981 + 982 + static int nau8822_suspend(struct snd_soc_component *component) 983 + { 984 + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); 985 + 986 + snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); 987 + 988 + regcache_mark_dirty(nau8822->regmap); 989 + 990 + return 0; 991 + } 992 + 993 + static int nau8822_resume(struct snd_soc_component *component) 994 + { 995 + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); 996 + 997 + regcache_sync(nau8822->regmap); 998 + 999 + snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY); 1000 + 1001 + return 0; 1002 + } 1003 + 1004 + /* 1005 + * These registers contain an "update" bit - bit 8. This means, for example, 1006 + * that one can write new DAC digital volume for both channels, but only when 1007 + * the update bit is set, will also the volume be updated - simultaneously for 1008 + * both channels. 1009 + */ 1010 + static const int update_reg[] = { 1011 + NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, 1012 + NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, 1013 + NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, 1014 + NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, 1015 + NAU8822_REG_LEFT_INP_PGA_CONTROL, 1016 + NAU8822_REG_RIGHT_INP_PGA_CONTROL, 1017 + NAU8822_REG_LHP_VOLUME, 1018 + NAU8822_REG_RHP_VOLUME, 1019 + NAU8822_REG_LSPKOUT_VOLUME, 1020 + NAU8822_REG_RSPKOUT_VOLUME, 1021 + }; 1022 + 1023 + static int nau8822_probe(struct snd_soc_component *component) 1024 + { 1025 + int i; 1026 + 1027 + /* 1028 + * Set the update bit in all registers, that have one. This way all 1029 + * writes to those registers will also cause the update bit to be 1030 + * written. 1031 + */ 1032 + for (i = 0; i < ARRAY_SIZE(update_reg); i++) 1033 + snd_soc_component_update_bits(component, 1034 + update_reg[i], 0x100, 0x100); 1035 + 1036 + return 0; 1037 + } 1038 + 1039 + static const struct snd_soc_component_driver soc_component_dev_nau8822 = { 1040 + .probe = nau8822_probe, 1041 + .suspend = nau8822_suspend, 1042 + .resume = nau8822_resume, 1043 + .set_bias_level = nau8822_set_bias_level, 1044 + .controls = nau8822_snd_controls, 1045 + .num_controls = ARRAY_SIZE(nau8822_snd_controls), 1046 + .dapm_widgets = nau8822_dapm_widgets, 1047 + .num_dapm_widgets = ARRAY_SIZE(nau8822_dapm_widgets), 1048 + .dapm_routes = nau8822_dapm_routes, 1049 + .num_dapm_routes = ARRAY_SIZE(nau8822_dapm_routes), 1050 + .idle_bias_on = 1, 1051 + .use_pmdown_time = 1, 1052 + .endianness = 1, 1053 + .non_legacy_dai_naming = 1, 1054 + }; 1055 + 1056 + static const struct regmap_config nau8822_regmap_config = { 1057 + .reg_bits = 7, 1058 + .val_bits = 9, 1059 + 1060 + .max_register = NAU8822_REG_MAX_REGISTER, 1061 + .volatile_reg = nau8822_volatile, 1062 + 1063 + .readable_reg = nau8822_readable_reg, 1064 + .writeable_reg = nau8822_writeable_reg, 1065 + 1066 + .cache_type = REGCACHE_RBTREE, 1067 + .reg_defaults = nau8822_reg_defaults, 1068 + .num_reg_defaults = ARRAY_SIZE(nau8822_reg_defaults), 1069 + }; 1070 + 1071 + static int nau8822_i2c_probe(struct i2c_client *i2c, 1072 + const struct i2c_device_id *id) 1073 + { 1074 + struct device *dev = &i2c->dev; 1075 + struct nau8822 *nau8822 = dev_get_platdata(dev); 1076 + int ret; 1077 + 1078 + if (!nau8822) { 1079 + nau8822 = devm_kzalloc(dev, sizeof(*nau8822), GFP_KERNEL); 1080 + if (nau8822 == NULL) 1081 + return -ENOMEM; 1082 + } 1083 + i2c_set_clientdata(i2c, nau8822); 1084 + 1085 + nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config); 1086 + if (IS_ERR(nau8822->regmap)) { 1087 + ret = PTR_ERR(nau8822->regmap); 1088 + dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); 1089 + return ret; 1090 + } 1091 + nau8822->dev = dev; 1092 + 1093 + /* Reset the codec */ 1094 + ret = regmap_write(nau8822->regmap, NAU8822_REG_RESET, 0x00); 1095 + if (ret != 0) { 1096 + dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); 1097 + return ret; 1098 + } 1099 + 1100 + ret = devm_snd_soc_register_component(dev, &soc_component_dev_nau8822, 1101 + &nau8822_dai, 1); 1102 + if (ret != 0) { 1103 + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); 1104 + return ret; 1105 + } 1106 + 1107 + return 0; 1108 + } 1109 + 1110 + static const struct i2c_device_id nau8822_i2c_id[] = { 1111 + { "nau8822", 0 }, 1112 + { } 1113 + }; 1114 + MODULE_DEVICE_TABLE(i2c, nau8822_i2c_id); 1115 + 1116 + #ifdef CONFIG_OF 1117 + static const struct of_device_id nau8822_of_match[] = { 1118 + { .compatible = "nuvoton,nau8822", }, 1119 + { } 1120 + }; 1121 + MODULE_DEVICE_TABLE(of, nau8822_of_match); 1122 + #endif 1123 + 1124 + static struct i2c_driver nau8822_i2c_driver = { 1125 + .driver = { 1126 + .name = "nau8822", 1127 + .of_match_table = of_match_ptr(nau8822_of_match), 1128 + }, 1129 + .probe = nau8822_i2c_probe, 1130 + .id_table = nau8822_i2c_id, 1131 + }; 1132 + module_i2c_driver(nau8822_i2c_driver); 1133 + 1134 + MODULE_DESCRIPTION("ASoC NAU8822 codec driver"); 1135 + MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>"); 1136 + MODULE_LICENSE("GPL v2");
+204
sound/soc/codecs/nau8822.h
··· 1 + /* 2 + * nau8822.h -- NAU8822 Soc Audio Codec driver 3 + * 4 + * Author: David Lin <ctlin0@nuvoton.com> 5 + * Co-author: John Hsu <kchsu0@nuvoton.com> 6 + * Co-author: Seven Li <wtli@nuvoton.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #ifndef __NAU8822_H__ 14 + #define __NAU8822_H__ 15 + 16 + #define NAU8822_REG_RESET 0x00 17 + #define NAU8822_REG_POWER_MANAGEMENT_1 0x01 18 + #define NAU8822_REG_POWER_MANAGEMENT_2 0x02 19 + #define NAU8822_REG_POWER_MANAGEMENT_3 0x03 20 + #define NAU8822_REG_AUDIO_INTERFACE 0x04 21 + #define NAU8822_REG_COMPANDING_CONTROL 0x05 22 + #define NAU8822_REG_CLOCKING 0x06 23 + #define NAU8822_REG_ADDITIONAL_CONTROL 0x07 24 + #define NAU8822_REG_GPIO_CONTROL 0x08 25 + #define NAU8822_REG_JACK_DETECT_CONTROL_1 0x09 26 + #define NAU8822_REG_DAC_CONTROL 0x0A 27 + #define NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME 0x0B 28 + #define NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME 0x0C 29 + #define NAU8822_REG_JACK_DETECT_CONTROL_2 0x0D 30 + #define NAU8822_REG_ADC_CONTROL 0x0E 31 + #define NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME 0x0F 32 + #define NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME 0x10 33 + #define NAU8822_REG_EQ1 0x12 34 + #define NAU8822_REG_EQ2 0x13 35 + #define NAU8822_REG_EQ3 0x14 36 + #define NAU8822_REG_EQ4 0x15 37 + #define NAU8822_REG_EQ5 0x16 38 + #define NAU8822_REG_DAC_LIMITER_1 0x18 39 + #define NAU8822_REG_DAC_LIMITER_2 0x19 40 + #define NAU8822_REG_NOTCH_FILTER_1 0x1B 41 + #define NAU8822_REG_NOTCH_FILTER_2 0x1C 42 + #define NAU8822_REG_NOTCH_FILTER_3 0x1D 43 + #define NAU8822_REG_NOTCH_FILTER_4 0x1E 44 + #define NAU8822_REG_ALC_CONTROL_1 0x20 45 + #define NAU8822_REG_ALC_CONTROL_2 0x21 46 + #define NAU8822_REG_ALC_CONTROL_3 0x22 47 + #define NAU8822_REG_NOISE_GATE 0x23 48 + #define NAU8822_REG_PLL_N 0x24 49 + #define NAU8822_REG_PLL_K1 0x25 50 + #define NAU8822_REG_PLL_K2 0x26 51 + #define NAU8822_REG_PLL_K3 0x27 52 + #define NAU8822_REG_3D_CONTROL 0x29 53 + #define NAU8822_REG_RIGHT_SPEAKER_CONTROL 0x2B 54 + #define NAU8822_REG_INPUT_CONTROL 0x2C 55 + #define NAU8822_REG_LEFT_INP_PGA_CONTROL 0x2D 56 + #define NAU8822_REG_RIGHT_INP_PGA_CONTROL 0x2E 57 + #define NAU8822_REG_LEFT_ADC_BOOST_CONTROL 0x2F 58 + #define NAU8822_REG_RIGHT_ADC_BOOST_CONTROL 0x30 59 + #define NAU8822_REG_OUTPUT_CONTROL 0x31 60 + #define NAU8822_REG_LEFT_MIXER_CONTROL 0x32 61 + #define NAU8822_REG_RIGHT_MIXER_CONTROL 0x33 62 + #define NAU8822_REG_LHP_VOLUME 0x34 63 + #define NAU8822_REG_RHP_VOLUME 0x35 64 + #define NAU8822_REG_LSPKOUT_VOLUME 0x36 65 + #define NAU8822_REG_RSPKOUT_VOLUME 0x37 66 + #define NAU8822_REG_AUX2_MIXER 0x38 67 + #define NAU8822_REG_AUX1_MIXER 0x39 68 + #define NAU8822_REG_POWER_MANAGEMENT_4 0x3A 69 + #define NAU8822_REG_LEFT_TIME_SLOT 0x3B 70 + #define NAU8822_REG_MISC 0x3C 71 + #define NAU8822_REG_RIGHT_TIME_SLOT 0x3D 72 + #define NAU8822_REG_DEVICE_REVISION 0x3E 73 + #define NAU8822_REG_DEVICE_ID 0x3F 74 + #define NAU8822_REG_DAC_DITHER 0x41 75 + #define NAU8822_REG_ALC_ENHANCE_1 0x46 76 + #define NAU8822_REG_ALC_ENHANCE_2 0x47 77 + #define NAU8822_REG_192KHZ_SAMPLING 0x48 78 + #define NAU8822_REG_MISC_CONTROL 0x49 79 + #define NAU8822_REG_INPUT_TIEOFF 0x4A 80 + #define NAU8822_REG_POWER_REDUCTION 0x4B 81 + #define NAU8822_REG_AGC_PEAK2PEAK 0x4C 82 + #define NAU8822_REG_AGC_PEAK_DETECT 0x4D 83 + #define NAU8822_REG_AUTOMUTE_CONTROL 0x4E 84 + #define NAU8822_REG_OUTPUT_TIEOFF 0x4F 85 + #define NAU8822_REG_MAX_REGISTER NAU8822_REG_OUTPUT_TIEOFF 86 + 87 + /* NAU8822_REG_POWER_MANAGEMENT_1 (0x1) */ 88 + #define NAU8822_REFIMP_MASK 0x3 89 + #define NAU8822_REFIMP_80K 0x1 90 + #define NAU8822_REFIMP_300K 0x2 91 + #define NAU8822_REFIMP_3K 0x3 92 + #define NAU8822_IOBUF_EN (0x1 << 2) 93 + #define NAU8822_ABIAS_EN (0x1 << 3) 94 + 95 + /* NAU8822_REG_AUDIO_INTERFACE (0x4) */ 96 + #define NAU8822_AIFMT_MASK (0x3 << 3) 97 + #define NAU8822_WLEN_MASK (0x3 << 5) 98 + #define NAU8822_WLEN_20 (0x1 << 5) 99 + #define NAU8822_WLEN_24 (0x2 << 5) 100 + #define NAU8822_WLEN_32 (0x3 << 5) 101 + #define NAU8822_LRP_MASK (0x1 << 7) 102 + #define NAU8822_BCLKP_MASK (0x1 << 8) 103 + 104 + /* NAU8822_REG_COMPANDING_CONTROL (0x5) */ 105 + #define NAU8822_ADDAP_SFT 0 106 + #define NAU8822_ADCCM_SFT 1 107 + #define NAU8822_DACCM_SFT 3 108 + 109 + /* NAU8822_REG_CLOCKING (0x6) */ 110 + #define NAU8822_CLKIOEN_MASK 0x1 111 + #define NAU8822_MCLKSEL_SFT 5 112 + #define NAU8822_MCLKSEL_MASK (0x7 << 5) 113 + #define NAU8822_BCLKSEL_SFT 2 114 + #define NAU8822_BCLKSEL_MASK (0x7 << 2) 115 + #define NAU8822_CLKM_MASK (0x1 << 8) 116 + #define NAU8822_CLKM_MCLK (0x0 << 8) 117 + #define NAU8822_CLKM_PLL (0x1 << 8) 118 + 119 + /* NAU8822_REG_ADDITIONAL_CONTROL (0x08) */ 120 + #define NAU8822_SMPLR_SFT 1 121 + #define NAU8822_SMPLR_MASK (0x7 << 1) 122 + #define NAU8822_SMPLR_48K (0x0 << 1) 123 + #define NAU8822_SMPLR_32K (0x1 << 1) 124 + #define NAU8822_SMPLR_24K (0x2 << 1) 125 + #define NAU8822_SMPLR_16K (0x3 << 1) 126 + #define NAU8822_SMPLR_12K (0x4 << 1) 127 + #define NAU8822_SMPLR_8K (0x5 << 1) 128 + 129 + /* NAU8822_REG_EQ1 (0x12) */ 130 + #define NAU8822_EQ1GC_SFT 0 131 + #define NAU8822_EQ1CF_SFT 5 132 + #define NAU8822_EQM_SFT 8 133 + 134 + /* NAU8822_REG_EQ2 (0x13) */ 135 + #define NAU8822_EQ2GC_SFT 0 136 + #define NAU8822_EQ2CF_SFT 5 137 + #define NAU8822_EQ2BW_SFT 8 138 + 139 + /* NAU8822_REG_EQ3 (0x14) */ 140 + #define NAU8822_EQ3GC_SFT 0 141 + #define NAU8822_EQ3CF_SFT 5 142 + #define NAU8822_EQ3BW_SFT 8 143 + 144 + /* NAU8822_REG_EQ4 (0x15) */ 145 + #define NAU8822_EQ4GC_SFT 0 146 + #define NAU8822_EQ4CF_SFT 5 147 + #define NAU8822_EQ4BW_SFT 8 148 + 149 + /* NAU8822_REG_EQ5 (0x16) */ 150 + #define NAU8822_EQ5GC_SFT 0 151 + #define NAU8822_EQ5CF_SFT 5 152 + 153 + /* NAU8822_REG_ALC_CONTROL_1 (0x20) */ 154 + #define NAU8822_ALCMINGAIN_SFT 0 155 + #define NAU8822_ALCMXGAIN_SFT 3 156 + #define NAU8822_ALCEN_SFT 7 157 + 158 + /* NAU8822_REG_ALC_CONTROL_2 (0x21) */ 159 + #define NAU8822_ALCSL_SFT 0 160 + #define NAU8822_ALCHT_SFT 4 161 + 162 + /* NAU8822_REG_ALC_CONTROL_3 (0x22) */ 163 + #define NAU8822_ALCATK_SFT 0 164 + #define NAU8822_ALCDCY_SFT 4 165 + #define NAU8822_ALCM_SFT 8 166 + 167 + /* NAU8822_REG_PLL_N (0x24) */ 168 + #define NAU8822_PLLMCLK_DIV2 (0x1 << 4) 169 + #define NAU8822_PLLN_MASK 0xF 170 + 171 + #define NAU8822_PLLK1_SFT 18 172 + #define NAU8822_PLLK1_MASK 0x3F 173 + 174 + /* NAU8822_REG_PLL_K2 (0x26) */ 175 + #define NAU8822_PLLK2_SFT 9 176 + #define NAU8822_PLLK2_MASK 0x1FF 177 + 178 + /* NAU8822_REG_PLL_K3 (0x27) */ 179 + #define NAU8822_PLLK3_MASK 0x1FF 180 + 181 + /* System Clock Source */ 182 + enum { 183 + NAU8822_CLK_MCLK, 184 + NAU8822_CLK_PLL, 185 + }; 186 + 187 + struct nau8822_pll { 188 + int pre_factor; 189 + int mclk_scaler; 190 + int pll_frac; 191 + int pll_int; 192 + }; 193 + 194 + /* Codec Private Data */ 195 + struct nau8822 { 196 + struct device *dev; 197 + struct regmap *regmap; 198 + int mclk_idx; 199 + struct nau8822_pll pll; 200 + int sysclk; 201 + int div_id; 202 + }; 203 + 204 + #endif /* __NAU8822_H__ */