From eb267cdcaa7d36a7816f3274be065853e8f4ced7 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Sun, 30 Apr 2017 18:11:00 +0300 Subject: [PATCH] ASoC: fsl: refine the asrc driver for imx8qm The clock source of ASRC in imx8qm is changed. Signed-off-by: Shengjiu Wang --- .../devicetree/bindings/sound/fsl,asrc.txt | 3 +- include/uapi/linux/mxc_asrc.h | 45 ++++++++++++++++++ sound/soc/fsl/fsl_asrc.c | 44 +++++++++++++++++- sound/soc/fsl/fsl_asrc.h | 1 - sound/soc/fsl/fsl_asrc_dma.c | 46 +++++++++++++------ sound/soc/fsl/fsl_asrc_m2m.c | 17 +++++-- 6 files changed, 134 insertions(+), 22 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt index 1d4d9f938689..cd2bd3daa7e1 100644 --- a/Documentation/devicetree/bindings/sound/fsl,asrc.txt +++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt @@ -8,7 +8,8 @@ three substreams within totally 10 channels. Required properties: - - compatible : Contains "fsl,imx35-asrc" or "fsl,imx53-asrc". + - compatible : Contains "fsl,imx35-asrc", "fsl,imx53-asrc", + "fsl,imx8qm-asrc0" or "fsl,imx8qm-asrc1". - reg : Offset and length of the register set for the device. diff --git a/include/uapi/linux/mxc_asrc.h b/include/uapi/linux/mxc_asrc.h index 7a2b7dfcdc5b..837deea53f5b 100644 --- a/include/uapi/linux/mxc_asrc.h +++ b/include/uapi/linux/mxc_asrc.h @@ -53,6 +53,28 @@ enum asrc_inclk { INCLK_SSI3_TX = 0x0b, INCLK_SPDIF_TX = 0x0c, INCLK_ASRCK1_CLK = 0x0f, +/* imx8 */ + INCLK_AUD_PLL_DIV_CLK0 = 0x10, + INCLK_AUD_PLL_DIV_CLK1 = 0x11, + INCLK_AUD_CLK0 = 0x12, + INCLK_AUD_CLK1 = 0x13, + INCLK_ESAI0_RX_CLK = 0x14, + INCLK_ESAI0_TX_CLK = 0x15, + INCLK_SPDIF0_RX = 0x16, + INCLK_SPDIF1_RX = 0x17, + INCLK_SAI0_RX_BCLK = 0x18, + INCLK_SAI0_TX_BCLK = 0x19, + INCLK_SAI1_RX_BCLK = 0x1a, + INCLK_SAI1_TX_BCLK = 0x1b, + INCLK_SAI2_RX_BCLK = 0x1c, + INCLK_SAI3_RX_BCLK = 0x1d, + INCLK_ASRC0_MUX_CLK = 0x1e, + + INCLK_ESAI1_RX_CLK = 0x20, + INCLK_ESAI1_TX_CLK = 0x21, + INCLK_SAI6_TX_BCLK = 0x22, + INCLK_HDMI_RX_SAI0_RX_BCLK = 0x24, + INCLK_HDMI_TX_SAI0_TX_BCLK = 0x25, }; enum asrc_outclk { @@ -70,6 +92,29 @@ enum asrc_outclk { OUTCLK_SSI3_RX = 0x0b, OUTCLK_SPDIF_RX = 0x0c, OUTCLK_ASRCK1_CLK = 0x0f, + +/* imx8 */ + OUTCLK_AUD_PLL_DIV_CLK0 = 0x10, + OUTCLK_AUD_PLL_DIV_CLK1 = 0x11, + OUTCLK_AUD_CLK0 = 0x12, + OUTCLK_AUD_CLK1 = 0x13, + OUTCLK_ESAI0_RX_CLK = 0x14, + OUTCLK_ESAI0_TX_CLK = 0x15, + OUTCLK_SPDIF0_RX = 0x16, + OUTCLK_SPDIF1_RX = 0x17, + OUTCLK_SAI0_RX_BCLK = 0x18, + OUTCLK_SAI0_TX_BCLK = 0x19, + OUTCLK_SAI1_RX_BCLK = 0x1a, + OUTCLK_SAI1_TX_BCLK = 0x1b, + OUTCLK_SAI2_RX_BCLK = 0x1c, + OUTCLK_SAI3_RX_BCLK = 0x1d, + OUTCLK_ASRCO_MUX_CLK = 0x1e, + + OUTCLK_ESAI1_RX_CLK = 0x20, + OUTCLK_ESAI1_TX_CLK = 0x21, + OUTCLK_SAI6_TX_BCLK = 0x22, + OUTCLK_HDMI_RX_SAI0_RX_BCLK = 0x24, + OUTCLK_HDMI_TX_SAI0_TX_BCLK = 0x25, }; enum asrc_word_width { diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index c41f491cb62f..c6203c81a2b6 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -49,23 +49,55 @@ static struct snd_pcm_hw_constraint_list fsl_asrc_rate_constraints = { */ static unsigned char input_clk_map_imx35[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, }; static unsigned char output_clk_map_imx35[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, }; /* i.MX53 uses the same map for input and output */ static unsigned char input_clk_map_imx53[] = { /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, }; static unsigned char output_clk_map_imx53[] = { /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, }; +/* i.MX8 uses the same map for input and output */ +static unsigned char input_clk_map_imx8_0[] = { + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, +}; + +static unsigned char output_clk_map_imx8_0[] = { + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, +}; + +static unsigned char input_clk_map_imx8_1[] = { + 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, + 0x0, 0x1, 0x2, 0x3, 0xb, 0xc, 0xf, 0xf, 0xd, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, + 0x4, 0x5, 0x6, 0xf, 0x8, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, +}; + +static unsigned char output_clk_map_imx8_1[] = { + 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, + 0x0, 0x1, 0x2, 0x3, 0xb, 0xc, 0xf, 0xf, 0xd, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, + 0x4, 0x5, 0x6, 0xf, 0x8, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, +}; static unsigned char *clk_map[2]; /** @@ -963,10 +995,18 @@ static int fsl_asrc_probe(struct platform_device *pdev) asrc_priv->channel_bits = 3; clk_map[IN] = input_clk_map_imx35; clk_map[OUT] = output_clk_map_imx35; - } else { + } else if (of_device_is_compatible(np, "fsl,imx53-asrc")) { asrc_priv->channel_bits = 4; clk_map[IN] = input_clk_map_imx53; clk_map[OUT] = output_clk_map_imx53; + } else if (of_device_is_compatible(np, "fsl,imx8qm-asrc0")) { + asrc_priv->channel_bits = 4; + clk_map[IN] = input_clk_map_imx8_0; + clk_map[OUT] = output_clk_map_imx8_0; + } else if (of_device_is_compatible(np, "fsl,imx8qm-asrc1")) { + asrc_priv->channel_bits = 4; + clk_map[IN] = input_clk_map_imx8_1; + clk_map[OUT] = output_clk_map_imx8_1; } ret = fsl_asrc_init(asrc_priv); @@ -1119,6 +1159,8 @@ static const struct dev_pm_ops fsl_asrc_pm = { static const struct of_device_id fsl_asrc_ids[] = { { .compatible = "fsl,imx35-asrc", }, { .compatible = "fsl,imx53-asrc", }, + { .compatible = "fsl,imx8qm-asrc0", }, + { .compatible = "fsl,imx8qm-asrc1", }, {} }; MODULE_DEVICE_TABLE(of, fsl_asrc_ids); diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 034d10dc11e9..8acc68af90c4 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -290,7 +290,6 @@ struct dma_block { - dma_addr_t dma_paddr; void *dma_vaddr; unsigned int length; }; diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 03471afa0f99..2682af55927e 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -202,25 +202,43 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, /* Get DMA request of Back-End */ tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx"); - tmp_data = tmp_chan->private; - pair->dma_data.dma_request = tmp_data->dma_request; - be_peripheral_type = tmp_data->peripheral_type; - dma_release_channel(tmp_chan); + if (tmp_chan) { + tmp_data = tmp_chan->private; + if (tmp_data) { + pair->dma_data.dma_request = tmp_data->dma_request; + be_peripheral_type = tmp_data->peripheral_type; + if (tx && be_peripheral_type == IMX_DMATYPE_SSI_DUAL) + pair->dma_data.dst_dualfifo = true; + if (!tx && be_peripheral_type == IMX_DMATYPE_SSI_DUAL) + pair->dma_data.src_dualfifo = true; + } + dma_release_channel(tmp_chan); + } /* Get DMA request of Front-End */ tmp_chan = fsl_asrc_get_dma_channel(pair, dir); - tmp_data = tmp_chan->private; - pair->dma_data.dma_request2 = tmp_data->dma_request; - pair->dma_data.peripheral_type = tmp_data->peripheral_type; - pair->dma_data.priority = tmp_data->priority; - dma_release_channel(tmp_chan); + if (tmp_chan) { + tmp_data = tmp_chan->private; + if (tmp_data) { + pair->dma_data.dma_request2 = tmp_data->dma_request; + pair->dma_data.peripheral_type = + tmp_data->peripheral_type; + pair->dma_data.priority = tmp_data->priority; + } + dma_release_channel(tmp_chan); + } - if (tx && be_peripheral_type == IMX_DMATYPE_SSI_DUAL) - pair->dma_data.dst_dualfifo = true; - if (!tx && be_peripheral_type == IMX_DMATYPE_SSI_DUAL) - pair->dma_data.src_dualfifo = true; + /* For sdma DEV_TO_DEV, there is two dma request + * But for emda DEV_TO_DEV, there is only one dma request, which is + * from the BE. + */ + if (pair->dma_data.dma_request2 != pair->dma_data.dma_request) + pair->dma_chan[dir] = + dma_request_channel(mask, filter, &pair->dma_data); + else + pair->dma_chan[dir] = + dma_request_slave_channel(dev_be, tx ? "tx" : "rx"); - pair->dma_chan[dir] = dma_request_channel(mask, filter, &pair->dma_data); if (!pair->dma_chan[dir]) { dev_err(dev, "failed to request DMA channel for Back-End\n"); return -EINVAL; diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c index 7363dc003aa6..f0b335697445 100644 --- a/sound/soc/fsl/fsl_asrc_m2m.c +++ b/sound/soc/fsl/fsl_asrc_m2m.c @@ -134,14 +134,12 @@ static int fsl_allocate_dma_buf(struct fsl_asrc_pair *pair) pair_err("failed to allocate input DMA buffer\n"); return -ENOMEM; } - input->dma_paddr = virt_to_dma(NULL, input->dma_vaddr); output->dma_vaddr = kzalloc(output->length, GFP_KERNEL); if (!output->dma_vaddr) { pair_err("failed to allocate output DMA buffer\n"); goto exit; } - output->dma_paddr = virt_to_dma(NULL, output->dma_vaddr); return 0; @@ -812,6 +810,7 @@ static int fsl_asrc_open(struct inode *inode, struct file *file) struct fsl_asrc_pair *pair; struct fsl_asrc_m2m *m2m; int ret; + int i; ret = signal_pending(current); if (ret) { @@ -839,7 +838,11 @@ static int fsl_asrc_open(struct inode *inode, struct file *file) file->private_data = pair; - pm_runtime_get_sync(dev); + clk_prepare_enable(asrc_priv->mem_clk); + clk_prepare_enable(asrc_priv->ipg_clk); + clk_prepare_enable(asrc_priv->spba_clk); + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) + clk_prepare_enable(asrc_priv->asrck_clk[i]); return 0; out: @@ -853,8 +856,8 @@ static int fsl_asrc_close(struct inode *inode, struct file *file) struct fsl_asrc_pair *pair = file->private_data; struct fsl_asrc_m2m *m2m = pair->private; struct fsl_asrc *asrc_priv = pair->asrc_priv; - struct device *dev = &asrc_priv->pdev->dev; unsigned long lock_flags; + int i; if (m2m->asrc_active) { m2m->asrc_active = 0; @@ -890,7 +893,11 @@ static int fsl_asrc_close(struct inode *inode, struct file *file) spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); file->private_data = NULL; - pm_runtime_put_sync(dev); + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) + clk_disable_unprepare(asrc_priv->asrck_clk[i]); + clk_disable_unprepare(asrc_priv->spba_clk); + clk_disable_unprepare(asrc_priv->ipg_clk); + clk_disable_unprepare(asrc_priv->mem_clk); return 0; }