From 099a9cd86939811c305120244a93ee9033ce0045 Mon Sep 17 00:00:00 2001 From: Xingyu Wu Date: Tue, 11 Oct 2022 21:16:56 +0800 Subject: [PATCH] sound:starfive:Remove i2srx-master and merge into starfive_i2s Remove i2srx-master.c and i2srx-master.h files, and merge into starfive_i2s.c and starfive_i2s.h files. Signed-off-by: Xingyu Wu --- sound/soc/starfive/Kconfig | 13 +- sound/soc/starfive/Makefile | 3 - sound/soc/starfive/i2srx-master.c | 879 -------------------------------------- sound/soc/starfive/i2srx-master.h | 152 ------- sound/soc/starfive/starfive_i2s.c | 219 ++++++++-- sound/soc/starfive/starfive_i2s.h | 3 + 6 files changed, 199 insertions(+), 1070 deletions(-) delete mode 100644 sound/soc/starfive/i2srx-master.c delete mode 100644 sound/soc/starfive/i2srx-master.h diff --git a/sound/soc/starfive/Kconfig b/sound/soc/starfive/Kconfig index b839ee8..4510c91 100644 --- a/sound/soc/starfive/Kconfig +++ b/sound/soc/starfive/Kconfig @@ -21,26 +21,19 @@ config SND_SOC_STARFIVE_PWMDAC_PCM Say Y or N if you want to add a custom ALSA extension that registers a PCM and uses PIO to transfer data. -config SND_SOC_STARFIVE_I2S_MASTER - tristate "Starfive I2S_Rx Master module" - depends on HAVE_CLK && SND_SOC_STARFIVE - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say 'Y' or 'M' here if you are building for StarFive SoCs - platforms that contain i2srx_3ch controller core. - config SND_SOC_STARFIVE_I2S tristate "Starfive I2S module" depends on HAVE_CLK && SND_SOC_STARFIVE select SND_SOC_GENERIC_DMAENGINE_PCM help Say 'Y' or 'M' here if you are building for StarFive SoCs - platforms that contain i2s controller core like i2stx_4ch0. + platforms that contain i2s controller core like i2stx_4ch0 + and i2srx_master. config SND_SOC_STARFIVE_PDM tristate "Starfive PDM module" depends on HAVE_CLK && SND_SOC_STARFIVE - select SND_SOC_STARFIVE_I2S_MASTER + select SND_SOC_STARFIVE_I2S select REGMAP_MMIO help Say Y or M if you want to add support for sf pdm driver. diff --git a/sound/soc/starfive/Makefile b/sound/soc/starfive/Makefile index 2709d34..9355f90 100644 --- a/sound/soc/starfive/Makefile +++ b/sound/soc/starfive/Makefile @@ -3,9 +3,6 @@ obj-$(CONFIG_SND_SOC_STARFIVE_PWMDAC) += pwmdac.o pwmdac-y := starfive_pwmdac.o starfive_pwmdac_transmitter.o pwmdac-$(CONFIG_SND_SOC_STARFIVE_PWMDAC_PCM) += starfive_pwmdac_pcm.o -snd-soc-i2srx-master-objs := i2srx-master.o -obj-$(CONFIG_SND_SOC_STARFIVE_I2S_MASTER) += snd-soc-i2srx-master.o - obj-$(CONFIG_SND_SOC_STARFIVE_PDM) += starfive_pdm.o obj-$(CONFIG_SND_SOC_STARFIVE_TDM) += starfive_tdm.o diff --git a/sound/soc/starfive/i2srx-master.c b/sound/soc/starfive/i2srx-master.c deleted file mode 100644 index b13b414..0000000 --- a/sound/soc/starfive/i2srx-master.c +++ /dev/null @@ -1,879 +0,0 @@ -/* - * ALSA SoC Synopsys I2S Audio Layer - * - * sound/soc/dwc/designware_i2s.c - * - * Copyright (C) 2010 ST Microelectronics - * Rajeev Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "i2srx-master.h" - -static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val) -{ - writel(val, io_base + reg); -} - -static inline u32 i2s_read_reg(void __iomem *io_base, int reg) -{ - return readl(io_base + reg); -} - -static inline void i2s_disable_channels(struct dw_i2s_dev *dev, u32 stream) -{ - u32 i = 0; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < 4; i++) - i2s_write_reg(dev->i2s_base, TER(i), 0); - } else { - for (i = 0; i < 4; i++) - i2s_write_reg(dev->i2s_base, RER(i), 0); - } -} - -static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream) -{ - u32 i = 0; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < 4; i++) - i2s_read_reg(dev->i2s_base, TOR(i)); - } else { - for (i = 0; i < 4; i++) - i2s_read_reg(dev->i2s_base, ROR(i)); - } -} - -static inline void i2s_disable_irqs(struct dw_i2s_dev *dev, u32 stream, - int chan_nr) -{ - u32 i, irq; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < (chan_nr / 2); i++) { - irq = i2s_read_reg(dev->i2s_base, IMR(i)); - i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x30); - } - } else { - for (i = 0; i < (chan_nr / 2); i++) { - irq = i2s_read_reg(dev->i2s_base, IMR(i)); - i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x03); - } - } -} - -static inline void i2s_enable_irqs(struct dw_i2s_dev *dev, u32 stream, - int chan_nr) -{ - u32 i, irq; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < (chan_nr / 2); i++) { - irq = i2s_read_reg(dev->i2s_base, IMR(i)); - i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x30); - } - } else { - for (i = 0; i < (chan_nr / 2); i++) { - irq = i2s_read_reg(dev->i2s_base, IMR(i)); - i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x03); - } - } -} - -static irqreturn_t i2s_irq_handler(int irq, void *dev_id) -{ - struct dw_i2s_dev *dev = dev_id; - bool irq_valid = false; - u32 isr[4]; - int i; - - for (i = 0; i < 4; i++) - isr[i] = i2s_read_reg(dev->i2s_base, ISR(i)); - - i2s_clear_irqs(dev, SNDRV_PCM_STREAM_PLAYBACK); - i2s_clear_irqs(dev, SNDRV_PCM_STREAM_CAPTURE); - - for (i = 0; i < 4; i++) { - /* - * Check if TX fifo is empty. If empty fill FIFO with samples - * NOTE: Only two channels supported - */ - if ((isr[i] & ISR_TXFE) && (i == 0) && dev->use_pio) { - dw_pcm_push_tx(dev); - irq_valid = true; - } - - /* - * Data available. Retrieve samples from FIFO - * NOTE: Only two channels supported - */ - if ((isr[i] & ISR_RXDA) && (i == 0) && dev->use_pio) { - dw_pcm_pop_rx(dev); - irq_valid = true; - } - - /* Error Handling: TX */ - if (isr[i] & ISR_TXFO) { - dev_err(dev->dev, "TX overrun (ch_id=%d)\n", i); - irq_valid = true; - } - - /* Error Handling: TX */ - if (isr[i] & ISR_RXFO) { - dev_err(dev->dev, "RX overrun (ch_id=%d)\n", i); - irq_valid = true; - } - } - - if (irq_valid) - return IRQ_HANDLED; - else - return IRQ_NONE; -} - -static void i2s_start(struct dw_i2s_dev *dev, - struct snd_pcm_substream *substream) -{ - struct i2s_clk_config_data *config = &dev->config; - - i2s_write_reg(dev->i2s_base, IER, 1); - i2s_enable_irqs(dev, substream->stream, config->chan_nr); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - i2s_write_reg(dev->i2s_base, ITER, 1); - else - i2s_write_reg(dev->i2s_base, IRER, 1); - - i2s_write_reg(dev->i2s_base, CER, 1); - -} - -static void i2s_stop(struct dw_i2s_dev *dev, - struct snd_pcm_substream *substream) -{ - - i2s_clear_irqs(dev, substream->stream); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - i2s_write_reg(dev->i2s_base, ITER, 0); - else - i2s_write_reg(dev->i2s_base, IRER, 0); - - i2s_disable_irqs(dev, substream->stream, 8); - - if (!dev->active) { - i2s_write_reg(dev->i2s_base, CER, 0); - i2s_write_reg(dev->i2s_base, IER, 0); - } -} - -static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) -{ - u32 ch_reg; - struct i2s_clk_config_data *config = &dev->config; - - - i2s_disable_channels(dev, stream); - - for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) { - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - i2s_write_reg(dev->i2s_base, TCR(ch_reg), - dev->xfer_resolution); - i2s_write_reg(dev->i2s_base, TFCR(ch_reg), - dev->fifo_th - 1); - i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); - } else { - i2s_write_reg(dev->i2s_base, RCR(ch_reg), - dev->xfer_resolution); - i2s_write_reg(dev->i2s_base, RFCR(ch_reg), - dev->fifo_th - 1); - i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); - } - - } -} - -static int dw_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) -{ - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - struct i2s_clk_config_data *config = &dev->config; - int ret; - unsigned int bclk_rate; - union dw_i2s_snd_dma_data *dma_data = NULL; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - config->data_width = 16; - dev->ccr = 0x00; - dev->xfer_resolution = 0x02; - dev->capture_dma_data.dt.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - break; - - /* There is a issue with hardware while using 24-bit */ -/* - case SNDRV_PCM_FORMAT_S24_LE: - config->data_width = 24; - dev->ccr = 0x08; - dev->xfer_resolution = 0x04; - dev->capture_dma_data.dt.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - break; -*/ - - case SNDRV_PCM_FORMAT_S32_LE: - config->data_width = 32; - dev->ccr = 0x10; - dev->xfer_resolution = 0x05; - dev->capture_dma_data.dt.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - break; - - default: - dev_err(dev->dev, "designware-i2s: unsupported PCM fmt"); - return -EINVAL; - } - - switch (params_rate(params)) { - case 8000: - bclk_rate = 512000; - break; - case 11025: - bclk_rate = 705600; - break; - case 16000: - bclk_rate = 1024000; - break; - default: - dev_err(dai->dev, "%d rate not supported\n", - params_rate(params)); - return -EINVAL; - } - - config->chan_nr = params_channels(params); - - switch (config->chan_nr) { - case EIGHT_CHANNEL_SUPPORT: - case SIX_CHANNEL_SUPPORT: - case FOUR_CHANNEL_SUPPORT: - case TWO_CHANNEL_SUPPORT: - break; - default: - dev_err(dev->dev, "channel not supported\n"); - return -EINVAL; - } - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - dma_data = &dev->capture_dma_data; - snd_soc_dai_set_dma_data(dai, substream, (void *)dma_data); - - dw_i2s_config(dev, substream->stream); - - i2s_write_reg(dev->i2s_base, CCR, dev->ccr); - - config->sample_rate = params_rate(params); - - - if (dev->capability & DW_I2S_MASTER) { - if (dev->i2s_clk_cfg) { - ret = dev->i2s_clk_cfg(config); - if (ret < 0) { - dev_err(dev->dev, "runtime audio clk config fail\n"); - return ret; - } - } else { - ret = clk_set_rate(dev->clk_i2srx_bclk_mst, bclk_rate); - if (ret) { - dev_err(dev->dev, "Can't set i2s bclk: %d\n", ret); - return ret; - } - } - } - return 0; -} - -static int dw_i2s_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - i2s_write_reg(dev->i2s_base, TXFFR, 1); - else - i2s_write_reg(dev->i2s_base, RXFFR, 1); - - return 0; -} - -static int dw_i2s_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - dev->active++; - i2s_start(dev, substream); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - dev->active--; - i2s_stop(dev, substream); - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) -{ - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); - int ret = 0; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - if (dev->capability & DW_I2S_SLAVE) - ret = 0; - else - ret = -EINVAL; - break; - case SND_SOC_DAIFMT_CBS_CFS: - if (dev->capability & DW_I2S_MASTER) - ret = 0; - else - ret = -EINVAL; - break; - case SND_SOC_DAIFMT_CBM_CFS: - case SND_SOC_DAIFMT_CBS_CFM: - ret = -EINVAL; - break; - default: - dev_dbg(dev->dev, "dwc : Invalid master/slave format\n"); - ret = -EINVAL; - break; - } - return ret; -} - -static const struct snd_soc_dai_ops dw_i2s_dai_ops = { - .hw_params = dw_i2s_hw_params, - .prepare = dw_i2s_prepare, - .trigger = dw_i2s_trigger, - .set_fmt = dw_i2s_set_fmt, -}; - -#ifdef CONFIG_PM -static int dw_i2s_runtime_suspend(struct device *dev) -{ - struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); - - if (dw_dev->capability & DW_I2S_MASTER) { - clk_disable_unprepare(dw_dev->clk_i2srx_lrck); - clk_disable_unprepare(dw_dev->clk_i2srx_bclk); - } - - return 0; -} - -static int dw_i2s_runtime_resume(struct device *dev) -{ - struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); - int ret; - - if (dw_dev->capability & DW_I2S_MASTER) { - ret = clk_prepare_enable(dw_dev->clk_i2srx_bclk); - if (ret) { - dev_err(dw_dev->dev, "Failed to enable clk_i2srx_3ch_bclk\n"); - return ret; - } - - ret = clk_prepare_enable(dw_dev->clk_i2srx_lrck); - if (ret) { - dev_err(dw_dev->dev, "Failed to enable clk_i2srx_3ch_lrck\n"); - return ret; - } - } - - return 0; -} - -static int dw_i2s_suspend(struct snd_soc_component *component) -{ - struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component); - - if (dev->capability & DW_I2S_MASTER) { - clk_disable_unprepare(dev->clk_i2srx_lrck); - clk_disable_unprepare(dev->clk_i2srx_bclk); - } - - return 0; -} - -static int dw_i2s_resume(struct snd_soc_component *component) -{ - struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component); - struct snd_soc_dai *dai; - int stream; - int ret; - - if (dev->capability & DW_I2S_MASTER) { - ret = clk_prepare_enable(dev->clk_i2srx_bclk); - if (ret) { - dev_err(dev->dev, "Failed to enable clk_i2srx_3ch_bclk\n"); - return ret; - } - - ret = clk_prepare_enable(dev->clk_i2srx_lrck); - if (ret) { - dev_err(dev->dev, "Failed to enable clk_i2srx_3ch_lrck\n"); - return ret; - } - } - - for_each_component_dais(component, dai) { - for_each_pcm_streams(stream) - if (snd_soc_dai_stream_active(dai, stream)) - dw_i2s_config(dev, stream); - } - - return 0; -} - -#else -#define dw_i2s_suspend NULL -#define dw_i2s_resume NULL -#endif - -static const struct snd_soc_component_driver dw_i2s_component = { - .name = "dw-i2s", - .suspend = dw_i2s_suspend, - .resume = dw_i2s_resume, -}; - -static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev) -{ - int ret = 0; - - static struct clk_bulk_data clks[] = { - { .id = "apb0" }, - { .id = "i2srx_apb" }, - { .id = "i2srx_bclk_mst" }, - { .id = "i2srx_lrck_mst" }, - { .id = "i2srx_bclk" }, - { .id = "i2srx_lrck" }, - }; - - ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks); - if (ret) { - dev_err(&pdev->dev, "%s: failed to get i2srx clocks\n", __func__); - goto exit; - } - - dev->clk_apb0 = clks[0].clk; - dev->clk_i2srx_apb = clks[1].clk; - dev->clk_i2srx_bclk_mst = clks[2].clk; - dev->clk_i2srx_lrck_mst = clks[3].clk; - dev->clk_i2srx_bclk = clks[4].clk; - dev->clk_i2srx_lrck = clks[5].clk; - - dev->rst_i2srx_apb = devm_reset_control_get_exclusive(&pdev->dev, "rst_apb_rx"); - if (IS_ERR(dev->rst_i2srx_apb)) { - dev_err(&pdev->dev, "failed to get apb_i2srx reset control\n"); - ret = PTR_ERR(dev->rst_i2srx_apb); - goto exit; - } - - dev->rst_i2srx_bclk = devm_reset_control_get_exclusive(&pdev->dev, "rst_bclk_rx"); - if (IS_ERR(dev->rst_i2srx_bclk)) { - dev_err(&pdev->dev, "failed to get i2s bclk rx reset control\n"); - ret = PTR_ERR(dev->rst_i2srx_bclk); - goto exit; - } - - reset_control_assert(dev->rst_i2srx_apb); - reset_control_assert(dev->rst_i2srx_bclk); - - ret = clk_prepare_enable(dev->clk_apb0); - if (ret) { - dev_err(&pdev->dev, "failed to prepare enable clk_apb0\n"); - goto exit; - } - - ret = clk_prepare_enable(dev->clk_i2srx_apb); - if (ret) { - dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_apb\n"); - goto err_dis_i2srx_apb; - } - - ret = clk_prepare_enable(dev->clk_i2srx_bclk_mst); - if (ret) { - dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_bclk_mst\n"); - goto err_dis_bclk_mst; - } - - ret = clk_prepare_enable(dev->clk_i2srx_lrck_mst); - if (ret) { - dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_lrck_mst\n"); - goto err_dis_lrck_mst; - } - - ret = clk_prepare_enable(dev->clk_i2srx_bclk); - if (ret) { - dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_bclk\n"); - goto err_dis_bclk; - } - - ret = clk_prepare_enable(dev->clk_i2srx_lrck); - if (ret) { - dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_lrck\n"); - goto err_dis_lrck; - } - - reset_control_deassert(dev->rst_i2srx_apb); - reset_control_deassert(dev->rst_i2srx_bclk); - - regmap_update_bits(dev->syscon_base, dev->syscon_offset_18, - I2SRX_3CH_ADC_MASK, I2SRX_3CH_ADC_EN); - return 0; - -err_dis_i2srx_apb: - clk_disable_unprepare(dev->clk_apb0); -err_dis_bclk_mst: - clk_disable_unprepare(dev->clk_i2srx_apb); -err_dis_lrck_mst: - clk_disable_unprepare(dev->clk_i2srx_bclk_mst); -err_dis_bclk: - clk_disable_unprepare(dev->clk_i2srx_lrck_mst); -err_dis_lrck: - clk_disable_unprepare(dev->clk_i2srx_bclk); -exit: - return ret; -} - -/* - * The following tables allow a direct lookup of various parameters - * defined in the I2S block's configuration in terms of sound system - * parameters. Each table is sized to the number of entries possible - * according to the number of configuration bits describing an I2S - * block parameter. - */ - -/* Maximum bit resolution of a channel - not uniformly spaced */ -static const u32 fifo_width[COMP_MAX_WORDSIZE] = { - 12, 16, 20, 24, 32, 0, 0, 0 -}; - -/* Width of (DMA) bus */ -static const u32 bus_widths[COMP_MAX_DATA_WIDTH] = { - DMA_SLAVE_BUSWIDTH_1_BYTE, - DMA_SLAVE_BUSWIDTH_2_BYTES, - DMA_SLAVE_BUSWIDTH_4_BYTES, - DMA_SLAVE_BUSWIDTH_UNDEFINED -}; - -/* PCM format to support channel resolution */ -static const u32 formats[COMP_MAX_WORDSIZE] = { - SNDRV_PCM_FMTBIT_S16_LE, - SNDRV_PCM_FMTBIT_S16_LE, - SNDRV_PCM_FMTBIT_S24_LE, - SNDRV_PCM_FMTBIT_S24_LE, - SNDRV_PCM_FMTBIT_S32_LE, - 0, - 0, - 0 -}; - -#define SF_IIS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - -static int dw_configure_dai(struct dw_i2s_dev *dev, - struct snd_soc_dai_driver *dw_i2s_dai, - unsigned int rates) -{ - /* - * Read component parameter registers to extract - * the I2S block's configuration. - */ - u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1); - u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2); - u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1)); - u32 idx; - - if (dev->capability & DWC_I2S_RECORD && - dev->quirks & DW_I2S_QUIRK_COMP_PARAM1) - comp1 = comp1 & ~BIT(5); - - if (dev->capability & DWC_I2S_PLAY && - dev->quirks & DW_I2S_QUIRK_COMP_PARAM1) - comp1 = comp1 & ~BIT(6); - - if (COMP1_TX_ENABLED(comp1)) { - dev_dbg(dev->dev, " designware: play supported\n"); - idx = COMP1_TX_WORDSIZE_0(comp1); - if (WARN_ON(idx >= ARRAY_SIZE(formats))) - return -EINVAL; - if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE) - idx = 1; - dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; - dw_i2s_dai->playback.channels_max = - 1 << (COMP1_TX_CHANNELS(comp1) + 1); - dw_i2s_dai->playback.formats = formats[idx]; - dw_i2s_dai->playback.rates = rates; - } - - if (COMP1_RX_ENABLED(comp1)) { - dev_dbg(dev->dev, "designware: record supported\n"); - idx = COMP2_RX_WORDSIZE_0(comp2); - if (WARN_ON(idx >= ARRAY_SIZE(formats))) - return -EINVAL; - if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE) - idx = 1; - dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; - dw_i2s_dai->capture.channels_max = - 1 << (COMP1_RX_CHANNELS(comp1) + 1); - dw_i2s_dai->capture.formats = SF_IIS_FORMATS; - dw_i2s_dai->capture.rates = rates; - } - - dev_dbg(dev->dev, "designware: i2s master mode supported\n"); - dev->capability |= DW_I2S_MASTER; - dev->fifo_th = fifo_depth / 2; - return 0; -} - -static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, - struct snd_soc_dai_driver *dw_i2s_dai, - struct resource *res) -{ - u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); - u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); - u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1)); - u32 idx = COMP1_APB_DATA_WIDTH(comp1); - u32 idx2; - int ret; - - if (WARN_ON(idx >= ARRAY_SIZE(bus_widths))) - return -EINVAL; - - ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000); - if (ret < 0) - return ret; - - if (COMP1_TX_ENABLED(comp1)) { - idx2 = COMP1_TX_WORDSIZE_0(comp1); - - dev->capability |= DWC_I2S_PLAY; - dev->play_dma_data.dt.addr = res->start + I2S_TXDMA; - dev->play_dma_data.dt.addr_width = bus_widths[idx]; - dev->play_dma_data.dt.fifo_size = fifo_depth * - (fifo_width[idx2]) >> 8; - dev->play_dma_data.dt.maxburst = 16; - } - if (COMP1_RX_ENABLED(comp1)) { - idx2 = COMP2_RX_WORDSIZE_0(comp2); - - /* force change to 1 */ - idx = 1; - idx2 = 1; - dev->capability |= DWC_I2S_RECORD; - dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; - dev->capture_dma_data.dt.addr_width = bus_widths[idx]; - dev->capture_dma_data.dt.fifo_size = fifo_depth * - (fifo_width[idx2] >> 8); - dev->capture_dma_data.dt.maxburst = 16; - } - - return 0; - -} - -static int dw_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); - return 0; -} - -static int dw_i2s_probe(struct platform_device *pdev) -{ - const struct i2s_platform_data *pdata = pdev->dev.platform_data; - struct device_node *np = pdev->dev.of_node; - struct of_phandle_args args; - struct dw_i2s_dev *dev; - struct resource *res; - int ret, irq; - struct snd_soc_dai_driver *dw_i2s_dai; - const char *clk_id; - - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL); - if (!dw_i2s_dai) - return -ENOMEM; - - - dw_i2s_dai->ops = &dw_i2s_dai_ops; - dw_i2s_dai->probe = dw_i2s_dai_probe; - - dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(dev->i2s_base)) - return PTR_ERR(dev->i2s_base); - - dev->dev = &pdev->dev; - - ret = of_parse_phandle_with_fixed_args(dev->dev->of_node, - "starfive,sys-syscon", 2, 0, &args); - if (ret) { - dev_err(dev->dev, "Failed to parse starfive,sys-syscon\n"); - return -EINVAL; - } - - dev->syscon_base = syscon_node_to_regmap(args.np); - of_node_put(args.np); - if (IS_ERR(dev->syscon_base)) - return PTR_ERR(dev->syscon_base); - - dev->syscon_offset_18 = args.args[0]; - dev->syscon_offset_34 = args.args[1]; - - irq = platform_get_irq_optional(pdev, 0); - if (irq >= 0) { - ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0, - pdev->name, dev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to request irq\n"); - return ret; - } - } - - if (of_device_is_compatible(np, "starfive,jh7110-i2srx-master")) { - /* config i2s data source: PDM */ - regmap_update_bits(dev->syscon_base, dev->syscon_offset_34, - AUDIO_SDIN_MUX_MASK, I2SRX_DATA_SRC_PDM); - - ret = dw_i2srx_clk_init(pdev, dev); - if (ret < 0) - goto err_clk_disable; - } - - dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; - dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; - - clk_id = "i2srx_bclk"; - ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res); - if (ret < 0) - return ret; - - if (dev->capability & DW_I2S_MASTER) { - if (pdata) { - dev->i2s_clk_cfg = pdata->i2s_clk_cfg; - if (!dev->i2s_clk_cfg) { - dev_err(&pdev->dev, "no clock configure method\n"); - return -ENODEV; - } - } - } - - dev_set_drvdata(&pdev->dev, dev); - ret = devm_snd_soc_register_component(&pdev->dev, &dw_i2s_component, - dw_i2s_dai, 1); - if (ret != 0) { - dev_err(&pdev->dev, "not able to register dai\n"); - goto err_clk_disable; - } - - if (!pdata) { - if (irq >= 0) { - ret = dw_pcm_register(pdev); - dev->use_pio = true; - } else { - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, - 0); - dev->use_pio = false; - } - - if (ret) { - dev_err(&pdev->dev, "could not register pcm: %d\n", - ret); - goto err_clk_disable; - } - } - - pm_runtime_enable(&pdev->dev); - return 0; - -err_clk_disable: - if (dev->capability & DW_I2S_MASTER) - clk_disable_unprepare(dev->clk_i2srx_bclk_mst); - return ret; -} - -static int dw_i2s_remove(struct platform_device *pdev) -{ - struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); - - if (dev->capability & DW_I2S_MASTER) - clk_disable_unprepare(dev->clk_i2srx_bclk_mst); - - pm_runtime_disable(&pdev->dev); - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id dw_i2s_of_match[] = { - { .compatible = "starfive,jh7110-i2srx-master", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, dw_i2s_of_match); -#endif - -static const struct dev_pm_ops dwc_pm_ops = { - SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL) -}; - -static struct platform_driver dw_i2s_driver = { - .probe = dw_i2s_probe, - .remove = dw_i2s_remove, - .driver = { - .name = "i2srx-master", - .of_match_table = of_match_ptr(dw_i2s_of_match), - .pm = &dwc_pm_ops, - }, -}; - -module_platform_driver(dw_i2s_driver); - -MODULE_AUTHOR("Rajeev Kumar "); -MODULE_AUTHOR("Walker Chen "); -MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:designware_i2s"); diff --git a/sound/soc/starfive/i2srx-master.h b/sound/soc/starfive/i2srx-master.h deleted file mode 100644 index a0b9adc..0000000 --- a/sound/soc/starfive/i2srx-master.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (ST) 2012 Rajeev Kumar (rajeevkumar.linux@gmail.com) - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __DESIGNWARE_LOCAL_H -#define __DESIGNWARE_LOCAL_H - -#include -#include -#include -#include -#include -#include - -/* common register for all channel */ -#define IER 0x000 -#define IRER 0x004 -#define ITER 0x008 -#define CER 0x00C -#define CCR 0x010 -#define RXFFR 0x014 -#define TXFFR 0x018 - -/* Interrupt status register fields */ -#define ISR_TXFO BIT(5) -#define ISR_TXFE BIT(4) -#define ISR_RXFO BIT(1) -#define ISR_RXDA BIT(0) - -/* I2STxRxRegisters for all channels */ -#define LRBR_LTHR(x) (0x40 * x + 0x020) -#define RRBR_RTHR(x) (0x40 * x + 0x024) -#define RER(x) (0x40 * x + 0x028) -#define TER(x) (0x40 * x + 0x02C) -#define RCR(x) (0x40 * x + 0x030) -#define TCR(x) (0x40 * x + 0x034) -#define ISR(x) (0x40 * x + 0x038) -#define IMR(x) (0x40 * x + 0x03C) -#define ROR(x) (0x40 * x + 0x040) -#define TOR(x) (0x40 * x + 0x044) -#define RFCR(x) (0x40 * x + 0x048) -#define TFCR(x) (0x40 * x + 0x04C) -#define RFF(x) (0x40 * x + 0x050) -#define TFF(x) (0x40 * x + 0x054) - -/* I2SCOMPRegisters */ -#define I2S_COMP_PARAM_2 0x01F0 -#define I2S_COMP_PARAM_1 0x01F4 -#define I2S_COMP_VERSION 0x01F8 -#define I2S_COMP_TYPE 0x01FC - -/* - * Component parameter register fields - define the I2S block's - * configuration. - */ -#define COMP1_TX_WORDSIZE_3(r) (((r) & GENMASK(27, 25)) >> 25) -#define COMP1_TX_WORDSIZE_2(r) (((r) & GENMASK(24, 22)) >> 22) -#define COMP1_TX_WORDSIZE_1(r) (((r) & GENMASK(21, 19)) >> 19) -#define COMP1_TX_WORDSIZE_0(r) (((r) & GENMASK(18, 16)) >> 16) -#define COMP1_TX_CHANNELS(r) (((r) & GENMASK(10, 9)) >> 9) -#define COMP1_RX_CHANNELS(r) (((r) & GENMASK(8, 7)) >> 7) -#define COMP1_RX_ENABLED(r) (((r) & BIT(6)) >> 6) -#define COMP1_TX_ENABLED(r) (((r) & BIT(5)) >> 5) -#define COMP1_MODE_EN(r) (((r) & BIT(4)) >> 4) -#define COMP1_FIFO_DEPTH_GLOBAL(r) (((r) & GENMASK(3, 2)) >> 2) -#define COMP1_APB_DATA_WIDTH(r) (((r) & GENMASK(1, 0)) >> 0) - -#define COMP2_RX_WORDSIZE_3(r) (((r) & GENMASK(12, 10)) >> 10) -#define COMP2_RX_WORDSIZE_2(r) (((r) & GENMASK(9, 7)) >> 7) -#define COMP2_RX_WORDSIZE_1(r) (((r) & GENMASK(5, 3)) >> 3) -#define COMP2_RX_WORDSIZE_0(r) (((r) & GENMASK(2, 0)) >> 0) - -/* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */ -#define COMP_MAX_WORDSIZE (1 << 3) -#define COMP_MAX_DATA_WIDTH (1 << 2) - -#define MAX_CHANNEL_NUM 8 -#define MIN_CHANNEL_NUM 2 - -/* SYSCON Registers */ -#define I2SRX_3CH_ADC_MASK 0x2 -#define I2SRX_3CH_ADC_EN BIT(1) -#define AUDIO_SDIN_MUX_MASK 0x3FC00 -#define I2SRX_DATA_SRC_PDM (0x91 << 10) - -union dw_i2s_snd_dma_data { - struct i2s_dma_data pd; - struct snd_dmaengine_dai_dma_data dt; -}; - -struct dw_i2s_dev { - void __iomem *i2s_base; - struct regmap *syscon_base; - int active; - unsigned int capability; - unsigned int quirks; - unsigned int i2s_reg_comp1; - unsigned int i2s_reg_comp2; - struct device *dev; - u32 ccr; - u32 xfer_resolution; - u32 fifo_th; - u32 syscon_offset_18; - u32 syscon_offset_34; - - struct clk *clk_apb0; - struct clk *clk_i2srx_apb; - struct clk *clk_i2srx_bclk_mst; - struct clk *clk_i2srx_lrck_mst; - struct clk *clk_i2srx_bclk; - struct clk *clk_i2srx_lrck; - struct reset_control *rst_i2srx_apb; - struct reset_control *rst_i2srx_bclk; - - /* data related to DMA transfers b/w i2s and DMAC */ - union dw_i2s_snd_dma_data play_dma_data; - union dw_i2s_snd_dma_data capture_dma_data; - struct i2s_clk_config_data config; - int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); - - /* data related to PIO transfers */ - bool use_pio; - struct snd_pcm_substream __rcu *tx_substream; - struct snd_pcm_substream __rcu *rx_substream; - unsigned int (*tx_fn)(struct dw_i2s_dev *dev, - struct snd_pcm_runtime *runtime, unsigned int tx_ptr, - bool *period_elapsed); - unsigned int (*rx_fn)(struct dw_i2s_dev *dev, - struct snd_pcm_runtime *runtime, unsigned int rx_ptr, - bool *period_elapsed); - unsigned int tx_ptr; - unsigned int rx_ptr; -}; - -#if IS_ENABLED(CONFIG_SND_DESIGNWARE_PCM) -void dw_pcm_push_tx(struct dw_i2s_dev *dev); -void dw_pcm_pop_rx(struct dw_i2s_dev *dev); -int dw_pcm_register(struct platform_device *pdev); -#else -static inline void dw_pcm_push_tx(struct dw_i2s_dev *dev) { } -static inline void dw_pcm_pop_rx(struct dw_i2s_dev *dev) { } -static inline int dw_pcm_register(struct platform_device *pdev) -{ - return -EINVAL; -} -#endif - -#endif diff --git a/sound/soc/starfive/starfive_i2s.c b/sound/soc/starfive/starfive_i2s.c index 28c749c..9b2ef6e7 100644 --- a/sound/soc/starfive/starfive_i2s.c +++ b/sound/soc/starfive/starfive_i2s.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "starfive_i2s.h" @@ -217,25 +218,37 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, struct i2s_clk_config_data *config = &dev->config; int ret; unsigned int bclk_rate; + bool playback; union dw_i2s_snd_dma_data *dma_data = NULL; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai_link *dai_link = rtd->dai_link; dai_link->stop_dma_first = 1; + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + playback = false; + else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + playback = true; + switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: config->data_width = 16; dev->ccr = 0x00; dev->xfer_resolution = 0x02; - dev->play_dma_data.dt.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + if (playback) + dev->play_dma_data.dt.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + else + dev->capture_dma_data.dt.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; break; case SNDRV_PCM_FORMAT_S32_LE: config->data_width = 32; dev->ccr = 0x10; dev->xfer_resolution = 0x05; - dev->play_dma_data.dt.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + if (playback) + dev->play_dma_data.dt.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + else + dev->capture_dma_data.dt.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; break; default: @@ -243,17 +256,37 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - switch (params_rate(params)) { - case 32000: - bclk_rate = 2048000; - break; - case 48000: - bclk_rate = 3072000; - break; - default: - dev_err(dai->dev, "%d rate not supported\n", - params_rate(params)); - return -EINVAL; + if (playback) { + switch (params_rate(params)) { + case 32000: + bclk_rate = 2048000; + break; + case 48000: + bclk_rate = 3072000; + break; + default: + dev_err(dai->dev, "%d rate not supported\n", + params_rate(params)); + ret = -EINVAL; + goto err_return; + } + } else { + switch (params_rate(params)) { + case 8000: + bclk_rate = 512000; + break; + case 11025: + bclk_rate = 705600; + break; + case 16000: + bclk_rate = 1024000; + break; + default: + dev_err(dai->dev, "%d rate not supported\n", + params_rate(params)); + ret = -EINVAL; + goto err_return; + } } config->chan_nr = params_channels(params); @@ -289,10 +322,13 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, goto err_return; } } else { - ret = clk_set_parent(dev->clk_mclk, dev->clk_mclk_ext); - if (ret) { - dev_err(dev->dev, "failed to set mclk parent to mclk_ext\n"); - goto err_return; + if (playback) { + ret = clk_set_parent(dev->clk_mclk, dev->clk_mclk_ext); + if (ret) { + dev_err(dev->dev, + "failed to set mclk parent to mclk_ext\n"); + goto err_return; + } } ret = clk_set_rate(dev->clk_i2s_bclk_mst, bclk_rate); @@ -480,6 +516,106 @@ static const struct snd_soc_component_driver dw_i2s_component = { .resume = dw_i2s_resume, }; +static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev) +{ + int ret = 0; + + static struct clk_bulk_data clks[] = { + { .id = "apb0" }, + { .id = "i2srx_apb" }, + { .id = "i2srx_bclk_mst" }, + { .id = "i2srx_lrck_mst" }, + { .id = "i2srx_bclk" }, + { .id = "i2srx_lrck" }, + }; + + ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks); + if (ret) { + dev_err(&pdev->dev, "%s: failed to get i2srx clocks\n", __func__); + goto exit; + } + + dev->clk_apb0 = clks[0].clk; + dev->clk_i2s_apb = clks[1].clk; + dev->clk_i2s_bclk_mst = clks[2].clk; + dev->clk_i2s_lrck_mst = clks[3].clk; + dev->clk_i2s_bclk = clks[4].clk; + dev->clk_i2s_lrck = clks[5].clk; + + dev->rst_i2s_apb = devm_reset_control_get_exclusive(&pdev->dev, "rst_apb_rx"); + if (IS_ERR(dev->rst_i2s_apb)) { + dev_err(&pdev->dev, "failed to get apb_i2srx reset control\n"); + ret = PTR_ERR(dev->rst_i2s_apb); + goto exit; + } + + dev->rst_i2s_bclk = devm_reset_control_get_exclusive(&pdev->dev, "rst_bclk_rx"); + if (IS_ERR(dev->rst_i2s_bclk)) { + dev_err(&pdev->dev, "failed to get i2s bclk rx reset control\n"); + ret = PTR_ERR(dev->rst_i2s_bclk); + goto exit; + } + + reset_control_assert(dev->rst_i2s_apb); + reset_control_assert(dev->rst_i2s_bclk); + + ret = clk_prepare_enable(dev->clk_apb0); + if (ret) { + dev_err(&pdev->dev, "failed to prepare enable clk_apb0\n"); + goto exit; + } + + ret = clk_prepare_enable(dev->clk_i2s_apb); + if (ret) { + dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_apb\n"); + goto err_dis_i2srx_apb; + } + + ret = clk_prepare_enable(dev->clk_i2s_bclk_mst); + if (ret) { + dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_bclk_mst\n"); + goto err_dis_bclk_mst; + } + + ret = clk_prepare_enable(dev->clk_i2s_lrck_mst); + if (ret) { + dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_lrck_mst\n"); + goto err_dis_lrck_mst; + } + + ret = clk_prepare_enable(dev->clk_i2s_bclk); + if (ret) { + dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_bclk\n"); + goto err_dis_bclk; + } + + ret = clk_prepare_enable(dev->clk_i2s_lrck); + if (ret) { + dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_lrck\n"); + goto err_dis_lrck; + } + + reset_control_deassert(dev->rst_i2s_apb); + reset_control_deassert(dev->rst_i2s_bclk); + + regmap_update_bits(dev->syscon_base, dev->syscon_offset_18, + I2SRX_3CH_ADC_MASK, I2SRX_3CH_ADC_EN); + return 0; + +err_dis_i2srx_apb: + clk_disable_unprepare(dev->clk_apb0); +err_dis_bclk_mst: + clk_disable_unprepare(dev->clk_i2s_apb); +err_dis_lrck_mst: + clk_disable_unprepare(dev->clk_i2s_bclk_mst); +err_dis_bclk: + clk_disable_unprepare(dev->clk_i2s_lrck_mst); +err_dis_lrck: + clk_disable_unprepare(dev->clk_i2s_bclk); +exit: + return ret; +} + static int dw_i2stx_4ch0_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev) { int ret = 0; @@ -534,12 +670,6 @@ static int dw_i2stx_4ch0_clk_init(struct platform_device *pdev, struct dw_i2s_de goto err_set_parent; } - ret = clk_prepare_enable(dev->clk_i2s_bclk_mst); - if (ret) { - dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_bclk_mst\n"); - goto err_dis_bclk_mst; - } - ret = clk_set_parent(dev->clk_i2s_lrck_mst, dev->clk_i2s_bclk_mst); if (ret) { dev_err(&pdev->dev, "failed to set parent clk_i2s_lrck_mst\n"); @@ -558,12 +688,17 @@ static int dw_i2stx_4ch0_clk_init(struct platform_device *pdev, struct dw_i2s_de goto err_dis_bclk_mst; } + ret = clk_prepare_enable(dev->clk_i2s_bclk_mst); + if (ret) { + dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_bclk_mst\n"); + goto err_dis_bclk_mst; + } + reset_control_deassert(dev->rst_i2s_apb); reset_control_deassert(dev->rst_i2s_bclk); return 0; - err_dis_bclk_mst: err_set_parent: clk_disable_unprepare(dev->clk_i2s_apb); @@ -720,8 +855,11 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, if (WARN_ON(idx >= ARRAY_SIZE(bus_widths))) return -EINVAL; - ret = dw_configure_dai(dev, dw_i2s_dai, + if (COMP1_TX_ENABLED(comp1)) + ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000); + if (COMP1_RX_ENABLED(comp1)) + ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000); if (ret < 0) return ret; @@ -738,6 +876,9 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, if (COMP1_RX_ENABLED(comp1)) { idx2 = COMP2_RX_WORDSIZE_0(comp2); + /* force change to 1 */ + idx = 1; + idx2 = 1; dev->capability |= DWC_I2S_RECORD; dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; dev->capture_dma_data.dt.addr_width = bus_widths[idx]; @@ -762,6 +903,7 @@ static int dw_i2s_probe(struct platform_device *pdev) { const struct i2s_platform_data *pdata = pdev->dev.platform_data; struct device_node *np = pdev->dev.of_node; + struct of_phandle_args args; struct dw_i2s_dev *dev; struct resource *res; int ret, irq; @@ -795,7 +937,30 @@ static int dw_i2s_probe(struct platform_device *pdev) } } - if (of_device_is_compatible(np, "starfive,jh7110-i2stx-4ch0")) { + if (of_device_is_compatible(np, "starfive,jh7110-i2srx-master")) { + ret = of_parse_phandle_with_fixed_args(dev->dev->of_node, + "starfive,sys-syscon", 2, 0, &args); + if (ret) { + dev_err(dev->dev, "Failed to parse starfive,sys-syscon\n"); + return -EINVAL; + } + + dev->syscon_base = syscon_node_to_regmap(args.np); + of_node_put(args.np); + if (IS_ERR(dev->syscon_base)) + return PTR_ERR(dev->syscon_base); + + dev->syscon_offset_18 = args.args[0]; + dev->syscon_offset_34 = args.args[1]; + + /* config i2s data source: PDM */ + regmap_update_bits(dev->syscon_base, dev->syscon_offset_34, + AUDIO_SDIN_MUX_MASK, I2SRX_DATA_SRC_PDM); + + ret = dw_i2srx_clk_init(pdev, dev); + if (ret < 0) + goto err_clk_disable; + } else if (of_device_is_compatible(np, "starfive,jh7110-i2stx-4ch0")) { /* hdmi audio */ ret = dw_i2stx_4ch0_clk_init(pdev, dev); if (ret < 0) @@ -878,6 +1043,7 @@ static int dw_i2s_remove(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id dw_i2s_of_match[] = { + { .compatible = "starfive,jh7110-i2srx-master", }, { .compatible = "starfive,jh7110-i2stx-4ch0", }, {}, }; @@ -902,6 +1068,7 @@ static struct platform_driver dw_i2s_driver = { module_platform_driver(dw_i2s_driver); MODULE_AUTHOR("Rajeev Kumar "); +MODULE_AUTHOR("Walker Chen "); MODULE_AUTHOR("Xingyu Wu "); MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/starfive/starfive_i2s.h b/sound/soc/starfive/starfive_i2s.h index 2e41b080..108412d 100644 --- a/sound/soc/starfive/starfive_i2s.h +++ b/sound/soc/starfive/starfive_i2s.h @@ -105,7 +105,10 @@ struct dw_i2s_dev { u32 ccr; u32 xfer_resolution; u32 fifo_th; + u32 syscon_offset_18; + u32 syscon_offset_34; + struct clk *clk_apb0; struct clk *clk_i2s_apb; struct clk *clk_i2s_bclk_mst; struct clk *clk_i2s_lrck_mst; -- 2.7.4