ret = regcache_sync(spdif->regmap); if (ret) {
clk_disable_unprepare(spdif->mclk);
clk_disable_unprepare(spdif->hclk);
}
return ret;
}
staticint rk_spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{ struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); unsignedint val = SPDIF_CFGR_HALFWORD_ENABLE; int srate, mclk; int ret;
srate = params_rate(params);
mclk = srate * 128;
switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE:
val |= SPDIF_CFGR_VDW_16; break; case SNDRV_PCM_FORMAT_S20_3LE:
val |= SPDIF_CFGR_VDW_20; break; case SNDRV_PCM_FORMAT_S24_LE:
val |= SPDIF_CFGR_VDW_24; break; default: return -EINVAL;
}
/* Set clock and calculate divider */
ret = clk_set_rate(spdif->mclk, mclk); if (ret != 0) {
dev_err(spdif->dev, "Failed to set module clock rate: %d\n",
ret); return ret;
}
ret = regmap_update_bits(spdif->regmap, SPDIF_CFGR,
SPDIF_CFGR_CLK_DIV_MASK |
SPDIF_CFGR_HALFWORD_ENABLE |
SDPIF_CFGR_VDW_MASK, val);
return ret;
}
staticint rk_spdif_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{ struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); int ret;
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR,
SPDIF_DMACR_TDE_ENABLE |
SPDIF_DMACR_TDL_MASK,
SPDIF_DMACR_TDE_ENABLE |
SPDIF_DMACR_TDL(16));
if (ret != 0) return ret;
ret = regmap_update_bits(spdif->regmap, SPDIF_XFER,
SPDIF_XFER_TXS_START,
SPDIF_XFER_TXS_START); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR,
SPDIF_DMACR_TDE_ENABLE,
SPDIF_DMACR_TDE_DISABLE);
if (ret != 0) return ret;
ret = regmap_update_bits(spdif->regmap, SPDIF_XFER,
SPDIF_XFER_TXS_START,
SPDIF_XFER_TXS_STOP); break; default:
ret = -EINVAL; break;
}
staticbool rk_spdif_wr_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case SPDIF_CFGR: case SPDIF_DMACR: case SPDIF_INTCR: case SPDIF_XFER: case SPDIF_SMPDR: returntrue; default: returnfalse;
}
}
staticbool rk_spdif_rd_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case SPDIF_CFGR: case SPDIF_SDBLR: case SPDIF_INTCR: case SPDIF_INTSR: case SPDIF_XFER: case SPDIF_SMPDR: returntrue; default: returnfalse;
}
}
staticbool rk_spdif_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case SPDIF_INTSR: case SPDIF_SDBLR: case SPDIF_SMPDR: returntrue; default: returnfalse;
}
}
/* Select the 8 channel SPDIF solution on RK3288 as * the 2 channel one does not appear to work
*/
regmap_write(grf, RK3288_GRF_SOC_CON2, BIT(1) << 16);
}
spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL); if (!spdif) return -ENOMEM;
spdif->hclk = devm_clk_get(&pdev->dev, "hclk"); if (IS_ERR(spdif->hclk)) return PTR_ERR(spdif->hclk);
spdif->mclk = devm_clk_get(&pdev->dev, "mclk"); if (IS_ERR(spdif->mclk)) return PTR_ERR(spdif->mclk);
regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs);
spdif->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "hclk", regs,
&rk_spdif_regmap_config); if (IS_ERR(spdif->regmap)) return PTR_ERR(spdif->regmap);
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.