/* * FIFO trigger level must be bigger than DMA burst or equal to it, * otherwise data is discarded on overflow.
*/
regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_DATA_FIFO_CSR,
TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK,
TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL);
switch (params_rate(params)) { case 32000:
spdifclock = 4096000; break; case 44100:
spdifclock = 5644800; break; case 48000:
spdifclock = 6144000; break; case 88200:
spdifclock = 11289600; break; case 96000:
spdifclock = 12288000; break; case 176400:
spdifclock = 22579200; break; case 192000:
spdifclock = 24576000; break; default: return -EINVAL;
}
ret = clk_set_rate(spdif->clk_spdif_out, spdifclock); if (ret) {
dev_err(dai->dev, "Can't set SPDIF clock rate: %d\n", ret); return ret;
}
rate = clk_get_rate(spdif->clk_spdif_out); if (rate != spdifclock)
dev_warn_once(dai->dev, "SPDIF clock rate %d doesn't match requested rate %lu\n",
spdifclock, rate);
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME:
tegra20_spdif_start_playback(spdif); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND:
tegra20_spdif_stop_playback(spdif); break; default: return -EINVAL;
}
parent_rate = clk_get_rate(parent); if (!parent_rate) {
dev_err(dai->dev, "Can't get parent clock rate\n"); return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(rates); i++) { if (parent_rate % (rates[i] * 128) == 0)
valid_rates |= BIT(i);
}
/* * At least one rate must be valid, otherwise the parent clock isn't * audio PLL. Nothing should be filtered in this case.
*/ if (!valid_rates)
valid_rates = BIT(ARRAY_SIZE(rates)) - 1;
/* * SPDIF and I2S share audio PLL. HDMI takes audio packets from SPDIF * and audio may not work on some TVs if clock rate isn't precise. * * PLL rate is controlled by I2S side. Filter out audio rates that * don't match PLL rate at the start of stream to allow both SPDIF * and I2S work simultaneously, assuming that PLL rate won't be * changed later on.
*/ return snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
tegra20_spdif_filter_rates, dai,
SNDRV_PCM_HW_PARAM_RATE, -1);
}
staticbool tegra20_spdif_wr_rd_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case TEGRA20_SPDIF_CTRL: case TEGRA20_SPDIF_STATUS: case TEGRA20_SPDIF_STROBE_CTRL: case TEGRA20_SPDIF_DATA_FIFO_CSR: case TEGRA20_SPDIF_DATA_OUT: case TEGRA20_SPDIF_DATA_IN: case TEGRA20_SPDIF_CH_STA_RX_A: case TEGRA20_SPDIF_CH_STA_RX_B: case TEGRA20_SPDIF_CH_STA_RX_C: case TEGRA20_SPDIF_CH_STA_RX_D: case TEGRA20_SPDIF_CH_STA_RX_E: case TEGRA20_SPDIF_CH_STA_RX_F: case TEGRA20_SPDIF_CH_STA_TX_A: case TEGRA20_SPDIF_CH_STA_TX_B: case TEGRA20_SPDIF_CH_STA_TX_C: case TEGRA20_SPDIF_CH_STA_TX_D: case TEGRA20_SPDIF_CH_STA_TX_E: case TEGRA20_SPDIF_CH_STA_TX_F: case TEGRA20_SPDIF_USR_STA_RX_A: case TEGRA20_SPDIF_USR_DAT_TX_A: returntrue; default: returnfalse;
}
}
staticbool tegra20_spdif_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case TEGRA20_SPDIF_STATUS: case TEGRA20_SPDIF_DATA_FIFO_CSR: case TEGRA20_SPDIF_DATA_OUT: case TEGRA20_SPDIF_DATA_IN: case TEGRA20_SPDIF_CH_STA_RX_A: case TEGRA20_SPDIF_CH_STA_RX_B: case TEGRA20_SPDIF_CH_STA_RX_C: case TEGRA20_SPDIF_CH_STA_RX_D: case TEGRA20_SPDIF_CH_STA_RX_E: case TEGRA20_SPDIF_CH_STA_RX_F: case TEGRA20_SPDIF_USR_STA_RX_A: case TEGRA20_SPDIF_USR_DAT_TX_A: returntrue; default: returnfalse;
}
}
staticbool tegra20_spdif_precious_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case TEGRA20_SPDIF_DATA_OUT: case TEGRA20_SPDIF_DATA_IN: case TEGRA20_SPDIF_USR_STA_RX_A: case TEGRA20_SPDIF_USR_DAT_TX_A: returntrue; default: returnfalse;
}
}
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.