freq = xcvr->soc_data->spdif_only ? freq / 5 : freq;
clk_disable_unprepare(xcvr->phy_clk);
fsl_asoc_reparent_pll_clocks(dev, xcvr->phy_clk,
xcvr->pll8k_clk, xcvr->pll11k_clk, freq);
ret = clk_set_rate(xcvr->phy_clk, freq); if (ret < 0) {
dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret); return ret;
}
ret = clk_prepare_enable(xcvr->phy_clk); if (ret) {
dev_err(dev, "failed to start PHY clock: %d\n", ret); return ret;
}
if (!xcvr->soc_data->use_phy) return0; /* Release AI interface from reset */
ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
FSL_XCVR_PHY_AI_CTRL_AI_RESETN); if (ret < 0) {
dev_err(dev, "Error while setting IER0: %d\n", ret); return ret;
}
switch (xcvr->mode) { case FSL_XCVR_MODE_SPDIF: if (xcvr->soc_data->spdif_only && tx) {
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL,
FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM,
FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM); if (ret < 0) {
dev_err(dai->dev, "Failed to set bypass fem: %d\n", ret); return ret;
}
}
fallthrough; case FSL_XCVR_MODE_ARC: if (tx) {
ret = fsl_xcvr_en_aud_pll(xcvr, fout); if (ret < 0) {
dev_err(dai->dev, "Failed to set TX freq %u: %d\n",
fout, ret); return ret;
}
ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL,
FSL_XCVR_TX_DPTH_CTRL_FRM_FMT); if (ret < 0) {
dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret); return ret;
}
switch (xcvr->mode) { case FSL_XCVR_MODE_SPDIF: case FSL_XCVR_MODE_ARC: if (xcvr->soc_data->spdif_only && tx)
ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
&xcvr->spdif_constr_rates); else
ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
&fsl_xcvr_spdif_rates_constr); break; case FSL_XCVR_MODE_EARC:
ret = fsl_xcvr_constr(substream, &fsl_xcvr_earc_channels_constr,
&fsl_xcvr_earc_rates_constr); break;
} if (ret < 0) return ret;
xcvr->streams |= BIT(substream->stream);
if (!xcvr->soc_data->spdif_only) { struct snd_soc_card *card = dai->component->card;
/* Disable XCVR controls if there is stream started */
down_read(&card->snd_card->controls_rwsem);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
up_read(&card->snd_card->controls_rwsem);
}
/* Enable XCVR controls if there is no stream started */ if (!xcvr->streams) { if (!xcvr->soc_data->spdif_only) { struct snd_soc_card *card = dai->component->card;
down_read(&card->snd_card->controls_rwsem);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_ARC));
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_EARC));
up_read(&card->snd_card->controls_rwsem);
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, 0); if (ret < 0) {
dev_err(dai->dev, "Failed to set IER0: %d\n", ret); return;
}
staticint fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsignedlong lock_flags; int ret = 0;
spin_lock_irqsave(&xcvr->lock, lock_flags);
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* set DPATH RESET */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
FSL_XCVR_EXT_CTRL_DPTH_RESET(tx)); if (ret < 0) {
dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret); goto release_lock;
}
if (tx) { switch (xcvr->mode) { case FSL_XCVR_MODE_EARC: /* set isr_cmdc_tx_en, w1c */
ret = regmap_write(xcvr->regmap,
FSL_XCVR_ISR_SET,
FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) {
dev_err(dai->dev, "err updating isr %d\n", ret); goto release_lock;
}
fallthrough; case FSL_XCVR_MODE_SPDIF:
ret = regmap_set_bits(xcvr->regmap,
FSL_XCVR_TX_DPTH_CTRL,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) {
dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret); goto release_lock;
} break;
}
}
/* enable DMA RD/WR */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0); if (ret < 0) {
dev_err(dai->dev, "Failed to enable DMA: %d\n", ret); goto release_lock;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); if (ret < 0) {
dev_err(dai->dev, "Error while setting IER0: %d\n", ret); goto release_lock;
}
/* clear DPATH RESET */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DPTH_RESET(tx), 0); if (ret < 0) {
dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret); goto release_lock;
}
break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* disable DMA RD/WR */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx),
FSL_XCVR_EXT_CTRL_DMA_DIS(tx)); if (ret < 0) {
dev_err(dai->dev, "Failed to disable DMA: %d\n", ret); goto release_lock;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, 0); if (ret < 0) {
dev_err(dai->dev, "Failed to clear IER0: %d\n", ret); goto release_lock;
}
if (tx) { switch (xcvr->mode) { case FSL_XCVR_MODE_SPDIF:
ret = regmap_clear_bits(xcvr->regmap,
FSL_XCVR_TX_DPTH_CTRL,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) {
dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret); goto release_lock;
} if (xcvr->soc_data->spdif_only) break; else
fallthrough; case FSL_XCVR_MODE_EARC: /* clear ISR_CMDC_TX_EN, W1C */
ret = regmap_write(xcvr->regmap,
FSL_XCVR_ISR_CLR,
FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) {
dev_err(dai->dev, "Err updating ISR %d\n", ret); goto release_lock;
} break;
}
} break; default:
ret = -EINVAL; break;
}
ret = request_firmware(&fw, xcvr->soc_data->fw_name, dev); if (ret) {
dev_err(dev, "failed to request firmware.\n"); return ret;
}
rem = fw->size;
/* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */ if (rem > 16384) {
dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem);
release_firmware(fw); return -ENOMEM;
}
for (page = 0; page < 10; page++) {
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_PAGE_MASK,
FSL_XCVR_EXT_CTRL_PAGE(page)); if (ret < 0) {
dev_err(dev, "FW: failed to set page %d, err=%d\n",
page, ret); goto err_firmware;
}
off = page * size;
out = min(rem, size); /* IPG clock is assumed to be running, otherwise it will hang */ if (out > 0) { /* write firmware into code memory */
memcpy_toio(xcvr->ram_addr, fw->data + off, out);
rem -= out; if (rem == 0) { /* last part of firmware written */ /* clean remaining part of code memory page */
memset_io(xcvr->ram_addr + out, 0, size - out);
}
} else { /* clean current page, including data memory */
memset_io(xcvr->ram_addr, 0, size);
}
}
err_firmware:
release_firmware(fw); if (ret < 0) return ret;
/* configure watermarks */
mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK;
val = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX);
val |= FSL_XCVR_EXT_CTRL_TX_FWM(FSL_XCVR_FIFO_WMK_TX); /* disable DMA RD/WR */
mask |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
val |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS; /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
mask |= FSL_XCVR_EXT_CTRL_PAGE_MASK;
val |= FSL_XCVR_EXT_CTRL_PAGE(8);
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val); if (ret < 0) {
dev_err(dev, "Failed to set watermarks: %d\n", ret); return ret;
}
/* Store Capabilities Data Structure into Data RAM */
memcpy_toio(xcvr->ram_addr + FSL_XCVR_CAP_DATA_STR, xcvr->cap_ds,
FSL_XCVR_CAPDS_SIZE); return0;
}
if (!xcvr->soc_data->use_phy) if ((reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA) ||
reg > FSL_XCVR_TX_DPTH_BCRR) returnfalse; switch (reg) { case FSL_XCVR_VERSION: case FSL_XCVR_EXT_CTRL: case FSL_XCVR_EXT_STATUS: case FSL_XCVR_EXT_IER0: case FSL_XCVR_EXT_IER1: case FSL_XCVR_EXT_ISR: case FSL_XCVR_EXT_ISR_SET: case FSL_XCVR_EXT_ISR_CLR: case FSL_XCVR_EXT_ISR_TOG: case FSL_XCVR_IER: case FSL_XCVR_ISR: case FSL_XCVR_ISR_SET: case FSL_XCVR_ISR_CLR: case FSL_XCVR_ISR_TOG: case FSL_XCVR_PHY_AI_CTRL: case FSL_XCVR_PHY_AI_CTRL_SET: case FSL_XCVR_PHY_AI_CTRL_CLR: case FSL_XCVR_PHY_AI_CTRL_TOG: case FSL_XCVR_PHY_AI_RDATA: case FSL_XCVR_CLK_CTRL: case FSL_XCVR_RX_DPTH_CTRL: case FSL_XCVR_RX_DPTH_CTRL_SET: case FSL_XCVR_RX_DPTH_CTRL_CLR: case FSL_XCVR_RX_DPTH_CTRL_TOG: case FSL_XCVR_RX_CS_DATA_0: case FSL_XCVR_RX_CS_DATA_1: case FSL_XCVR_RX_CS_DATA_2: case FSL_XCVR_RX_CS_DATA_3: case FSL_XCVR_RX_CS_DATA_4: case FSL_XCVR_RX_CS_DATA_5: case FSL_XCVR_RX_DPTH_CNTR_CTRL: case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_RX_DPTH_TSCR: case FSL_XCVR_RX_DPTH_BCR: case FSL_XCVR_RX_DPTH_BCTR: case FSL_XCVR_RX_DPTH_BCRR: case FSL_XCVR_TX_DPTH_CTRL: case FSL_XCVR_TX_DPTH_CTRL_SET: case FSL_XCVR_TX_DPTH_CTRL_CLR: case FSL_XCVR_TX_DPTH_CTRL_TOG: case FSL_XCVR_TX_CS_DATA_0: case FSL_XCVR_TX_CS_DATA_1: case FSL_XCVR_TX_CS_DATA_2: case FSL_XCVR_TX_CS_DATA_3: case FSL_XCVR_TX_CS_DATA_4: case FSL_XCVR_TX_CS_DATA_5: case FSL_XCVR_TX_DPTH_CNTR_CTRL: case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_TX_DPTH_TSCR: case FSL_XCVR_TX_DPTH_BCR: case FSL_XCVR_TX_DPTH_BCTR: case FSL_XCVR_TX_DPTH_BCRR: case FSL_XCVR_DEBUG_REG_0: case FSL_XCVR_DEBUG_REG_1: returntrue; default: returnfalse;
}
}
if (!xcvr->soc_data->use_phy) if (reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA) returnfalse; switch (reg) { case FSL_XCVR_EXT_CTRL: case FSL_XCVR_EXT_IER0: case FSL_XCVR_EXT_IER1: case FSL_XCVR_EXT_ISR: case FSL_XCVR_EXT_ISR_SET: case FSL_XCVR_EXT_ISR_CLR: case FSL_XCVR_EXT_ISR_TOG: case FSL_XCVR_IER: case FSL_XCVR_ISR_SET: case FSL_XCVR_ISR_CLR: case FSL_XCVR_ISR_TOG: case FSL_XCVR_PHY_AI_CTRL: case FSL_XCVR_PHY_AI_CTRL_SET: case FSL_XCVR_PHY_AI_CTRL_CLR: case FSL_XCVR_PHY_AI_CTRL_TOG: case FSL_XCVR_PHY_AI_WDATA: case FSL_XCVR_CLK_CTRL: case FSL_XCVR_RX_DPTH_CTRL: case FSL_XCVR_RX_DPTH_CTRL_SET: case FSL_XCVR_RX_DPTH_CTRL_CLR: case FSL_XCVR_RX_DPTH_CTRL_TOG: case FSL_XCVR_RX_DPTH_CNTR_CTRL: case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_TX_DPTH_CTRL: case FSL_XCVR_TX_DPTH_CTRL_SET: case FSL_XCVR_TX_DPTH_CTRL_CLR: case FSL_XCVR_TX_DPTH_CTRL_TOG: case FSL_XCVR_TX_CS_DATA_0: case FSL_XCVR_TX_CS_DATA_1: case FSL_XCVR_TX_CS_DATA_2: case FSL_XCVR_TX_CS_DATA_3: case FSL_XCVR_TX_CS_DATA_4: case FSL_XCVR_TX_CS_DATA_5: case FSL_XCVR_TX_DPTH_CNTR_CTRL: case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG: returntrue; default: returnfalse;
}
}
staticbool fsl_xcvr_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case FSL_XCVR_EXT_STATUS: case FSL_XCVR_EXT_ISR: case FSL_XCVR_EXT_ISR_SET: case FSL_XCVR_EXT_ISR_CLR: case FSL_XCVR_EXT_ISR_TOG: case FSL_XCVR_ISR: case FSL_XCVR_ISR_SET: case FSL_XCVR_ISR_CLR: case FSL_XCVR_ISR_TOG: case FSL_XCVR_PHY_AI_CTRL: case FSL_XCVR_PHY_AI_CTRL_SET: case FSL_XCVR_PHY_AI_CTRL_CLR: case FSL_XCVR_PHY_AI_CTRL_TOG: case FSL_XCVR_PHY_AI_RDATA: case FSL_XCVR_RX_CS_DATA_0: case FSL_XCVR_RX_CS_DATA_1: case FSL_XCVR_RX_CS_DATA_2: case FSL_XCVR_RX_CS_DATA_3: case FSL_XCVR_RX_CS_DATA_4: case FSL_XCVR_RX_CS_DATA_5: case FSL_XCVR_RX_DPTH_CNTR_CTRL: case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_RX_DPTH_TSCR: case FSL_XCVR_RX_DPTH_BCR: case FSL_XCVR_RX_DPTH_BCTR: case FSL_XCVR_RX_DPTH_BCRR: case FSL_XCVR_TX_DPTH_CNTR_CTRL: case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_TX_DPTH_TSCR: case FSL_XCVR_TX_DPTH_BCR: case FSL_XCVR_TX_DPTH_BCTR: case FSL_XCVR_TX_DPTH_BCRR: case FSL_XCVR_DEBUG_REG_0: case FSL_XCVR_DEBUG_REG_1: returntrue; default: returnfalse;
}
}
if (isr & FSL_XCVR_IRQ_NEW_CS) {
dev_dbg(dev, "Received new CS block\n");
isr_clr |= FSL_XCVR_IRQ_NEW_CS; if (xcvr->soc_data->fw_name) { /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_PAGE_MASK,
FSL_XCVR_EXT_CTRL_PAGE(8));
¤ 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.0.164Bemerkung:
¤
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.