| 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | // |
| 3 | // nau8325.c -- Nuvoton NAU8325 audio codec driver |
| 4 | // |
| 5 | // Copyright 2023 Nuvoton Technology Crop. |
| 6 | // Author: Seven Lee <WTLI@nuvoton.com> |
| 7 | // David Lin <CTLIN0@nuvoton.com> |
| 8 | // |
| 9 | |
| 10 | #include <linux/clk.h> |
| 11 | #include <linux/delay.h> |
| 12 | #include <linux/init.h> |
| 13 | #include <linux/i2c.h> |
| 14 | #include <linux/module.h> |
| 15 | #include <linux/regmap.h> |
| 16 | #include <linux/slab.h> |
| 17 | #include <sound/core.h> |
| 18 | #include <sound/initval.h> |
| 19 | #include <sound/pcm.h> |
| 20 | #include <sound/pcm_params.h> |
| 21 | #include <sound/soc.h> |
| 22 | #include <sound/tlv.h> |
| 23 | #include "nau8325.h" |
| 24 | |
| 25 | /* Range of Master Clock MCLK (Hz) */ |
| 26 | #define MASTER_CLK_MAX 49152000 |
| 27 | #define MASTER_CLK_MIN 2048000 |
| 28 | |
| 29 | /* scaling for MCLK source */ |
| 30 | #define CLK_PROC_BYPASS (-1) |
| 31 | |
| 32 | /* the maximum CLK_DAC */ |
| 33 | #define CLK_DA_AD_MAX 6144000 |
| 34 | |
| 35 | /* from MCLK input */ |
| 36 | #define MCLK_SRC 4 |
| 37 | |
| 38 | static const struct nau8325_src_attr mclk_n1_div[] = { |
| 39 | { 1, 0x0 }, |
| 40 | { 2, 0x1 }, |
| 41 | { 3, 0x2 }, |
| 42 | }; |
| 43 | |
| 44 | /* over sampling rate */ |
| 45 | static const struct nau8325_osr_attr osr_dac_sel[] = { |
| 46 | { 64, 2 }, /* OSR 64, SRC 1/4 */ |
| 47 | { 256, 0 }, /* OSR 256, SRC 1 */ |
| 48 | { 128, 1 }, /* OSR 128, SRC 1/2 */ |
| 49 | { 0, 0 }, |
| 50 | { 32, 3 }, /* OSR 32, SRC 1/8 */ |
| 51 | }; |
| 52 | |
| 53 | static const struct nau8325_src_attr mclk_n2_div[] = { |
| 54 | { 0, 0x0 }, |
| 55 | { 1, 0x1 }, |
| 56 | { 2, 0x2 }, |
| 57 | { 3, 0x3 }, |
| 58 | { 4, 0x4 }, |
| 59 | }; |
| 60 | |
| 61 | static const struct nau8325_src_attr mclk_n3_mult[] = { |
| 62 | { 0, 0x1 }, |
| 63 | { 1, 0x2 }, |
| 64 | { 2, 0x3 }, |
| 65 | { 3, 0x4 }, |
| 66 | }; |
| 67 | |
| 68 | /* Sample Rate and MCLK_SRC selections */ |
| 69 | static const struct nau8325_srate_attr target_srate_table[] = { |
| 70 | /* { FS, range, max, { MCLK source }} */ |
| 71 | { 48000, 2, true, { 12288000, 19200000, 24000000 } }, |
| 72 | { 16000, 1, false, { 4096000, 6400000, 8000000 } }, |
| 73 | { 8000, 0, false, { 2048000, 3200000, 4000000 }}, |
| 74 | { 44100, 2, true, { 11289600, 17640000, 22050000 }}, |
| 75 | { 64000, 3, false, { 16384000, 25600000, 32000000 } }, |
| 76 | { 96000, 3, true, { 24576000, 38400000, 48000000 } }, |
| 77 | { 12000, 0, true, { 3072000, 4800000, 6000000 } }, |
| 78 | { 24000, 1, true, { 6144000, 9600000, 12000000 } }, |
| 79 | { 32000, 2, false, { 8192000, 12800000, 16000000 } }, |
| 80 | }; |
| 81 | |
| 82 | static const struct reg_default nau8325_reg_defaults[] = { |
| 83 | { NAU8325_R00_HARDWARE_RST, 0x0000 }, |
| 84 | { NAU8325_R01_SOFTWARE_RST, 0x0000 }, |
| 85 | { NAU8325_R03_CLK_CTRL, 0x0000 }, |
| 86 | { NAU8325_R04_ENA_CTRL, 0x0000 }, |
| 87 | { NAU8325_R05_INTERRUPT_CTRL, 0x007f }, |
| 88 | { NAU8325_R09_IRQOUT, 0x0000 }, |
| 89 | { NAU8325_R0A_IO_CTRL, 0x0000 }, |
| 90 | { NAU8325_R0B_PDM_CTRL, 0x0000 }, |
| 91 | { NAU8325_R0C_TDM_CTRL, 0x0000 }, |
| 92 | { NAU8325_R0D_I2S_PCM_CTRL1, 0x000a }, |
| 93 | { NAU8325_R0E_I2S_PCM_CTRL2, 0x0000 }, |
| 94 | { NAU8325_R0F_L_TIME_SLOT, 0x0000 }, |
| 95 | { NAU8325_R10_R_TIME_SLOT, 0x0000 }, |
| 96 | { NAU8325_R11_HPF_CTRL, 0x0000 }, |
| 97 | { NAU8325_R12_MUTE_CTRL, 0x0000 }, |
| 98 | { NAU8325_R13_DAC_VOLUME, 0xf3f3 }, |
| 99 | { NAU8325_R29_DAC_CTRL1, 0x0081 }, |
| 100 | { NAU8325_R2A_DAC_CTRL2, 0x0000 }, |
| 101 | { NAU8325_R2C_ALC_CTRL1, 0x000e }, |
| 102 | { NAU8325_R2D_ALC_CTRL2, 0x8400 }, |
| 103 | { NAU8325_R2E_ALC_CTRL3, 0x0000 }, |
| 104 | { NAU8325_R2F_ALC_CTRL4, 0x003f }, |
| 105 | { NAU8325_R40_CLK_DET_CTRL, 0xa801 }, |
| 106 | { NAU8325_R50_MIXER_CTRL, 0x0000 }, |
| 107 | { NAU8325_R55_MISC_CTRL, 0x0000 }, |
| 108 | { NAU8325_R60_BIAS_ADJ, 0x0000 }, |
| 109 | { NAU8325_R61_ANALOG_CONTROL_1, 0x0000 }, |
| 110 | { NAU8325_R62_ANALOG_CONTROL_2, 0x0000 }, |
| 111 | { NAU8325_R63_ANALOG_CONTROL_3, 0x0000 }, |
| 112 | { NAU8325_R64_ANALOG_CONTROL_4, 0x0000 }, |
| 113 | { NAU8325_R65_ANALOG_CONTROL_5, 0x0000 }, |
| 114 | { NAU8325_R66_ANALOG_CONTROL_6, 0x0000 }, |
| 115 | { NAU8325_R69_CLIP_CTRL, 0x0000 }, |
| 116 | { NAU8325_R73_RDAC, 0x0008 }, |
| 117 | }; |
| 118 | |
| 119 | static bool nau8325_readable_reg(struct device *dev, unsigned int reg) |
| 120 | { |
| 121 | switch (reg) { |
| 122 | case NAU8325_R02_DEVICE_ID ... NAU8325_R06_INT_CLR_STATUS: |
| 123 | case NAU8325_R09_IRQOUT ... NAU8325_R13_DAC_VOLUME: |
| 124 | case NAU8325_R1D_DEBUG_READ1: |
| 125 | case NAU8325_R1F_DEBUG_READ2: |
| 126 | case NAU8325_R22_DEBUG_READ3: |
| 127 | case NAU8325_R29_DAC_CTRL1 ... NAU8325_R2A_DAC_CTRL2: |
| 128 | case NAU8325_R2C_ALC_CTRL1 ... NAU8325_R2F_ALC_CTRL4: |
| 129 | case NAU8325_R40_CLK_DET_CTRL: |
| 130 | case NAU8325_R49_TEST_STATUS ... NAU8325_R4A_ANALOG_READ: |
| 131 | case NAU8325_R50_MIXER_CTRL: |
| 132 | case NAU8325_R55_MISC_CTRL: |
| 133 | case NAU8325_R60_BIAS_ADJ ... NAU8325_R66_ANALOG_CONTROL_6: |
| 134 | case NAU8325_R69_CLIP_CTRL: |
| 135 | case NAU8325_R73_RDAC: |
| 136 | return true; |
| 137 | default: |
| 138 | return false; |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | static bool nau8325_writeable_reg(struct device *dev, unsigned int reg) |
| 143 | { |
| 144 | switch (reg) { |
| 145 | case NAU8325_R00_HARDWARE_RST: |
| 146 | case NAU8325_R03_CLK_CTRL ... NAU8325_R06_INT_CLR_STATUS: |
| 147 | case NAU8325_R09_IRQOUT ... NAU8325_R13_DAC_VOLUME: |
| 148 | case NAU8325_R29_DAC_CTRL1 ... NAU8325_R2A_DAC_CTRL2: |
| 149 | case NAU8325_R2C_ALC_CTRL1 ... NAU8325_R2F_ALC_CTRL4: |
| 150 | case NAU8325_R40_CLK_DET_CTRL: |
| 151 | case NAU8325_R50_MIXER_CTRL: |
| 152 | case NAU8325_R55_MISC_CTRL: |
| 153 | case NAU8325_R60_BIAS_ADJ ... NAU8325_R66_ANALOG_CONTROL_6: |
| 154 | case NAU8325_R69_CLIP_CTRL: |
| 155 | case NAU8325_R73_RDAC: |
| 156 | return true; |
| 157 | default: |
| 158 | return false; |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | static bool nau8325_volatile_reg(struct device *dev, unsigned int reg) |
| 163 | { |
| 164 | switch (reg) { |
| 165 | case NAU8325_R00_HARDWARE_RST ... NAU8325_R02_DEVICE_ID: |
| 166 | case NAU8325_R06_INT_CLR_STATUS: |
| 167 | case NAU8325_R1D_DEBUG_READ1: |
| 168 | case NAU8325_R1F_DEBUG_READ2: |
| 169 | case NAU8325_R22_DEBUG_READ3: |
| 170 | case NAU8325_R4A_ANALOG_READ: |
| 171 | return true; |
| 172 | default: |
| 173 | return false; |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | static const char * const nau8325_dac_oversampl_texts[] = { |
| 178 | "64" , "256" , "128" , "32" , |
| 179 | }; |
| 180 | |
| 181 | static const unsigned int nau8325_dac_oversampl_values[] = { |
| 182 | 0, 1, 2, 4, |
| 183 | }; |
| 184 | |
| 185 | static const struct soc_enum nau8325_dac_oversampl_enum = |
| 186 | SOC_VALUE_ENUM_SINGLE(NAU8325_R29_DAC_CTRL1, |
| 187 | NAU8325_DAC_OVERSAMPLE_SFT, 0x7, |
| 188 | ARRAY_SIZE(nau8325_dac_oversampl_texts), |
| 189 | nau8325_dac_oversampl_texts, |
| 190 | nau8325_dac_oversampl_values); |
| 191 | |
| 192 | static const DECLARE_TLV_DB_MINMAX_MUTE(dac_vol_tlv, -8000, 600); |
| 193 | |
| 194 | static const struct snd_kcontrol_new nau8325_snd_controls[] = { |
| 195 | SOC_ENUM("DAC Oversampling Rate" , nau8325_dac_oversampl_enum), |
| 196 | SOC_DOUBLE_TLV("Speaker Volume" , NAU8325_R13_DAC_VOLUME, |
| 197 | NAU8325_DAC_VOLUME_L_SFT, NAU8325_DAC_VOLUME_R_SFT, |
| 198 | NAU8325_DAC_VOLUME_R_EN, 0, dac_vol_tlv), |
| 199 | SOC_SINGLE("ALC Max Gain" , NAU8325_R2C_ALC_CTRL1, |
| 200 | NAU8325_ALC_MAXGAIN_SFT, NAU8325_ALC_MAXGAIN_MAX, 0), |
| 201 | SOC_SINGLE("ALC Min Gain" , NAU8325_R2C_ALC_CTRL1, |
| 202 | NAU8325_ALC_MINGAIN_SFT, NAU8325_ALC_MINGAIN_MAX, 0), |
| 203 | SOC_SINGLE("ALC Decay Timer" , NAU8325_R2D_ALC_CTRL2, |
| 204 | NAU8325_ALC_DCY_SFT, NAU8325_ALC_DCY_MAX, 0), |
| 205 | SOC_SINGLE("ALC Attack Timer" , NAU8325_R2D_ALC_CTRL2, |
| 206 | NAU8325_ALC_ATK_SFT, NAU8325_ALC_ATK_MAX, 0), |
| 207 | SOC_SINGLE("ALC Hold Time" , NAU8325_R2D_ALC_CTRL2, |
| 208 | NAU8325_ALC_HLD_SFT, NAU8325_ALC_HLD_MAX, 0), |
| 209 | SOC_SINGLE("ALC Target Level" , NAU8325_R2D_ALC_CTRL2, |
| 210 | NAU8325_ALC_LVL_SFT, NAU8325_ALC_LVL_MAX, 0), |
| 211 | SOC_SINGLE("ALC Enable Switch" , NAU8325_R2E_ALC_CTRL3, |
| 212 | NAU8325_ALC_EN_SFT, 1, 0), |
| 213 | }; |
| 214 | |
| 215 | static int nau8325_dac_event(struct snd_soc_dapm_widget *w, |
| 216 | struct snd_kcontrol *kcontrol, int event) |
| 217 | { |
| 218 | struct snd_soc_component *component = |
| 219 | snd_soc_dapm_to_component(dapm: w->dapm); |
| 220 | struct nau8325 *nau8325 = snd_soc_component_get_drvdata(c: component); |
| 221 | |
| 222 | switch (event) { |
| 223 | case SND_SOC_DAPM_POST_PMU: |
| 224 | regmap_update_bits(map: nau8325->regmap, NAU8325_R12_MUTE_CTRL, |
| 225 | NAU8325_SOFT_MUTE, val: 0); |
| 226 | msleep(msecs: 30); |
| 227 | break; |
| 228 | case SND_SOC_DAPM_PRE_PMD: |
| 229 | /* Soft mute the output to prevent the pop noise. */ |
| 230 | regmap_update_bits(map: nau8325->regmap, NAU8325_R12_MUTE_CTRL, |
| 231 | NAU8325_SOFT_MUTE, NAU8325_SOFT_MUTE); |
| 232 | msleep(msecs: 30); |
| 233 | break; |
| 234 | default: |
| 235 | return -EINVAL; |
| 236 | } |
| 237 | |
| 238 | return 0; |
| 239 | } |
| 240 | |
| 241 | static int nau8325_powerup_event(struct snd_soc_dapm_widget *w, |
| 242 | struct snd_kcontrol *kcontrol, int event) |
| 243 | { |
| 244 | struct snd_soc_component *component = |
| 245 | snd_soc_dapm_to_component(dapm: w->dapm); |
| 246 | struct nau8325 *nau8325 = snd_soc_component_get_drvdata(c: component); |
| 247 | |
| 248 | if (nau8325->clock_detection) |
| 249 | return 0; |
| 250 | |
| 251 | switch (event) { |
| 252 | case SND_SOC_DAPM_POST_PMU: |
| 253 | regmap_update_bits(map: nau8325->regmap, NAU8325_R40_CLK_DET_CTRL, |
| 254 | NAU8325_PWRUP_DFT, NAU8325_PWRUP_DFT); |
| 255 | break; |
| 256 | case SND_SOC_DAPM_POST_PMD: |
| 257 | regmap_update_bits(map: nau8325->regmap, NAU8325_R40_CLK_DET_CTRL, |
| 258 | NAU8325_PWRUP_DFT, val: 0); |
| 259 | break; |
| 260 | default: |
| 261 | return -EINVAL; |
| 262 | } |
| 263 | |
| 264 | return 0; |
| 265 | } |
| 266 | |
| 267 | static const struct snd_soc_dapm_widget nau8325_dapm_widgets[] = { |
| 268 | SND_SOC_DAPM_SUPPLY("Power Up" , SND_SOC_NOPM, 0, 0, |
| 269 | nau8325_powerup_event, SND_SOC_DAPM_POST_PMU | |
| 270 | SND_SOC_DAPM_POST_PMD), |
| 271 | SND_SOC_DAPM_DAC_E("DACL" , NULL, NAU8325_R04_ENA_CTRL, |
| 272 | NAU8325_DAC_LEFT_CH_EN_SFT, 0, nau8325_dac_event, |
| 273 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
| 274 | SND_SOC_DAPM_DAC_E("DACR" , NULL, NAU8325_R04_ENA_CTRL, |
| 275 | NAU8325_DAC_RIGHT_CH_EN_SFT, 0, nau8325_dac_event, |
| 276 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
| 277 | SND_SOC_DAPM_AIF_IN("AIFRX" , "Playback" , 0, SND_SOC_NOPM, 0, 0), |
| 278 | |
| 279 | SND_SOC_DAPM_OUTPUT("SPKL" ), |
| 280 | SND_SOC_DAPM_OUTPUT("SPKR" ), |
| 281 | }; |
| 282 | |
| 283 | static const struct snd_soc_dapm_route nau8325_dapm_routes[] = { |
| 284 | { "DACL" , NULL, "Power Up" }, |
| 285 | { "DACR" , NULL, "Power Up" }, |
| 286 | |
| 287 | { "DACL" , NULL, "AIFRX" }, |
| 288 | { "DACR" , NULL, "AIFRX" }, |
| 289 | { "SPKL" , NULL, "DACL" }, |
| 290 | { "SPKR" , NULL, "DACR" }, |
| 291 | }; |
| 292 | |
| 293 | static int nau8325_srate_clk_apply(struct nau8325 *nau8325, |
| 294 | const struct nau8325_srate_attr *srate_table, |
| 295 | int n1_sel, int mclk_mult_sel, int n2_sel) |
| 296 | { |
| 297 | if (!srate_table || n2_sel < 0 || n2_sel >= ARRAY_SIZE(mclk_n2_div) || |
| 298 | n1_sel < 0 || n1_sel >= ARRAY_SIZE(mclk_n1_div)) { |
| 299 | dev_dbg(nau8325->dev, "The CLK isn't supported." ); |
| 300 | return -EINVAL; |
| 301 | } |
| 302 | |
| 303 | regmap_update_bits(map: nau8325->regmap, NAU8325_R40_CLK_DET_CTRL, |
| 304 | NAU8325_REG_SRATE_MASK | NAU8325_REG_DIV_MAX, |
| 305 | val: (srate_table->range << NAU8325_REG_SRATE_SFT) | |
| 306 | (srate_table->max ? NAU8325_REG_DIV_MAX : 0)); |
| 307 | regmap_update_bits(map: nau8325->regmap, NAU8325_R03_CLK_CTRL, |
| 308 | NAU8325_MCLK_SRC_MASK, val: mclk_n2_div[n2_sel].val); |
| 309 | regmap_update_bits(map: nau8325->regmap, NAU8325_R03_CLK_CTRL, |
| 310 | NAU8325_CLK_MUL_SRC_MASK, |
| 311 | val: mclk_n1_div[n1_sel].val << NAU8325_CLK_MUL_SRC_SFT); |
| 312 | |
| 313 | if (mclk_mult_sel != CLK_PROC_BYPASS) { |
| 314 | regmap_update_bits(map: nau8325->regmap, NAU8325_R03_CLK_CTRL, |
| 315 | NAU8325_MCLK_SEL_MASK, |
| 316 | val: mclk_n3_mult[mclk_mult_sel].val << |
| 317 | NAU8325_MCLK_SEL_SFT); |
| 318 | } else { |
| 319 | regmap_update_bits(map: nau8325->regmap, NAU8325_R03_CLK_CTRL, |
| 320 | NAU8325_MCLK_SEL_MASK, val: 0); |
| 321 | } |
| 322 | |
| 323 | switch (mclk_mult_sel) { |
| 324 | case 2: |
| 325 | regmap_update_bits(map: nau8325->regmap, NAU8325_R65_ANALOG_CONTROL_5, |
| 326 | NAU8325_MCLK4XEN_EN, NAU8325_MCLK4XEN_EN); |
| 327 | break; |
| 328 | case 3: |
| 329 | regmap_update_bits(map: nau8325->regmap, NAU8325_R65_ANALOG_CONTROL_5, |
| 330 | NAU8325_MCLK4XEN_EN | NAU8325_MCLK8XEN_EN, |
| 331 | NAU8325_MCLK4XEN_EN | NAU8325_MCLK8XEN_EN); |
| 332 | break; |
| 333 | default: |
| 334 | regmap_update_bits(map: nau8325->regmap, NAU8325_R65_ANALOG_CONTROL_5, |
| 335 | NAU8325_MCLK4XEN_EN | NAU8325_MCLK8XEN_EN, val: 0); |
| 336 | break; |
| 337 | } |
| 338 | |
| 339 | return 0; |
| 340 | } |
| 341 | |
| 342 | static int nau8325_clksrc_n2(struct nau8325 *nau8325, |
| 343 | const struct nau8325_srate_attr *srate_table, |
| 344 | int mclk, int *n2_sel) |
| 345 | { |
| 346 | int i, mclk_src, ratio; |
| 347 | |
| 348 | ratio = NAU8325_MCLK_FS_RATIO_NUM; |
| 349 | for (i = 0; i < ARRAY_SIZE(mclk_n2_div); i++) { |
| 350 | mclk_src = mclk >> mclk_n2_div[i].param; |
| 351 | if (srate_table->mclk_src[NAU8325_MCLK_FS_RATIO_256] == mclk_src) { |
| 352 | ratio = NAU8325_MCLK_FS_RATIO_256; |
| 353 | break; |
| 354 | } else if (srate_table->mclk_src[NAU8325_MCLK_FS_RATIO_400] == mclk_src) { |
| 355 | ratio = NAU8325_MCLK_FS_RATIO_400; |
| 356 | break; |
| 357 | } else if (srate_table->mclk_src[NAU8325_MCLK_FS_RATIO_500] == mclk_src) { |
| 358 | ratio = NAU8325_MCLK_FS_RATIO_500; |
| 359 | break; |
| 360 | } |
| 361 | } |
| 362 | if (ratio != NAU8325_MCLK_FS_RATIO_NUM) |
| 363 | *n2_sel = i; |
| 364 | |
| 365 | return ratio; |
| 366 | } |
| 367 | |
| 368 | static const struct nau8325_srate_attr *target_srate_attribute(int srate) |
| 369 | { |
| 370 | int i; |
| 371 | |
| 372 | for (i = 0; i < ARRAY_SIZE(target_srate_table); i++) |
| 373 | if (target_srate_table[i].fs == srate) |
| 374 | break; |
| 375 | |
| 376 | if (i == ARRAY_SIZE(target_srate_table)) |
| 377 | goto proc_err; |
| 378 | |
| 379 | return &target_srate_table[i]; |
| 380 | |
| 381 | proc_err: |
| 382 | return NULL; |
| 383 | } |
| 384 | |
| 385 | static int nau8325_clksrc_choose(struct nau8325 *nau8325, |
| 386 | const struct nau8325_srate_attr **srate_table, |
| 387 | int *n1_sel, int *mult_sel, int *n2_sel) |
| 388 | { |
| 389 | int i, j, mclk, mclk_max, ratio, ratio_sel, n2_max; |
| 390 | |
| 391 | if (!nau8325->mclk || !nau8325->fs) |
| 392 | goto proc_err; |
| 393 | |
| 394 | /* select sampling rate and MCLK_SRC */ |
| 395 | *srate_table = target_srate_attribute(srate: nau8325->fs); |
| 396 | if (!*srate_table) |
| 397 | goto proc_err; |
| 398 | |
| 399 | /* First check clock from MCLK directly, decide N2 for MCLK_SRC. |
| 400 | * If not good, consider 1/N1 and Multiplier. |
| 401 | */ |
| 402 | ratio = nau8325_clksrc_n2(nau8325, srate_table: *srate_table, mclk: nau8325->mclk, n2_sel); |
| 403 | if (ratio != NAU8325_MCLK_FS_RATIO_NUM) { |
| 404 | *n1_sel = 0; |
| 405 | *mult_sel = CLK_PROC_BYPASS; |
| 406 | *n2_sel = MCLK_SRC; |
| 407 | goto proc_done; |
| 408 | } |
| 409 | |
| 410 | /* Get MCLK_SRC through 1/N, Multiplier, and then 1/N2. */ |
| 411 | mclk_max = 0; |
| 412 | for (i = 0; i < ARRAY_SIZE(mclk_n1_div); i++) { |
| 413 | for (j = 0; j < ARRAY_SIZE(mclk_n3_mult); j++) { |
| 414 | mclk = nau8325->mclk << mclk_n3_mult[j].param; |
| 415 | mclk = mclk / mclk_n1_div[i].param; |
| 416 | ratio = nau8325_clksrc_n2(nau8325, |
| 417 | srate_table: *srate_table, mclk, n2_sel); |
| 418 | if (ratio != NAU8325_MCLK_FS_RATIO_NUM && |
| 419 | (mclk_max < mclk || i > *n1_sel)) { |
| 420 | mclk_max = mclk; |
| 421 | n2_max = *n2_sel; |
| 422 | *n1_sel = i; |
| 423 | *mult_sel = j; |
| 424 | ratio_sel = ratio; |
| 425 | goto proc_done; |
| 426 | } |
| 427 | } |
| 428 | } |
| 429 | if (mclk_max) { |
| 430 | *n2_sel = n2_max; |
| 431 | ratio = ratio_sel; |
| 432 | goto proc_done; |
| 433 | } |
| 434 | |
| 435 | proc_err: |
| 436 | dev_dbg(nau8325->dev, "The MCLK %d is invalid. It can't get MCLK_SRC of 256/400/500 FS (%d)" , |
| 437 | nau8325->mclk, nau8325->fs); |
| 438 | return -EINVAL; |
| 439 | proc_done: |
| 440 | dev_dbg(nau8325->dev, "nau8325->fs=%d,range=0x%x, %s, (n1,mu,n2,dmu):(%d,%d,%d), MCLK_SRC=%uHz (%d)" , |
| 441 | nau8325->fs, (*srate_table)->range, |
| 442 | (*srate_table)->max ? "MAX" : "MIN" , |
| 443 | *n1_sel == CLK_PROC_BYPASS ? |
| 444 | CLK_PROC_BYPASS : mclk_n1_div[*n1_sel].param, |
| 445 | *mult_sel == CLK_PROC_BYPASS ? |
| 446 | CLK_PROC_BYPASS : 1 << mclk_n3_mult[*mult_sel].param, |
| 447 | 1 << mclk_n2_div[*n2_sel].param, |
| 448 | (*srate_table)->mclk_src[ratio], |
| 449 | (*srate_table)->mclk_src[ratio] / nau8325->fs); |
| 450 | |
| 451 | return 0; |
| 452 | } |
| 453 | |
| 454 | static int nau8325_clock_config(struct nau8325 *nau8325) |
| 455 | { |
| 456 | const struct nau8325_srate_attr *srate_table; |
| 457 | int ret, n1_sel, mult_sel, n2_sel; |
| 458 | |
| 459 | ret = nau8325_clksrc_choose(nau8325, srate_table: &srate_table, |
| 460 | n1_sel: &n1_sel, mult_sel: &mult_sel, n2_sel: &n2_sel); |
| 461 | if (ret) |
| 462 | goto err; |
| 463 | |
| 464 | ret = nau8325_srate_clk_apply(nau8325, srate_table, |
| 465 | n1_sel, mclk_mult_sel: mult_sel, n2_sel); |
| 466 | if (ret) |
| 467 | goto err; |
| 468 | |
| 469 | return 0; |
| 470 | err: |
| 471 | return ret; |
| 472 | } |
| 473 | |
| 474 | static const struct nau8325_osr_attr *nau8325_get_osr(struct nau8325 *nau8325) |
| 475 | { |
| 476 | unsigned int osr; |
| 477 | |
| 478 | regmap_read(map: nau8325->regmap, NAU8325_R29_DAC_CTRL1, val: &osr); |
| 479 | osr &= NAU8325_DAC_OVERSAMPLE_MASK; |
| 480 | if (osr >= ARRAY_SIZE(osr_dac_sel)) |
| 481 | return NULL; |
| 482 | |
| 483 | return &osr_dac_sel[osr]; |
| 484 | } |
| 485 | |
| 486 | static int nau8325_dai_startup(struct snd_pcm_substream *substream, |
| 487 | struct snd_soc_dai *dai) |
| 488 | { |
| 489 | struct snd_soc_component *component = dai->component; |
| 490 | struct nau8325 *nau8325 = snd_soc_component_get_drvdata(c: component); |
| 491 | const struct nau8325_osr_attr *osr; |
| 492 | |
| 493 | osr = nau8325_get_osr(nau8325); |
| 494 | if (!osr || !osr->osr) |
| 495 | return -EINVAL; |
| 496 | |
| 497 | return snd_pcm_hw_constraint_minmax(runtime: substream->runtime, |
| 498 | SNDRV_PCM_HW_PARAM_RATE, |
| 499 | min: 0, CLK_DA_AD_MAX / osr->osr); |
| 500 | } |
| 501 | |
| 502 | static int nau8325_hw_params(struct snd_pcm_substream *substream, |
| 503 | struct snd_pcm_hw_params *params, |
| 504 | struct snd_soc_dai *dai) |
| 505 | { |
| 506 | struct snd_soc_component *component = dai->component; |
| 507 | struct nau8325 *nau8325 = snd_soc_component_get_drvdata(c: component); |
| 508 | unsigned int val_len = 0; |
| 509 | const struct nau8325_osr_attr *osr; |
| 510 | int ret; |
| 511 | |
| 512 | nau8325->fs = params_rate(p: params); |
| 513 | osr = nau8325_get_osr(nau8325); |
| 514 | if (!osr || !osr->osr || nau8325->fs * osr->osr > CLK_DA_AD_MAX) { |
| 515 | ret = -EINVAL; |
| 516 | goto err; |
| 517 | } |
| 518 | regmap_update_bits(map: nau8325->regmap, NAU8325_R03_CLK_CTRL, |
| 519 | NAU8325_CLK_DAC_SRC_MASK, |
| 520 | val: osr->clk_src << NAU8325_CLK_DAC_SRC_SFT); |
| 521 | |
| 522 | ret = nau8325_clock_config(nau8325); |
| 523 | if (ret) |
| 524 | goto err; |
| 525 | |
| 526 | switch (params_width(p: params)) { |
| 527 | case 16: |
| 528 | val_len |= NAU8325_I2S_DL_16; |
| 529 | break; |
| 530 | case 20: |
| 531 | val_len |= NAU8325_I2S_DL_20; |
| 532 | break; |
| 533 | case 24: |
| 534 | val_len |= NAU8325_I2S_DL_24; |
| 535 | break; |
| 536 | case 32: |
| 537 | val_len |= NAU8325_I2S_DL_32; |
| 538 | break; |
| 539 | default: |
| 540 | ret = -EINVAL; |
| 541 | goto err; |
| 542 | } |
| 543 | |
| 544 | regmap_update_bits(map: nau8325->regmap, NAU8325_R0D_I2S_PCM_CTRL1, |
| 545 | NAU8325_I2S_DL_MASK, val: val_len); |
| 546 | |
| 547 | return 0; |
| 548 | |
| 549 | err: |
| 550 | return ret; |
| 551 | } |
| 552 | |
| 553 | static int nau8325_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
| 554 | { |
| 555 | struct snd_soc_component *component = dai->component; |
| 556 | struct nau8325 *nau8325 = snd_soc_component_get_drvdata(c: component); |
| 557 | unsigned int ctrl1_val = 0; |
| 558 | |
| 559 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
| 560 | case SND_SOC_DAIFMT_CBC_CFC: |
| 561 | break; |
| 562 | default: |
| 563 | return -EINVAL; |
| 564 | } |
| 565 | |
| 566 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
| 567 | case SND_SOC_DAIFMT_NB_NF: |
| 568 | break; |
| 569 | case SND_SOC_DAIFMT_IB_NF: |
| 570 | ctrl1_val |= NAU8325_I2S_BP_INV; |
| 571 | break; |
| 572 | default: |
| 573 | return -EINVAL; |
| 574 | } |
| 575 | |
| 576 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
| 577 | case SND_SOC_DAIFMT_I2S: |
| 578 | ctrl1_val |= NAU8325_I2S_DF_I2S; |
| 579 | break; |
| 580 | case SND_SOC_DAIFMT_LEFT_J: |
| 581 | ctrl1_val |= NAU8325_I2S_DF_LEFT; |
| 582 | break; |
| 583 | case SND_SOC_DAIFMT_RIGHT_J: |
| 584 | ctrl1_val |= NAU8325_I2S_DF_RIGTH; |
| 585 | break; |
| 586 | case SND_SOC_DAIFMT_DSP_A: |
| 587 | ctrl1_val |= NAU8325_I2S_DF_PCM_AB; |
| 588 | break; |
| 589 | case SND_SOC_DAIFMT_DSP_B: |
| 590 | ctrl1_val |= NAU8325_I2S_DF_PCM_AB; |
| 591 | ctrl1_val |= NAU8325_I2S_PCMB_EN; |
| 592 | break; |
| 593 | default: |
| 594 | return -EINVAL; |
| 595 | } |
| 596 | |
| 597 | regmap_update_bits(map: nau8325->regmap, NAU8325_R0D_I2S_PCM_CTRL1, |
| 598 | NAU8325_I2S_DF_MASK | NAU8325_I2S_BP_MASK | |
| 599 | NAU8325_I2S_PCMB_EN, val: ctrl1_val); |
| 600 | |
| 601 | return 0; |
| 602 | } |
| 603 | |
| 604 | static int nau8325_set_sysclk(struct snd_soc_component *component, int clk_id, |
| 605 | int source, unsigned int freq, int dir) |
| 606 | { |
| 607 | struct nau8325 *nau8325 = snd_soc_component_get_drvdata(c: component); |
| 608 | |
| 609 | if (freq < MASTER_CLK_MIN || freq > MASTER_CLK_MAX) { |
| 610 | dev_dbg(nau8325->dev, "MCLK exceeds the range, MCLK:%d" , freq); |
| 611 | return -EINVAL; |
| 612 | } |
| 613 | |
| 614 | nau8325->mclk = freq; |
| 615 | dev_dbg(nau8325->dev, "MCLK %dHz" , nau8325->mclk); |
| 616 | |
| 617 | return 0; |
| 618 | } |
| 619 | |
| 620 | static const struct snd_soc_component_driver nau8325_component_driver = { |
| 621 | .set_sysclk = nau8325_set_sysclk, |
| 622 | .suspend_bias_off = true, |
| 623 | .controls = nau8325_snd_controls, |
| 624 | .num_controls = ARRAY_SIZE(nau8325_snd_controls), |
| 625 | .dapm_widgets = nau8325_dapm_widgets, |
| 626 | .num_dapm_widgets = ARRAY_SIZE(nau8325_dapm_widgets), |
| 627 | .dapm_routes = nau8325_dapm_routes, |
| 628 | .num_dapm_routes = ARRAY_SIZE(nau8325_dapm_routes), |
| 629 | }; |
| 630 | |
| 631 | static const struct snd_soc_dai_ops nau8325_dai_ops = { |
| 632 | .startup = nau8325_dai_startup, |
| 633 | .hw_params = nau8325_hw_params, |
| 634 | .set_fmt = nau8325_set_fmt, |
| 635 | }; |
| 636 | |
| 637 | #define NAU8325_RATES SNDRV_PCM_RATE_8000_96000 |
| 638 | #define NAU8325_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ |
| 639 | | SNDRV_PCM_FMTBIT_S24_3LE) |
| 640 | |
| 641 | static struct snd_soc_dai_driver nau8325_dai = { |
| 642 | .name = NAU8325_CODEC_DAI, |
| 643 | .playback = { |
| 644 | .stream_name = "Playback" , |
| 645 | .channels_min = 1, |
| 646 | .channels_max = 2, |
| 647 | .rates = NAU8325_RATES, |
| 648 | .formats = NAU8325_FORMATS, |
| 649 | }, |
| 650 | .ops = &nau8325_dai_ops, |
| 651 | }; |
| 652 | |
| 653 | static const struct regmap_config nau8325_regmap_config = { |
| 654 | .reg_bits = NAU8325_REG_ADDR_LEN, |
| 655 | .val_bits = NAU8325_REG_DATA_LEN, |
| 656 | |
| 657 | .max_register = NAU8325_REG_MAX, |
| 658 | .readable_reg = nau8325_readable_reg, |
| 659 | .writeable_reg = nau8325_writeable_reg, |
| 660 | .volatile_reg = nau8325_volatile_reg, |
| 661 | |
| 662 | .cache_type = REGCACHE_RBTREE, |
| 663 | .reg_defaults = nau8325_reg_defaults, |
| 664 | .num_reg_defaults = ARRAY_SIZE(nau8325_reg_defaults), |
| 665 | }; |
| 666 | |
| 667 | static void nau8325_reset_chip(struct regmap *regmap) |
| 668 | { |
| 669 | regmap_write(map: regmap, NAU8325_R00_HARDWARE_RST, val: 0x0001); |
| 670 | regmap_write(map: regmap, NAU8325_R00_HARDWARE_RST, val: 0x0000); |
| 671 | } |
| 672 | |
| 673 | static void nau8325_init_regs(struct nau8325 *nau8325) |
| 674 | { |
| 675 | struct regmap *regmap = nau8325->regmap; |
| 676 | struct device *dev = nau8325->dev; |
| 677 | |
| 678 | /* set ALC parameters */ |
| 679 | regmap_update_bits(map: regmap, NAU8325_R2C_ALC_CTRL1, |
| 680 | NAU8325_ALC_MAXGAIN_MASK, |
| 681 | val: 0x7 << NAU8325_ALC_MAXGAIN_SFT); |
| 682 | regmap_update_bits(map: regmap, NAU8325_R2D_ALC_CTRL2, |
| 683 | NAU8325_ALC_DCY_MASK | NAU8325_ALC_ATK_MASK | |
| 684 | NAU8325_ALC_HLD_MASK, val: (0x5 << NAU8325_ALC_DCY_SFT) | |
| 685 | (0x3 << NAU8325_ALC_ATK_SFT) | |
| 686 | (0x5 << NAU8325_ALC_HLD_SFT)); |
| 687 | /* Enable ALC to avoid signal distortion when battery low. */ |
| 688 | if (nau8325->alc_enable) |
| 689 | regmap_update_bits(map: regmap, NAU8325_R2E_ALC_CTRL3, |
| 690 | NAU8325_ALC_EN, NAU8325_ALC_EN); |
| 691 | if (nau8325->clock_detection) |
| 692 | regmap_update_bits(map: regmap, NAU8325_R40_CLK_DET_CTRL, |
| 693 | NAU8325_CLKPWRUP_DIS | |
| 694 | NAU8325_PWRUP_DFT, val: 0); |
| 695 | else |
| 696 | regmap_update_bits(map: regmap, NAU8325_R40_CLK_DET_CTRL, |
| 697 | NAU8325_CLKPWRUP_DIS | NAU8325_PWRUP_DFT, |
| 698 | NAU8325_CLKPWRUP_DIS); |
| 699 | if (nau8325->clock_det_data) |
| 700 | regmap_update_bits(map: regmap, NAU8325_R40_CLK_DET_CTRL, |
| 701 | NAU8325_APWRUP_EN, NAU8325_APWRUP_EN); |
| 702 | else |
| 703 | regmap_update_bits(map: regmap, NAU8325_R40_CLK_DET_CTRL, |
| 704 | NAU8325_APWRUP_EN, val: 0); |
| 705 | |
| 706 | /* DAC Reference Voltage Setting */ |
| 707 | switch (nau8325->dac_vref_microvolt) { |
| 708 | case 1800000: |
| 709 | regmap_update_bits(map: regmap, NAU8325_R73_RDAC, |
| 710 | NAU8325_DACVREFSEL_MASK, val: 0 << NAU8325_DACVREFSEL_SFT); |
| 711 | break; |
| 712 | case 2700000: |
| 713 | regmap_update_bits(map: regmap, NAU8325_R73_RDAC, |
| 714 | NAU8325_DACVREFSEL_MASK, val: 1 << NAU8325_DACVREFSEL_SFT); |
| 715 | break; |
| 716 | case 2880000: |
| 717 | regmap_update_bits(map: regmap, NAU8325_R73_RDAC, |
| 718 | NAU8325_DACVREFSEL_MASK, val: 2 << NAU8325_DACVREFSEL_SFT); |
| 719 | break; |
| 720 | case 3060000: |
| 721 | regmap_update_bits(map: regmap, NAU8325_R73_RDAC, |
| 722 | NAU8325_DACVREFSEL_MASK, val: 3 << NAU8325_DACVREFSEL_SFT); |
| 723 | break; |
| 724 | default: |
| 725 | dev_dbg(dev, "Invalid dac-vref-microvolt %d" , nau8325->dac_vref_microvolt); |
| 726 | |
| 727 | } |
| 728 | |
| 729 | /* DAC Reference Voltage Decoupling Capacitors. */ |
| 730 | regmap_update_bits(map: regmap, NAU8325_R63_ANALOG_CONTROL_3, |
| 731 | NAU8325_CLASSD_COARSE_GAIN_MASK, val: 0x4); |
| 732 | /* Auto-Att Min Gain 0dB, Class-D N Driver Slew Rate -25%. */ |
| 733 | regmap_update_bits(map: regmap, NAU8325_R64_ANALOG_CONTROL_4, |
| 734 | NAU8325_CLASSD_SLEWN_MASK, val: 0x7); |
| 735 | |
| 736 | /* VMID Tieoff (VMID Resistor Selection) */ |
| 737 | switch (nau8325->vref_impedance_ohms) { |
| 738 | case 0: |
| 739 | regmap_update_bits(map: regmap, NAU8325_R60_BIAS_ADJ, |
| 740 | NAU8325_BIAS_VMID_SEL_MASK, val: 0 << NAU8325_BIAS_VMID_SEL_SFT); |
| 741 | break; |
| 742 | case 25000: |
| 743 | regmap_update_bits(map: regmap, NAU8325_R60_BIAS_ADJ, |
| 744 | NAU8325_BIAS_VMID_SEL_MASK, val: 1 << NAU8325_BIAS_VMID_SEL_SFT); |
| 745 | break; |
| 746 | case 125000: |
| 747 | regmap_update_bits(map: regmap, NAU8325_R60_BIAS_ADJ, |
| 748 | NAU8325_BIAS_VMID_SEL_MASK, val: 2 << NAU8325_BIAS_VMID_SEL_SFT); |
| 749 | break; |
| 750 | case 2500: |
| 751 | regmap_update_bits(map: regmap, NAU8325_R60_BIAS_ADJ, |
| 752 | NAU8325_BIAS_VMID_SEL_MASK, val: 3 << NAU8325_BIAS_VMID_SEL_SFT); |
| 753 | break; |
| 754 | default: |
| 755 | dev_dbg(dev, "Invalid vref-impedance-ohms %d" , nau8325->vref_impedance_ohms); |
| 756 | } |
| 757 | |
| 758 | |
| 759 | /* enable VMID, BIAS, DAC, DCA CLOCK, Voltage/Current Amps |
| 760 | */ |
| 761 | regmap_update_bits(map: regmap, NAU8325_R61_ANALOG_CONTROL_1, |
| 762 | NAU8325_DACEN_MASK | NAU8325_DACCLKEN_MASK | |
| 763 | NAU8325_DACEN_R_MASK | NAU8325_DACCLKEN_R_MASK | |
| 764 | NAU8325_CLASSDEN_MASK | NAU8325_VMDFSTENB_MASK | |
| 765 | NAU8325_BIASEN_MASK | NAU8325_VMIDEN_MASK, |
| 766 | val: (0x1 << NAU8325_DACEN_SFT) | |
| 767 | (0x1 << NAU8325_DACCLKEN_SFT) | |
| 768 | (0x1 << NAU8325_DACEN_R_SFT) | |
| 769 | (0x1 << NAU8325_DACCLKEN_R_SFT) | |
| 770 | (0x1 << NAU8325_CLASSDEN_SFT) | |
| 771 | (0x1 << NAU8325_VMDFSTENB_SFT) | |
| 772 | (0x1 << NAU8325_BIASEN_SFT) | 0x3); |
| 773 | |
| 774 | /* Enable ALC to avoid signal distortion when battery low. */ |
| 775 | if (nau8325->alc_enable) |
| 776 | regmap_update_bits(map: regmap, NAU8325_R2E_ALC_CTRL3, |
| 777 | NAU8325_ALC_EN, NAU8325_ALC_EN); |
| 778 | if (nau8325->clock_det_data) |
| 779 | regmap_update_bits(map: regmap, NAU8325_R40_CLK_DET_CTRL, |
| 780 | NAU8325_APWRUP_EN, NAU8325_APWRUP_EN); |
| 781 | else |
| 782 | regmap_update_bits(map: regmap, NAU8325_R40_CLK_DET_CTRL, |
| 783 | NAU8325_APWRUP_EN, val: 0); |
| 784 | if (nau8325->clock_detection) |
| 785 | regmap_update_bits(map: regmap, NAU8325_R40_CLK_DET_CTRL, |
| 786 | NAU8325_CLKPWRUP_DIS | |
| 787 | NAU8325_PWRUP_DFT, val: 0); |
| 788 | else |
| 789 | regmap_update_bits(map: regmap, NAU8325_R40_CLK_DET_CTRL, |
| 790 | NAU8325_CLKPWRUP_DIS | NAU8325_PWRUP_DFT, |
| 791 | NAU8325_CLKPWRUP_DIS); |
| 792 | regmap_update_bits(map: regmap, NAU8325_R29_DAC_CTRL1, |
| 793 | NAU8325_DAC_OVERSAMPLE_MASK, |
| 794 | NAU8325_DAC_OVERSAMPLE_128); |
| 795 | } |
| 796 | |
| 797 | static void nau8325_print_device_properties(struct nau8325 *nau8325) |
| 798 | { |
| 799 | struct device *dev = nau8325->dev; |
| 800 | |
| 801 | dev_dbg(dev, "vref-impedance-ohms: %d" , nau8325->vref_impedance_ohms); |
| 802 | dev_dbg(dev, "dac-vref-microvolt: %d" , nau8325->dac_vref_microvolt); |
| 803 | dev_dbg(dev, "alc-enable: %d" , nau8325->alc_enable); |
| 804 | dev_dbg(dev, "clock-det-data: %d" , nau8325->clock_det_data); |
| 805 | dev_dbg(dev, "clock-detection-disable: %d" , nau8325->clock_detection); |
| 806 | } |
| 807 | |
| 808 | static int nau8325_read_device_properties(struct device *dev, |
| 809 | struct nau8325 *nau8325) |
| 810 | { |
| 811 | int ret; |
| 812 | |
| 813 | nau8325->alc_enable = |
| 814 | device_property_read_bool(dev, propname: "nuvoton,alc-enable" ); |
| 815 | nau8325->clock_det_data = |
| 816 | device_property_read_bool(dev, propname: "nuvoton,clock-det-data" ); |
| 817 | nau8325->clock_detection = |
| 818 | !device_property_read_bool(dev, propname: "nuvoton,clock-detection-disable" ); |
| 819 | |
| 820 | ret = device_property_read_u32(dev, propname: "nuvoton,vref-impedance-ohms" , |
| 821 | val: &nau8325->vref_impedance_ohms); |
| 822 | if (ret) |
| 823 | nau8325->vref_impedance_ohms = 125000; |
| 824 | ret = device_property_read_u32(dev, propname: "nuvoton,dac-vref-microvolt" , |
| 825 | val: &nau8325->dac_vref_microvolt); |
| 826 | if (ret) |
| 827 | nau8325->dac_vref_microvolt = 2880000; |
| 828 | |
| 829 | return 0; |
| 830 | } |
| 831 | |
| 832 | static int nau8325_i2c_probe(struct i2c_client *i2c, |
| 833 | const struct i2c_device_id *id) |
| 834 | { |
| 835 | struct device *dev = &i2c->dev; |
| 836 | struct nau8325 *nau8325 = dev_get_platdata(dev); |
| 837 | int ret, value; |
| 838 | |
| 839 | if (!nau8325) { |
| 840 | nau8325 = devm_kzalloc(dev, size: sizeof(*nau8325), GFP_KERNEL); |
| 841 | if (!nau8325) { |
| 842 | ret = -ENOMEM; |
| 843 | goto err; |
| 844 | } |
| 845 | ret = nau8325_read_device_properties(dev, nau8325); |
| 846 | if (ret) |
| 847 | goto err; |
| 848 | } |
| 849 | i2c_set_clientdata(client: i2c, data: nau8325); |
| 850 | |
| 851 | nau8325->regmap = devm_regmap_init_i2c(i2c, &nau8325_regmap_config); |
| 852 | if (IS_ERR(ptr: nau8325->regmap)) { |
| 853 | ret = PTR_ERR(ptr: nau8325->regmap); |
| 854 | goto err; |
| 855 | } |
| 856 | nau8325->dev = dev; |
| 857 | nau8325_print_device_properties(nau8325); |
| 858 | |
| 859 | nau8325_reset_chip(regmap: nau8325->regmap); |
| 860 | ret = regmap_read(map: nau8325->regmap, NAU8325_R02_DEVICE_ID, val: &value); |
| 861 | if (ret) { |
| 862 | dev_dbg(dev, "Failed to read device id (%d)" , ret); |
| 863 | goto err; |
| 864 | } |
| 865 | nau8325_init_regs(nau8325); |
| 866 | |
| 867 | ret = devm_snd_soc_register_component(dev, component_driver: &nau8325_component_driver, |
| 868 | dai_drv: &nau8325_dai, num_dai: 1); |
| 869 | err: |
| 870 | return ret; |
| 871 | } |
| 872 | |
| 873 | static const struct i2c_device_id nau8325_i2c_ids[] = { |
| 874 | { "nau8325" }, |
| 875 | { } |
| 876 | }; |
| 877 | MODULE_DEVICE_TABLE(i2c, nau8325_i2c_ids); |
| 878 | |
| 879 | #ifdef CONFIG_OF |
| 880 | static const struct of_device_id nau8325_of_ids[] = { |
| 881 | { .compatible = "nuvoton,nau8325" , }, |
| 882 | {} |
| 883 | }; |
| 884 | MODULE_DEVICE_TABLE(of, nau8325_of_ids); |
| 885 | #endif |
| 886 | |
| 887 | static struct i2c_driver nau8325_i2c_driver = { |
| 888 | .driver = { |
| 889 | .name = "nau8325" , |
| 890 | .of_match_table = of_match_ptr(nau8325_of_ids), |
| 891 | }, |
| 892 | .probe = nau8325_i2c_probe, |
| 893 | .id_table = nau8325_i2c_ids, |
| 894 | }; |
| 895 | module_i2c_driver(nau8325_i2c_driver); |
| 896 | |
| 897 | MODULE_DESCRIPTION("ASoC NAU8325 driver" ); |
| 898 | MODULE_AUTHOR("Seven Lee <WTLI@nuvoton.com>" ); |
| 899 | MODULE_AUTHOR("David Lin <CTLIN0@nuvoton.com>" ); |
| 900 | MODULE_LICENSE("GPL" ); |
| 901 | |