.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * AD193X Audio Codec driver supporting AD1936/7/8/9 |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright 2010 Analog Devices Inc. |
---|
5 | | - * |
---|
6 | | - * Licensed under the GPL-2 or later. |
---|
7 | 6 | */ |
---|
8 | 7 | |
---|
9 | 8 | #include <linux/module.h> |
---|
.. | .. |
---|
36 | 35 | ad193x_deemp); |
---|
37 | 36 | |
---|
38 | 37 | static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); |
---|
| 38 | + |
---|
| 39 | +static const unsigned int ad193x_sb[] = {32}; |
---|
| 40 | + |
---|
| 41 | +static struct snd_pcm_hw_constraint_list constr = { |
---|
| 42 | + .list = ad193x_sb, |
---|
| 43 | + .count = ARRAY_SIZE(ad193x_sb), |
---|
| 44 | +}; |
---|
39 | 45 | |
---|
40 | 46 | static const struct snd_kcontrol_new ad193x_snd_controls[] = { |
---|
41 | 47 | /* DAC volume control */ |
---|
.. | .. |
---|
93 | 99 | SND_SOC_DAPM_INPUT("ADC2IN"), |
---|
94 | 100 | }; |
---|
95 | 101 | |
---|
| 102 | +static int ad193x_check_pll(struct snd_soc_dapm_widget *source, |
---|
| 103 | + struct snd_soc_dapm_widget *sink) |
---|
| 104 | +{ |
---|
| 105 | + struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm); |
---|
| 106 | + struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); |
---|
| 107 | + |
---|
| 108 | + return !!ad193x->sysclk; |
---|
| 109 | +} |
---|
| 110 | + |
---|
96 | 111 | static const struct snd_soc_dapm_route audio_paths[] = { |
---|
97 | 112 | { "DAC", NULL, "SYSCLK" }, |
---|
98 | 113 | { "DAC Output", NULL, "DAC" }, |
---|
.. | .. |
---|
101 | 116 | { "DAC2OUT", NULL, "DAC Output" }, |
---|
102 | 117 | { "DAC3OUT", NULL, "DAC Output" }, |
---|
103 | 118 | { "DAC4OUT", NULL, "DAC Output" }, |
---|
104 | | - { "SYSCLK", NULL, "PLL_PWR" }, |
---|
| 119 | + { "SYSCLK", NULL, "PLL_PWR", &ad193x_check_pll }, |
---|
105 | 120 | }; |
---|
106 | 121 | |
---|
107 | 122 | static const struct snd_soc_dapm_route ad193x_adc_audio_paths[] = { |
---|
.. | .. |
---|
128 | 143 | * DAI ops entries |
---|
129 | 144 | */ |
---|
130 | 145 | |
---|
131 | | -static int ad193x_mute(struct snd_soc_dai *dai, int mute) |
---|
| 146 | +static int ad193x_mute(struct snd_soc_dai *dai, int mute, int direction) |
---|
132 | 147 | { |
---|
133 | 148 | struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component); |
---|
134 | 149 | |
---|
.. | .. |
---|
181 | 196 | { |
---|
182 | 197 | struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(codec_dai->component); |
---|
183 | 198 | unsigned int adc_serfmt = 0; |
---|
| 199 | + unsigned int dac_serfmt = 0; |
---|
184 | 200 | unsigned int adc_fmt = 0; |
---|
185 | 201 | unsigned int dac_fmt = 0; |
---|
186 | 202 | |
---|
187 | 203 | /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S |
---|
188 | | - * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) |
---|
| 204 | + * with TDM), ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) and DAC I2S mode |
---|
| 205 | + * (SND_SOC_DAIFMT_I2S) |
---|
189 | 206 | */ |
---|
190 | 207 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
---|
191 | 208 | case SND_SOC_DAIFMT_I2S: |
---|
192 | 209 | adc_serfmt |= AD193X_ADC_SERFMT_TDM; |
---|
| 210 | + dac_serfmt |= AD193X_DAC_SERFMT_STEREO; |
---|
193 | 211 | break; |
---|
194 | 212 | case SND_SOC_DAIFMT_DSP_A: |
---|
195 | 213 | adc_serfmt |= AD193X_ADC_SERFMT_AUX; |
---|
| 214 | + dac_serfmt |= AD193X_DAC_SERFMT_TDM; |
---|
196 | 215 | break; |
---|
197 | 216 | default: |
---|
198 | 217 | if (ad193x_has_adc(ad193x)) |
---|
199 | 218 | return -EINVAL; |
---|
200 | | - break; |
---|
201 | 219 | } |
---|
202 | 220 | |
---|
203 | 221 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
---|
.. | .. |
---|
220 | 238 | default: |
---|
221 | 239 | return -EINVAL; |
---|
222 | 240 | } |
---|
| 241 | + |
---|
| 242 | + /* For DSP_*, LRCLK's polarity must be inverted */ |
---|
| 243 | + if (fmt & SND_SOC_DAIFMT_DSP_A) |
---|
| 244 | + dac_fmt ^= AD193X_DAC_LEFT_HIGH; |
---|
223 | 245 | |
---|
224 | 246 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
---|
225 | 247 | case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */ |
---|
.. | .. |
---|
248 | 270 | regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2, |
---|
249 | 271 | AD193X_ADC_FMT_MASK, adc_fmt); |
---|
250 | 272 | } |
---|
| 273 | + regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL0, |
---|
| 274 | + AD193X_DAC_SERFMT_MASK, dac_serfmt); |
---|
251 | 275 | regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1, |
---|
252 | 276 | AD193X_DAC_FMT_MASK, dac_fmt); |
---|
253 | 277 | |
---|
.. | .. |
---|
258 | 282 | int clk_id, unsigned int freq, int dir) |
---|
259 | 283 | { |
---|
260 | 284 | struct snd_soc_component *component = codec_dai->component; |
---|
| 285 | + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); |
---|
261 | 286 | struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); |
---|
| 287 | + |
---|
| 288 | + if (clk_id == AD193X_SYSCLK_MCLK) { |
---|
| 289 | + /* MCLK must be 512 x fs */ |
---|
| 290 | + if (dir == SND_SOC_CLOCK_OUT || freq != 24576000) |
---|
| 291 | + return -EINVAL; |
---|
| 292 | + |
---|
| 293 | + regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL1, |
---|
| 294 | + AD193X_PLL_SRC_MASK, |
---|
| 295 | + AD193X_PLL_DAC_SRC_MCLK | |
---|
| 296 | + AD193X_PLL_CLK_SRC_MCLK); |
---|
| 297 | + |
---|
| 298 | + snd_soc_dapm_sync(dapm); |
---|
| 299 | + return 0; |
---|
| 300 | + } |
---|
262 | 301 | switch (freq) { |
---|
263 | 302 | case 12288000: |
---|
264 | 303 | case 18432000: |
---|
.. | .. |
---|
321 | 360 | return 0; |
---|
322 | 361 | } |
---|
323 | 362 | |
---|
| 363 | +static int ad193x_startup(struct snd_pcm_substream *substream, |
---|
| 364 | + struct snd_soc_dai *dai) |
---|
| 365 | +{ |
---|
| 366 | + return snd_pcm_hw_constraint_list(substream->runtime, 0, |
---|
| 367 | + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, |
---|
| 368 | + &constr); |
---|
| 369 | +} |
---|
| 370 | + |
---|
324 | 371 | static const struct snd_soc_dai_ops ad193x_dai_ops = { |
---|
| 372 | + .startup = ad193x_startup, |
---|
325 | 373 | .hw_params = ad193x_hw_params, |
---|
326 | | - .digital_mute = ad193x_mute, |
---|
| 374 | + .mute_stream = ad193x_mute, |
---|
327 | 375 | .set_tdm_slot = ad193x_set_tdm_slot, |
---|
328 | 376 | .set_sysclk = ad193x_set_dai_sysclk, |
---|
329 | 377 | .set_fmt = ad193x_set_dai_fmt, |
---|
| 378 | + .no_capture_mute = 1, |
---|
330 | 379 | }; |
---|
331 | 380 | |
---|
332 | 381 | /* codec DAI instance */ |
---|
.. | .. |
---|
351 | 400 | .ops = &ad193x_dai_ops, |
---|
352 | 401 | }; |
---|
353 | 402 | |
---|
| 403 | +/* codec DAI instance for DAC only */ |
---|
| 404 | +static struct snd_soc_dai_driver ad193x_no_adc_dai = { |
---|
| 405 | + .name = "ad193x-hifi", |
---|
| 406 | + .playback = { |
---|
| 407 | + .stream_name = "Playback", |
---|
| 408 | + .channels_min = 2, |
---|
| 409 | + .channels_max = 8, |
---|
| 410 | + .rates = SNDRV_PCM_RATE_48000, |
---|
| 411 | + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | |
---|
| 412 | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, |
---|
| 413 | + }, |
---|
| 414 | + .ops = &ad193x_dai_ops, |
---|
| 415 | +}; |
---|
| 416 | + |
---|
| 417 | +/* codec register values to set after reset */ |
---|
| 418 | +static void ad193x_reg_default_init(struct ad193x_priv *ad193x) |
---|
| 419 | +{ |
---|
| 420 | + static const struct reg_sequence reg_init[] = { |
---|
| 421 | + { 0, 0x99 }, /* PLL_CLK_CTRL0: pll input: mclki/xi 12.288Mhz */ |
---|
| 422 | + { 1, 0x04 }, /* PLL_CLK_CTRL1: no on-chip Vref */ |
---|
| 423 | + { 2, 0x40 }, /* DAC_CTRL0: TDM mode */ |
---|
| 424 | + { 3, 0x00 }, /* DAC_CTRL1: reset */ |
---|
| 425 | + { 4, 0x1A }, /* DAC_CTRL2: 48kHz de-emphasis, unmute dac */ |
---|
| 426 | + { 5, 0x00 }, /* DAC_CHNL_MUTE: unmute DAC channels */ |
---|
| 427 | + { 6, 0x00 }, /* DAC_L1_VOL: no attenuation */ |
---|
| 428 | + { 7, 0x00 }, /* DAC_R1_VOL: no attenuation */ |
---|
| 429 | + { 8, 0x00 }, /* DAC_L2_VOL: no attenuation */ |
---|
| 430 | + { 9, 0x00 }, /* DAC_R2_VOL: no attenuation */ |
---|
| 431 | + { 10, 0x00 }, /* DAC_L3_VOL: no attenuation */ |
---|
| 432 | + { 11, 0x00 }, /* DAC_R3_VOL: no attenuation */ |
---|
| 433 | + { 12, 0x00 }, /* DAC_L4_VOL: no attenuation */ |
---|
| 434 | + { 13, 0x00 }, /* DAC_R4_VOL: no attenuation */ |
---|
| 435 | + }; |
---|
| 436 | + static const struct reg_sequence reg_adc_init[] = { |
---|
| 437 | + { 14, 0x03 }, /* ADC_CTRL0: high-pass filter enable */ |
---|
| 438 | + { 15, 0x43 }, /* ADC_CTRL1: sata delay=1, adc aux mode */ |
---|
| 439 | + { 16, 0x00 }, /* ADC_CTRL2: reset */ |
---|
| 440 | + }; |
---|
| 441 | + |
---|
| 442 | + regmap_multi_reg_write(ad193x->regmap, reg_init, ARRAY_SIZE(reg_init)); |
---|
| 443 | + |
---|
| 444 | + if (ad193x_has_adc(ad193x)) { |
---|
| 445 | + regmap_multi_reg_write(ad193x->regmap, reg_adc_init, |
---|
| 446 | + ARRAY_SIZE(reg_adc_init)); |
---|
| 447 | + } |
---|
| 448 | +} |
---|
| 449 | + |
---|
354 | 450 | static int ad193x_component_probe(struct snd_soc_component *component) |
---|
355 | 451 | { |
---|
356 | 452 | struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); |
---|
.. | .. |
---|
358 | 454 | int num, ret; |
---|
359 | 455 | |
---|
360 | 456 | /* default setting for ad193x */ |
---|
361 | | - |
---|
362 | | - /* unmute dac channels */ |
---|
363 | | - regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0); |
---|
364 | | - /* de-emphasis: 48kHz, powedown dac */ |
---|
365 | | - regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A); |
---|
366 | | - /* dac in tdm mode */ |
---|
367 | | - regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40); |
---|
368 | | - |
---|
369 | | - /* adc only */ |
---|
370 | | - if (ad193x_has_adc(ad193x)) { |
---|
371 | | - /* high-pass filter enable */ |
---|
372 | | - regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3); |
---|
373 | | - /* sata delay=1, adc aux mode */ |
---|
374 | | - regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43); |
---|
375 | | - } |
---|
376 | | - |
---|
377 | | - /* pll input: mclki/xi */ |
---|
378 | | - regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ |
---|
379 | | - regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04); |
---|
| 457 | + ad193x_reg_default_init(ad193x); |
---|
380 | 458 | |
---|
381 | 459 | /* adc only */ |
---|
382 | 460 | if (ad193x_has_adc(ad193x)) { |
---|
.. | .. |
---|
444 | 522 | |
---|
445 | 523 | dev_set_drvdata(dev, ad193x); |
---|
446 | 524 | |
---|
| 525 | + if (ad193x_has_adc(ad193x)) |
---|
| 526 | + return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x, |
---|
| 527 | + &ad193x_dai, 1); |
---|
447 | 528 | return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x, |
---|
448 | | - &ad193x_dai, 1); |
---|
| 529 | + &ad193x_no_adc_dai, 1); |
---|
449 | 530 | } |
---|
450 | 531 | EXPORT_SYMBOL_GPL(ad193x_probe); |
---|
451 | 532 | |
---|