/* * TODO: * It would have been nice to check the actual rate against the sample rate * requested in hw_params(). Unfortunately, I was not able to make the mode * detection and IRQ work reliably: * * 1. IRQs are generated on mode change only, so there is no notification * on transition between no signal and mode 0 (32kHz). * 2. Mode detection very often has glitches, and may detects the * lowest or the highest mode before zeroing in on the actual mode. * * This makes calling snd_pcm_stop() difficult to get right. Even notifying * the kcontrol would be very unreliable at this point. * Let's keep things simple until the magic spell that makes this work is * found.
*/
/* * If max width is zero, we are not capturing anything. * Also Sometimes, when the capture is on but there is no data, * mode is SPDIFIN_MODE_NUM, but not always ...
*/ if (FIELD_GET(SPDIFIN_STAT0_MAXW, stat) &&
mode < SPDIFIN_MODE_NUM)
rate = priv->conf->mode_rates[mode];
staticunsignedint axg_spdifin_mode_timer(struct axg_spdifin *priv, int mode, unsignedint rate)
{ /* * Number of period of the reference clock during a period of the * input signal reference clock
*/ return rate / (128 * priv->conf->mode_rates[mode]);
}
staticint axg_spdifin_sample_mode_config(struct snd_soc_dai *dai, struct axg_spdifin *priv)
{ unsignedint rate, t_next; int ret, i = SPDIFIN_MODE_NUM - 1;
/* Set spdif input reference clock */
ret = clk_set_rate(priv->refclk, priv->conf->ref_rate); if (ret) {
dev_err(dai->dev, "reference clock rate set failed\n"); return ret;
}
/* * The rate actually set might be slightly different, get * the actual rate for the following mode calculation
*/
rate = clk_get_rate(priv->refclk);
/* HW will update mode every 1ms */
regmap_update_bits(priv->map, SPDIFIN_CTRL1,
SPDIFIN_CTRL1_BASE_TIMER,
FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000));
/* Threshold based on the maximum width between two edges */
regmap_update_bits(priv->map, SPDIFIN_CTRL0,
SPDIFIN_CTRL0_WIDTH_SEL, 0);
/* Calculate the last timer which has no threshold */
t_next = axg_spdifin_mode_timer(priv, i, rate);
axg_spdifin_write_timer(priv->map, i, t_next);
do { unsignedint t;
i -= 1;
/* Calculate the timer */
t = axg_spdifin_mode_timer(priv, i, rate);
/* Set the timer value */
axg_spdifin_write_timer(priv->map, i, t);
/* Set the threshold value */
axg_spdifin_write_threshold(priv->map, i, 3 * (t + t_next));
/* Save the current timer for the next threshold calculation */
t_next = t;
priv->conf = of_device_get_match_data(dev); if (!priv->conf) {
dev_err(dev, "failed to match device\n"); return -ENODEV;
}
regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs);
priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifin_regmap_cfg); if (IS_ERR(priv->map)) {
dev_err(dev, "failed to init regmap: %ld\n",
PTR_ERR(priv->map)); return PTR_ERR(priv->map);
}
priv->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(priv->pclk)) return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get pclk\n");
priv->refclk = devm_clk_get(dev, "refclk"); if (IS_ERR(priv->refclk)) return dev_err_probe(dev, PTR_ERR(priv->refclk), "failed to get mclk\n");
dai_drv = axg_spdifin_get_dai_drv(dev, priv); if (IS_ERR(dai_drv)) {
dev_err(dev, "failed to get dai driver: %ld\n",
PTR_ERR(dai_drv)); return PTR_ERR(dai_drv);
}
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.