Lines Matching +full:boost +full:- +full:bypass
1 // SPDX-License-Identifier: GPL-2.0-only
3 * wm8978.c -- WM8978 ALSA SoC Audio Codec driver
5 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
7 * Copyright 2006-2009 Wolfson Microelectronics PLC.
106 static const char *wm8978_companding[] = {"Off", "NC", "u-law", "A-law"};
133 static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
134 static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
135 static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
136 static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
137 static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1);
212 /* OUT1 - Headphones */
220 /* OUT2 - Speakers */
228 /* OUT3/4 - Line Output */
232 /* Mixer #3: Boost (Input) mixer */
233 SOC_DOUBLE_R("PGA Boost (+20dB)",
236 SOC_DOUBLE_R_TLV("L2/R2 Boost Volume",
239 SOC_DOUBLE_R_TLV("Aux Boost Volume",
265 SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_LEFT_MIXER_CONTROL, 1, 1, 0),
271 SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_RIGHT_MIXER_CONTROL, 1, 1, 0),
311 SND_SOC_DAPM_PGA("Left Boost Mixer", WM8978_POWER_MANAGEMENT_2,
313 SND_SOC_DAPM_PGA("Right Boost Mixer", WM8978_POWER_MANAGEMENT_2,
354 {"Right Output Mixer", "Line Bypass Switch", "Right Boost Mixer"},
358 {"Left Output Mixer", "Line Bypass Switch", "Left Boost Mixer"},
373 /* Boost Mixer */
374 {"Right ADC", NULL, "Right Boost Mixer"},
376 {"Right Boost Mixer", NULL, "RAUX"},
377 {"Right Boost Mixer", NULL, "Right Capture PGA"},
378 {"Right Boost Mixer", NULL, "R2"},
380 {"Left ADC", NULL, "Left Boost Mixer"},
382 {"Left Boost Mixer", NULL, "LAUX"},
383 {"Left Boost Mixer", NULL, "Left Capture PGA"},
384 {"Left Boost Mixer", NULL, "L2"},
417 pll_div->div2 = 1; in pll_factors()
420 pll_div->div2 = 0; in pll_factors()
424 dev_warn(component->dev, in pll_factors()
428 pll_div->n = n_div; in pll_factors()
429 n_mod = target - source * n_div; in pll_factors()
436 pll_div->k = k; in pll_factors()
464 return -EINVAL; in wm8978_enum_mclk()
475 unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk, in wm8978_configure_pll()
476 f_256fs = wm8978->f_256fs; in wm8978_configure_pll()
480 return -EINVAL; in wm8978_configure_pll()
485 wm8978->mclk_idx = -1; in wm8978_configure_pll()
497 return -EINVAL; in wm8978_configure_pll()
505 dev_dbg(component->dev, "%s: OPCLKDIV=%d\n", __func__, opclk_div); in wm8978_configure_pll()
508 (opclk_div - 1) << 4); in wm8978_configure_pll()
510 wm8978->f_pllout = f_opclk * opclk_div; in wm8978_configure_pll()
522 int idx = wm8978_enum_mclk(f_256fs, f_mclk, &wm8978->f_pllout); in wm8978_configure_pll()
526 wm8978->mclk_idx = idx; in wm8978_configure_pll()
528 return -EINVAL; in wm8978_configure_pll()
531 f2 = wm8978->f_pllout * 4; in wm8978_configure_pll()
533 dev_dbg(component->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__, in wm8978_configure_pll()
534 wm8978->f_mclk, wm8978->f_pllout); in wm8978_configure_pll()
536 pll_factors(component, &pll_div, f2, wm8978->f_mclk); in wm8978_configure_pll()
538 dev_dbg(component->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n", in wm8978_configure_pll()
565 struct snd_soc_component *component = codec_dai->component; in wm8978_set_dai_clkdiv()
571 wm8978->f_opclk = div; in wm8978_set_dai_clkdiv()
573 if (wm8978->f_mclk) in wm8978_set_dai_clkdiv()
578 * user-requested OPCLK frquency as good as possible. in wm8978_set_dai_clkdiv()
585 * find an exact MCLK divider configuration - it will in wm8978_set_dai_clkdiv()
592 return -EINVAL; in wm8978_set_dai_clkdiv()
596 return -EINVAL; in wm8978_set_dai_clkdiv()
599 dev_dbg(component->dev, "%s: ID %d, value %u\n", __func__, div_id, div); in wm8978_set_dai_clkdiv()
610 struct snd_soc_component *component = codec_dai->component; in wm8978_set_dai_sysclk()
614 dev_dbg(component->dev, "%s: ID %d, freq %u\n", __func__, clk_id, freq); in wm8978_set_dai_sysclk()
617 wm8978->f_mclk = freq; in wm8978_set_dai_sysclk()
620 if (wm8978->f_opclk) in wm8978_set_dai_sysclk()
626 wm8978->sysclk = clk_id; in wm8978_set_dai_sysclk()
629 if (wm8978->sysclk == WM8978_PLL && (!freq || clk_id == WM8978_MCLK)) { in wm8978_set_dai_sysclk()
633 /* GPIO1 into default mode as input - before configuring PLL */ in wm8978_set_dai_sysclk()
638 wm8978->sysclk = WM8978_MCLK; in wm8978_set_dai_sysclk()
639 wm8978->f_pllout = 0; in wm8978_set_dai_sysclk()
640 wm8978->f_opclk = 0; in wm8978_set_dai_sysclk()
651 struct snd_soc_component *component = codec_dai->component; in wm8978_set_dai_fmt()
659 dev_dbg(component->dev, "%s\n", __func__); in wm8978_set_dai_fmt()
670 return -EINVAL; in wm8978_set_dai_fmt()
687 return -EINVAL; in wm8978_set_dai_fmt()
704 return -EINVAL; in wm8978_set_dai_fmt()
720 struct snd_soc_component *component = dai->component; in wm8978_hw_params()
732 if (!wm8978->f_mclk) in wm8978_hw_params()
733 return -EINVAL; in wm8978_hw_params()
773 wm8978->f_256fs = params_rate(params) * 256; in wm8978_hw_params()
775 if (wm8978->sysclk == WM8978_MCLK) { in wm8978_hw_params()
776 wm8978->mclk_idx = -1; in wm8978_hw_params()
777 f_sel = wm8978->f_mclk; in wm8978_hw_params()
779 if (!wm8978->f_opclk) { in wm8978_hw_params()
785 f_sel = wm8978->f_pllout; in wm8978_hw_params()
788 if (wm8978->mclk_idx < 0) { in wm8978_hw_params()
790 if (f_sel < wm8978->f_256fs || f_sel > 12 * wm8978->f_256fs) in wm8978_hw_params()
791 return -EINVAL; in wm8978_hw_params()
794 diff = abs(wm8978->f_256fs * 3 - in wm8978_hw_params()
807 best = wm8978->mclk_idx; in wm8978_hw_params()
812 dev_warn(component->dev, "Imprecise sampling rate: %uHz%s\n", in wm8978_hw_params()
814 wm8978->sysclk == WM8978_MCLK ? in wm8978_hw_params()
817 dev_dbg(component->dev, "%s: width %d, rate %u, MCLK divisor #%d\n", __func__, in wm8978_hw_params()
826 if (wm8978->sysclk != current_clk_id) { in wm8978_hw_params()
827 if (wm8978->sysclk == WM8978_PLL) in wm8978_hw_params()
841 struct snd_soc_component *component = dai->component; in wm8978_mute()
843 dev_dbg(component->dev, "%s: %d\n", __func__, mute); in wm8978_mute()
879 /* Preserve PLL - OPCLK may be used by someone */ in wm8978_set_bias_level()
886 dev_dbg(component->dev, "%s: %d, %x\n", __func__, level, power1); in wm8978_set_bias_level()
905 .name = "wm8978-hifi",
932 regcache_mark_dirty(wm8978->regmap); in wm8978_suspend()
942 regcache_sync(wm8978->regmap); in wm8978_resume()
946 if (wm8978->f_pllout) in wm8978_resume()
954 * These registers contain an "update" bit - bit 8. This means, for example,
956 * the update bit is set, will also the volume be updated - simultaneously for
981 wm8978->sysclk = WM8978_PLL; in wm8978_probe()
1027 wm8978 = devm_kzalloc(&i2c->dev, sizeof(struct wm8978_priv), in wm8978_i2c_probe()
1030 return -ENOMEM; in wm8978_i2c_probe()
1032 wm8978->regmap = devm_regmap_init_i2c(i2c, &wm8978_regmap_config); in wm8978_i2c_probe()
1033 if (IS_ERR(wm8978->regmap)) { in wm8978_i2c_probe()
1034 ret = PTR_ERR(wm8978->regmap); in wm8978_i2c_probe()
1035 dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); in wm8978_i2c_probe()
1042 ret = regmap_write(wm8978->regmap, WM8978_RESET, 0); in wm8978_i2c_probe()
1044 dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); in wm8978_i2c_probe()
1048 ret = devm_snd_soc_register_component(&i2c->dev, in wm8978_i2c_probe()
1051 dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); in wm8978_i2c_probe()