/* * This file implements the platform operations common to the playback and * capture frontend DAI. The logic behind this two types of fifo is very * similar but some difference exist. * These differences are handled in the respective DAI drivers
*/
int axg_fifo_pcm_trigger(struct snd_soc_component *component, struct snd_pcm_substream *ss, int cmd)
{ struct axg_fifo *fifo = axg_fifo_data(ss);
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
__dma_enable(fifo, true); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP:
__dma_enable(fifo, false); break; default: return -EINVAL;
}
/* * Start the fifo request on the smallest of the following: * - Half the fifo size * - Half the period size
*/
threshold = min(period / 2, fifo->depth / 2);
/* * With the threshold in bytes, register value is: * V = (threshold / burst) - 1
*/
threshold /= AXG_FIFO_BURST;
regmap_field_write(fifo->field_threshold,
threshold ? threshold - 1 : 0);
if (status & FIFO_INT_COUNT_REPEAT) {
snd_pcm_period_elapsed(ss); return IRQ_HANDLED;
}
return IRQ_NONE;
}
int axg_fifo_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *ss)
{ struct axg_fifo *fifo = axg_fifo_data(ss); struct device *dev = axg_fifo_dev(ss); int ret;
snd_soc_set_runtime_hwparams(ss, &axg_fifo_hw);
/* * Make sure the buffer and period size are multiple of the FIFO * burst
*/
ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
AXG_FIFO_BURST); if (ret) return ret;
ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
AXG_FIFO_BURST); if (ret) return ret;
/* Use the threaded irq handler only with non-atomic links */
ret = request_threaded_irq(fifo->irq, NULL,
axg_fifo_pcm_irq_block,
IRQF_ONESHOT, dev_name(dev), ss); if (ret) return ret;
/* Enable pclk to access registers and clock the fifo ip */
ret = clk_prepare_enable(fifo->pclk); if (ret) goto free_irq;
/* Setup status2 so it reports the memory pointer */
regmap_update_bits(fifo->map, FIFO_CTRL1,
CTRL1_STATUS2_SEL,
FIELD_PREP(CTRL1_STATUS2_SEL, STATUS2_SEL_DDR_READ));
/* Make sure the dma is initially disabled */
__dma_enable(fifo, false);
/* Disable irqs until params are ready */
regmap_update_bits(fifo->map, FIFO_CTRL0,
CTRL0_INT_EN, 0);
/* Clear any pending interrupt */
axg_fifo_ack_irq(fifo, FIFO_INT_MASK);
/* Take memory arbitror out of reset */
ret = reset_control_deassert(fifo->arb); if (ret) goto free_clk;
regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs);
fifo->map = devm_regmap_init_mmio(dev, regs, &axg_fifo_regmap_cfg); if (IS_ERR(fifo->map)) {
dev_err(dev, "failed to init regmap: %ld\n",
PTR_ERR(fifo->map)); return PTR_ERR(fifo->map);
}
fifo->pclk = devm_clk_get(dev, NULL); if (IS_ERR(fifo->pclk)) return dev_err_probe(dev, PTR_ERR(fifo->pclk), "failed to get pclk\n");
fifo->arb = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(fifo->arb)) return dev_err_probe(dev, PTR_ERR(fifo->arb), "failed to get arb reset\n");
fifo->irq = of_irq_get(dev->of_node, 0); if (fifo->irq <= 0) {
dev_err(dev, "failed to get irq: %d\n", fifo->irq); return fifo->irq;
}
fifo->field_threshold =
devm_regmap_field_alloc(dev, fifo->map, data->field_threshold); if (IS_ERR(fifo->field_threshold)) return PTR_ERR(fifo->field_threshold);
ret = of_property_read_u32(dev->of_node, "amlogic,fifo-depth",
&fifo->depth); if (ret) { /* Error out for anything but a missing property */ if (ret != -EINVAL) return ret; /* * If the property is missing, it might be because of an old * DT. In such case, assume the smallest known fifo depth
*/
fifo->depth = 256;
dev_warn(dev, "fifo depth not found, assume %u bytes\n",
fifo->depth);
}
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.