diff options
| -rw-r--r-- | sound/soc/codecs/pcm512x.c | 178 |
1 files changed, 159 insertions, 19 deletions
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 9974f201a08f..4b5f1fe9be97 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c | |||
| @@ -54,6 +54,9 @@ struct pcm512x_priv { | |||
| 54 | int pll_d; | 54 | int pll_d; |
| 55 | int pll_p; | 55 | int pll_p; |
| 56 | unsigned long real_pll; | 56 | unsigned long real_pll; |
| 57 | unsigned long overclock_pll; | ||
| 58 | unsigned long overclock_dac; | ||
| 59 | unsigned long overclock_dsp; | ||
| 57 | }; | 60 | }; |
| 58 | 61 | ||
| 59 | /* | 62 | /* |
| @@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg) | |||
| 224 | } | 227 | } |
| 225 | } | 228 | } |
| 226 | 229 | ||
| 230 | static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol, | ||
| 231 | struct snd_ctl_elem_value *ucontrol) | ||
| 232 | { | ||
| 233 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
| 234 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
| 235 | |||
| 236 | ucontrol->value.integer.value[0] = pcm512x->overclock_pll; | ||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | |||
| 240 | static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol, | ||
| 241 | struct snd_ctl_elem_value *ucontrol) | ||
| 242 | { | ||
| 243 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
| 244 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
| 245 | |||
| 246 | switch (codec->dapm.bias_level) { | ||
| 247 | case SND_SOC_BIAS_OFF: | ||
| 248 | case SND_SOC_BIAS_STANDBY: | ||
| 249 | break; | ||
| 250 | default: | ||
| 251 | return -EBUSY; | ||
| 252 | } | ||
| 253 | |||
| 254 | pcm512x->overclock_pll = ucontrol->value.integer.value[0]; | ||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol, | ||
| 259 | struct snd_ctl_elem_value *ucontrol) | ||
| 260 | { | ||
| 261 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
| 262 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
| 263 | |||
| 264 | ucontrol->value.integer.value[0] = pcm512x->overclock_dsp; | ||
| 265 | return 0; | ||
| 266 | } | ||
| 267 | |||
| 268 | static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol, | ||
| 269 | struct snd_ctl_elem_value *ucontrol) | ||
| 270 | { | ||
| 271 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
| 272 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
| 273 | |||
| 274 | switch (codec->dapm.bias_level) { | ||
| 275 | case SND_SOC_BIAS_OFF: | ||
| 276 | case SND_SOC_BIAS_STANDBY: | ||
| 277 | break; | ||
| 278 | default: | ||
| 279 | return -EBUSY; | ||
| 280 | } | ||
| 281 | |||
| 282 | pcm512x->overclock_dsp = ucontrol->value.integer.value[0]; | ||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol, | ||
| 287 | struct snd_ctl_elem_value *ucontrol) | ||
| 288 | { | ||
| 289 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
| 290 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
| 291 | |||
| 292 | ucontrol->value.integer.value[0] = pcm512x->overclock_dac; | ||
| 293 | return 0; | ||
| 294 | } | ||
| 295 | |||
| 296 | static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol, | ||
| 297 | struct snd_ctl_elem_value *ucontrol) | ||
| 298 | { | ||
| 299 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
| 300 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
| 301 | |||
| 302 | switch (codec->dapm.bias_level) { | ||
| 303 | case SND_SOC_BIAS_OFF: | ||
| 304 | case SND_SOC_BIAS_STANDBY: | ||
| 305 | break; | ||
| 306 | default: | ||
| 307 | return -EBUSY; | ||
| 308 | } | ||
| 309 | |||
| 310 | pcm512x->overclock_dac = ucontrol->value.integer.value[0]; | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 227 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); | 314 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); |
| 228 | static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); | 315 | static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); |
| 229 | static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); | 316 | static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); |
| @@ -328,6 +415,13 @@ SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), | |||
| 328 | SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), | 415 | SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), |
| 329 | SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), | 416 | SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), |
| 330 | SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), | 417 | SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), |
| 418 | |||
| 419 | SOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0, | ||
| 420 | pcm512x_overclock_pll_get, pcm512x_overclock_pll_put), | ||
| 421 | SOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0, | ||
| 422 | pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put), | ||
| 423 | SOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0, | ||
| 424 | pcm512x_overclock_dac_get, pcm512x_overclock_dac_put), | ||
| 331 | }; | 425 | }; |
| 332 | 426 | ||
| 333 | static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { | 427 | static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { |
| @@ -346,6 +440,45 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { | |||
| 346 | { "OUTR", NULL, "DACR" }, | 440 | { "OUTR", NULL, "DACR" }, |
| 347 | }; | 441 | }; |
| 348 | 442 | ||
| 443 | static unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x) | ||
| 444 | { | ||
| 445 | return 25000000 + 25000000 * pcm512x->overclock_pll / 100; | ||
| 446 | } | ||
| 447 | |||
| 448 | static unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x) | ||
| 449 | { | ||
| 450 | return 50000000 + 50000000 * pcm512x->overclock_dsp / 100; | ||
| 451 | } | ||
| 452 | |||
| 453 | static unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x, | ||
| 454 | unsigned long rate) | ||
| 455 | { | ||
| 456 | return rate + rate * pcm512x->overclock_dac / 100; | ||
| 457 | } | ||
| 458 | |||
| 459 | static unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x) | ||
| 460 | { | ||
| 461 | if (!pcm512x->pll_out) | ||
| 462 | return 25000000; | ||
| 463 | return pcm512x_pll_max(pcm512x); | ||
| 464 | } | ||
| 465 | |||
| 466 | static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x, | ||
| 467 | unsigned long dac_rate) | ||
| 468 | { | ||
| 469 | /* | ||
| 470 | * If the DAC is not actually overclocked, use the good old | ||
| 471 | * NCP target rate... | ||
| 472 | */ | ||
| 473 | if (dac_rate <= 6144000) | ||
| 474 | return 1536000; | ||
| 475 | /* | ||
| 476 | * ...but if the DAC is in fact overclocked, bump the NCP target | ||
| 477 | * rate to get the recommended dividers even when overclocking. | ||
| 478 | */ | ||
| 479 | return pcm512x_dac_max(pcm512x, 1536000); | ||
| 480 | } | ||
| 481 | |||
| 349 | static const u32 pcm512x_dai_rates[] = { | 482 | static const u32 pcm512x_dai_rates[] = { |
| 350 | 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, | 483 | 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, |
| 351 | 88200, 96000, 176400, 192000, 384000, | 484 | 88200, 96000, 176400, 192000, 384000, |
| @@ -359,6 +492,7 @@ static const struct snd_pcm_hw_constraint_list constraints_slave = { | |||
| 359 | static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, | 492 | static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, |
| 360 | struct snd_pcm_hw_rule *rule) | 493 | struct snd_pcm_hw_rule *rule) |
| 361 | { | 494 | { |
| 495 | struct pcm512x_priv *pcm512x = rule->private; | ||
| 362 | struct snd_interval ranges[2]; | 496 | struct snd_interval ranges[2]; |
| 363 | int frame_size; | 497 | int frame_size; |
| 364 | 498 | ||
| @@ -377,7 +511,7 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, | |||
| 377 | */ | 511 | */ |
| 378 | memset(ranges, 0, sizeof(ranges)); | 512 | memset(ranges, 0, sizeof(ranges)); |
| 379 | ranges[0].min = 8000; | 513 | ranges[0].min = 8000; |
| 380 | ranges[0].max = 25000000 / frame_size / 2; | 514 | ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2; |
| 381 | ranges[1].min = DIV_ROUND_UP(16000000, frame_size); | 515 | ranges[1].min = DIV_ROUND_UP(16000000, frame_size); |
| 382 | ranges[1].max = 384000; | 516 | ranges[1].max = 384000; |
| 383 | break; | 517 | break; |
| @@ -408,7 +542,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream, | |||
| 408 | return snd_pcm_hw_rule_add(substream->runtime, 0, | 542 | return snd_pcm_hw_rule_add(substream->runtime, 0, |
| 409 | SNDRV_PCM_HW_PARAM_RATE, | 543 | SNDRV_PCM_HW_PARAM_RATE, |
| 410 | pcm512x_hw_rule_rate, | 544 | pcm512x_hw_rule_rate, |
| 411 | NULL, | 545 | pcm512x, |
| 412 | SNDRV_PCM_HW_PARAM_FRAME_BITS, | 546 | SNDRV_PCM_HW_PARAM_FRAME_BITS, |
| 413 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | 547 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
| 414 | 548 | ||
| @@ -517,6 +651,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, | |||
| 517 | unsigned long bclk_rate) | 651 | unsigned long bclk_rate) |
| 518 | { | 652 | { |
| 519 | struct device *dev = dai->dev; | 653 | struct device *dev = dai->dev; |
| 654 | struct snd_soc_codec *codec = dai->codec; | ||
| 655 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
| 520 | unsigned long sck_rate; | 656 | unsigned long sck_rate; |
| 521 | int pow2; | 657 | int pow2; |
| 522 | 658 | ||
| @@ -527,9 +663,10 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, | |||
| 527 | * as many factors of 2 as possible, as that makes it easier | 663 | * as many factors of 2 as possible, as that makes it easier |
| 528 | * to find a fast DAC rate | 664 | * to find a fast DAC rate |
| 529 | */ | 665 | */ |
| 530 | pow2 = 1 << fls((25000000 - 16000000) / bclk_rate); | 666 | pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate); |
| 531 | for (; pow2; pow2 >>= 1) { | 667 | for (; pow2; pow2 >>= 1) { |
| 532 | sck_rate = rounddown(25000000, bclk_rate * pow2); | 668 | sck_rate = rounddown(pcm512x_pll_max(pcm512x), |
| 669 | bclk_rate * pow2); | ||
| 533 | if (sck_rate >= 16000000) | 670 | if (sck_rate >= 16000000) |
| 534 | break; | 671 | break; |
| 535 | } | 672 | } |
| @@ -678,7 +815,7 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai, | |||
| 678 | return 0; /* futile, quit early */ | 815 | return 0; /* futile, quit early */ |
| 679 | 816 | ||
| 680 | /* run DAC no faster than 6144000 Hz */ | 817 | /* run DAC no faster than 6144000 Hz */ |
| 681 | for (dac_rate = rounddown(6144000, osr_rate); | 818 | for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate); |
| 682 | dac_rate; | 819 | dac_rate; |
| 683 | dac_rate -= osr_rate) { | 820 | dac_rate -= osr_rate) { |
| 684 | 821 | ||
| @@ -805,7 +942,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, | |||
| 805 | osr_rate = 16 * sample_rate; | 942 | osr_rate = 16 * sample_rate; |
| 806 | 943 | ||
| 807 | /* run DSP no faster than 50 MHz */ | 944 | /* run DSP no faster than 50 MHz */ |
| 808 | dsp_div = mck_rate > 50000000 ? 2 : 1; | 945 | dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1; |
| 809 | 946 | ||
| 810 | dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); | 947 | dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); |
| 811 | if (dac_rate) { | 948 | if (dac_rate) { |
| @@ -836,7 +973,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, | |||
| 836 | dacsrc_rate = pllin_rate; | 973 | dacsrc_rate = pllin_rate; |
| 837 | } else { | 974 | } else { |
| 838 | /* run DAC no faster than 6144000 Hz */ | 975 | /* run DAC no faster than 6144000 Hz */ |
| 839 | unsigned long dac_mul = 6144000 / osr_rate; | 976 | unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000) |
| 977 | / osr_rate; | ||
| 840 | unsigned long sck_mul = sck_rate / osr_rate; | 978 | unsigned long sck_mul = sck_rate / osr_rate; |
| 841 | 979 | ||
| 842 | for (; dac_mul; dac_mul--) { | 980 | for (; dac_mul; dac_mul--) { |
| @@ -863,28 +1001,30 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, | |||
| 863 | dacsrc_rate = sck_rate; | 1001 | dacsrc_rate = sck_rate; |
| 864 | } | 1002 | } |
| 865 | 1003 | ||
| 1004 | osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); | ||
| 1005 | if (osr_div > 128) { | ||
| 1006 | dev_err(dev, "Failed to find OSR divider\n"); | ||
| 1007 | return -EINVAL; | ||
| 1008 | } | ||
| 1009 | |||
| 866 | dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate); | 1010 | dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate); |
| 867 | if (dac_div > 128) { | 1011 | if (dac_div > 128) { |
| 868 | dev_err(dev, "Failed to find DAC divider\n"); | 1012 | dev_err(dev, "Failed to find DAC divider\n"); |
| 869 | return -EINVAL; | 1013 | return -EINVAL; |
| 870 | } | 1014 | } |
| 1015 | dac_rate = dacsrc_rate / dac_div; | ||
| 871 | 1016 | ||
| 872 | ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000); | 1017 | ncp_div = DIV_ROUND_CLOSEST(dac_rate, |
| 873 | if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) { | 1018 | pcm512x_ncp_target(pcm512x, dac_rate)); |
| 1019 | if (ncp_div > 128 || dac_rate / ncp_div > 2048000) { | ||
| 874 | /* run NCP no faster than 2048000 Hz, but why? */ | 1020 | /* run NCP no faster than 2048000 Hz, but why? */ |
| 875 | ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000); | 1021 | ncp_div = DIV_ROUND_UP(dac_rate, 2048000); |
| 876 | if (ncp_div > 128) { | 1022 | if (ncp_div > 128) { |
| 877 | dev_err(dev, "Failed to find NCP divider\n"); | 1023 | dev_err(dev, "Failed to find NCP divider\n"); |
| 878 | return -EINVAL; | 1024 | return -EINVAL; |
| 879 | } | 1025 | } |
| 880 | } | 1026 | } |
| 881 | 1027 | ||
| 882 | osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); | ||
| 883 | if (osr_div > 128) { | ||
| 884 | dev_err(dev, "Failed to find OSR divider\n"); | ||
| 885 | return -EINVAL; | ||
| 886 | } | ||
| 887 | |||
| 888 | idac = mck_rate / (dsp_div * sample_rate); | 1028 | idac = mck_rate / (dsp_div * sample_rate); |
| 889 | 1029 | ||
| 890 | ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1); | 1030 | ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1); |
| @@ -937,11 +1077,11 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, | |||
| 937 | return ret; | 1077 | return ret; |
| 938 | } | 1078 | } |
| 939 | 1079 | ||
| 940 | if (sample_rate <= 48000) | 1080 | if (sample_rate <= pcm512x_dac_max(pcm512x, 48000)) |
| 941 | fssp = PCM512x_FSSP_48KHZ; | 1081 | fssp = PCM512x_FSSP_48KHZ; |
| 942 | else if (sample_rate <= 96000) | 1082 | else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000)) |
| 943 | fssp = PCM512x_FSSP_96KHZ; | 1083 | fssp = PCM512x_FSSP_96KHZ; |
| 944 | else if (sample_rate <= 192000) | 1084 | else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000)) |
| 945 | fssp = PCM512x_FSSP_192KHZ; | 1085 | fssp = PCM512x_FSSP_192KHZ; |
| 946 | else | 1086 | else |
| 947 | fssp = PCM512x_FSSP_384KHZ; | 1087 | fssp = PCM512x_FSSP_384KHZ; |
