val = readl(mmio_base + XLNX_AUD_CTRL);
val |= AUD_CTRL_RESET_MASK;
writel(val, mmio_base + XLNX_AUD_CTRL);
val = readl(mmio_base + XLNX_AUD_CTRL); /* Poll for maximum timeout of approximately 100ms (1 * 100)*/ while ((val & AUD_CTRL_RESET_MASK) && (retries < 100)) {
mdelay(1);
retries++;
val = readl(mmio_base + XLNX_AUD_CTRL);
} if (val & AUD_CTRL_RESET_MASK) return -ENODEV;
return 0;
}
staticvoid xlnx_formatter_disable_irqs(void __iomem *mmio_base, int stream)
{
u32 val;
val = readl(mmio_base + XLNX_AUD_CTRL);
val &= ~AUD_CTRL_IOC_IRQ_MASK; if (stream == SNDRV_PCM_STREAM_CAPTURE)
val &= ~AUD_CTRL_TOUT_IRQ_MASK;
/* Resize the period bytes as divisible by 64 */
err = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
XLNX_AUD_ALIGN_BYTES); if (err) {
dev_err(component->dev, "Unable to set constraint on period bytes\n"); return err;
}
/* Resize the buffer bytes as divisible by 64 */
err = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
XLNX_AUD_ALIGN_BYTES); if (err) {
dev_err(component->dev, "Unable to set constraint on buffer bytes\n"); return err;
}
/* Set periods as integer multiple */
err = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) {
dev_err(component->dev, "Unable to set constraint on periods to be integer\n"); return err;
}
/* enable DMA IOC irq */
val = readl(stream_data->mmio + XLNX_AUD_CTRL);
val |= AUD_CTRL_IOC_IRQ_MASK;
writel(val, stream_data->mmio + XLNX_AUD_CTRL);
val = readl(stream_data->mmio + XLNX_AUD_CTRL);
bits_per_sample = params_width(params); switch (bits_per_sample) { case 8:
val |= (BIT_DEPTH_8 << AUD_CTRL_DATA_WIDTH_SHIFT); break; case 16:
val |= (BIT_DEPTH_16 << AUD_CTRL_DATA_WIDTH_SHIFT); break; case 20:
val |= (BIT_DEPTH_20 << AUD_CTRL_DATA_WIDTH_SHIFT); break; case 24:
val |= (BIT_DEPTH_24 << AUD_CTRL_DATA_WIDTH_SHIFT); break; case 32:
val |= (BIT_DEPTH_32 << AUD_CTRL_DATA_WIDTH_SHIFT); break; default: return -EINVAL;
}
val |= active_ch << AUD_CTRL_ACTIVE_CH_SHIFT;
writel(val, stream_data->mmio + XLNX_AUD_CTRL);
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME:
val = readl(stream_data->mmio + XLNX_AUD_CTRL);
val |= AUD_CTRL_DMA_EN_MASK;
writel(val, stream_data->mmio + XLNX_AUD_CTRL); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND:
val = readl(stream_data->mmio + XLNX_AUD_CTRL);
val &= ~AUD_CTRL_DMA_EN_MASK;
writel(val, stream_data->mmio + XLNX_AUD_CTRL); break;
}
aud_drv_data = devm_kzalloc(dev, sizeof(*aud_drv_data), GFP_KERNEL); if (!aud_drv_data) return -ENOMEM;
aud_drv_data->axi_clk = devm_clk_get(dev, "s_axi_lite_aclk"); if (IS_ERR(aud_drv_data->axi_clk)) {
ret = PTR_ERR(aud_drv_data->axi_clk);
dev_err(dev, "failed to get s_axi_lite_aclk(%d)\n", ret); return ret;
}
ret = clk_prepare_enable(aud_drv_data->axi_clk); if (ret) {
dev_err(dev, "failed to enable s_axi_lite_aclk(%d)\n", ret); return ret;
}
aud_drv_data->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(aud_drv_data->mmio)) {
dev_err(dev, "audio formatter ioremap failed\n");
ret = PTR_ERR(aud_drv_data->mmio); goto clk_err;
}
val = readl(aud_drv_data->mmio + XLNX_AUD_CORE_CONFIG); if (val & AUD_CFG_MM2S_MASK) {
aud_drv_data->mm2s_presence = true;
ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio +
XLNX_MM2S_OFFSET); if (ret) {
dev_err(dev, "audio formatter reset failed\n"); goto clk_err;
}
xlnx_formatter_disable_irqs(aud_drv_data->mmio +
XLNX_MM2S_OFFSET,
SNDRV_PCM_STREAM_PLAYBACK);
aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev, "irq_mm2s"); if (aud_drv_data->mm2s_irq < 0) {
ret = aud_drv_data->mm2s_irq; goto clk_err;
}
ret = devm_request_irq(dev, aud_drv_data->mm2s_irq,
xlnx_mm2s_irq_handler, 0, "xlnx_formatter_pcm_mm2s_irq", dev); if (ret) {
dev_err(dev, "xlnx audio mm2s irq request failed\n"); goto clk_err;
}
} if (val & AUD_CFG_S2MM_MASK) {
aud_drv_data->s2mm_presence = true;
ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio +
XLNX_S2MM_OFFSET); if (ret) {
dev_err(dev, "audio formatter reset failed\n"); goto clk_err;
}
xlnx_formatter_disable_irqs(aud_drv_data->mmio +
XLNX_S2MM_OFFSET,
SNDRV_PCM_STREAM_CAPTURE);
aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev, "irq_s2mm"); if (aud_drv_data->s2mm_irq < 0) {
ret = aud_drv_data->s2mm_irq; goto clk_err;
}
ret = devm_request_irq(dev, aud_drv_data->s2mm_irq,
xlnx_s2mm_irq_handler, 0, "xlnx_formatter_pcm_s2mm_irq",
dev); if (ret) {
dev_err(dev, "xlnx audio s2mm irq request failed\n"); goto clk_err;
}
}
dev_set_drvdata(dev, aud_drv_data);
ret = devm_snd_soc_register_component(dev, &xlnx_asoc_component,
NULL, 0); if (ret) {
dev_err(dev, "pcm platform device register failed\n"); goto clk_err;
}
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.