[Audio] I2S and WM8960
authorcurry.zhang <curry.zhang@starfivetech.com>
Wed, 4 May 2022 08:03:41 +0000 (01:03 -0700)
committercurry.zhang <curry.zhang@starfivetech.com>
Wed, 4 May 2022 08:03:41 +0000 (01:03 -0700)
1) Add standard system clock tree API
2) Modify wm8960 and I2S drivers

Signed-off-by: curry.zhang <curry.zhang@starfivetech.com>
arch/riscv/boot/dts/starfive/codecs/sf_wm8960.dtsi [new file with mode: 0755]
arch/riscv/boot/dts/starfive/jh7110-fpga.dts
arch/riscv/boot/dts/starfive/jh7110.dtsi
sound/soc/codecs/wm8960.c [changed mode: 0644->0755]
sound/soc/codecs/wm8960.h [changed mode: 0644->0755]
sound/soc/dwc/Kconfig [changed mode: 0644->0755]
sound/soc/dwc/dwc-i2s.c [changed mode: 0644->0755]
sound/soc/dwc/local.h [changed mode: 0644->0755]

diff --git a/arch/riscv/boot/dts/starfive/codecs/sf_wm8960.dtsi b/arch/riscv/boot/dts/starfive/codecs/sf_wm8960.dtsi
new file mode 100755 (executable)
index 0000000..c5cb532
--- /dev/null
@@ -0,0 +1,38 @@
+&sound{
+       /* i2s + wm8960 */
+       simple-audio-card,dai-link@0 {
+               reg = <0>;
+               status = "okay";
+               format = "i2s";
+               bitclock-master = <&sndcodec1>;
+               frame-master = <&sndcodec1>;
+               
+               widgets =
+                               "Microphone", "Mic Jack",
+                               "Line", "Line In",
+                               "Line", "Line Out",
+                               "Speaker", "Speaker",
+                               "Headphone", "Headphone Jack";
+               routing =
+                               "Headphone Jack", "HP_L",
+                               "Headphone Jack", "HP_R",
+                               "Speaker", "SPK_LP",
+                               "Speaker", "SPK_LN",
+                               "LINPUT1", "Mic Jack",
+                               "LINPUT3", "Mic Jack",
+                               "RINPUT1", "Mic Jack",
+                               "RINPUT2", "Mic Jack";
+               cpu0 {
+                       sound-dai = <&i2srx_3ch>;
+               };
+               cpu1 {
+                       sound-dai = <&i2stx_4ch1>;
+               };
+               
+               sndcodec1:codec {
+                       sound-dai = <&wm8960>;
+                       clocks = <&clkgen JH7110_MCLK>;
+                       clock-names = "mclk";
+               };
+       };
+};
index 972f86f..eca37ae 100755 (executable)
@@ -6,6 +6,7 @@
 
 /dts-v1/;
 #include "jh7110-common.dtsi"
+//#include "codecs/sf_wm8960.dtsi"
 
 / {
        model = "StarFive JH7110 FPGA";
@@ -18,4 +19,4 @@
 
 &wdog {
        clock-frequency = <2000000>;
-};
\ No newline at end of file
+};
index f6aabc2..ebeb684 100755 (executable)
                        status = "disabled";
                };
 
-               i2srx_3ch: i2srx-3ch@100e0000 {
+               i2srx_3ch: i2srx_3ch@100e0000 {
                        compatible = "snps,designware-i2srx";
                        reg = <0x0 0x100e0000 0x0 0x1000>;
-                       clocks = <&apb0clk>;
-                       clock-names = "i2sclk";
+                       clocks = <&clkgen JH7110_APB0>,
+                               <&clkgen JH7110_I2SRX0_3CH_CLK_APB>,
+                               <&clkgen JH7110_I2SRX_3CH_BCLK_MST>;
+                       clock-names = "apb0", "3ch-apb",
+                                       "3ch-bclk";
+                       resets = <&rstgen RSTN_U0_I2SRX_3CH_APB>,
+                               <&rstgen RSTN_U0_I2SRX_3CH_BCLK>;
+                       reset-names = "rst_apb_rx", "rst_bclk_rx";
                        interrupts = <42>;
                        interrupt-names = "rx";
+                       dmas = <&dma 24 1>;
+                       dma-names = "rx";
                        #sound-dai-cells = <0>;
                        status = "disabled";
                };
 
-               i2stx_4ch0: i2stx-4ch0@120b0000 {
+               i2stx_4ch0: i2stx_4ch0@120b0000 {
                        compatible = "snps,designware-i2stx-4ch0";
                        reg = <0x0 0x120b0000 0x0 0x1000>;
-                       clocks = <&apb0clk>;
-                       clock-names = "i2sclk";
+                       clocks = <&clkgen JH7110_MCLK_INNER>,
+                               <&clkgen JH7110_I2STX_4CH0_BCLK_MST>,
+                               <&clkgen JH7110_I2STX_4CH0_LRCK_MST>,
+                               <&clkgen JH7110_MCLK>,
+                               <&clkgen JH7110_I2STX0_4CHBCLK>,
+                               <&clkgen JH7110_I2STX0_4CHLRCK>;
+                       clock-names = "inner", "bclk-mst",
+                                       "lrck-mst", "mclk",
+                                       "bclk0", "lrck0";
+                       resets = <&rstgen RSTN_U0_I2STX_4CH_APB>,
+                                        <&rstgen RSTN_U0_I2STX_4CH_BCLK>;
+                        reset-names = "rst_apb0", "rst_bclk0";
                        interrupts = <58>;
                        interrupt-names = "tx";
+                       dmas = <&dma 47 1>;
+                       dma-names = "tx";
                        #sound-dai-cells = <0>;
                        status = "disabled";
                };
 
-               i2stx_4ch1: i2sdac1@120c0000 {
+               i2stx_4ch1: i2stx_4ch1@120c0000 {
                        compatible = "snps,designware-i2stx-4ch1";
                        reg = <0x0 0x120c0000 0x0 0x1000>;
-                       clocks = <&apb0clk>;
-                       clock-names = "i2sclk";
+                       clocks = <&clkgen JH7110_MCLK_INNER>,
+                               <&clkgen JH7110_I2STX_4CH1_BCLK_MST>,
+                                <&clkgen JH7110_I2STX_4CH1_LRCK_MST>,
+                                <&clkgen JH7110_MCLK>,
+                                <&clkgen JH7110_I2STX1_4CHBCLK>,
+                                <&clkgen JH7110_I2STX1_4CHLRCK>;
+                        clock-names = "inner", "bclk-mst1",
+                                        "lrck-mst1", "mclk",
+                                        "bclk1", "lrck1";
+                        resets = <&rstgen RSTN_U1_I2STX_4CH_APB>,
+                               <&rstgen RSTN_U1_I2STX_4CH_BCLK>;
+                        reset-names = "rst_apb1", "rst_bclk1";
                        interrupts = <59>;
                        interrupt-names = "tx";
+                       dmas = <&dma 48 1>;
+                       dma-names = "tx";
                        #sound-dai-cells = <0>;
                        status = "disabled";
                };
old mode 100644 (file)
new mode 100755 (executable)
index 3c8e728..09f5bb2
 #include <sound/initval.h>
 #include <sound/tlv.h>
 #include <sound/wm8960.h>
+#include <linux/debugfs.h>
 
 #include "wm8960.h"
 
-#define WM8960_MCLK             4096000
+#define WM8960_MCLK             51200000//4096000
 /* R25 - Power 1 */
 #define WM8960_VMID_MASK 0x180
 #define WM8960_VREF      0x40
@@ -134,6 +135,7 @@ struct wm8960_priv {
        int freq_in;
        bool is_stream_in_use[2];
        struct wm8960_data pdata;
+       struct dentry *debug_file;
 };
 
 #define wm8960_reset(c)        regmap_write(c, WM8960_RESET, 0)
@@ -695,6 +697,13 @@ int wm8960_configure_pll(struct snd_soc_component *component, int freq_in,
        lrclk = wm8960->lrclk;
        closest = freq_in;
 
+       /* Judge whether the lr clock is 0, if equal to 0, there is
+        * no need to perform the following steps*/
+       if (!lrclk)
+       {
+               return 0;
+       }
+
        best_freq_out = -EINVAL;
        *sysclk_idx = *dac_idx = *bclk_idx = -1;
 
@@ -743,16 +752,9 @@ static int wm8960_configure_clocking(struct snd_soc_component *component)
        int i, j, k;
        int ret;
 
-       /*
-        * For Slave mode clocking should still be configured,
-        * so this if statement should be removed, but some platform
-        * may not work if the sysclk is not configured, to avoid such
-        * compatible issue, just add '!wm8960->sysclk' condition in
-        * this if statement.
-        */
-       if (!(iface1 & (1 << 6)) && !wm8960->sysclk) {
-               dev_warn(component->dev,
-                        "slave mode, but proceeding with no clock configuration\n");
+       if (!(iface1 & (1<<6))) {
+               dev_dbg(component->dev,
+                       "Codec is slave mode, no need to configure clock\n");
                return 0;
        }
 
@@ -1288,8 +1290,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 {
        struct snd_soc_component *component = dai->component;
        struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
-       clk_id = WM8960_SYSCLK_MCLK;
-
+       clk_id = WM8960_SYSCLK_PLL;
 
        switch (clk_id) {
        case WM8960_SYSCLK_MCLK:
@@ -1347,6 +1348,25 @@ static struct snd_soc_dai_driver wm8960_dai = {
        .symmetric_rate = 1,
 };
 
+static int wm8960_reg_debug_show(struct seq_file *s, void *data)
+{
+       struct snd_soc_component *component = s->private;
+        int i, reg;
+       for (i = 0; i < WM8960_REG_MAX; i++)
+       {
+               reg = snd_soc_component_read(component, i);
+               printk("wm8960 reg:0x%x: 0x%x\n", i, reg);
+       }
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wm8960_reg_debug);
+
+static void wm8960_create_debugfs(struct snd_soc_component *component)
+{
+       struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+       wm8960->debug_file = debugfs_create_file("wm8960_reg", 0666, NULL,
+               component, &wm8960_reg_debug_fops);
+}
 static int wm8960_probe(struct snd_soc_component *component)
 {
        struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
@@ -1376,6 +1396,7 @@ static int wm8960_probe(struct snd_soc_component *component)
        snd_soc_add_component_controls(component, wm8960_snd_controls,
                                     ARRAY_SIZE(wm8960_snd_controls));
        wm8960_add_widgets(component);
+       wm8960_create_debugfs(component);
 
        return 0;
 }
@@ -1432,7 +1453,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
        if (wm8960 == NULL)
                return -ENOMEM;
 
-       wm8960->clk_id = WM8960_SYSCLK_MCLK;
+       wm8960->clk_id = WM8960_SYSCLK_PLL;
 
        wm8960->mclk = devm_clk_get(&i2c->dev, "mclk");
        if (IS_ERR(wm8960->mclk)) {
old mode 100644 (file)
new mode 100755 (executable)
index 63ba6c0..2a5b4d8
@@ -64,6 +64,8 @@
 #define WM8960_PLL3            0x36
 #define WM8960_PLL4            0x37
 
+#define WM8960_REG_MAX         0x38
+
 
 /*
  * WM8960 Clock dividers
old mode 100644 (file)
new mode 100755 (executable)
index 71a58f7..6b249e1
@@ -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_JH7110
+       bool "Synopsys I2S Device Driver for Starfive JH7110 SOC platform"
+       depends on SND_DESIGNWARE_I2S
+       help
+        Say Y or N if you want to use on Starfive JH7110 SOC platform.
+
+        This functionality is specially suited for I2S devices that run on
+        Starfive JH7110 SOC platform.
old mode 100644 (file)
new mode 100755 (executable)
index 5ab1718..30b2e4c
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
+#include <linux/reset.h>
 #include "local.h"
 
+static const char * const rst_name[RST_AUDIO_NUM] = {
+       [RST_APB0_BUS] = "rst_apb0",
+       [RST_BCLK_0] = "rst_bclk0",
+       [RST_APB1_BUS] = "rst_apb1",
+       [RST_BCLK_1] = "rst_bclk1",
+       [RST_APB_RX] = "rst_apb_rx",
+       [RST_BCLK_RX] = "rst_bclk_rx",
+};
+
 static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
 {
        writel(val, io_base + reg);
@@ -187,7 +197,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_JH7110
        union dw_i2s_snd_dma_data *dma_data = NULL;
+#endif
 
        if (!(dev->capability & DWC_I2S_RECORD) &&
                        (substream->stream == SNDRV_PCM_STREAM_CAPTURE))
@@ -197,13 +209,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_JH7110
        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;
 }
 
@@ -308,7 +321,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
 static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
+#ifndef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7110
        snd_soc_dai_set_dma_data(dai, substream, NULL);
+#endif
 }
 
 static int dw_i2s_prepare(struct snd_pcm_substream *substream,
@@ -447,6 +462,238 @@ 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" },               //clock-names in dts file
+               { .id = "3ch-apb" },
+               { .id = "3ch-bclk" },
+       };
+
+       ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks);
+       if (ret) {
+               dev_err(&pdev->dev,"%s: failed to get audio_subsys clocks\n", __func__);
+               goto err_out_clock;
+       }
+       dev->clks[CLK_ADC_APB0] = clks[0].clk;
+       dev->clks[CLK_ADC_APB] = clks[1].clk;
+       dev->clks[CLK_ADC_LRCLK] = clks[2].clk;
+
+       ret = clk_prepare_enable(dev->clks[CLK_ADC_APB0]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_APB0\n", __func__);
+               goto err_out_clock;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_ADC_APB]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_APB\n", __func__);
+               goto err_out_clock;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_ADC_LRCLK]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_LRCLK\n", __func__);
+               goto err_out_clock;
+       }
+
+       dev->rstc[RST_APB_RX] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_APB_RX]);
+       if (IS_ERR(dev->rstc[RST_APB_RX])) {
+               dev_err(&pdev->dev, "%s: failed to get apb_i2srx reset control,ret = %d\n", __func__);
+                return PTR_ERR(dev->rstc[RST_APB_RX]);
+       }
+
+       dev->rstc[RST_BCLK_RX] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_BCLK_RX]);
+       if (IS_ERR(dev->rstc[RST_BCLK_RX])) {
+               dev_err(&pdev->dev, "%s: failed to get i2s bclk rx reset control,ret = %d\n", __func__);
+                return PTR_ERR(dev->rstc[RST_BCLK_RX]);
+       }
+
+       reset_control_deassert(dev->rstc[RST_APB_RX]);
+       reset_control_deassert(dev->rstc[RST_BCLK_RX]);
+
+
+       return 0;
+
+err_out_clock:
+       return ret;
+}
+
+static int dw_i2stx_4ch0_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+       static struct clk_bulk_data i2sclk[] = {
+               { .id = "inner" },              //clock-names in dts file
+               { .id = "bclk-mst" },
+               { .id = "lrck-mst" },
+               { .id = "mclk" },
+               { .id = "bclk0" },
+               { .id = "lrck0" },
+       };
+
+       int ret = 0;
+
+       ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(i2sclk), i2sclk);
+       if (ret) {
+               printk(KERN_INFO "%s: failed to get i2stx 4ch0 clocks\n", __func__);
+               return ret;
+       }
+
+       dev->clks[CLK_DAC_INNER] = i2sclk[0].clk;
+       dev->clks[CLK_DAC_BCLK_MST] = i2sclk[1].clk;
+       dev->clks[CLK_DAC_LRCLK_MST] = i2sclk[2].clk;
+       dev->clks[CLK_MCLK] = i2sclk[3].clk;
+       dev->clks[CLK_DAC_BCLK0] = i2sclk[4].clk;
+       dev->clks[CLK_DAC_LRCLK0] = i2sclk[5].clk;
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_INNER]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_INNER\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_BCLK_MST]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_BCLK_MST\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_LRCLK_MST]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_LRCLK_MST\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_MCLK]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_MCLK\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_BCLK0]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_BCLK0\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_LRCLK0]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_LRCLK0\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       dev->rstc[RST_APB0_BUS] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_APB0_BUS]);
+       if (IS_ERR(dev->rstc[RST_APB0_BUS])) {
+               dev_err(&pdev->dev, "%s: failed to get apb_i2stx reset control, ret = %d\n", __func__);
+                return PTR_ERR(dev->rstc[RST_APB0_BUS]);
+       }
+
+       dev->rstc[RST_BCLK_0] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_BCLK_0]);
+       if (IS_ERR(dev->rstc[RST_BCLK_0])) {
+               dev_err(&pdev->dev, "%s: failed to get i2s bclk0 reset control, ret = %d\n", __func__);
+                return PTR_ERR(dev->rstc[RST_BCLK_0]);
+       }
+
+       reset_control_deassert(dev->rstc[RST_APB0_BUS]);
+       reset_control_deassert(dev->rstc[RST_BCLK_0]);
+
+err_clk_i2s:
+       return ret;
+}
+
+static int dw_i2stx_4ch1_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+       static struct clk_bulk_data i2sclk[] = {
+               { .id = "inner" },              //clock-names in dts file
+               { .id = "bclk-mst1" },
+               { .id = "lrck-mst1" },
+               { .id = "mclk" },
+               { .id = "bclk1" },
+               { .id = "lrck1" },
+       };
+
+       int ret = 0;
+
+       ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(i2sclk), i2sclk);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to get i2stx 4ch0 clocks\n", __func__);
+               return ret;
+       }
+
+       dev->clks[CLK_DAC_INNER] = i2sclk[0].clk;
+       dev->clks[CLK_DAC_BCLK_MST_1] = i2sclk[1].clk;
+       dev->clks[CLK_DAC_LRCLK_MST_1] = i2sclk[2].clk;
+       dev->clks[CLK_MCLK] = i2sclk[3].clk;
+       dev->clks[CLK_DAC_BCLK_1] = i2sclk[4].clk;
+       dev->clks[CLK_DAC_LRCLK_1] = i2sclk[5].clk;
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_INNER]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_INNER\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_BCLK_MST_1]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_BCLK_MST_1\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_LRCLK_MST_1]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_LRCLK_MST_1\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_MCLK]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_MCLK\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_BCLK_1]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_BCLK_1\n", __func__);
+               goto err_clk_i2s;
+       }
+
+       ret = clk_prepare_enable(dev->clks[CLK_DAC_LRCLK_1]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_LRCLK_1\n", __func__);
+               goto err_clk_i2s;
+       }
+       dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_INNER] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_INNER]));
+       dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_BCLK_MST_1] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_BCLK_MST_1]));
+       dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_LRCLK_MST_1] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_LRCLK_MST_1]));
+       dev_dbg(&pdev->dev, "dev->clks[CLK_MCLK] = %lu \n", clk_get_rate(dev->clks[CLK_MCLK]));
+       dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_BCLK_1] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_BCLK_1]));
+       dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_LRCLK_1] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_LRCLK_1]));
+
+       dev->rstc[RST_APB1_BUS] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_APB1_BUS]);
+       if (IS_ERR(dev->rstc[RST_APB1_BUS])) {
+               dev_err(&pdev->dev, "%s: failed to get apb_i2stx reset control, ret = %d\n", __func__);
+                return PTR_ERR(dev->rstc[RST_APB1_BUS]);
+       }
+
+       dev->rstc[RST_BCLK_1] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_BCLK_1]);
+       if (IS_ERR(dev->rstc[RST_BCLK_1])) {
+               dev_err(&pdev->dev, "%s: failed to get i2s bclk1 reset control, ret = %d\n", __func__);
+                return PTR_ERR(dev->rstc[RST_BCLK_1]);
+       }
+
+       reset_control_assert(dev->rstc[RST_APB1_BUS]);
+       reset_control_assert(dev->rstc[RST_BCLK_1]);
+
+       udelay(5);
+
+       reset_control_deassert(dev->rstc[RST_APB1_BUS]);
+       reset_control_deassert(dev->rstc[RST_BCLK_1]);
+
+err_clk_i2s:
+       return ret;
+}
+
 /*
  * The following tables allow a direct lookup of various parameters
  * defined in the I2S block's configuration in terms of sound system
@@ -617,9 +864,20 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
 
 }
 
+#ifdef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7110
+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;
+}
+#endif
+
 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 dw_i2s_dev *dev;
        struct resource *res;
        int ret, irq;
@@ -635,6 +893,9 @@ 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_JH7110
+       dw_i2s_dai->probe = dw_i2s_dai_probe;
+#endif
 
        dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(dev->i2s_base))
@@ -652,6 +913,20 @@ static int dw_i2s_probe(struct platform_device *pdev)
                }
        }
 
+       if (of_device_is_compatible(np, "snps,designware-i2srx")) { //record
+               ret = dw_i2srx_clk_init(pdev, dev);
+               if (ret < 0)
+                       goto err_clk_disable;
+       } else if (of_device_is_compatible(np, "snps,designware-i2stx-4ch0")) {   //playback
+               ret = dw_i2stx_4ch0_clk_init(pdev, dev);
+               if (ret < 0)
+                       goto err_clk_disable;
+       } else if (of_device_is_compatible(np, "snps,designware-i2stx-4ch1")) {   //playback
+               ret = dw_i2stx_4ch1_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;
        if (pdata) {
old mode 100644 (file)
new mode 100755 (executable)
index 1c361eb..baf4062
 #define MAX_CHANNEL_NUM                8
 #define MIN_CHANNEL_NUM                2
 
+enum {
+       CLK_DAC_INNER = 0,
+       CLK_DAC_BCLK_MST,
+       CLK_DAC_LRCLK_MST,
+       CLK_MCLK,
+       CLK_DAC_BCLK0,
+       CLK_DAC_LRCLK0,
+       CLK_DAC_BCLK_MST_1,
+       CLK_DAC_LRCLK_MST_1,
+       CLK_DAC_BCLK_1,
+       CLK_DAC_LRCLK_1,
+       CLK_ADC_APB0,
+       CLK_ADC_APB,
+       CLK_ADC_LRCLK,
+       CLK_AUDIO_NUM,
+};
+
+enum {
+       RST_APB0_BUS = 0,
+       RST_BCLK_0,
+       RST_APB1_BUS,
+       RST_BCLK_1,
+       RST_APB_RX,
+       RST_BCLK_RX,
+       RST_AUDIO_NUM,
+};
+
 union dw_i2s_snd_dma_data {
        struct i2s_dma_data pd;
        struct snd_dmaengine_dai_dma_data dt;
@@ -99,6 +126,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;