staticint wm8804_aif_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
/* * We can't use the same notifier block for more than one supply and * there's no way I can see to get from a callback to the caller * except container_of().
*/ #define WM8804_REGULATOR_EVENT(n) \ staticint wm8804_regulator_event_##n(struct notifier_block *nb, \ unsignedlong event, void *data) \
{ \ struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \
disable_nb[n]); \ if (event & REGULATOR_EVENT_DISABLE) { \
regcache_mark_dirty(wm8804->regmap); \
} \ return 0; \
}
switch (event) { case SND_SOC_DAPM_POST_PMU: /* power up the aif */ if (!wm8804->aif_pwr)
snd_soc_component_update_bits(component, WM8804_PWRDN, 0x10, 0x0);
wm8804->aif_pwr++; break; case SND_SOC_DAPM_POST_PMD: /* power down only both paths are disabled */
wm8804->aif_pwr--; if (!wm8804->aif_pwr)
snd_soc_component_update_bits(component, WM8804_PWRDN, 0x10, 0x10); break;
}
if (snd_soc_component_test_bits(component, e->reg, mask, val)) { /* save the current power state of the transmitter */
txpwr = snd_soc_component_read(component, WM8804_PWRDN) & 0x4;
/* power down the transmitter */
snd_soc_component_update_bits(component, WM8804_PWRDN, 0x4, 0x4);
/* set the tx source */
snd_soc_component_update_bits(component, e->reg, mask, val);
staticbool wm8804_volatile(struct device *dev, unsignedint reg)
{ switch (reg) { case WM8804_RST_DEVID1: case WM8804_DEVID2: case WM8804_DEVREV: case WM8804_INTSTAT: case WM8804_SPDSTAT: case WM8804_RXCHAN1: case WM8804_RXCHAN2: case WM8804_RXCHAN3: case WM8804_RXCHAN4: case WM8804_RXCHAN5: returntrue; default: returnfalse;
}
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S:
format = 0x2; break; case SND_SOC_DAIFMT_RIGHT_J:
format = 0x0; break; case SND_SOC_DAIFMT_LEFT_J:
format = 0x1; break; case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B:
format = 0x3; break; default:
dev_err(dai->dev, "Unknown dai format\n"); return -EINVAL;
}
/* set data format */
snd_soc_component_update_bits(component, WM8804_AIFTX, 0x3, format);
snd_soc_component_update_bits(component, WM8804_AIFRX, 0x3, format);
/* * Scale the output frequency up; the PLL should run in the * region of 90-100MHz.
*/ for (i = 0; i < ARRAY_SIZE(post_table); i++) {
tmp = target * post_table[i].div; if ((tmp >= 90000000 && tmp <= 100000000) &&
(mclk_div == post_table[i].mclkdiv)) {
pll_div->freqmode = post_table[i].freqmode;
pll_div->mclkdiv = post_table[i].mclkdiv;
target *= post_table[i].div; break;
}
}
if (i == ARRAY_SIZE(post_table)) {
pr_err("%s: Unable to scale output frequency: %uHz\n",
__func__, target); return -EINVAL;
}
if (Ndiv < 5 || Ndiv > 13) {
pr_err("%s: WM8804 N value is not within the recommended range: %lu\n",
__func__, Ndiv); return -EINVAL;
}
pll_div->n = Ndiv;
if (!freq_in || !freq_out) { /* disable the PLL */
regmap_update_bits_check(wm8804->regmap, WM8804_PWRDN,
0x1, 0x1, &change); if (change)
pm_runtime_put(wm8804->dev);
} else { int ret; struct pll_div pll_div;
ret = pll_factors(&pll_div, freq_out, freq_in,
wm8804->mclk_div); if (ret) return ret;
/* power down the PLL before reprogramming it */
regmap_update_bits_check(wm8804->regmap, WM8804_PWRDN,
0x1, 0x1, &change); if (!change)
pm_runtime_get_sync(wm8804->dev);
/* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) { struct regulator *regulator = wm8804->supplies[i].consumer;
ret = devm_regulator_register_notifier(regulator,
&wm8804->disable_nb[i]); if (ret != 0) {
dev_err(dev, "Failed to register regulator notifier: %d\n",
ret); return ret;
}
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
wm8804->supplies); if (ret) {
dev_err(dev, "Failed to enable supplies: %d\n", ret); return ret;
}
gpiod_set_value_cansleep(wm8804->reset, 1);
ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1); if (ret < 0) {
dev_err(dev, "Failed to read device ID: %d\n", ret); goto err_reg_enable;
}
ret = regmap_read(regmap, WM8804_DEVID2, &id2); if (ret < 0) {
dev_err(dev, "Failed to read device ID: %d\n", ret); goto err_reg_enable;
}
id2 = (id2 << 8) | id1;
if (id2 != 0x8805) {
dev_err(dev, "Invalid device ID: %#x\n", id2);
ret = -EINVAL; goto err_reg_enable;
}
ret = regmap_read(regmap, WM8804_DEVREV, &id1); if (ret < 0) {
dev_err(dev, "Failed to read device revision: %d\n",
ret); goto err_reg_enable;
}
dev_info(dev, "revision %c\n", id1 + 'A');
if (!wm8804->reset) {
ret = wm8804_soft_reset(wm8804); if (ret < 0) {
dev_err(dev, "Failed to issue reset: %d\n", ret); goto err_reg_enable;
}
}
ret = devm_snd_soc_register_component(dev, &soc_component_dev_wm8804,
&wm8804_dai, 1); if (ret < 0) {
dev_err(dev, "Failed to register CODEC: %d\n", ret); goto err_reg_enable;
}
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.