1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * This driver supports the digital controls for the internal codec 4 * found in Allwinner's A33 SoCs. 5 * 6 * (C) Copyright 2010-2016 7 * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com> 8 * huangxin <huangxin@Reuuimllatech.com> 9 * Mylène Josserand <mylene.josserand@free-electrons.com> 10 */ 11 12 #include <linux/module.h> 13 #include <linux/delay.h> 14 #include <linux/clk.h> 15 #include <linux/io.h> 16 #include <linux/of_device.h> 17 #include <linux/pm_runtime.h> 18 #include <linux/regmap.h> 19 #include <linux/log2.h> 20 21 #include <sound/pcm_params.h> 22 #include <sound/soc.h> 23 #include <sound/soc-dapm.h> 24 25 #define SUN8I_SYSCLK_CTL 0x00c 26 #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11 27 #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL (0x2 << 8) 28 #define SUN8I_SYSCLK_CTL_AIF2CLK_ENA 7 29 #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL (0x2 << 4) 30 #define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3 31 #define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0 32 #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK (0x0 << 0) 33 #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK (0x1 << 0) 34 #define SUN8I_MOD_CLK_ENA 0x010 35 #define SUN8I_MOD_CLK_ENA_AIF1 15 36 #define SUN8I_MOD_CLK_ENA_ADC 3 37 #define SUN8I_MOD_CLK_ENA_DAC 2 38 #define SUN8I_MOD_RST_CTL 0x014 39 #define SUN8I_MOD_RST_CTL_AIF1 15 40 #define SUN8I_MOD_RST_CTL_ADC 3 41 #define SUN8I_MOD_RST_CTL_DAC 2 42 #define SUN8I_SYS_SR_CTRL 0x018 43 #define SUN8I_SYS_SR_CTRL_AIF1_FS 12 44 #define SUN8I_SYS_SR_CTRL_AIF2_FS 8 45 #define SUN8I_AIF1CLK_CTRL 0x040 46 #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD 15 47 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV 14 48 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13 49 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9 50 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6 51 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4 52 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4) 53 #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 54 #define SUN8I_AIF1_ADCDAT_CTRL 0x044 55 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15 56 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA 14 57 #define SUN8I_AIF1_DACDAT_CTRL 0x048 58 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15 59 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14 60 #define SUN8I_AIF1_MXR_SRC 0x04c 61 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L 15 62 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL 14 63 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL 13 64 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR 12 65 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R 11 66 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10 67 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9 68 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8 69 #define SUN8I_ADC_DIG_CTRL 0x100 70 #define SUN8I_ADC_DIG_CTRL_ENAD 15 71 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2 72 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1 73 #define SUN8I_DAC_DIG_CTRL 0x120 74 #define SUN8I_DAC_DIG_CTRL_ENDA 15 75 #define SUN8I_DAC_MXR_SRC 0x130 76 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15 77 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14 78 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13 79 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12 80 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11 81 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10 82 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9 83 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8 84 85 #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK GENMASK(9, 8) 86 #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK GENMASK(5, 4) 87 #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12) 88 #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) 89 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9) 90 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) 91 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) 92 #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) 93 94 struct sun8i_codec_quirks { 95 bool legacy_widgets : 1; 96 bool lrck_inversion : 1; 97 }; 98 99 struct sun8i_codec { 100 struct regmap *regmap; 101 struct clk *clk_module; 102 const struct sun8i_codec_quirks *quirks; 103 }; 104 105 static int sun8i_codec_runtime_resume(struct device *dev) 106 { 107 struct sun8i_codec *scodec = dev_get_drvdata(dev); 108 int ret; 109 110 regcache_cache_only(scodec->regmap, false); 111 112 ret = regcache_sync(scodec->regmap); 113 if (ret) { 114 dev_err(dev, "Failed to sync regmap cache\n"); 115 return ret; 116 } 117 118 return 0; 119 } 120 121 static int sun8i_codec_runtime_suspend(struct device *dev) 122 { 123 struct sun8i_codec *scodec = dev_get_drvdata(dev); 124 125 regcache_cache_only(scodec->regmap, true); 126 regcache_mark_dirty(scodec->regmap); 127 128 return 0; 129 } 130 131 static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) 132 { 133 unsigned int rate = params_rate(params); 134 135 switch (rate) { 136 case 8000: 137 case 7350: 138 return 0x0; 139 case 11025: 140 return 0x1; 141 case 12000: 142 return 0x2; 143 case 16000: 144 return 0x3; 145 case 22050: 146 return 0x4; 147 case 24000: 148 return 0x5; 149 case 32000: 150 return 0x6; 151 case 44100: 152 return 0x7; 153 case 48000: 154 return 0x8; 155 case 96000: 156 return 0x9; 157 case 192000: 158 return 0xa; 159 default: 160 return -EINVAL; 161 } 162 } 163 164 static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 165 { 166 struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component); 167 u32 value; 168 169 /* clock masters */ 170 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 171 case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */ 172 value = 0x1; 173 break; 174 case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */ 175 value = 0x0; 176 break; 177 default: 178 return -EINVAL; 179 } 180 regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 181 BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD), 182 value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD); 183 184 /* clock inversion */ 185 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 186 case SND_SOC_DAIFMT_NB_NF: /* Normal */ 187 value = 0x0; 188 break; 189 case SND_SOC_DAIFMT_IB_IF: /* Inversion */ 190 value = 0x1; 191 break; 192 default: 193 return -EINVAL; 194 } 195 regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 196 BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV), 197 value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV); 198 199 /* 200 * It appears that the DAI and the codec in the A33 SoC don't 201 * share the same polarity for the LRCK signal when they mean 202 * 'normal' and 'inverted' in the datasheet. 203 * 204 * Since the DAI here is our regular i2s driver that have been 205 * tested with way more codecs than just this one, it means 206 * that the codec probably gets it backward, and we have to 207 * invert the value here. 208 */ 209 value ^= scodec->quirks->lrck_inversion; 210 regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 211 BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV), 212 value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); 213 214 /* DAI format */ 215 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 216 case SND_SOC_DAIFMT_I2S: 217 value = 0x0; 218 break; 219 case SND_SOC_DAIFMT_LEFT_J: 220 value = 0x1; 221 break; 222 case SND_SOC_DAIFMT_RIGHT_J: 223 value = 0x2; 224 break; 225 case SND_SOC_DAIFMT_DSP_A: 226 case SND_SOC_DAIFMT_DSP_B: 227 value = 0x3; 228 break; 229 default: 230 return -EINVAL; 231 } 232 regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 233 SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK, 234 value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT); 235 236 return 0; 237 } 238 239 struct sun8i_codec_clk_div { 240 u8 div; 241 u8 val; 242 }; 243 244 static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = { 245 { .div = 1, .val = 0 }, 246 { .div = 2, .val = 1 }, 247 { .div = 4, .val = 2 }, 248 { .div = 6, .val = 3 }, 249 { .div = 8, .val = 4 }, 250 { .div = 12, .val = 5 }, 251 { .div = 16, .val = 6 }, 252 { .div = 24, .val = 7 }, 253 { .div = 32, .val = 8 }, 254 { .div = 48, .val = 9 }, 255 { .div = 64, .val = 10 }, 256 { .div = 96, .val = 11 }, 257 { .div = 128, .val = 12 }, 258 { .div = 192, .val = 13 }, 259 }; 260 261 static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec, 262 unsigned int rate, 263 unsigned int word_size) 264 { 265 unsigned long clk_rate = clk_get_rate(scodec->clk_module); 266 unsigned int div = clk_rate / rate / word_size / 2; 267 unsigned int best_val = 0, best_diff = ~0; 268 int i; 269 270 for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) { 271 const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i]; 272 unsigned int diff = abs(bdiv->div - div); 273 274 if (diff < best_diff) { 275 best_diff = diff; 276 best_val = bdiv->val; 277 } 278 } 279 280 return best_val; 281 } 282 283 static int sun8i_codec_get_lrck_div(unsigned int channels, 284 unsigned int word_size) 285 { 286 unsigned int div = word_size * channels; 287 288 if (div < 16 || div > 256) 289 return -EINVAL; 290 291 return ilog2(div) - 4; 292 } 293 294 static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, 295 struct snd_pcm_hw_params *params, 296 struct snd_soc_dai *dai) 297 { 298 struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component); 299 int sample_rate, lrck_div; 300 u8 bclk_div; 301 302 /* 303 * The CPU DAI handles only a sample of 16 bits. Configure the 304 * codec to handle this type of sample resolution. 305 */ 306 regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 307 SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK, 308 SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16); 309 310 bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16); 311 regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 312 SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, 313 bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); 314 315 lrck_div = sun8i_codec_get_lrck_div(params_channels(params), 316 params_physical_width(params)); 317 if (lrck_div < 0) 318 return lrck_div; 319 320 regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 321 SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, 322 lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); 323 324 sample_rate = sun8i_codec_get_hw_rate(params); 325 if (sample_rate < 0) 326 return sample_rate; 327 328 regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, 329 SUN8I_SYS_SR_CTRL_AIF1_FS_MASK, 330 sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS); 331 332 return 0; 333 } 334 335 static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = { 336 SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch", 337 SUN8I_AIF1_MXR_SRC, 338 SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L, 339 SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0), 340 SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch", 341 SUN8I_AIF1_MXR_SRC, 342 SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL, 343 SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0), 344 SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch", 345 SUN8I_AIF1_MXR_SRC, 346 SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL, 347 SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0), 348 SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch", 349 SUN8I_AIF1_MXR_SRC, 350 SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR, 351 SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0), 352 }; 353 354 static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = { 355 SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch", 356 SUN8I_DAC_MXR_SRC, 357 SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L, 358 SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0), 359 SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch", 360 SUN8I_DAC_MXR_SRC, 361 SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L, 362 SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0), 363 SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC, 364 SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL, 365 SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0), 366 SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC, 367 SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL, 368 SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0), 369 }; 370 371 static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { 372 /* System Clocks */ 373 SND_SOC_DAPM_CLOCK_SUPPLY("mod"), 374 375 SND_SOC_DAPM_SUPPLY("AIF1CLK", 376 SUN8I_SYSCLK_CTL, 377 SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0), 378 SND_SOC_DAPM_SUPPLY("SYSCLK", 379 SUN8I_SYSCLK_CTL, 380 SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0), 381 382 /* Module Clocks */ 383 SND_SOC_DAPM_SUPPLY("CLK AIF1", 384 SUN8I_MOD_CLK_ENA, 385 SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0), 386 SND_SOC_DAPM_SUPPLY("CLK ADC", 387 SUN8I_MOD_CLK_ENA, 388 SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0), 389 SND_SOC_DAPM_SUPPLY("CLK DAC", 390 SUN8I_MOD_CLK_ENA, 391 SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0), 392 393 /* Module Resets */ 394 SND_SOC_DAPM_SUPPLY("RST AIF1", 395 SUN8I_MOD_RST_CTL, 396 SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0), 397 SND_SOC_DAPM_SUPPLY("RST ADC", 398 SUN8I_MOD_RST_CTL, 399 SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0), 400 SND_SOC_DAPM_SUPPLY("RST DAC", 401 SUN8I_MOD_RST_CTL, 402 SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0), 403 404 /* Module Supplies */ 405 SND_SOC_DAPM_SUPPLY("ADC", 406 SUN8I_ADC_DIG_CTRL, 407 SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0), 408 SND_SOC_DAPM_SUPPLY("DAC", 409 SUN8I_DAC_DIG_CTRL, 410 SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0), 411 412 /* AIF "ADC" Outputs */ 413 SND_SOC_DAPM_AIF_IN("AIF1 AD0L", "Capture", 0, 414 SUN8I_AIF1_ADCDAT_CTRL, 415 SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0), 416 SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0, 417 SUN8I_AIF1_ADCDAT_CTRL, 418 SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0), 419 420 /* AIF "ADC" Mixers */ 421 SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0, 422 sun8i_aif1_ad0_mixer_controls), 423 SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0, 424 sun8i_aif1_ad0_mixer_controls), 425 426 /* AIF "DAC" Inputs */ 427 SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0, 428 SUN8I_AIF1_DACDAT_CTRL, 429 SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), 430 SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 0, 431 SUN8I_AIF1_DACDAT_CTRL, 432 SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), 433 434 /* ADC Inputs (connected to analog codec DAPM context) */ 435 SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0), 436 SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), 437 438 /* DAC Outputs (connected to analog codec DAPM context) */ 439 SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), 440 SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), 441 442 /* DAC Mixers */ 443 SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0, 444 sun8i_dac_mixer_controls), 445 SOC_MIXER_ARRAY("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0, 446 sun8i_dac_mixer_controls), 447 }; 448 449 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { 450 /* Clock Routes */ 451 { "AIF1CLK", NULL, "mod" }, 452 453 { "SYSCLK", NULL, "AIF1CLK" }, 454 455 { "CLK AIF1", NULL, "AIF1CLK" }, 456 { "CLK AIF1", NULL, "SYSCLK" }, 457 { "RST AIF1", NULL, "CLK AIF1" }, 458 { "AIF1 AD0L", NULL, "RST AIF1" }, 459 { "AIF1 AD0R", NULL, "RST AIF1" }, 460 { "AIF1 DA0L", NULL, "RST AIF1" }, 461 { "AIF1 DA0R", NULL, "RST AIF1" }, 462 463 { "CLK ADC", NULL, "SYSCLK" }, 464 { "RST ADC", NULL, "CLK ADC" }, 465 { "ADC", NULL, "RST ADC" }, 466 { "ADCL", NULL, "ADC" }, 467 { "ADCR", NULL, "ADC" }, 468 469 { "CLK DAC", NULL, "SYSCLK" }, 470 { "RST DAC", NULL, "CLK DAC" }, 471 { "DAC", NULL, "RST DAC" }, 472 { "DACL", NULL, "DAC" }, 473 { "DACR", NULL, "DAC" }, 474 475 /* AIF "ADC" Output Routes */ 476 { "AIF1 AD0L", NULL, "Left Digital ADC Mixer" }, 477 { "AIF1 AD0R", NULL, "Right Digital ADC Mixer" }, 478 479 /* AIF "ADC" Mixer Routes */ 480 { "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" }, 481 { "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" }, 482 483 { "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" }, 484 { "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" }, 485 486 /* DAC Output Routes */ 487 { "DACL", NULL, "Left Digital DAC Mixer" }, 488 { "DACR", NULL, "Right Digital DAC Mixer" }, 489 490 /* DAC Mixer Routes */ 491 { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" }, 492 { "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" }, 493 494 { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" }, 495 { "Right Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCR" }, 496 }; 497 498 static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = { 499 /* Legacy ADC Inputs (connected to analog codec DAPM context) */ 500 SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0), 501 SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0), 502 503 /* Legacy DAC Outputs (connected to analog codec DAPM context) */ 504 SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0), 505 SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0), 506 }; 507 508 static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = { 509 /* Legacy ADC Routes */ 510 { "ADCL", NULL, "AIF1 Slot 0 Left ADC" }, 511 { "ADCR", NULL, "AIF1 Slot 0 Right ADC" }, 512 513 /* Legacy DAC Routes */ 514 { "AIF1 Slot 0 Left", NULL, "DACL" }, 515 { "AIF1 Slot 0 Right", NULL, "DACR" }, 516 }; 517 518 static int sun8i_codec_component_probe(struct snd_soc_component *component) 519 { 520 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 521 struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); 522 int ret; 523 524 /* Add widgets for backward compatibility with old device trees. */ 525 if (scodec->quirks->legacy_widgets) { 526 ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets, 527 ARRAY_SIZE(sun8i_codec_legacy_widgets)); 528 if (ret) 529 return ret; 530 531 ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes, 532 ARRAY_SIZE(sun8i_codec_legacy_routes)); 533 if (ret) 534 return ret; 535 } 536 537 /* 538 * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod") 539 * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also 540 * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO 541 * directly to simplify the clock tree. 542 */ 543 regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL, 544 SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK | 545 SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK, 546 SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL | 547 SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL); 548 549 /* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */ 550 regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL, 551 BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC), 552 SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK); 553 554 return 0; 555 } 556 557 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = { 558 .hw_params = sun8i_codec_hw_params, 559 .set_fmt = sun8i_set_fmt, 560 }; 561 562 static struct snd_soc_dai_driver sun8i_codec_dai = { 563 .name = "sun8i", 564 /* playback capabilities */ 565 .playback = { 566 .stream_name = "Playback", 567 .channels_min = 1, 568 .channels_max = 2, 569 .rates = SNDRV_PCM_RATE_8000_192000, 570 .formats = SNDRV_PCM_FMTBIT_S16_LE, 571 }, 572 /* capture capabilities */ 573 .capture = { 574 .stream_name = "Capture", 575 .channels_min = 1, 576 .channels_max = 2, 577 .rates = SNDRV_PCM_RATE_8000_192000, 578 .formats = SNDRV_PCM_FMTBIT_S16_LE, 579 .sig_bits = 24, 580 }, 581 /* pcm operations */ 582 .ops = &sun8i_codec_dai_ops, 583 }; 584 585 static const struct snd_soc_component_driver sun8i_soc_component = { 586 .dapm_widgets = sun8i_codec_dapm_widgets, 587 .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), 588 .dapm_routes = sun8i_codec_dapm_routes, 589 .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes), 590 .probe = sun8i_codec_component_probe, 591 .idle_bias_on = 1, 592 .use_pmdown_time = 1, 593 .endianness = 1, 594 .non_legacy_dai_naming = 1, 595 }; 596 597 static const struct regmap_config sun8i_codec_regmap_config = { 598 .reg_bits = 32, 599 .reg_stride = 4, 600 .val_bits = 32, 601 .max_register = SUN8I_DAC_MXR_SRC, 602 603 .cache_type = REGCACHE_FLAT, 604 }; 605 606 static int sun8i_codec_probe(struct platform_device *pdev) 607 { 608 struct sun8i_codec *scodec; 609 void __iomem *base; 610 int ret; 611 612 scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL); 613 if (!scodec) 614 return -ENOMEM; 615 616 scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); 617 if (IS_ERR(scodec->clk_module)) { 618 dev_err(&pdev->dev, "Failed to get the module clock\n"); 619 return PTR_ERR(scodec->clk_module); 620 } 621 622 base = devm_platform_ioremap_resource(pdev, 0); 623 if (IS_ERR(base)) { 624 dev_err(&pdev->dev, "Failed to map the registers\n"); 625 return PTR_ERR(base); 626 } 627 628 scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base, 629 &sun8i_codec_regmap_config); 630 if (IS_ERR(scodec->regmap)) { 631 dev_err(&pdev->dev, "Failed to create our regmap\n"); 632 return PTR_ERR(scodec->regmap); 633 } 634 635 scodec->quirks = of_device_get_match_data(&pdev->dev); 636 637 platform_set_drvdata(pdev, scodec); 638 639 pm_runtime_enable(&pdev->dev); 640 if (!pm_runtime_enabled(&pdev->dev)) { 641 ret = sun8i_codec_runtime_resume(&pdev->dev); 642 if (ret) 643 goto err_pm_disable; 644 } 645 646 ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component, 647 &sun8i_codec_dai, 1); 648 if (ret) { 649 dev_err(&pdev->dev, "Failed to register codec\n"); 650 goto err_suspend; 651 } 652 653 return ret; 654 655 err_suspend: 656 if (!pm_runtime_status_suspended(&pdev->dev)) 657 sun8i_codec_runtime_suspend(&pdev->dev); 658 659 err_pm_disable: 660 pm_runtime_disable(&pdev->dev); 661 662 return ret; 663 } 664 665 static int sun8i_codec_remove(struct platform_device *pdev) 666 { 667 pm_runtime_disable(&pdev->dev); 668 if (!pm_runtime_status_suspended(&pdev->dev)) 669 sun8i_codec_runtime_suspend(&pdev->dev); 670 671 return 0; 672 } 673 674 static const struct sun8i_codec_quirks sun8i_a33_quirks = { 675 .legacy_widgets = true, 676 .lrck_inversion = true, 677 }; 678 679 static const struct sun8i_codec_quirks sun50i_a64_quirks = { 680 }; 681 682 static const struct of_device_id sun8i_codec_of_match[] = { 683 { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks }, 684 { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks }, 685 {} 686 }; 687 MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); 688 689 static const struct dev_pm_ops sun8i_codec_pm_ops = { 690 SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend, 691 sun8i_codec_runtime_resume, NULL) 692 }; 693 694 static struct platform_driver sun8i_codec_driver = { 695 .driver = { 696 .name = "sun8i-codec", 697 .of_match_table = sun8i_codec_of_match, 698 .pm = &sun8i_codec_pm_ops, 699 }, 700 .probe = sun8i_codec_probe, 701 .remove = sun8i_codec_remove, 702 }; 703 module_platform_driver(sun8i_codec_driver); 704 705 MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver"); 706 MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>"); 707 MODULE_LICENSE("GPL"); 708 MODULE_ALIAS("platform:sun8i-codec"); 709