1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // CS530x CODEC driver 4 // 5 // Copyright (C) 2024 Cirrus Logic, Inc. and 6 // Cirrus Logic International Semiconductor Ltd. 7 8 #include <sound/core.h> 9 #include <linux/delay.h> 10 #include <linux/i2c.h> 11 #include <linux/init.h> 12 #include <sound/initval.h> 13 #include <linux/module.h> 14 #include <sound/pcm.h> 15 #include <sound/pcm_params.h> 16 #include <linux/pm.h> 17 #include <linux/property.h> 18 #include <linux/slab.h> 19 #include <sound/soc.h> 20 #include <sound/tlv.h> 21 22 #include "cs530x.h" 23 24 #define CS530X_MAX_ADC_CH 8 25 #define CS530X_MIN_ADC_CH 2 26 27 static const char *cs530x_supply_names[CS530X_NUM_SUPPLIES] = { 28 "vdd-a", 29 "vdd-io", 30 }; 31 32 static const struct reg_default cs530x_reg_defaults[] = { 33 { CS530X_CLK_CFG_0, 0x30 }, 34 { CS530X_CLK_CFG_1, 0x0001 }, 35 { CS530X_CHIP_ENABLE, 0 }, 36 { CS530X_ASP_CFG, 0 }, 37 { CS530X_SIGNAL_PATH_CFG, 0 }, 38 { CS530X_IN_ENABLES, 0 }, 39 { CS530X_IN_RAMP_SUM, 0x0022 }, 40 { CS530X_IN_FILTER, 0 }, 41 { CS530X_IN_HIZ, 0 }, 42 { CS530X_IN_INV, 0 }, 43 { CS530X_IN_VOL_CTRL1_0, 0x8000 }, 44 { CS530X_IN_VOL_CTRL1_1, 0x8000 }, 45 { CS530X_IN_VOL_CTRL2_0, 0x8000 }, 46 { CS530X_IN_VOL_CTRL2_1, 0x8000 }, 47 { CS530X_IN_VOL_CTRL3_0, 0x8000 }, 48 { CS530X_IN_VOL_CTRL3_1, 0x8000 }, 49 { CS530X_IN_VOL_CTRL4_0, 0x8000 }, 50 { CS530X_IN_VOL_CTRL4_1, 0x8000 }, 51 { CS530X_PAD_FN, 0 }, 52 { CS530X_PAD_LVL, 0 }, 53 }; 54 55 static bool cs530x_read_and_write_regs(unsigned int reg) 56 { 57 switch (reg) { 58 case CS530X_CLK_CFG_0: 59 case CS530X_CLK_CFG_1: 60 case CS530X_CHIP_ENABLE: 61 case CS530X_ASP_CFG: 62 case CS530X_SIGNAL_PATH_CFG: 63 case CS530X_IN_ENABLES: 64 case CS530X_IN_RAMP_SUM: 65 case CS530X_IN_FILTER: 66 case CS530X_IN_HIZ: 67 case CS530X_IN_INV: 68 case CS530X_IN_VOL_CTRL1_0: 69 case CS530X_IN_VOL_CTRL1_1: 70 case CS530X_IN_VOL_CTRL2_0: 71 case CS530X_IN_VOL_CTRL2_1: 72 case CS530X_IN_VOL_CTRL3_0: 73 case CS530X_IN_VOL_CTRL3_1: 74 case CS530X_IN_VOL_CTRL4_0: 75 case CS530X_IN_VOL_CTRL4_1: 76 case CS530X_PAD_FN: 77 case CS530X_PAD_LVL: 78 return true; 79 default: 80 return false; 81 } 82 } 83 84 static bool cs530x_readable_register(struct device *dev, unsigned int reg) 85 { 86 switch (reg) { 87 case CS530X_DEVID: 88 case CS530X_REVID: 89 return true; 90 default: 91 return cs530x_read_and_write_regs(reg); 92 } 93 } 94 95 static bool cs530x_writeable_register(struct device *dev, unsigned int reg) 96 { 97 switch (reg) { 98 case CS530X_SW_RESET: 99 case CS530X_IN_VOL_CTRL5: 100 return true; 101 default: 102 return cs530x_read_and_write_regs(reg); 103 } 104 } 105 106 static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol, 107 struct snd_ctl_elem_value *ucontrol) 108 { 109 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 110 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 111 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 112 struct regmap *regmap = cs530x->regmap; 113 int ret; 114 115 snd_soc_dapm_mutex_lock(dapm); 116 117 ret = snd_soc_put_volsw(kcontrol, ucontrol); 118 if (ret) 119 goto volsw_err; 120 121 /* Write IN_VU bit for the volume change to take effect */ 122 regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_IN_VU); 123 124 volsw_err: 125 snd_soc_dapm_mutex_unlock(dapm); 126 127 return ret; 128 } 129 130 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0); 131 132 static const char * const cs530x_in_filter_text[] = { 133 "Min Phase Slow Roll-off", 134 "Min Phase Fast Roll-off", 135 "Linear Phase Slow Roll-off", 136 "Linear Phase Fast Roll-off", 137 }; 138 139 static SOC_ENUM_SINGLE_DECL(cs530x_in_filter_enum, CS530X_IN_FILTER, 140 CS530X_IN_FILTER_SHIFT, 141 cs530x_in_filter_text); 142 143 static const char * const cs530x_in_4ch_sum_text[] = { 144 "None", 145 "Groups of 2", 146 "Groups of 4", 147 }; 148 149 static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch4_enum, CS530X_IN_RAMP_SUM, 150 CS530X_IN_SUM_MODE_SHIFT, 151 cs530x_in_4ch_sum_text); 152 153 static const struct snd_kcontrol_new cs530x_in_sum_4ch_controls[] = { 154 SOC_ENUM("IN Sum Select", cs530x_in_sum_ch4_enum), 155 }; 156 157 static const char * const cs530x_in_8ch_sum_text[] = { 158 "None", 159 "Groups of 2", 160 "Groups of 4", 161 "Groups of 8", 162 }; 163 164 static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM, 165 CS530X_IN_SUM_MODE_SHIFT, 166 cs530x_in_8ch_sum_text); 167 168 static const struct snd_kcontrol_new cs530x_in_sum_8ch_controls[] = { 169 SOC_ENUM("IN Sum Select", cs530x_in_sum_ch8_enum), 170 }; 171 172 173 static const char * const cs530x_vol_ramp_text[] = { 174 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", 175 "15ms/6dB", "30ms/6dB", 176 }; 177 178 static SOC_ENUM_SINGLE_DECL(cs530x_ramp_inc_enum, CS530X_IN_RAMP_SUM, 179 CS530X_RAMP_RATE_INC_SHIFT, 180 cs530x_vol_ramp_text); 181 182 static SOC_ENUM_SINGLE_DECL(cs530x_ramp_dec_enum, CS530X_IN_RAMP_SUM, 183 CS530X_RAMP_RATE_DEC_SHIFT, 184 cs530x_vol_ramp_text); 185 186 static const struct snd_kcontrol_new cs530x_in_1_to_2_controls[] = { 187 SOC_SINGLE_EXT_TLV("IN1 Volume", CS530X_IN_VOL_CTRL1_0, 0, 255, 1, 188 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 189 SOC_SINGLE_EXT_TLV("IN2 Volume", CS530X_IN_VOL_CTRL1_1, 0, 255, 1, 190 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 191 192 SOC_ENUM("IN DEC Filter Select", cs530x_in_filter_enum), 193 SOC_ENUM("Input Ramp Up", cs530x_ramp_inc_enum), 194 SOC_ENUM("Input Ramp Down", cs530x_ramp_dec_enum), 195 196 SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_IN1_INV_SHIFT, 1, 0), 197 SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_IN2_INV_SHIFT, 1, 0), 198 }; 199 200 static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = { 201 SOC_SINGLE_EXT_TLV("IN3 Volume", CS530X_IN_VOL_CTRL2_0, 0, 255, 1, 202 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 203 SOC_SINGLE_EXT_TLV("IN4 Volume", CS530X_IN_VOL_CTRL2_1, 0, 255, 1, 204 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 205 206 SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_IN3_INV_SHIFT, 1, 0), 207 SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_IN4_INV_SHIFT, 1, 0), 208 }; 209 210 static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = { 211 SOC_SINGLE_EXT_TLV("IN5 Volume", CS530X_IN_VOL_CTRL3_0, 0, 255, 1, 212 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 213 SOC_SINGLE_EXT_TLV("IN6 Volume", CS530X_IN_VOL_CTRL3_1, 0, 255, 1, 214 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 215 SOC_SINGLE_EXT_TLV("IN7 Volume", CS530X_IN_VOL_CTRL4_0, 0, 255, 1, 216 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 217 SOC_SINGLE_EXT_TLV("IN8 Volume", CS530X_IN_VOL_CTRL4_1, 0, 255, 1, 218 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 219 220 SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_IN5_INV_SHIFT, 1, 0), 221 SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_IN6_INV_SHIFT, 1, 0), 222 SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_IN7_INV_SHIFT, 1, 0), 223 SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_IN8_INV_SHIFT, 1, 0), 224 }; 225 226 static int cs530x_adc_event(struct snd_soc_dapm_widget *w, 227 struct snd_kcontrol *kcontrol, int event) 228 { 229 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 230 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 231 struct regmap *regmap = cs530x->regmap; 232 233 switch (event) { 234 case SND_SOC_DAPM_PRE_PMU: 235 cs530x->adc_pairs_count++; 236 break; 237 case SND_SOC_DAPM_POST_PMU: 238 regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + 239 (w->shift * 2), CS530X_IN_MUTE); 240 regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + 241 ((w->shift+1) * 2), CS530X_IN_MUTE); 242 243 cs530x->adc_pairs_count--; 244 if (!cs530x->adc_pairs_count) { 245 usleep_range(1000, 1100); 246 return regmap_write(regmap, CS530X_IN_VOL_CTRL5, 247 CS530X_IN_VU); 248 } 249 break; 250 case SND_SOC_DAPM_PRE_PMD: 251 regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + 252 (w->shift * 2), CS530X_IN_MUTE); 253 regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + 254 ((w->shift+1) * 2), CS530X_IN_MUTE); 255 return regmap_write(regmap, CS530X_IN_VOL_CTRL5, 256 CS530X_IN_VU); 257 default: 258 return -EINVAL; 259 } 260 261 return 0; 262 } 263 264 static const struct snd_kcontrol_new adc12_ctrl = 265 SOC_DAPM_SINGLE_VIRT("Switch", 1); 266 267 static const struct snd_kcontrol_new adc34_ctrl = 268 SOC_DAPM_SINGLE_VIRT("Switch", 1); 269 270 static const struct snd_kcontrol_new adc56_ctrl = 271 SOC_DAPM_SINGLE_VIRT("Switch", 1); 272 273 static const struct snd_kcontrol_new adc78_ctrl = 274 SOC_DAPM_SINGLE_VIRT("Switch", 1); 275 276 static const struct snd_kcontrol_new in_hpf_ctrl = 277 SOC_DAPM_SINGLE_VIRT("Switch", 1); 278 279 /* General DAPM widgets for all devices */ 280 static const struct snd_soc_dapm_widget cs530x_gen_dapm_widgets[] = { 281 SND_SOC_DAPM_SUPPLY("Global Enable", CS530X_CHIP_ENABLE, 0, 0, NULL, 0), 282 }; 283 284 /* ADC's Channels 1 and 2 plus generic ADC DAPM events */ 285 static const struct snd_soc_dapm_widget cs530x_adc_ch12_dapm_widgets[] = { 286 SND_SOC_DAPM_INPUT("IN1"), 287 SND_SOC_DAPM_INPUT("IN2"), 288 SND_SOC_DAPM_ADC_E("ADC1", NULL, CS530X_IN_ENABLES, 0, 0, 289 cs530x_adc_event, 290 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | 291 SND_SOC_DAPM_PRE_PMU), 292 SND_SOC_DAPM_ADC("ADC2", NULL, CS530X_IN_ENABLES, 1, 0), 293 SND_SOC_DAPM_SWITCH("ADC12 Enable", SND_SOC_NOPM, 0, 0, &adc12_ctrl), 294 SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_IN_HPF_EN_SHIFT, 295 0, &in_hpf_ctrl), 296 }; 297 298 /* ADC's Channels 3 and 4 */ 299 static const struct snd_soc_dapm_widget cs530x_adc_ch34_dapm_widgets[] = { 300 SND_SOC_DAPM_INPUT("IN3"), 301 SND_SOC_DAPM_INPUT("IN4"), 302 SND_SOC_DAPM_ADC_E("ADC3", NULL, CS530X_IN_ENABLES, 2, 0, 303 cs530x_adc_event, 304 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | 305 SND_SOC_DAPM_PRE_PMU), 306 SND_SOC_DAPM_ADC("ADC4", NULL, CS530X_IN_ENABLES, 3, 0), 307 SND_SOC_DAPM_SWITCH("ADC34 Enable", SND_SOC_NOPM, 0, 0, &adc34_ctrl), 308 }; 309 310 /* ADC's Channels 5 to 8 */ 311 static const struct snd_soc_dapm_widget cs530x_adc_ch58_dapm_widgets[] = { 312 SND_SOC_DAPM_INPUT("IN5"), 313 SND_SOC_DAPM_INPUT("IN6"), 314 SND_SOC_DAPM_INPUT("IN7"), 315 SND_SOC_DAPM_INPUT("IN8"), 316 SND_SOC_DAPM_ADC_E("ADC5", NULL, CS530X_IN_ENABLES, 4, 0, 317 cs530x_adc_event, 318 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | 319 SND_SOC_DAPM_PRE_PMU), 320 SND_SOC_DAPM_ADC("ADC6", NULL, CS530X_IN_ENABLES, 5, 0), 321 SND_SOC_DAPM_SWITCH("ADC56 Enable", SND_SOC_NOPM, 0, 0, &adc56_ctrl), 322 SND_SOC_DAPM_ADC_E("ADC7", NULL, CS530X_IN_ENABLES, 6, 0, 323 cs530x_adc_event, 324 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | 325 SND_SOC_DAPM_PRE_PMU), 326 SND_SOC_DAPM_ADC("ADC8", NULL, CS530X_IN_ENABLES, 7, 0), 327 SND_SOC_DAPM_SWITCH("ADC78 Enable", SND_SOC_NOPM, 0, 0, &adc78_ctrl), 328 }; 329 330 static const struct snd_soc_dapm_route adc_ch1_2_routes[] = { 331 { "ADC1", NULL, "Global Enable" }, 332 { "ADC2", NULL, "Global Enable" }, 333 334 { "ADC12 Enable", "Switch", "IN1" }, 335 { "ADC12 Enable", "Switch", "IN2" }, 336 { "ADC1", NULL, "ADC12 Enable" }, 337 { "ADC2", NULL, "ADC12 Enable" }, 338 { "IN HPF", "Switch", "ADC1" }, 339 { "IN HPF", "Switch", "ADC2" }, 340 341 { "AIF Capture", NULL, "IN HPF" }, 342 { "AIF Capture", NULL, "ADC1" }, 343 { "AIF Capture", NULL, "ADC2" }, 344 }; 345 346 static const struct snd_soc_dapm_route adc_ch3_4_routes[] = { 347 { "ADC3", NULL, "Global Enable" }, 348 { "ADC4", NULL, "Global Enable" }, 349 350 { "ADC34 Enable", "Switch", "IN3" }, 351 { "ADC34 Enable", "Switch", "IN4" }, 352 { "ADC3", NULL, "ADC34 Enable" }, 353 { "ADC4", NULL, "ADC34 Enable" }, 354 { "IN HPF", "Switch", "ADC3" }, 355 { "IN HPF", "Switch", "ADC4" }, 356 357 { "AIF Capture", NULL, "ADC3" }, 358 { "AIF Capture", NULL, "ADC4" }, 359 }; 360 361 static const struct snd_soc_dapm_route adc_ch5_8_routes[] = { 362 { "ADC5", NULL, "Global Enable" }, 363 { "ADC6", NULL, "Global Enable" }, 364 { "ADC7", NULL, "Global Enable" }, 365 { "ADC8", NULL, "Global Enable" }, 366 367 { "ADC56 Enable", "Switch", "IN5" }, 368 { "ADC56 Enable", "Switch", "IN6" }, 369 { "ADC5", NULL, "ADC56 Enable" }, 370 { "ADC6", NULL, "ADC56 Enable" }, 371 { "IN HPF", "Switch", "ADC5" }, 372 { "IN HPF", "Switch", "ADC6" }, 373 374 { "AIF Capture", NULL, "ADC5" }, 375 { "AIF Capture", NULL, "ADC6" }, 376 377 { "ADC78 Enable", "Switch", "IN7" }, 378 { "ADC78 Enable", "Switch", "IN8" }, 379 { "ADC7", NULL, "ADC78 Enable" }, 380 { "ADC8", NULL, "ADC78 Enable" }, 381 { "IN HPF", "Switch", "ADC7" }, 382 { "IN HPF", "Switch", "ADC8" }, 383 384 { "AIF Capture", NULL, "ADC7" }, 385 { "AIF Capture", NULL, "ADC8" }, 386 }; 387 388 static void cs530x_add_12_adc_widgets(struct snd_soc_component *component) 389 { 390 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 391 392 snd_soc_add_component_controls(component, 393 cs530x_in_1_to_2_controls, 394 ARRAY_SIZE(cs530x_in_1_to_2_controls)); 395 396 snd_soc_dapm_new_controls(dapm, cs530x_adc_ch12_dapm_widgets, 397 ARRAY_SIZE(cs530x_adc_ch12_dapm_widgets)); 398 399 snd_soc_dapm_add_routes(dapm, adc_ch1_2_routes, 400 ARRAY_SIZE(adc_ch1_2_routes)); 401 } 402 403 static void cs530x_add_34_adc_widgets(struct snd_soc_component *component) 404 { 405 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 406 407 snd_soc_add_component_controls(component, 408 cs530x_in_3_to_4_controls, 409 ARRAY_SIZE(cs530x_in_3_to_4_controls)); 410 411 snd_soc_dapm_new_controls(dapm, cs530x_adc_ch34_dapm_widgets, 412 ARRAY_SIZE(cs530x_adc_ch34_dapm_widgets)); 413 414 snd_soc_dapm_add_routes(dapm, adc_ch3_4_routes, 415 ARRAY_SIZE(adc_ch3_4_routes)); 416 } 417 418 static int cs530x_set_bclk(struct snd_soc_component *component, const int freq) 419 { 420 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 421 struct regmap *regmap = cs530x->regmap; 422 unsigned int bclk_val; 423 424 switch (freq) { 425 case 2822400: 426 case 3072000: 427 bclk_val = CS530X_BCLK_2P822_3P072; 428 break; 429 case 5644800: 430 case 6144000: 431 bclk_val = CS530X_BCLK_5P6448_6P144; 432 break; 433 case 11289600: 434 case 12288000: 435 bclk_val = CS530X_BCLK_11P2896_12P288; 436 break; 437 case 22579200: 438 case 24576000: 439 bclk_val = CS530X_BCLK_24P5792_24P576; 440 break; 441 default: 442 dev_err(component->dev, "Invalid BCLK frequency %d\n", freq); 443 return -EINVAL; 444 } 445 446 dev_dbg(component->dev, "BCLK frequency is %d\n", freq); 447 448 return regmap_update_bits(regmap, CS530X_ASP_CFG, 449 CS530X_ASP_BCLK_FREQ_MASK, bclk_val); 450 } 451 452 static int cs530x_set_pll_refclk(struct snd_soc_component *component, 453 const unsigned int freq) 454 { 455 struct cs530x_priv *priv = snd_soc_component_get_drvdata(component); 456 struct regmap *regmap = priv->regmap; 457 unsigned int refclk; 458 459 switch (freq) { 460 case 2822400: 461 case 3072000: 462 refclk = CS530X_REFCLK_2P822_3P072; 463 break; 464 case 5644800: 465 case 6144000: 466 refclk = CS530X_REFCLK_5P6448_6P144; 467 break; 468 case 11289600: 469 case 12288000: 470 refclk = CS530X_REFCLK_11P2896_12P288; 471 break; 472 case 22579200: 473 case 24576000: 474 refclk = CS530X_REFCLK_24P5792_24P576; 475 break; 476 default: 477 dev_err(component->dev, "Invalid PLL refclk %d\n", freq); 478 return -EINVAL; 479 } 480 481 return regmap_update_bits(regmap, CS530X_CLK_CFG_0, 482 CS530X_PLL_REFCLK_FREQ_MASK, refclk); 483 } 484 485 static int cs530x_hw_params(struct snd_pcm_substream *substream, 486 struct snd_pcm_hw_params *params, 487 struct snd_soc_dai *dai) 488 { 489 struct snd_soc_component *component = dai->component; 490 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 491 struct regmap *regmap = cs530x->regmap; 492 int ret = 0, fs = params_rate(params), bclk; 493 unsigned int fs_val; 494 495 496 switch (fs) { 497 case 32000: 498 fs_val = CS530X_FS_32K; 499 break; 500 case 44100: 501 case 48000: 502 fs_val = CS530X_FS_48K_44P1K; 503 break; 504 case 88200: 505 case 96000: 506 fs_val = CS530X_FS_96K_88P2K; 507 break; 508 case 176400: 509 case 192000: 510 fs_val = CS530X_FS_192K_176P4K; 511 break; 512 case 356800: 513 case 384000: 514 fs_val = CS530X_FS_384K_356P8K; 515 break; 516 case 705600: 517 case 768000: 518 fs_val = CS530X_FS_768K_705P6K; 519 break; 520 default: 521 dev_err(component->dev, "Invalid sample rate %d\n", fs); 522 return -EINVAL; 523 } 524 525 cs530x->fs = fs; 526 regmap_update_bits(regmap, CS530X_CLK_CFG_1, 527 CS530X_SAMPLE_RATE_MASK, fs_val); 528 529 530 if (regmap_test_bits(regmap, CS530X_SIGNAL_PATH_CFG, 531 CS530X_TDM_EN_MASK)) { 532 dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n", 533 cs530x->tdm_slots, cs530x->tdm_width); 534 bclk = snd_soc_tdm_params_to_bclk(params, 535 cs530x->tdm_width, 536 cs530x->tdm_slots, 537 1); 538 } else { 539 bclk = snd_soc_params_to_bclk(params); 540 } 541 542 if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0, 543 CS530X_PLL_REFCLK_SRC_MASK)) { 544 ret = cs530x_set_pll_refclk(component, bclk); 545 if (ret) 546 return ret; 547 } 548 549 return cs530x_set_bclk(component, bclk); 550 } 551 552 static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 553 { 554 struct snd_soc_component *component = dai->component; 555 struct cs530x_priv *priv = snd_soc_component_get_drvdata(component); 556 struct regmap *regmap = priv->regmap; 557 unsigned int asp_fmt, asp_cfg = 0; 558 559 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 560 case SND_SOC_DAIFMT_CBS_CFS: 561 break; 562 case SND_SOC_DAIFMT_CBM_CFM: 563 asp_cfg = CS530X_ASP_PRIMARY; 564 break; 565 default: 566 return -EINVAL; 567 } 568 569 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 570 case SND_SOC_DAIFMT_DSP_A: 571 asp_fmt = CS530X_ASP_FMT_DSP_A; 572 break; 573 case SND_SOC_DAIFMT_I2S: 574 asp_fmt = CS530X_ASP_FMT_I2S; 575 break; 576 case SND_SOC_DAIFMT_LEFT_J: 577 asp_fmt = CS530X_ASP_FMT_LJ; 578 break; 579 default: 580 return -EINVAL; 581 } 582 583 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 584 case SND_SOC_DAIFMT_NB_NF: 585 break; 586 case SND_SOC_DAIFMT_IB_IF: 587 asp_cfg |= CS530X_ASP_BCLK_INV; 588 break; 589 default: 590 return -EINVAL; 591 } 592 593 regmap_update_bits(regmap, CS530X_ASP_CFG, 594 CS530X_ASP_PRIMARY | CS530X_ASP_BCLK_INV, 595 asp_cfg); 596 597 return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG, 598 CS530X_ASP_FMT_MASK, asp_fmt); 599 } 600 601 static bool cs530x_check_mclk_freq(struct snd_soc_component *component, 602 const unsigned int freq) 603 { 604 switch (freq) { 605 case 24576000: 606 case 22579200: 607 case 12288000: 608 case 11289600: 609 return true; 610 default: 611 dev_err(component->dev, "Invalid MCLK %d\n", freq); 612 return false; 613 } 614 } 615 616 static int cs530x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 617 unsigned int rx_mask, int slots, int slot_width) 618 { 619 struct snd_soc_component *component = dai->component; 620 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 621 struct regmap *regmap = cs530x->regmap; 622 unsigned int val; 623 624 switch (tx_mask) { 625 case CS530X_0_1_TDM_SLOT_MASK: 626 case CS530X_0_3_TDM_SLOT_MASK: 627 case CS530X_0_7_TDM_SLOT_MASK: 628 val = CS530X_0_7_TDM_SLOT_VAL; 629 break; 630 case CS530X_2_3_TDM_SLOT_MASK: 631 val = CS530X_2_3_TDM_SLOT_VAL; 632 break; 633 case CS530X_4_5_TDM_SLOT_MASK: 634 case CS530X_4_7_TDM_SLOT_MASK: 635 val = CS530X_4_7_TDM_SLOT_VAL; 636 break; 637 case CS530X_6_7_TDM_SLOT_MASK: 638 val = CS530X_6_7_TDM_SLOT_VAL; 639 break; 640 case CS530X_8_9_TDM_SLOT_MASK: 641 case CS530X_8_11_TDM_SLOT_MASK: 642 case CS530X_8_15_TDM_SLOT_MASK: 643 val = CS530X_8_15_TDM_SLOT_VAL; 644 break; 645 case CS530X_10_11_TDM_SLOT_MASK: 646 val = CS530X_10_11_TDM_SLOT_VAL; 647 break; 648 case CS530X_12_13_TDM_SLOT_MASK: 649 case CS530X_12_15_TDM_SLOT_MASK: 650 val = CS530X_12_15_TDM_SLOT_VAL; 651 break; 652 case CS530X_14_15_TDM_SLOT_MASK: 653 val = CS530X_14_15_TDM_SLOT_VAL; 654 break; 655 default: 656 dev_err(component->dev, "Invalid TX slot(s) 0x%x\n", tx_mask); 657 return -EINVAL; 658 } 659 660 cs530x->tdm_width = slot_width; 661 cs530x->tdm_slots = slots; 662 663 return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG, 664 CS530X_ASP_TDM_SLOT_MASK, 665 val << CS530X_ASP_TDM_SLOT_SHIFT); 666 } 667 668 static const struct snd_soc_dai_ops cs530x_dai_ops = { 669 .set_fmt = cs530x_set_fmt, 670 .hw_params = cs530x_hw_params, 671 .set_tdm_slot = cs530x_set_tdm_slot, 672 }; 673 674 static const struct snd_soc_dai_driver cs530x_dai = { 675 .name = "cs530x-dai", 676 .capture = { 677 .stream_name = "AIF Capture", 678 .channels_min = 2, 679 .channels_max = 8, 680 .rates = SNDRV_PCM_RATE_KNOT, 681 .formats = SNDRV_PCM_FMTBIT_S32_LE, 682 }, 683 .ops = &cs530x_dai_ops, 684 .symmetric_rate = 1, 685 .symmetric_sample_bits = 1, 686 }; 687 688 static int cs530x_set_pll(struct snd_soc_component *component, int pll_id, 689 int source, unsigned int freq_in, 690 unsigned int freq_out) 691 { 692 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 693 struct regmap *regmap = cs530x->regmap; 694 unsigned int sysclk_src; 695 int ret; 696 697 regmap_read(regmap, CS530X_CLK_CFG_0, &sysclk_src); 698 699 /* Check if the source is the PLL */ 700 if ((sysclk_src & CS530X_SYSCLK_SRC_MASK) == 0) 701 return 0; 702 703 switch (source) { 704 case CS530X_PLL_SRC_MCLK: 705 if (!cs530x_check_mclk_freq(component, freq_in)) 706 return -EINVAL; 707 708 ret = cs530x_set_pll_refclk(component, freq_in); 709 if (ret) 710 return ret; 711 712 break; 713 case CS530X_PLL_SRC_BCLK: 714 break; 715 default: 716 dev_err(component->dev, "Invalid PLL source %d\n", source); 717 return -EINVAL; 718 } 719 720 return regmap_update_bits(regmap, CS530X_CLK_CFG_0, 721 CS530X_PLL_REFCLK_SRC_MASK, source); 722 } 723 724 static int cs530x_component_probe(struct snd_soc_component *component) 725 { 726 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 727 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 728 int num_widgets; 729 730 snd_soc_dapm_new_controls(dapm, cs530x_gen_dapm_widgets, 731 ARRAY_SIZE(cs530x_gen_dapm_widgets)); 732 733 switch (cs530x->devtype) { 734 case CS5302: 735 cs530x_add_12_adc_widgets(component); 736 break; 737 case CS5304: 738 cs530x_add_12_adc_widgets(component); 739 cs530x_add_34_adc_widgets(component); 740 741 num_widgets = ARRAY_SIZE(cs530x_in_sum_4ch_controls); 742 snd_soc_add_component_controls(component, 743 cs530x_in_sum_4ch_controls, 744 num_widgets); 745 break; 746 747 case CS5308: 748 cs530x_add_12_adc_widgets(component); 749 cs530x_add_34_adc_widgets(component); 750 751 num_widgets = ARRAY_SIZE(cs530x_in_5_to_8_controls); 752 snd_soc_add_component_controls(component, 753 cs530x_in_5_to_8_controls, 754 num_widgets); 755 756 num_widgets = ARRAY_SIZE(cs530x_in_sum_8ch_controls); 757 snd_soc_add_component_controls(component, 758 cs530x_in_sum_8ch_controls, 759 num_widgets); 760 761 num_widgets = ARRAY_SIZE(cs530x_adc_ch58_dapm_widgets); 762 snd_soc_dapm_new_controls(dapm, cs530x_adc_ch58_dapm_widgets, 763 num_widgets); 764 765 snd_soc_dapm_add_routes(dapm, adc_ch5_8_routes, 766 ARRAY_SIZE(adc_ch5_8_routes)); 767 break; 768 default: 769 dev_err(component->dev, "Invalid device type %d\n", 770 cs530x->devtype); 771 return -EINVAL; 772 } 773 774 return 0; 775 } 776 777 static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id, 778 int source, unsigned int freq, int dir) 779 { 780 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 781 struct regmap *regmap = cs530x->regmap; 782 783 switch (source) { 784 case CS530X_SYSCLK_SRC_MCLK: 785 if (freq != 24560000 && freq != 22572000) { 786 dev_err(component->dev, "Invalid MCLK source rate %d\n", 787 freq); 788 return -EINVAL; 789 } 790 791 cs530x->mclk_rate = freq; 792 break; 793 case CS530X_SYSCLK_SRC_PLL: 794 break; 795 default: 796 dev_err(component->dev, "Invalid clock id %d\n", clk_id); 797 return -EINVAL; 798 } 799 800 return regmap_update_bits(regmap, CS530X_CLK_CFG_0, 801 CS530X_SYSCLK_SRC_MASK, 802 source << CS530X_SYSCLK_SRC_SHIFT); 803 } 804 805 static const struct snd_soc_component_driver soc_component_dev_cs530x = { 806 .probe = cs530x_component_probe, 807 .set_sysclk = cs530x_set_sysclk, 808 .set_pll = cs530x_set_pll, 809 .endianness = 1, 810 }; 811 812 const struct regmap_config cs530x_regmap = { 813 .reg_bits = 16, 814 .val_bits = 16, 815 816 .max_register = CS530X_MAX_REGISTER, 817 .readable_reg = cs530x_readable_register, 818 .writeable_reg = cs530x_writeable_register, 819 820 .cache_type = REGCACHE_MAPLE, 821 .reg_defaults = cs530x_reg_defaults, 822 .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults), 823 }; 824 EXPORT_SYMBOL_NS_GPL(cs530x_regmap, SND_SOC_CS530X); 825 826 static int cs530x_check_device_id(struct cs530x_priv *cs530x) 827 { 828 struct device *dev = cs530x->dev; 829 unsigned int dev_id, rev; 830 int ret; 831 832 ret = regmap_read(cs530x->regmap, CS530X_DEVID, &dev_id); 833 if (ret) 834 return dev_err_probe(dev, ret, "Can't read device ID\n"); 835 836 ret = regmap_read(cs530x->regmap, CS530X_REVID, &rev); 837 if (ret) 838 return dev_err_probe(dev, ret, "Can't read REV ID\n"); 839 840 dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x\n", dev_id, rev); 841 842 switch (dev_id) { 843 case CS530X_2CH_ADC_DEV_ID: 844 cs530x->num_adcs = 2; 845 break; 846 case CS530X_4CH_ADC_DEV_ID: 847 cs530x->num_adcs = 4; 848 break; 849 case CS530X_8CH_ADC_DEV_ID: 850 cs530x->num_adcs = 8; 851 break; 852 default: 853 return dev_err_probe(dev, -EINVAL, "Invalid device ID 0x%x\n", 854 dev_id); 855 } 856 857 return 0; 858 } 859 860 static int cs530x_parse_device_properties(struct cs530x_priv *cs530x) 861 { 862 struct regmap *regmap = cs530x->regmap; 863 struct device *dev = cs530x->dev; 864 unsigned int val = 0; 865 866 switch (cs530x->num_adcs) { 867 case 8: 868 if (device_property_read_bool(dev, "cirrus,in-hiz-pin78")) 869 val = CS530X_IN78_HIZ; 870 871 if (device_property_read_bool(dev, "cirrus,in-hiz-pin56")) 872 val |= CS530X_IN56_HIZ; 873 874 fallthrough; 875 case 4: 876 if (device_property_read_bool(dev, "cirrus,in-hiz-pin34")) 877 val |= CS530X_IN34_HIZ; 878 879 fallthrough; 880 case 2: 881 if (device_property_read_bool(dev, "cirrus,in-hiz-pin12")) 882 val |= CS530X_IN12_HIZ; 883 884 return regmap_set_bits(regmap, CS530X_IN_HIZ, val); 885 default: 886 return dev_err_probe(dev, -EINVAL, 887 "Invalid number of adcs %d\n", 888 cs530x->num_adcs); 889 } 890 } 891 892 int cs530x_probe(struct cs530x_priv *cs530x) 893 { 894 struct device *dev = cs530x->dev; 895 int ret, i; 896 897 cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai, 898 sizeof(*(cs530x->dev_dai)), 899 GFP_KERNEL); 900 if (!cs530x->dev_dai) 901 return -ENOMEM; 902 903 for (i = 0; i < ARRAY_SIZE(cs530x->supplies); i++) 904 cs530x->supplies[i].supply = cs530x_supply_names[i]; 905 906 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs530x->supplies), 907 cs530x->supplies); 908 if (ret != 0) 909 return dev_err_probe(dev, ret, "Failed to request supplies"); 910 911 ret = regulator_bulk_enable(ARRAY_SIZE(cs530x->supplies), 912 cs530x->supplies); 913 if (ret != 0) 914 return dev_err_probe(dev, ret, "Failed to enable supplies"); 915 916 cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset", 917 GPIOD_OUT_HIGH); 918 if (IS_ERR(cs530x->reset_gpio)) { 919 ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio), 920 "Reset gpio not available\n"); 921 goto err_regulator; 922 } 923 924 if (cs530x->reset_gpio) { 925 usleep_range(2000, 2100); 926 gpiod_set_value_cansleep(cs530x->reset_gpio, 0); 927 } 928 929 usleep_range(5000, 5100); 930 ret = cs530x_check_device_id(cs530x); 931 if (ret) 932 goto err_reset; 933 934 if (!cs530x->reset_gpio) { 935 ret = regmap_write(cs530x->regmap, CS530X_SW_RESET, 936 CS530X_SW_RST_VAL); 937 if (ret) { 938 dev_err_probe(dev, ret, "Soft Reset Failed\n"); 939 goto err_reset; 940 } 941 } 942 943 ret = cs530x_parse_device_properties(cs530x); 944 if (ret) 945 goto err_reset; 946 947 cs530x->dev_dai->capture.channels_max = cs530x->num_adcs; 948 949 ret = devm_snd_soc_register_component(dev, 950 &soc_component_dev_cs530x, cs530x->dev_dai, 1); 951 if (ret) { 952 dev_err_probe(dev, ret, "Can't register cs530x component\n"); 953 goto err_reset; 954 } 955 956 return 0; 957 958 err_reset: 959 gpiod_set_value_cansleep(cs530x->reset_gpio, 1); 960 961 err_regulator: 962 regulator_bulk_disable(ARRAY_SIZE(cs530x->supplies), 963 cs530x->supplies); 964 965 return ret; 966 } 967 EXPORT_SYMBOL_NS_GPL(cs530x_probe, SND_SOC_CS530X); 968 969 MODULE_DESCRIPTION("CS530X CODEC Driver"); 970 MODULE_AUTHOR("Paul Handrigan <paulha@opensource.cirrus.com>"); 971 MODULE_LICENSE("GPL"); 972
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.