summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorWalker Chen <walker.chen@starfivetech.com>2021-12-29 11:02:54 +0300
committerjianlong.huang <jianlong.huang@starfivetech.com>2022-04-21 08:28:24 +0300
commit41c2df1ce672fe6172edbcf98df6fb9b8bae2c03 (patch)
treeb356bc206a6b0334f56dbc756388a9ec89bffcab /sound
parentba4fdc30c4bf79a804047f3312426d1a6bf2cdda (diff)
downloadlinux-41c2df1ce672fe6172edbcf98df6fb9b8bae2c03.tar.xz
modify clock tree and support i2s audio
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm8960.c6
-rw-r--r--sound/soc/dwc/Kconfig8
-rw-r--r--sound/soc/dwc/dwc-i2s.c517
-rw-r--r--sound/soc/dwc/local.h49
4 files changed, 440 insertions, 140 deletions
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index cb6991c76900..9de7a9f33129 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -1354,7 +1354,7 @@ static int wm8960_probe(struct snd_soc_component *component)
else
wm8960->set_bias_level = wm8960_set_bias_level_out3;
- #if 1
+#if 1
snd_soc_component_update_bits(component, WM8960_LDAC, 0x100, 0x100);
snd_soc_component_update_bits(component, WM8960_RDAC, 0x100, 0x100);
snd_soc_component_update_bits(component, WM8960_LOUT1, 0x100, 0x100);
@@ -1368,7 +1368,7 @@ static int wm8960_probe(struct snd_soc_component *component)
snd_soc_component_update_bits(component, WM8960_ROUT1, 0x7f, 0x6f);
snd_soc_component_update_bits(component, WM8960_LOUT2, 0x7f, 0x7f);
snd_soc_component_update_bits(component, WM8960_ROUT2, 0x7f, 0x7f);
- #endif
+#endif
snd_soc_add_component_controls(component, wm8960_snd_controls,
ARRAY_SIZE(wm8960_snd_controls));
@@ -1473,14 +1473,12 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100);
regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100);
regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100);
-
regmap_update_bits(wm8960->regmap, WM8960_LINPATH, 0x138, 0x138);
regmap_update_bits(wm8960->regmap, WM8960_RINPATH, 0x138, 0x138);
regmap_update_bits(wm8960->regmap, WM8960_POWER1, 0x7E, 0x7E);
regmap_update_bits(wm8960->regmap, WM8960_POWER3, 0x30, 0x30);
regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x19F, 0x197);
regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x19F, 0x197);
-
/* ADCLRC pin configured as GPIO. */
regmap_update_bits(wm8960->regmap, WM8960_IFACE2, 1 << 6,
wm8960->pdata.gpio_cfg[0] << 6);
diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig
index 0cd1a15f40aa..25b3826f1f96 100644
--- a/sound/soc/dwc/Kconfig
+++ b/sound/soc/dwc/Kconfig
@@ -18,3 +18,11 @@ config SND_DESIGNWARE_PCM
This functionality is specially suited for I2S devices that don't have
DMA support.
+config SND_DESIGNWARE_I2S_STARFIVE_JH7100
+ bool "Synopsys I2S Device Driver for Starfive JH7100 SOC platform"
+ depends on SND_DESIGNWARE_I2S
+ help
+ Say Y or N if you want to use on Starfive JH7100 SOC platform.
+
+ This functionality is specially suited for I2S devices that run on
+ Starfive JH7100 SOC platform.
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 5c15a63286d2..d1481835ad26 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/device.h>
+#include <linux/reset.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/interrupt.h>
@@ -26,6 +27,37 @@
#include <sound/dmaengine_pcm.h>
#include "local.h"
+static const char *clk_name[CLK_AUDIO_NUM] = {
+ [CLK_AUDIO_ROOT] = "audio_root",
+ [CLK_AUDIO_SRC] = "audio_src",
+ [CLK_AUDIO_12288] = "audio_12288",
+ [CLK_DMA1P_AHB] = "dma1p_ahb",
+ [CLK_ADC_MCLK] = "adc_mclk",
+ [CLK_APB_I2SADC] = "i2sadc_apb",
+ [CLK_I2SVAD] = "i2svad_apb",
+ [CLK_ADC_BCLK] = "i2sadc0_bclk",
+ [CLK_ADC_LRCLK] = "i2sadc0_lrclk",
+ [CLK_ADC_BCLK_IOPAD] = "i2sadc_bclk_iopad",
+ [CLK_ADC_LRCLK_IOPAD] = "i2sadc_lrclk_iopad",
+ [CLK_DAC_MCLK] = "dac_mclk",
+ [CLK_DAC_BCLK] = "i2sdac0_bclk",
+ [CLK_DAC_LRCLK] = "i2sdac0_lrclk",
+ [CLK_DAC_BCLK_IOPAD] = "i2sdac_bclk_iopad",
+ [CLK_DAC_LRCLK_IOPAD] = "i2sdac_lrclk_iopad",
+ [CLK_APB_I2SDAC] = "i2sdac_apb",
+};
+
+static const char * const rst_name[RST_AUDIO_NUM] = {
+ [RST_APB_BUS] = "apb_bus",
+ [RST_DMA1P_AHB] = "dma1p_ahb",
+ [RST_APB_I2SADC] = "apb_i2sadc",
+ [RST_I2SADC_SRST] = "i2sadc_srst",
+ [RST_APB_I2SVAD] = "apb_i2svad",
+ [RST_I2SVAD_SRST] = "i2svad_srst",
+ [RST_APB_I2SDAC] = "apb_i2sdac",
+ [RST_I2SDAC_SRST] = "i2sdac_srst",
+};
+
static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
{
writel(val, io_base + reg);
@@ -187,6 +219,9 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+#ifndef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7100
+ union dw_i2s_snd_dma_data *dma_data = NULL;
+#endif
if (!(dev->capability & DWC_I2S_RECORD) &&
(substream->stream == SNDRV_PCM_STREAM_CAPTURE))
@@ -196,6 +231,14 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream,
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
return -EINVAL;
+#ifndef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7100
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = &dev->play_dma_data;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ dma_data = &dev->capture_dma_data;
+
+ snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
+#endif
return 0;
}
@@ -225,6 +268,291 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
}
}
+#define CLKGEN_BASE_ADDR 0x11800000UL
+#define AUDIO_DIV_CTRL 0x17C
+static int init_audio_subsys(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+ int ret = 0;
+ int i = 0;
+
+ static struct clk_bulk_data clks[] = {
+ { .id = "audio_root" }, //clock-names in dts file
+ { .id = "audio_src" },
+ { .id = "audio_12288" },
+ { .id = "dma1p_ahb" },
+ };
+ struct reset_control_bulk_data resets[] = {
+ { .id = "apb_bus" },
+ { .id = "dma1p_ahb" },
+ };
+
+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to get audio_subsys clocks\n", __func__);
+ goto err_out_clock;
+ }
+
+ for (i = 0; i < CLK_ADC_MCLK; i++)
+ dev->clks[i] = clks[i].clk;
+
+ ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ARRAY_SIZE(resets), resets);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to get audio_subsys resets\n", __func__);
+ goto err_out_clock;
+ }
+
+ dev->rstc[RST_APB_BUS] = resets[0].rstc;
+ dev->rstc[RST_DMA1P_AHB] = resets[1].rstc;
+
+ ret = clk_bulk_prepare_enable(ARRAY_SIZE(clks), clks);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to enable clocks.\n", __func__);
+ goto err_out_clock;
+ }
+
+ reset_control_deassert(dev->rstc[RST_APB_BUS]);
+ reset_control_deassert(dev->rstc[RST_DMA1P_AHB]);
+
+ ret = clk_set_rate(dev->clks[CLK_AUDIO_SRC], 12288000);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to set 12.28 MHz rate for clk_audio_src\n", __func__);
+ goto err_out_clock;
+ }
+
+ reset_control_bulk_put(ARRAY_SIZE(resets), resets);
+ return 0;
+
+err_out_clock:
+ return ret;
+}
+
+static int init_i2srx_3ch(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+ int ret = 0;
+
+ dev->rstc[RST_APB_I2SADC] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_APB_I2SADC]);
+ if (IS_ERR(dev->rstc[RST_APB_I2SADC])) {
+ dev_err(&pdev->dev, "%s: failed to get apb_i2sadc reset control\n", __func__);
+ return PTR_ERR(dev->rstc[RST_APB_I2SADC]);
+ }
+ dev->rstc[RST_I2SADC_SRST] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_I2SADC_SRST]);
+ if (IS_ERR(dev->rstc[RST_I2SADC_SRST])) {
+ dev_err(&pdev->dev, "%s: failed to get i2sadc_srst reset control\n", __func__);
+ return PTR_ERR(dev->rstc[RST_I2SADC_SRST]);
+ }
+ reset_control_assert(dev->rstc[RST_APB_I2SADC]);
+ reset_control_assert(dev->rstc[RST_I2SADC_SRST]);
+
+ dev->clks[CLK_ADC_MCLK] = devm_clk_get(&pdev->dev, clk_name[CLK_ADC_MCLK]);
+ if (IS_ERR(dev->clks[CLK_ADC_MCLK])) {
+ dev_err(&pdev->dev, "%s: failed to get clk_adc_mclk: %ld\n", __func__,
+ PTR_ERR(dev->clks[CLK_ADC_MCLK]));
+ return PTR_ERR(dev->clks[CLK_ADC_MCLK]);
+ }
+ ret = clk_prepare_enable(dev->clks[CLK_ADC_MCLK]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to prepare enable adc_mclk\n", __func__);
+ return ret;
+ }
+
+ dev->clks[CLK_APB_I2SADC] = devm_clk_get(&pdev->dev, clk_name[CLK_APB_I2SADC]);
+ if (IS_ERR(dev->clks[CLK_APB_I2SADC])) {
+ dev_err(&pdev->dev, "%s: failed to get clk_apb_i2sadc: %ld\n", __func__,
+ PTR_ERR(dev->clks[CLK_APB_I2SADC]));
+ return PTR_ERR(dev->clks[CLK_APB_I2SADC]);
+ }
+ ret = clk_prepare_enable(dev->clks[CLK_APB_I2SADC]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to prepare enable i2sadc_apb\n", __func__);
+ return ret;
+ }
+
+ reset_control_deassert(dev->rstc[RST_APB_I2SADC]);
+ reset_control_deassert(dev->rstc[RST_I2SADC_SRST]);
+
+ return 0;
+}
+
+static int init_i2svad(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+ int ret = 0;
+
+ dev->clks[CLK_I2SVAD] = devm_clk_get(&pdev->dev, clk_name[CLK_I2SVAD]);
+ if (IS_ERR(dev->clks[CLK_I2SVAD])) {
+ dev_err(&pdev->dev, "%s: failed to get clk_i2svad_apb: %ld\n", __func__,
+ PTR_ERR(dev->clks[CLK_I2SVAD]));
+ return PTR_ERR(dev->clks[CLK_I2SVAD]);
+ }
+
+ dev->rstc[RST_APB_I2SVAD] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_APB_I2SVAD]);
+ if (IS_ERR(dev->rstc[RST_APB_I2SVAD])) {
+ dev_err(&pdev->dev, "%s: failed to get apb_i2svad reset control\n", __func__);
+ return PTR_ERR(dev->rstc[RST_APB_I2SVAD]);
+ }
+
+ dev->rstc[RST_I2SVAD_SRST] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_I2SVAD_SRST]);
+ if (IS_ERR(dev->rstc[RST_I2SVAD_SRST])) {
+ dev_err(&pdev->dev, "%s: failed to get i2svad_srst reset control\n", __func__);
+ return PTR_ERR(dev->rstc[RST_I2SVAD_SRST]);
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_I2SVAD]);
+ if (ret < 0) {
+ printk(KERN_INFO "%s: failed to enable clk_i2svad_apb\n", __func__);
+ return ret;
+ }
+
+ reset_control_deassert(dev->rstc[RST_APB_I2SVAD]);
+ reset_control_deassert(dev->rstc[RST_I2SVAD_SRST]);
+
+ return 0;
+}
+
+static int dw_i2sdac_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+ static struct clk_bulk_data i2sclk[] = {
+ { .id = "dac_mclk" }, //clock-names in dts file
+ { .id = "i2sdac0_bclk" },
+ { .id = "i2sdac0_lrclk" },
+ { .id = "i2sdac_apb" },
+ { .id = "i2sdac_bclk_iopad" },
+ { .id = "i2sdac_lrclk_iopad" },
+ };
+
+ int ret = 0;
+
+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(i2sclk), i2sclk);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to get i2sdac clocks\n", __func__);
+ return ret;
+ }
+
+ dev->clks[CLK_DAC_MCLK] = i2sclk[0].clk;
+ dev->clks[CLK_DAC_BCLK] = i2sclk[1].clk;
+ dev->clks[CLK_DAC_LRCLK] = i2sclk[2].clk;
+ dev->clks[CLK_APB_I2SDAC] = i2sclk[3].clk;
+ dev->clks[CLK_DAC_BCLK_IOPAD] = i2sclk[4].clk;
+ dev->clks[CLK_DAC_LRCLK_IOPAD] = i2sclk[5].clk;
+
+ dev->rstc[RST_APB_I2SDAC] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_APB_I2SDAC]);
+ if (IS_ERR(dev->rstc[RST_APB_I2SDAC])) {
+ dev_err(&pdev->dev, "%s: failed to get apb_i2sdac reset control\n", __func__);
+ return PTR_ERR(dev->rstc[RST_APB_I2SDAC]);
+ }
+
+ dev->rstc[RST_I2SDAC_SRST] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_I2SDAC_SRST]);
+ if (IS_ERR(dev->rstc[RST_I2SDAC_SRST])) {
+ dev_err(&pdev->dev, "%s: failed to get i2sdac_srst reset control\n", __func__);
+ return PTR_ERR(dev->rstc[RST_I2SDAC_SRST]);
+ }
+ reset_control_assert(dev->rstc[RST_APB_I2SDAC]);
+ reset_control_assert(dev->rstc[RST_I2SDAC_SRST]);
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_MCLK]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable dac_mclk\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_APB_I2SDAC]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable clk_apb_i2sdac\n", __func__);
+ goto err_clk_i2s;
+ }
+ reset_control_deassert(dev->rstc[RST_APB_I2SDAC]); // ---> clk_apb_i2sdac
+ reset_control_deassert(dev->rstc[RST_I2SDAC_SRST]); // ---> clk_i2sdac_bclk
+
+ ret = clk_set_parent(dev->clks[CLK_DAC_BCLK], dev->clks[CLK_DAC_BCLK_IOPAD]);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to set parent for clk_i2sdac0_bclk\n", __func__);
+ goto err_clk_i2s;
+ }
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_BCLK]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to prepare enable i2sdac0_bclk\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_set_parent(dev->clks[CLK_DAC_LRCLK], dev->clks[CLK_DAC_LRCLK_IOPAD]);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to set parent for clk_i2sdac0_lrclk\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_LRCLK]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable i2sdac0_lrclk\n", __func__);
+ goto err_clk_i2s;
+ }
+
+err_clk_i2s:
+ return ret;
+}
+
+#define VAD_BASE 0x10420000UL
+#define VAD_SW 0x844
+#define VAD_I2S_CTRL 0x884
+static int dw_i2sadc_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+ static struct clk_bulk_data i2sclk[] = {
+ { .id = "i2sadc0_bclk" },
+ { .id = "i2sadc0_lrclk" },
+ { .id = "i2sadc_bclk_iopad" },
+ { .id = "i2sadc_lrclk_iopad" },
+ };
+
+ int ret = 0;
+ unsigned int val = 0;
+
+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(i2sclk), i2sclk);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to get i2sadc clocks\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ dev->clks[CLK_ADC_BCLK] = i2sclk[0].clk;
+ dev->clks[CLK_ADC_LRCLK] = i2sclk[1].clk;
+ dev->clks[CLK_ADC_BCLK_IOPAD] = i2sclk[2].clk;
+ dev->clks[CLK_ADC_LRCLK_IOPAD] = i2sclk[3].clk;
+
+ ret = clk_set_parent(dev->clks[CLK_ADC_BCLK], dev->clks[CLK_ADC_BCLK_IOPAD]);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to set parent for clk_i2sdac0_bclk\n", __func__);
+ goto err_clk_i2s;
+ }
+ ret = clk_prepare_enable(dev->clks[CLK_ADC_BCLK]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to prepare enable i2sdac0_bclk\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_set_parent(dev->clks[CLK_ADC_LRCLK], dev->clks[CLK_ADC_LRCLK_IOPAD]);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to set parent for clk_i2sdac0_lrclk\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_ADC_LRCLK]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to prepare enable i2sdac0_lrclk\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ // _SET_SYSCON_REG_SCFG_ctrl_i2sadc_enable
+ val = readl(dev->vad_base + VAD_SW);
+ val |= (0x1<<1);
+ writel(val, dev->vad_base + VAD_SW);
+
+ // _SET_SYSCON_REG_SCFG_aon_i2s_ctrl_adci2s_d0_sel
+ val = readl(dev->vad_base + VAD_I2S_CTRL);
+ val &= ~(0x7);
+ val |= (AUDIO_IN_SPIO_SD0 & 0x7);
+ writel(val, dev->vad_base + VAD_I2S_CTRL);
+
+err_clk_i2s:
+ return ret;
+}
+
static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
@@ -298,6 +626,14 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+#ifndef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7100
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+#endif
+}
+
static int dw_i2s_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -371,6 +707,7 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
.startup = dw_i2s_startup,
+ .shutdown = dw_i2s_shutdown,
.hw_params = dw_i2s_hw_params,
.prepare = dw_i2s_prepare,
.trigger = dw_i2s_trigger,
@@ -604,6 +941,7 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
}
+#ifdef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7100
static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -611,143 +949,13 @@ static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
return 0;
}
-
-static int dw_i2sadc_clk_init(struct dw_i2s_dev* pdw_i2s_dev, struct device* pdev)
-{
- int ret;
-
- pdw_i2s_dev->clk_apb = devm_clk_get(pdev, "i2sadc_apb");
- if (IS_ERR(pdw_i2s_dev->clk_apb))
- return PTR_ERR(pdw_i2s_dev->clk_apb);
-
- ret = clk_prepare_enable(pdw_i2s_dev->clk_apb);
- if (ret < 0)
- return ret;
-
- pdw_i2s_dev->i2svad = devm_clk_get(pdev, "i2svad_apb");
- if (IS_ERR(pdw_i2s_dev->i2svad)) {
- ret = PTR_ERR(pdw_i2s_dev->i2svad);
- goto err_adc_apb_clk_disable;
- }
-
- ret = clk_prepare_enable(pdw_i2s_dev->i2svad);
- if (ret < 0)
- goto err_adc_apb_clk_disable;
-
- pdw_i2s_dev->i2s_mclk = devm_clk_get(pdev, "i2sadc_mclk");
- if (IS_ERR(pdw_i2s_dev->i2s_mclk)) {
- ret = PTR_ERR(pdw_i2s_dev->i2s_mclk);
- goto err_i2svad_apb_clk_disable;
- }
-
- ret = clk_prepare_enable(pdw_i2s_dev->i2s_mclk);
- if (ret < 0)
- goto err_i2svad_apb_clk_disable;
-
- pdw_i2s_dev->i2s_bclk = devm_clk_get(pdev, "i2sadc_bclk");
- if (IS_ERR(pdw_i2s_dev->i2s_bclk)) {
- ret = PTR_ERR(pdw_i2s_dev->i2s_bclk);
- goto err_adc_mclk_disable;
- }
-
- ret = clk_prepare_enable(pdw_i2s_dev->i2s_bclk);
- if (ret < 0)
- goto err_adc_mclk_disable;
-
- pdw_i2s_dev->i2s_lrclk = devm_clk_get(pdev, "i2sadc_lrclk");
- if (IS_ERR(pdw_i2s_dev->i2s_lrclk)) {
- ret = PTR_ERR(pdw_i2s_dev->i2s_lrclk);
- goto err_adc_bclk_disable;
- }
-
- ret = clk_prepare_enable(pdw_i2s_dev->i2s_lrclk);
- if (ret < 0)
- goto err_adc_bclk_disable;
-
- return 0;
-
-err_adc_bclk_disable:
- clk_disable_unprepare(pdw_i2s_dev->i2s_bclk);
-err_adc_mclk_disable:
- clk_disable_unprepare(pdw_i2s_dev->i2s_mclk);
-err_i2svad_apb_clk_disable:
- clk_disable_unprepare(pdw_i2s_dev->i2svad);
-err_adc_apb_clk_disable:
- clk_disable_unprepare(pdw_i2s_dev->clk_apb);
-
- return ret;
-}
-
-static int dw_i2sdac_clk_init(struct dw_i2s_dev* pdw_i2s_dev, struct device* pdev)
-{
- int ret;
-
- pdw_i2s_dev->clk_apb = devm_clk_get(pdev, "i2sdac_apb");
- if (IS_ERR(pdw_i2s_dev->clk_apb))
- return PTR_ERR(pdw_i2s_dev->clk_apb);
-
- ret = clk_prepare_enable(pdw_i2s_dev->clk_apb);
- if (ret < 0)
- return ret;
-
- pdw_i2s_dev->i2svad = devm_clk_get(pdev, "i2svad_apb");
- if (IS_ERR(pdw_i2s_dev->i2svad)) {
- ret = PTR_ERR(pdw_i2s_dev->i2svad);
- goto err_adc_apb_clk_disable;
- }
-
- ret = clk_prepare_enable(pdw_i2s_dev->i2svad);
- if (ret < 0)
- goto err_adc_apb_clk_disable;
-
- pdw_i2s_dev->i2s_mclk = devm_clk_get(pdev, "i2sdac_mclk");
- if (IS_ERR(pdw_i2s_dev->i2s_mclk)) {
- ret = PTR_ERR(pdw_i2s_dev->i2s_mclk);
- goto err_i2svad_apb_clk_disable;
- }
-
- ret = clk_prepare_enable(pdw_i2s_dev->i2s_mclk);
- if (ret < 0)
- goto err_i2svad_apb_clk_disable;
-
- pdw_i2s_dev->i2s_bclk = devm_clk_get(pdev, "i2sdac_bclk");
- if (IS_ERR(pdw_i2s_dev->i2s_bclk)) {
- ret = PTR_ERR(pdw_i2s_dev->i2s_bclk);
- goto err_adc_mclk_disable;
- }
-
- ret = clk_prepare_enable(pdw_i2s_dev->i2s_bclk);
- if (ret < 0)
- goto err_adc_mclk_disable;
-
- pdw_i2s_dev->i2s_lrclk = devm_clk_get(pdev, "i2sdac_lrclk");
- if (IS_ERR(pdw_i2s_dev->i2s_lrclk)) {
- ret = PTR_ERR(pdw_i2s_dev->i2s_lrclk);
- goto err_adc_bclk_disable;
- }
-
- ret = clk_prepare_enable(pdw_i2s_dev->i2s_lrclk);
- if (ret < 0)
- goto err_adc_bclk_disable;
-
- return 0;
-
-err_adc_bclk_disable:
- clk_disable_unprepare(pdw_i2s_dev->i2s_bclk);
-err_adc_mclk_disable:
- clk_disable_unprepare(pdw_i2s_dev->i2s_mclk);
-err_i2svad_apb_clk_disable:
- clk_disable_unprepare(pdw_i2s_dev->i2svad);
-err_adc_apb_clk_disable:
- clk_disable_unprepare(pdw_i2s_dev->clk_apb);
-
- return ret;
-}
+#endif
static int dw_i2s_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct i2s_platform_data *pdata = pdev->dev.platform_data;
+ struct device_node *np = pdev->dev.of_node;
struct dw_i2s_dev *dev;
struct resource *res;
int ret, irq;
@@ -763,12 +971,20 @@ static int dw_i2s_probe(struct platform_device *pdev)
return -ENOMEM;
dw_i2s_dai->ops = &dw_i2s_dai_ops;
+#ifdef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7100
dw_i2s_dai->probe = dw_i2s_dai_probe;
+#endif
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->i2s_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dev->i2s_base))
return PTR_ERR(dev->i2s_base);
+
+ dev->vad_base = ioremap(VAD_BASE, 0x900);
+ if (IS_ERR(dev->vad_base)) {
+ printk(KERN_INFO "%s: failed to alloc memory for vad_base\n", __func__);
+ return PTR_ERR(dev->vad_base);
+ }
dev->dev = &pdev->dev;
@@ -829,6 +1045,34 @@ static int dw_i2s_probe(struct platform_device *pdev)
goto err_clk_disable;
}
+ if (of_device_is_compatible(np, "snps,designware-i2sadc0")) { //record
+ ret = init_audio_subsys(pdev, dev);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to init_audio_subsys!\n", __func__);
+ goto err_clk_disable;
+ }
+
+ ret = init_i2srx_3ch(pdev, dev);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to init_i2srx_3ch\n", __func__);
+ goto err_clk_disable;
+ }
+
+ ret = init_i2svad(pdev, dev);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to init_i2svad\n", __func__);
+ goto err_clk_disable;
+ }
+
+ ret = dw_i2sadc_clk_init(pdev, dev);
+ if (ret < 0)
+ goto err_clk_disable;
+ } else if (of_device_is_compatible(np, "snps,designware-i2sdac0")) { //playback
+ ret = dw_i2sdac_clk_init(pdev, dev);
+ if (ret < 0)
+ goto err_clk_disable;
+ }
+
dev_set_drvdata(&pdev->dev, dev);
ret = devm_snd_soc_register_component(&pdev->dev, &dw_i2s_component,
dw_i2s_dai, 1);
@@ -855,6 +1099,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
}
pm_runtime_enable(&pdev->dev);
+
return 0;
err_all_clk_disable:
@@ -884,10 +1129,9 @@ static int dw_i2s_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id dw_i2s_of_match[] = {
- { .compatible = "snps,designware-i2s", },
- { .compatible = "snps,designware-i2sadc0", },
- { .compatible = "snps,designware-i2sdac0", },
- //{ .compatible = "snps,designware-i2sdac1", },
+ { .compatible = "snps,designware-i2sadc0", },
+ { .compatible = "snps,designware-i2sdac0", },
+ //{ .compatible = "snps,designware-i2sdac1", },
{},
};
@@ -911,6 +1155,7 @@ static struct platform_driver dw_i2s_driver = {
module_platform_driver(dw_i2s_driver);
MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>");
+MODULE_AUTHOR("Walker Chen <walker.chen@starfivetech.com>");
MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:designware_i2s");
diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h
index c5c5000cef61..402ddada2e72 100644
--- a/sound/soc/dwc/local.h
+++ b/sound/soc/dwc/local.h
@@ -81,6 +81,51 @@
#define MAX_CHANNEL_NUM 8
#define MIN_CHANNEL_NUM 2
+enum {
+ CLK_AUDIO_ROOT = 0,
+ CLK_AUDIO_SRC,
+ CLK_AUDIO_12288,
+ CLK_DMA1P_AHB,
+ CLK_ADC_MCLK,
+ CLK_APB_I2SADC,
+ CLK_I2SVAD,
+ CLK_ADC_BCLK,
+ CLK_ADC_LRCLK,
+ CLK_ADC_BCLK_IOPAD,
+ CLK_ADC_LRCLK_IOPAD,
+ CLK_DAC_MCLK,
+ CLK_DAC_BCLK,
+ CLK_DAC_LRCLK,
+ CLK_DAC_BCLK_IOPAD,
+ CLK_DAC_LRCLK_IOPAD,
+ CLK_APB_I2SDAC,
+ CLK_AUDIO_NUM,
+};
+
+enum {
+ RST_APB_BUS = 0,
+ RST_DMA1P_AHB,
+ RST_APB_I2SADC,
+ RST_I2SADC_SRST,
+ RST_APB_I2SVAD,
+ RST_I2SVAD_SRST,
+ RST_APB_I2SDAC,
+ RST_I2SDAC_SRST,
+ RST_AUDIO_NUM,
+};
+
+enum audio_mode {
+ AUDIO_IN_NONE = -1,
+ AUDIO_IN_GPIO_SD2 = 0,
+ AUDIO_IN_GPIO_SD1,
+ AUDIO_IN_SPIO_SD0,
+ AUDIO_IN_DAC16K_SD0,
+ AUDIO_IN_ANA_ADC_SD1,
+ AUDIO_IN_ANA_ADC_SD0,
+ AUDIO_IN_PDM_SD1,
+ AUDIO_IN_PDM_SD0,
+};
+
union dw_i2s_snd_dma_data {
struct i2s_dma_data pd;
struct snd_dmaengine_dai_dma_data dt;
@@ -88,6 +133,7 @@ union dw_i2s_snd_dma_data {
struct dw_i2s_dev {
void __iomem *i2s_base;
+ void __iomem *vad_base;
struct clk *clk;
struct clk *clk_apb;
struct clk* i2svad;
@@ -104,6 +150,9 @@ struct dw_i2s_dev {
u32 xfer_resolution;
u32 fifo_th;
+ struct clk *clks[CLK_AUDIO_NUM];
+ struct reset_control *rstc[RST_AUDIO_NUM];
+
/* 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;