1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 // 3 // cs35l45.c - CS35L45 ALSA SoC audio driver 4 // 5 // Copyright 2019-2022 Cirrus Logic, Inc. 6 // 7 // Author: James Schulman <james.schulman@cirrus.com> 8 9 #include <linux/gpio/consumer.h> 10 #include <linux/module.h> 11 #include <linux/pm_runtime.h> 12 #include <linux/property.h> 13 #include <linux/regulator/consumer.h> 14 #include <sound/core.h> 15 #include <sound/pcm.h> 16 #include <sound/pcm_params.h> 17 #include <sound/soc.h> 18 #include <sound/tlv.h> 19 20 #include "cs35l45.h" 21 22 static int cs35l45_global_en_ev(struct snd_soc_dapm_widget *w, 23 struct snd_kcontrol *kcontrol, int event) 24 { 25 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 26 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component); 27 28 dev_dbg(cs35l45->dev, "%s event : %x\n", __func__, event); 29 30 switch (event) { 31 case SND_SOC_DAPM_POST_PMU: 32 regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES, 33 CS35L45_GLOBAL_EN_MASK); 34 35 usleep_range(CS35L45_POST_GLOBAL_EN_US, CS35L45_POST_GLOBAL_EN_US + 100); 36 break; 37 case SND_SOC_DAPM_PRE_PMD: 38 usleep_range(CS35L45_PRE_GLOBAL_DIS_US, CS35L45_PRE_GLOBAL_DIS_US + 100); 39 40 regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES, 0); 41 break; 42 default: 43 break; 44 } 45 46 return 0; 47 } 48 49 static const char * const cs35l45_asp_tx_txt[] = { 50 "Zero", "ASP_RX1", "ASP_RX2", 51 "VMON", "IMON", "ERR_VOL", 52 "VDD_BATTMON", "VDD_BSTMON", 53 "Interpolator", "IL_TARGET", 54 }; 55 56 static const unsigned int cs35l45_asp_tx_val[] = { 57 CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2, 58 CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL, 59 CS35L45_PCM_SRC_VDD_BATTMON, CS35L45_PCM_SRC_VDD_BSTMON, 60 CS35L45_PCM_SRC_INTERPOLATOR, CS35L45_PCM_SRC_IL_TARGET, 61 }; 62 63 static const struct soc_enum cs35l45_asp_tx_enums[] = { 64 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX1_INPUT, 0, CS35L45_PCM_SRC_MASK, 65 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 66 cs35l45_asp_tx_val), 67 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX2_INPUT, 0, CS35L45_PCM_SRC_MASK, 68 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 69 cs35l45_asp_tx_val), 70 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX3_INPUT, 0, CS35L45_PCM_SRC_MASK, 71 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 72 cs35l45_asp_tx_val), 73 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX4_INPUT, 0, CS35L45_PCM_SRC_MASK, 74 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 75 cs35l45_asp_tx_val), 76 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX5_INPUT, 0, CS35L45_PCM_SRC_MASK, 77 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 78 cs35l45_asp_tx_val), 79 }; 80 81 static const char * const cs35l45_dac_txt[] = { 82 "Zero", "ASP_RX1", "ASP_RX2" 83 }; 84 85 static const unsigned int cs35l45_dac_val[] = { 86 CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2 87 }; 88 89 static const struct soc_enum cs35l45_dacpcm_enums[] = { 90 SOC_VALUE_ENUM_SINGLE(CS35L45_DACPCM1_INPUT, 0, CS35L45_PCM_SRC_MASK, 91 ARRAY_SIZE(cs35l45_dac_txt), cs35l45_dac_txt, 92 cs35l45_dac_val), 93 }; 94 95 static const struct snd_kcontrol_new cs35l45_asp_muxes[] = { 96 SOC_DAPM_ENUM("ASP_TX1 Source", cs35l45_asp_tx_enums[0]), 97 SOC_DAPM_ENUM("ASP_TX2 Source", cs35l45_asp_tx_enums[1]), 98 SOC_DAPM_ENUM("ASP_TX3 Source", cs35l45_asp_tx_enums[2]), 99 SOC_DAPM_ENUM("ASP_TX4 Source", cs35l45_asp_tx_enums[3]), 100 SOC_DAPM_ENUM("ASP_TX5 Source", cs35l45_asp_tx_enums[4]), 101 }; 102 103 static const struct snd_kcontrol_new cs35l45_dac_muxes[] = { 104 SOC_DAPM_ENUM("DACPCM1 Source", cs35l45_dacpcm_enums[0]), 105 }; 106 107 static const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = { 108 SND_SOC_DAPM_SUPPLY("GLOBAL_EN", SND_SOC_NOPM, 0, 0, 109 cs35l45_global_en_ev, 110 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 111 SND_SOC_DAPM_SUPPLY("ASP_EN", CS35L45_BLOCK_ENABLES2, CS35L45_ASP_EN_SHIFT, 0, NULL, 0), 112 113 SND_SOC_DAPM_SIGGEN("VMON_SRC"), 114 SND_SOC_DAPM_SIGGEN("IMON_SRC"), 115 SND_SOC_DAPM_SIGGEN("VDD_BATTMON_SRC"), 116 SND_SOC_DAPM_SIGGEN("VDD_BSTMON_SRC"), 117 SND_SOC_DAPM_SIGGEN("ERR_VOL"), 118 SND_SOC_DAPM_SIGGEN("AMP_INTP"), 119 SND_SOC_DAPM_SIGGEN("IL_TARGET"), 120 SND_SOC_DAPM_ADC("VMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_VMON_EN_SHIFT, 0), 121 SND_SOC_DAPM_ADC("IMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_IMON_EN_SHIFT, 0), 122 SND_SOC_DAPM_ADC("VDD_BATTMON", NULL, CS35L45_BLOCK_ENABLES, 123 CS35L45_VDD_BATTMON_EN_SHIFT, 0), 124 SND_SOC_DAPM_ADC("VDD_BSTMON", NULL, CS35L45_BLOCK_ENABLES, 125 CS35L45_VDD_BSTMON_EN_SHIFT, 0), 126 127 SND_SOC_DAPM_AIF_IN("ASP_RX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX1_EN_SHIFT, 0), 128 SND_SOC_DAPM_AIF_IN("ASP_RX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX2_EN_SHIFT, 0), 129 130 SND_SOC_DAPM_AIF_OUT("ASP_TX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX1_EN_SHIFT, 0), 131 SND_SOC_DAPM_AIF_OUT("ASP_TX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX2_EN_SHIFT, 0), 132 SND_SOC_DAPM_AIF_OUT("ASP_TX3", NULL, 2, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX3_EN_SHIFT, 0), 133 SND_SOC_DAPM_AIF_OUT("ASP_TX4", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX4_EN_SHIFT, 0), 134 SND_SOC_DAPM_AIF_OUT("ASP_TX5", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX5_EN_SHIFT, 0), 135 136 SND_SOC_DAPM_MUX("ASP_TX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[0]), 137 SND_SOC_DAPM_MUX("ASP_TX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[1]), 138 SND_SOC_DAPM_MUX("ASP_TX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[2]), 139 SND_SOC_DAPM_MUX("ASP_TX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[3]), 140 SND_SOC_DAPM_MUX("ASP_TX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[4]), 141 142 SND_SOC_DAPM_MUX("DACPCM1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dac_muxes[0]), 143 144 SND_SOC_DAPM_OUT_DRV("AMP", SND_SOC_NOPM, 0, 0, NULL, 0), 145 146 SND_SOC_DAPM_OUTPUT("SPK"), 147 }; 148 149 #define CS35L45_ASP_MUX_ROUTE(name) \ 150 { name" Source", "ASP_RX1", "ASP_RX1" }, \ 151 { name" Source", "ASP_RX2", "ASP_RX2" }, \ 152 { name" Source", "VMON", "VMON" }, \ 153 { name" Source", "IMON", "IMON" }, \ 154 { name" Source", "ERR_VOL", "ERR_VOL" }, \ 155 { name" Source", "VDD_BATTMON", "VDD_BATTMON" }, \ 156 { name" Source", "VDD_BSTMON", "VDD_BSTMON" }, \ 157 { name" Source", "Interpolator", "AMP_INTP" }, \ 158 { name" Source", "IL_TARGET", "IL_TARGET" } 159 160 #define CS35L45_DAC_MUX_ROUTE(name) \ 161 { name" Source", "ASP_RX1", "ASP_RX1" }, \ 162 { name" Source", "ASP_RX2", "ASP_RX2" } 163 164 static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = { 165 /* Feedback */ 166 { "VMON", NULL, "VMON_SRC" }, 167 { "IMON", NULL, "IMON_SRC" }, 168 { "VDD_BATTMON", NULL, "VDD_BATTMON_SRC" }, 169 { "VDD_BSTMON", NULL, "VDD_BSTMON_SRC" }, 170 171 { "Capture", NULL, "ASP_TX1"}, 172 { "Capture", NULL, "ASP_TX2"}, 173 { "Capture", NULL, "ASP_TX3"}, 174 { "Capture", NULL, "ASP_TX4"}, 175 { "Capture", NULL, "ASP_TX5"}, 176 { "ASP_TX1", NULL, "ASP_TX1 Source"}, 177 { "ASP_TX2", NULL, "ASP_TX2 Source"}, 178 { "ASP_TX3", NULL, "ASP_TX3 Source"}, 179 { "ASP_TX4", NULL, "ASP_TX4 Source"}, 180 { "ASP_TX5", NULL, "ASP_TX5 Source"}, 181 182 { "ASP_TX1", NULL, "ASP_EN" }, 183 { "ASP_TX2", NULL, "ASP_EN" }, 184 { "ASP_TX3", NULL, "ASP_EN" }, 185 { "ASP_TX4", NULL, "ASP_EN" }, 186 { "ASP_TX1", NULL, "GLOBAL_EN" }, 187 { "ASP_TX2", NULL, "GLOBAL_EN" }, 188 { "ASP_TX3", NULL, "GLOBAL_EN" }, 189 { "ASP_TX4", NULL, "GLOBAL_EN" }, 190 { "ASP_TX5", NULL, "GLOBAL_EN" }, 191 192 CS35L45_ASP_MUX_ROUTE("ASP_TX1"), 193 CS35L45_ASP_MUX_ROUTE("ASP_TX2"), 194 CS35L45_ASP_MUX_ROUTE("ASP_TX3"), 195 CS35L45_ASP_MUX_ROUTE("ASP_TX4"), 196 CS35L45_ASP_MUX_ROUTE("ASP_TX5"), 197 198 /* Playback */ 199 { "ASP_RX1", NULL, "Playback" }, 200 { "ASP_RX2", NULL, "Playback" }, 201 { "ASP_RX1", NULL, "ASP_EN" }, 202 { "ASP_RX2", NULL, "ASP_EN" }, 203 204 { "AMP", NULL, "DACPCM1 Source"}, 205 { "AMP", NULL, "GLOBAL_EN"}, 206 207 CS35L45_DAC_MUX_ROUTE("DACPCM1"), 208 209 { "SPK", NULL, "AMP"}, 210 }; 211 212 static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true); 213 214 static const struct snd_kcontrol_new cs35l45_controls[] = { 215 /* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */ 216 SOC_SINGLE_S_TLV("Digital PCM Volume", 217 CS35L45_AMP_PCM_CONTROL, 218 CS35L45_AMP_VOL_PCM_SHIFT + 1, 219 -409, 48, 220 (CS35L45_AMP_VOL_PCM_WIDTH - 1) - 1, 221 0, cs35l45_dig_pcm_vol_tlv), 222 }; 223 224 static int cs35l45_set_pll(struct cs35l45_private *cs35l45, unsigned int freq) 225 { 226 unsigned int val; 227 int freq_id; 228 229 freq_id = cs35l45_get_clk_freq_id(freq); 230 if (freq_id < 0) { 231 dev_err(cs35l45->dev, "Invalid freq: %u\n", freq); 232 return -EINVAL; 233 } 234 235 regmap_read(cs35l45->regmap, CS35L45_REFCLK_INPUT, &val); 236 val = (val & CS35L45_PLL_REFCLK_FREQ_MASK) >> CS35L45_PLL_REFCLK_FREQ_SHIFT; 237 if (val == freq_id) 238 return 0; 239 240 regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK); 241 regmap_update_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, 242 CS35L45_PLL_REFCLK_FREQ_MASK, 243 freq_id << CS35L45_PLL_REFCLK_FREQ_SHIFT); 244 regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK); 245 regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK); 246 regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK); 247 248 return 0; 249 } 250 251 static int cs35l45_asp_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 252 { 253 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(codec_dai->component); 254 unsigned int asp_fmt, fsync_inv, bclk_inv; 255 256 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 257 case SND_SOC_DAIFMT_CBC_CFC: 258 break; 259 default: 260 dev_err(cs35l45->dev, "Invalid DAI clocking\n"); 261 return -EINVAL; 262 } 263 264 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 265 case SND_SOC_DAIFMT_DSP_A: 266 asp_fmt = CS35l45_ASP_FMT_DSP_A; 267 break; 268 case SND_SOC_DAIFMT_I2S: 269 asp_fmt = CS35L45_ASP_FMT_I2S; 270 break; 271 default: 272 dev_err(cs35l45->dev, "Invalid DAI format\n"); 273 return -EINVAL; 274 } 275 276 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 277 case SND_SOC_DAIFMT_NB_IF: 278 fsync_inv = 1; 279 bclk_inv = 0; 280 break; 281 case SND_SOC_DAIFMT_IB_NF: 282 fsync_inv = 0; 283 bclk_inv = 1; 284 break; 285 case SND_SOC_DAIFMT_IB_IF: 286 fsync_inv = 1; 287 bclk_inv = 1; 288 break; 289 case SND_SOC_DAIFMT_NB_NF: 290 fsync_inv = 0; 291 bclk_inv = 0; 292 break; 293 default: 294 dev_warn(cs35l45->dev, "Invalid DAI clock polarity\n"); 295 return -EINVAL; 296 } 297 298 regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2, 299 CS35L45_ASP_FMT_MASK | 300 CS35L45_ASP_FSYNC_INV_MASK | 301 CS35L45_ASP_BCLK_INV_MASK, 302 (asp_fmt << CS35L45_ASP_FMT_SHIFT) | 303 (fsync_inv << CS35L45_ASP_FSYNC_INV_SHIFT) | 304 (bclk_inv << CS35L45_ASP_BCLK_INV_SHIFT)); 305 306 return 0; 307 } 308 309 static int cs35l45_asp_hw_params(struct snd_pcm_substream *substream, 310 struct snd_pcm_hw_params *params, 311 struct snd_soc_dai *dai) 312 { 313 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); 314 unsigned int asp_width, asp_wl, global_fs, slot_multiple, asp_fmt; 315 int bclk; 316 317 switch (params_rate(params)) { 318 case 44100: 319 global_fs = CS35L45_44P100_KHZ; 320 break; 321 case 48000: 322 global_fs = CS35L45_48P0_KHZ; 323 break; 324 case 88200: 325 global_fs = CS35L45_88P200_KHZ; 326 break; 327 case 96000: 328 global_fs = CS35L45_96P0_KHZ; 329 break; 330 default: 331 dev_warn(cs35l45->dev, "Unsupported sample rate (%d)\n", 332 params_rate(params)); 333 return -EINVAL; 334 } 335 336 regmap_update_bits(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE, 337 CS35L45_GLOBAL_FS_MASK, 338 global_fs << CS35L45_GLOBAL_FS_SHIFT); 339 340 asp_wl = params_width(params); 341 342 if (cs35l45->slot_width) 343 asp_width = cs35l45->slot_width; 344 else 345 asp_width = params_width(params); 346 347 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 348 regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2, 349 CS35L45_ASP_WIDTH_RX_MASK, 350 asp_width << CS35L45_ASP_WIDTH_RX_SHIFT); 351 352 regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL5, 353 CS35L45_ASP_WL_MASK, 354 asp_wl << CS35L45_ASP_WL_SHIFT); 355 } else { 356 regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2, 357 CS35L45_ASP_WIDTH_TX_MASK, 358 asp_width << CS35L45_ASP_WIDTH_TX_SHIFT); 359 360 regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL1, 361 CS35L45_ASP_WL_MASK, 362 asp_wl << CS35L45_ASP_WL_SHIFT); 363 } 364 365 if (cs35l45->sysclk_set) 366 return 0; 367 368 /* I2S always has an even number of channels */ 369 regmap_read(cs35l45->regmap, CS35L45_ASP_CONTROL2, &asp_fmt); 370 asp_fmt = (asp_fmt & CS35L45_ASP_FMT_MASK) >> CS35L45_ASP_FMT_SHIFT; 371 if (asp_fmt == CS35L45_ASP_FMT_I2S) 372 slot_multiple = 2; 373 else 374 slot_multiple = 1; 375 376 bclk = snd_soc_tdm_params_to_bclk(params, asp_width, 377 cs35l45->slot_count, slot_multiple); 378 379 return cs35l45_set_pll(cs35l45, bclk); 380 } 381 382 static int cs35l45_asp_set_tdm_slot(struct snd_soc_dai *dai, 383 unsigned int tx_mask, unsigned int rx_mask, 384 int slots, int slot_width) 385 { 386 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); 387 388 if (slot_width && ((slot_width < 16) || (slot_width > 128))) 389 return -EINVAL; 390 391 cs35l45->slot_width = slot_width; 392 cs35l45->slot_count = slots; 393 394 return 0; 395 } 396 397 static int cs35l45_asp_set_sysclk(struct snd_soc_dai *dai, 398 int clk_id, unsigned int freq, int dir) 399 { 400 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); 401 int ret; 402 403 if (clk_id != 0) { 404 dev_err(cs35l45->dev, "Invalid clk_id %d\n", clk_id); 405 return -EINVAL; 406 } 407 408 cs35l45->sysclk_set = false; 409 if (freq == 0) 410 return 0; 411 412 ret = cs35l45_set_pll(cs35l45, freq); 413 if (ret < 0) 414 return -EINVAL; 415 416 cs35l45->sysclk_set = true; 417 418 return 0; 419 } 420 421 static int cs35l45_mute_stream(struct snd_soc_dai *dai, int mute, int stream) 422 { 423 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); 424 unsigned int global_fs, val, hpf_tune; 425 426 if (mute) 427 return 0; 428 429 regmap_read(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE, &global_fs); 430 global_fs = (global_fs & CS35L45_GLOBAL_FS_MASK) >> CS35L45_GLOBAL_FS_SHIFT; 431 switch (global_fs) { 432 case CS35L45_44P100_KHZ: 433 hpf_tune = CS35L45_HPF_44P1; 434 break; 435 case CS35L45_88P200_KHZ: 436 hpf_tune = CS35L45_HPF_88P2; 437 break; 438 default: 439 hpf_tune = CS35l45_HPF_DEFAULT; 440 break; 441 } 442 443 regmap_read(cs35l45->regmap, CS35L45_AMP_PCM_HPF_TST, &val); 444 if (val != hpf_tune) { 445 struct reg_sequence hpf_override_seq[] = { 446 { 0x00000040, 0x00000055 }, 447 { 0x00000040, 0x000000AA }, 448 { 0x00000044, 0x00000055 }, 449 { 0x00000044, 0x000000AA }, 450 { CS35L45_AMP_PCM_HPF_TST, hpf_tune }, 451 { 0x00000040, 0x00000000 }, 452 { 0x00000044, 0x00000000 }, 453 }; 454 regmap_multi_reg_write(cs35l45->regmap, hpf_override_seq, 455 ARRAY_SIZE(hpf_override_seq)); 456 } 457 458 return 0; 459 } 460 461 static const struct snd_soc_dai_ops cs35l45_asp_dai_ops = { 462 .set_fmt = cs35l45_asp_set_fmt, 463 .hw_params = cs35l45_asp_hw_params, 464 .set_tdm_slot = cs35l45_asp_set_tdm_slot, 465 .set_sysclk = cs35l45_asp_set_sysclk, 466 .mute_stream = cs35l45_mute_stream, 467 }; 468 469 static struct snd_soc_dai_driver cs35l45_dai[] = { 470 { 471 .name = "cs35l45", 472 .playback = { 473 .stream_name = "Playback", 474 .channels_min = 1, 475 .channels_max = 2, 476 .rates = CS35L45_RATES, 477 .formats = CS35L45_FORMATS, 478 }, 479 .capture = { 480 .stream_name = "Capture", 481 .channels_min = 1, 482 .channels_max = 5, 483 .rates = CS35L45_RATES, 484 .formats = CS35L45_FORMATS, 485 }, 486 .symmetric_rate = true, 487 .symmetric_sample_bits = true, 488 .ops = &cs35l45_asp_dai_ops, 489 }, 490 }; 491 492 static const struct snd_soc_component_driver cs35l45_component = { 493 .dapm_widgets = cs35l45_dapm_widgets, 494 .num_dapm_widgets = ARRAY_SIZE(cs35l45_dapm_widgets), 495 496 .dapm_routes = cs35l45_dapm_routes, 497 .num_dapm_routes = ARRAY_SIZE(cs35l45_dapm_routes), 498 499 .controls = cs35l45_controls, 500 .num_controls = ARRAY_SIZE(cs35l45_controls), 501 502 .name = "cs35l45", 503 504 .endianness = 1, 505 }; 506 507 static int __maybe_unused cs35l45_runtime_suspend(struct device *dev) 508 { 509 struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); 510 511 regcache_cache_only(cs35l45->regmap, true); 512 513 dev_dbg(cs35l45->dev, "Runtime suspended\n"); 514 515 return 0; 516 } 517 518 static int __maybe_unused cs35l45_runtime_resume(struct device *dev) 519 { 520 struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); 521 int ret; 522 523 dev_dbg(cs35l45->dev, "Runtime resume\n"); 524 525 regcache_cache_only(cs35l45->regmap, false); 526 ret = regcache_sync(cs35l45->regmap); 527 if (ret != 0) 528 dev_warn(cs35l45->dev, "regcache_sync failed: %d\n", ret); 529 530 /* Clear global error status */ 531 regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK); 532 regmap_set_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK); 533 regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK); 534 return ret; 535 } 536 537 static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45) 538 { 539 unsigned int val; 540 541 if (device_property_read_u32(cs35l45->dev, 542 "cirrus,asp-sdout-hiz-ctrl", &val) == 0) { 543 regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL3, 544 CS35L45_ASP_DOUT_HIZ_CTRL_MASK, 545 val << CS35L45_ASP_DOUT_HIZ_CTRL_SHIFT); 546 } 547 548 return 0; 549 } 550 551 static int cs35l45_initialize(struct cs35l45_private *cs35l45) 552 { 553 struct device *dev = cs35l45->dev; 554 unsigned int dev_id[5]; 555 unsigned int sts; 556 int ret; 557 558 ret = regmap_read_poll_timeout(cs35l45->regmap, CS35L45_IRQ1_EINT_4, sts, 559 (sts & CS35L45_OTP_BOOT_DONE_STS_MASK), 560 1000, 5000); 561 if (ret < 0) { 562 dev_err(cs35l45->dev, "Timeout waiting for OTP boot\n"); 563 return ret; 564 } 565 566 ret = regmap_bulk_read(cs35l45->regmap, CS35L45_DEVID, dev_id, ARRAY_SIZE(dev_id)); 567 if (ret) { 568 dev_err(cs35l45->dev, "Get Device ID failed: %d\n", ret); 569 return ret; 570 } 571 572 switch (dev_id[0]) { 573 case 0x35A450: 574 break; 575 default: 576 dev_err(cs35l45->dev, "Bad DEVID 0x%x\n", dev_id[0]); 577 return -ENODEV; 578 } 579 580 dev_info(cs35l45->dev, "Cirrus Logic CS35L45: REVID %02X OTPID %02X\n", 581 dev_id[1], dev_id[4]); 582 583 regmap_write(cs35l45->regmap, CS35L45_IRQ1_EINT_4, 584 CS35L45_OTP_BOOT_DONE_STS_MASK | CS35L45_OTP_BUSY_MASK); 585 586 ret = cs35l45_apply_patch(cs35l45); 587 if (ret < 0) { 588 dev_err(dev, "Failed to apply init patch %d\n", ret); 589 return ret; 590 } 591 592 ret = cs35l45_apply_property_config(cs35l45); 593 if (ret < 0) 594 return ret; 595 596 pm_runtime_set_autosuspend_delay(cs35l45->dev, 3000); 597 pm_runtime_use_autosuspend(cs35l45->dev); 598 pm_runtime_set_active(cs35l45->dev); 599 pm_runtime_enable(cs35l45->dev); 600 601 return 0; 602 } 603 604 int cs35l45_probe(struct cs35l45_private *cs35l45) 605 { 606 struct device *dev = cs35l45->dev; 607 int ret; 608 609 cs35l45->vdd_batt = devm_regulator_get(dev, "vdd-batt"); 610 if (IS_ERR(cs35l45->vdd_batt)) 611 return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_batt), 612 "Failed to request vdd-batt\n"); 613 614 cs35l45->vdd_a = devm_regulator_get(dev, "vdd-a"); 615 if (IS_ERR(cs35l45->vdd_a)) 616 return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_a), 617 "Failed to request vdd-a\n"); 618 619 /* VDD_BATT must always be enabled before other supplies */ 620 ret = regulator_enable(cs35l45->vdd_batt); 621 if (ret < 0) 622 return dev_err_probe(dev, ret, "Failed to enable vdd-batt\n"); 623 624 ret = regulator_enable(cs35l45->vdd_a); 625 if (ret < 0) 626 return dev_err_probe(dev, ret, "Failed to enable vdd-a\n"); 627 628 /* If reset is shared only one instance can claim it */ 629 cs35l45->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 630 if (IS_ERR(cs35l45->reset_gpio)) { 631 ret = PTR_ERR(cs35l45->reset_gpio); 632 cs35l45->reset_gpio = NULL; 633 if (ret == -EBUSY) { 634 dev_dbg(dev, "Reset line busy, assuming shared reset\n"); 635 } else { 636 dev_err_probe(dev, ret, "Failed to get reset GPIO\n"); 637 goto err; 638 } 639 } 640 641 if (cs35l45->reset_gpio) { 642 usleep_range(CS35L45_RESET_HOLD_US, CS35L45_RESET_HOLD_US + 100); 643 gpiod_set_value_cansleep(cs35l45->reset_gpio, 1); 644 } 645 646 usleep_range(CS35L45_RESET_US, CS35L45_RESET_US + 100); 647 648 ret = cs35l45_initialize(cs35l45); 649 if (ret < 0) 650 goto err_reset; 651 652 ret = devm_snd_soc_register_component(dev, &cs35l45_component, 653 cs35l45_dai, 654 ARRAY_SIZE(cs35l45_dai)); 655 if (ret < 0) 656 goto err_reset; 657 658 return 0; 659 660 err_reset: 661 gpiod_set_value_cansleep(cs35l45->reset_gpio, 0); 662 err: 663 regulator_disable(cs35l45->vdd_a); 664 regulator_disable(cs35l45->vdd_batt); 665 666 return ret; 667 } 668 EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45); 669 670 void cs35l45_remove(struct cs35l45_private *cs35l45) 671 { 672 pm_runtime_disable(cs35l45->dev); 673 674 gpiod_set_value_cansleep(cs35l45->reset_gpio, 0); 675 regulator_disable(cs35l45->vdd_a); 676 /* VDD_BATT must be the last to power-off */ 677 regulator_disable(cs35l45->vdd_batt); 678 } 679 EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45); 680 681 const struct dev_pm_ops cs35l45_pm_ops = { 682 SET_RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL) 683 }; 684 EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45); 685 686 MODULE_DESCRIPTION("ASoC CS35L45 driver"); 687 MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); 688 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); 689 MODULE_LICENSE("Dual BSD/GPL"); 690 MODULE_IMPORT_NS(SND_SOC_CS35L45_TABLES); 691