From de93b47dcd21ac73cb9e3d5c594f763cd5b2593d Mon Sep 17 00:00:00 2001 From: "curry.zhang" Date: Wed, 4 May 2022 01:03:41 -0700 Subject: [PATCH] [Audio] I2S and WM8960 1) Add standard system clock tree API 2) Modify wm8960 and I2S drivers Signed-off-by: curry.zhang --- arch/riscv/boot/dts/starfive/codecs/sf_wm8960.dtsi | 38 +++ arch/riscv/boot/dts/starfive/jh7110-fpga.dts | 3 +- arch/riscv/boot/dts/starfive/jh7110.dtsi | 50 +++- sound/soc/codecs/wm8960.c | 49 ++-- sound/soc/codecs/wm8960.h | 2 + sound/soc/dwc/Kconfig | 8 + sound/soc/dwc/dwc-i2s.c | 277 ++++++++++++++++++++- sound/soc/dwc/local.h | 30 +++ 8 files changed, 432 insertions(+), 25 deletions(-) create mode 100755 arch/riscv/boot/dts/starfive/codecs/sf_wm8960.dtsi mode change 100644 => 100755 sound/soc/codecs/wm8960.c mode change 100644 => 100755 sound/soc/codecs/wm8960.h mode change 100644 => 100755 sound/soc/dwc/Kconfig mode change 100644 => 100755 sound/soc/dwc/dwc-i2s.c mode change 100644 => 100755 sound/soc/dwc/local.h 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 index 0000000..c5cb532a --- /dev/null +++ b/arch/riscv/boot/dts/starfive/codecs/sf_wm8960.dtsi @@ -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"; + }; + }; +}; diff --git a/arch/riscv/boot/dts/starfive/jh7110-fpga.dts b/arch/riscv/boot/dts/starfive/jh7110-fpga.dts index 972f86f..eca37ae 100755 --- a/arch/riscv/boot/dts/starfive/jh7110-fpga.dts +++ b/arch/riscv/boot/dts/starfive/jh7110-fpga.dts @@ -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 +}; diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index f6aabc2..ebeb684 100755 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -957,35 +957,67 @@ 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"; }; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c old mode 100644 new mode 100755 index 3c8e728..09f5bb2 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -22,10 +22,11 @@ #include #include #include +#include #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)) { diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h old mode 100644 new mode 100755 index 63ba6c0..2a5b4d8 --- a/sound/soc/codecs/wm8960.h +++ b/sound/soc/codecs/wm8960.h @@ -64,6 +64,8 @@ #define WM8960_PLL3 0x36 #define WM8960_PLL4 0x37 +#define WM8960_REG_MAX 0x38 + /* * WM8960 Clock dividers diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig old mode 100644 new mode 100755 index 71a58f7..6b249e1 --- 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_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. diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c old mode 100644 new mode 100755 index 5ab1718..30b2e4c --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -24,8 +24,18 @@ #include #include #include +#include #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) { diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h old mode 100644 new mode 100755 index 1c361eb..baf4062 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -81,6 +81,33 @@ #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; -- 2.7.4