staticbool wm8955_writeable(struct device *dev, unsignedint reg)
{ switch (reg) { case WM8955_LOUT1_VOLUME: case WM8955_ROUT1_VOLUME: case WM8955_DAC_CONTROL: case WM8955_AUDIO_INTERFACE: case WM8955_SAMPLE_RATE: case WM8955_LEFT_DAC_VOLUME: case WM8955_RIGHT_DAC_VOLUME: case WM8955_BASS_CONTROL: case WM8955_TREBLE_CONTROL: case WM8955_RESET: case WM8955_ADDITIONAL_CONTROL_1: case WM8955_ADDITIONAL_CONTROL_2: case WM8955_POWER_MANAGEMENT_1: case WM8955_POWER_MANAGEMENT_2: case WM8955_ADDITIONAL_CONTROL_3: case WM8955_LEFT_OUT_MIX_1: case WM8955_LEFT_OUT_MIX_2: case WM8955_RIGHT_OUT_MIX_1: case WM8955_RIGHT_OUT_MIX_2: case WM8955_MONO_OUT_MIX_1: case WM8955_MONO_OUT_MIX_2: case WM8955_LOUT2_VOLUME: case WM8955_ROUT2_VOLUME: case WM8955_MONOOUT_VOLUME: case WM8955_CLOCKING_PLL: case WM8955_PLL_CONTROL_1: case WM8955_PLL_CONTROL_2: case WM8955_PLL_CONTROL_3: case WM8955_PLL_CONTROL_4: returntrue; default: returnfalse;
}
}
/* The size in bits of the FLL divide multiplied by 10
* to allow rounding later */ #define FIXED_FLL_SIZE ((1 << 22) * 10)
staticint wm8955_pll_factors(struct device *dev, int Fref, int Fout, struct pll_factors *pll)
{
u64 Kpart; unsignedint K, Ndiv, Nmod, target;
dev_dbg(dev, "Fref=%u Fout=%u\n", Fref, Fout);
/* The oscilator should run at should be 90-100MHz, and * there's a divide by 4 plus an optional divide by 2 in the * output path to generate the system clock. The clock table
* is sortd so we should always generate a suitable target. */
target = Fout * 4; if (target < 90000000) {
pll->outdiv = 1;
target *= 2;
} else {
pll->outdiv = 0;
}
/* Lookup table specifying SRATE (table 25 in datasheet); some of the * output frequencies have been rounded to the standard frequencies
* they are intended to match where the error is slight. */ staticstruct { int mclk; int fs; int usb; int sr;
} clock_cfgs[] = {
{ 18432000, 8000, 0, 3, },
{ 18432000, 12000, 0, 9, },
{ 18432000, 16000, 0, 11, },
{ 18432000, 24000, 0, 29, },
{ 18432000, 32000, 0, 13, },
{ 18432000, 48000, 0, 1, },
{ 18432000, 96000, 0, 15, },
staticint wm8955_configure_clocking(struct snd_soc_component *component)
{ struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component); int i, ret, val; int clocking = 0; int srate = 0; int sr = -1; struct pll_factors pll;
/* If we're not running a sample rate currently just pick one */ if (wm8955->fs == 0)
wm8955->fs = 8000;
/* Can we generate an exact output? */ for (i = 0; i < ARRAY_SIZE(clock_cfgs); i++) { if (wm8955->fs != clock_cfgs[i].fs) continue;
sr = i;
if (wm8955->mclk_rate == clock_cfgs[i].mclk) break;
}
/* We should never get here with an unsupported sample rate */ if (sr == -1) {
dev_err(component->dev, "Sample rate %dHz unsupported\n",
wm8955->fs);
WARN_ON(sr == -1); return -EINVAL;
}
if (i == ARRAY_SIZE(clock_cfgs)) { /* If we can't generate the right clock from MCLK then * we should configure the PLL to supply us with an * appropriate clock.
*/
clocking |= WM8955_MCLKSEL;
/* Use the last divider configuration we saw for the
* sample rate. */
ret = wm8955_pll_factors(component->dev, wm8955->mclk_rate,
clock_cfgs[sr].mclk, &pll); if (ret != 0) {
dev_err(component->dev, "Unable to generate %dHz from %dHz MCLK\n",
wm8955->fs, wm8955->mclk_rate); return -EINVAL;
}
staticint wm8955_sysclk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event)
{ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); int ret = 0;
/* Always disable the clocks - if we're doing reconfiguration this * avoids misclocking.
*/
snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
WM8955_DIGENB, 0);
snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
WM8955_PLL_RB | WM8955_PLLEN, 0);
switch (event) { case SND_SOC_DAPM_POST_PMD: break; case SND_SOC_DAPM_PRE_PMU:
ret = wm8955_configure_clocking(component); break; default:
ret = -EINVAL; break;
}
staticint wm8955_set_deemph(struct snd_soc_component *component)
{ struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component); int val, i, best;
/* If we're using deemphasis select the nearest available sample * rate.
*/ if (wm8955->deemph) {
best = 1; for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { if (abs(deemph_settings[i] - wm8955->fs) <
abs(deemph_settings[best] - wm8955->fs))
best = i;
}
val = best << WM8955_DEEMPH_SHIFT;
} else {
val = 0;
}
/* Not a stereo pair so they line up with the DAPM switches */
SOC_SINGLE_TLV("Mono Left Bypass Volume", WM8955_MONO_OUT_MIX_1, 4, 7, 1,
mono_tlv),
SOC_SINGLE_TLV("Mono Right Bypass Volume", WM8955_MONO_OUT_MIX_2, 4, 7, 1,
mono_tlv),
/* The names are chosen to make the control names nice */
SND_SOC_DAPM_MIXER("Left", SND_SOC_NOPM, 0, 0,
lmixer, ARRAY_SIZE(lmixer)),
SND_SOC_DAPM_MIXER("Right", SND_SOC_NOPM, 0, 0,
rmixer, ARRAY_SIZE(rmixer)),
SND_SOC_DAPM_MIXER("Mono", SND_SOC_NOPM, 0, 0,
mmixer, ARRAY_SIZE(mmixer)),
/* If the chip is clocked then disable the clocks and force a * reconfiguration, otherwise DAPM will power up the
* clocks for us later. */
ret = snd_soc_component_read(component, WM8955_POWER_MANAGEMENT_1); if (ret < 0) return ret; if (ret & WM8955_DIGENB) {
snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
WM8955_DIGENB, 0);
snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
WM8955_PLL_RB | WM8955_PLLEN, 0);
wm8955_configure_clocking(component);
}
return 0;
}
staticint wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsignedint freq, int dir)
{ struct snd_soc_component *component = dai->component; struct wm8955_priv *priv = snd_soc_component_get_drvdata(component); int div;
switch (clk_id) { case WM8955_CLK_MCLK: if (freq > 15000000) {
priv->mclk_rate = freq /= 2;
div = WM8955_MCLKDIV2;
} else {
priv->mclk_rate = freq;
div = 0;
}
/* Minimum bias current */
snd_soc_component_update_bits(component, WM8955_ADDITIONAL_CONTROL_1,
WM8955_VSEL_MASK, 0); break;
case SND_SOC_BIAS_OFF: /* Low resistance VROI to help discharge */
snd_soc_component_update_bits(component,
WM8955_ADDITIONAL_CONTROL_3,
WM8955_VROI, 0);
/* Turn off VMID and VREF */
snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
WM8955_VREF |
WM8955_VMIDSEL_MASK, 0);
/* Also enable adaptive bass boost by default */
snd_soc_component_update_bits(component, WM8955_BASS_CONTROL, WM8955_BB, WM8955_BB);
/* Set platform data values */ if (pdata) { if (pdata->out2_speaker)
snd_soc_component_update_bits(component, WM8955_ADDITIONAL_CONTROL_2,
WM8955_ROUT2INV, WM8955_ROUT2INV);
if (pdata->monoin_diff)
snd_soc_component_update_bits(component, WM8955_MONO_OUT_MIX_1,
WM8955_DMEN, WM8955_DMEN);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.