diff options
Diffstat (limited to 'sound/soc/meson/axg-fifo.c')
| -rw-r--r-- | sound/soc/meson/axg-fifo.c | 77 |
1 files changed, 37 insertions, 40 deletions
diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index b2e867113226..75909196b769 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -3,6 +3,7 @@ // Copyright (c) 2018 BayLibre, SAS. // Author: Jerome Brunet <jbrunet@baylibre.com> +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/of_irq.h> #include <linux/of_platform.h> @@ -22,16 +23,16 @@ * These differences are handled in the respective DAI drivers */ -static struct snd_pcm_hardware axg_fifo_hw = { +static const struct snd_pcm_hardware axg_fifo_hw = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_PAUSE), - + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), .formats = AXG_FIFO_FORMATS, .rate_min = 5512, - .rate_max = 192000, + .rate_max = 768000, .channels_min = 1, .channels_max = AXG_FIFO_CH_MAX, .period_bytes_min = AXG_FIFO_BURST, @@ -45,9 +46,9 @@ static struct snd_pcm_hardware axg_fifo_hw = { static struct snd_soc_dai *axg_fifo_dai(struct snd_pcm_substream *ss) { - struct snd_soc_pcm_runtime *rtd = ss->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(ss); - return asoc_rtd_to_cpu(rtd, 0); + return snd_soc_rtd_to_cpu(rtd, 0); } static struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss) @@ -113,7 +114,7 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component, { struct snd_pcm_runtime *runtime = ss->runtime; struct axg_fifo *fifo = axg_fifo_data(ss); - unsigned int burst_num, period, threshold; + unsigned int burst_num, period, threshold, irq_en; dma_addr_t end_ptr; period = params_period_bytes(params); @@ -142,10 +143,11 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component, regmap_field_write(fifo->field_threshold, threshold ? threshold - 1 : 0); - /* Enable block count irq */ + /* Enable irq if necessary */ + irq_en = runtime->no_period_wakeup ? 0 : FIFO_INT_COUNT_REPEAT; regmap_update_bits(fifo->map, FIFO_CTRL0, - CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), - CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT)); + CTRL0_INT_EN, + FIELD_PREP(CTRL0_INT_EN, irq_en)); return 0; } @@ -175,9 +177,9 @@ int axg_fifo_pcm_hw_free(struct snd_soc_component *component, { struct axg_fifo *fifo = axg_fifo_data(ss); - /* Disable the block count irq */ + /* Disable irqs */ regmap_update_bits(fifo->map, FIFO_CTRL0, - CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0); + CTRL0_INT_EN, 0); return 0; } @@ -186,13 +188,13 @@ EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free); static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask) { regmap_update_bits(fifo->map, FIFO_CTRL1, - CTRL1_INT_CLR(FIFO_INT_MASK), - CTRL1_INT_CLR(mask)); + CTRL1_INT_CLR, + FIELD_PREP(CTRL1_INT_CLR, mask)); /* Clear must also be cleared */ regmap_update_bits(fifo->map, FIFO_CTRL1, - CTRL1_INT_CLR(FIFO_INT_MASK), - 0); + CTRL1_INT_CLR, + FIELD_PREP(CTRL1_INT_CLR, 0)); } static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id) @@ -202,18 +204,19 @@ static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id) unsigned int status; regmap_read(fifo->map, FIFO_STATUS1, &status); + status = FIELD_GET(STATUS1_INT_STS, status); + axg_fifo_ack_irq(fifo, status); - status = STATUS1_INT_STS(status) & FIFO_INT_MASK; - if (status & FIFO_INT_COUNT_REPEAT) - snd_pcm_period_elapsed(ss); - else + if (status & ~FIFO_INT_COUNT_REPEAT) dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n", status); - /* Ack irqs */ - axg_fifo_ack_irq(fifo, status); + if (status & FIFO_INT_COUNT_REPEAT) { + snd_pcm_period_elapsed(ss); + return IRQ_HANDLED; + } - return IRQ_RETVAL(status); + return IRQ_NONE; } int axg_fifo_pcm_open(struct snd_soc_component *component, @@ -241,8 +244,10 @@ int axg_fifo_pcm_open(struct snd_soc_component *component, if (ret) return ret; - ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0, - dev_name(dev), ss); + /* 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; @@ -253,15 +258,15 @@ int axg_fifo_pcm_open(struct snd_soc_component *component, /* Setup status2 so it reports the memory pointer */ regmap_update_bits(fifo->map, FIFO_CTRL1, - CTRL1_STATUS2_SEL_MASK, - CTRL1_STATUS2_SEL(STATUS2_SEL_DDR_READ)); + 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(FIFO_INT_MASK), 0); + CTRL0_INT_EN, 0); /* Clear any pending interrupt */ axg_fifo_ack_irq(fifo, FIFO_INT_MASK); @@ -350,20 +355,12 @@ int axg_fifo_probe(struct platform_device *pdev) } fifo->pclk = devm_clk_get(dev, NULL); - if (IS_ERR(fifo->pclk)) { - if (PTR_ERR(fifo->pclk) != -EPROBE_DEFER) - dev_err(dev, "failed to get pclk: %ld\n", - PTR_ERR(fifo->pclk)); - return PTR_ERR(fifo->pclk); - } + 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)) { - if (PTR_ERR(fifo->arb) != -EPROBE_DEFER) - dev_err(dev, "failed to get arb reset: %ld\n", - PTR_ERR(fifo->arb)); - return PTR_ERR(fifo->arb); - } + 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) { |
