summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichaelZhuxx <78013124+MichaelZhuxx@users.noreply.github.com>2021-12-29 15:36:48 +0300
committerGitHub <noreply@github.com>2021-12-29 15:36:48 +0300
commit52ca39c92857443259cc503e6788a6fab398949d (patch)
tree7132f116c069434a13a169fc490bcddc49471d92
parente198e99258dfe0e121378dc146ff125e68b95db1 (diff)
parent2db1d325be7acf9aa7e626873b4d677bedeeff96 (diff)
downloadlinux-52ca39c92857443259cc503e6788a6fab398949d.tar.xz
Merge pull request #38 from starfive-tech/visionfive-5.15.y-devel
[NOT-FOR-UPSTREAM] riscv: Fix StarFive JH7100 Fedora defconfig
-rwxr-xr-xarch/riscv/boot/dts/starfive/codecs/sf_wm8960.dtsi38
-rw-r--r--arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight-a1.dts4
-rw-r--r--arch/riscv/boot/dts/starfive/jh7100-common.dtsi18
-rw-r--r--arch/riscv/boot/dts/starfive/jh7100.dtsi314
-rw-r--r--arch/riscv/configs/starfive_jh7100_fedora_defconfig9
-rw-r--r--drivers/clk/starfive/clk-starfive-jh7100-audio.c59
-rw-r--r--drivers/clk/starfive/clk-starfive-jh7100.c18
-rw-r--r--drivers/clk/starfive/clk-starfive-jh7100.h2
-rw-r--r--include/dt-bindings/clock/starfive-jh7100-audio.h7
-rw-r--r--sound/soc/codecs/wm8960.c43
-rw-r--r--sound/soc/dwc/Kconfig8
-rw-r--r--sound/soc/dwc/dwc-i2s.c387
-rw-r--r--sound/soc/dwc/local.h49
13 files changed, 767 insertions, 189 deletions
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 000000000000..151fb1bf3270
--- /dev/null
+++ b/arch/riscv/boot/dts/starfive/codecs/sf_wm8960.dtsi
@@ -0,0 +1,38 @@
+&sound{
+ /* i2s + wm8960 */
+ simple-audio-card,dai-link@1 {
+ reg = <1>;
+ 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 = <&i2sadc0>;
+ };
+ cpu1 {
+ sound-dai = <&i2sdac0>;
+ };
+
+ sndcodec1:codec {
+ sound-dai = <&wm8960>;
+ clocks = <&wm8960_mclk>;
+ clock-names = "mclk";
+ };
+ };
+};
diff --git a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight-a1.dts b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight-a1.dts
index d307e44590f3..c7e6b793d763 100644
--- a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight-a1.dts
+++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight-a1.dts
@@ -20,5 +20,7 @@
&gpio {
/* don't reset gpio mux for serial console and reset gpio */
- starfive,keep-gpiomux = <13 14 63>;
+ starfive,keep-gpiomux = <13 14 63 0 2 3 45>;
};
+
+#include "codecs/sf_wm8960.dtsi"
diff --git a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
index 1144dfd65e0e..ff3e6b746132 100644
--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
@@ -130,6 +130,9 @@
};
&gpio {
+ /* don't reset gpio mux for serial console on uart3 */
+ starfive,keep-gpiomux = <13 14 0 2 3 45>;
+
gmac_pins: gmac-0 {
gtxclk-pins {
pins = <PAD_FUNC_SHARE(115)>;
@@ -266,11 +269,11 @@
<GPIOMUX(5,
GPO_PWM_PAD_OUT_BIT1,
GPO_PWM_PAD_OE_N_BIT1,
- GPI_NONE)>,
- <GPIOMUX(45,
- GPO_PWM_PAD_OUT_BIT2,
- GPO_PWM_PAD_OE_N_BIT2,
GPI_NONE)>;
+ // <GPIOMUX(45,
+ // GPO_PWM_PAD_OUT_BIT2,
+ // GPO_PWM_PAD_OE_N_BIT2,
+ // GPI_NONE)>;
bias-disable;
drive-strength = <35>;
input-disable;
@@ -468,6 +471,13 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
status = "okay";
+
+ wm8960: codec@1a {
+ compatible = "wlf,wm8960";
+ reg = <0x1a>;
+ #sound-dai-cells = <0>;
+ wlf,shared-lrclk;
+ };
};
&i2c2 {
diff --git a/arch/riscv/boot/dts/starfive/jh7100.dtsi b/arch/riscv/boot/dts/starfive/jh7100.dtsi
index d4c88766f99b..48f87141f00e 100644
--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
@@ -243,155 +243,6 @@
interrupts = <31>;
};
- i2sadc0: i2sadc0@10400000 {
- compatible = "snps,designware-i2sadc0";
- reg = <0x0 0x10400000 0x0 0x1000>;
- clocks = <&clkgen JH7100_CLK_APB1_BUS>;
- clock-names = "i2sclk";
- interrupt-parent = <&plic>;
- #sound-dai-cells = <0>;
- dmas = <&dma2p 28>;
- dma-names = "rx";
- };
-
- i2svad: i2svad@10420000 {
- compatible = "starfive,sf-i2svad";
- reg = <0x0 0x10420000 0x0 0x1000> ;
- clocks = <&audclk JH7100_AUDCLK_I2SVAD_APB>;
- clock-names = "i2svad_apb";
- resets = <&audrst JH7100_AUDRSTN_I2SVAD_APB>,
- <&audrst JH7100_AUDRSTN_I2SVAD_SRST>;
- reset-names = "apb_i2svad", "i2svad_srst";
- interrupts = <60>, <61>;
- interrupt-names = "spintr", "slintr";
- #sound-dai-cells = <0>;
- };
-
- pwmdac: pwmdac@10440000 {
- compatible = "starfive,pwmdac";
- reg = <0x0 0x10440000 0x0 0x1000>;
- clocks = <&clkgen JH7100_CLK_AUDIO_ROOT>,
- <&clkgen JH7100_CLK_AUDIO_SRC>,
- <&clkgen JH7100_CLK_AUDIO_12288>,
- <&audclk JH7100_AUDCLK_DMA1P_AHB>,
- <&audclk JH7100_AUDCLK_PWMDAC_APB>,
- <&audclk JH7100_AUDCLK_DAC_MCLK>;
- clock-names = "audio_root",
- "audio_src",
- "audio_12288",
- "dma1p_ahb",
- "pwmdac_apb",
- "dac_mclk";
- resets = <&audrst JH7100_AUDRSTN_APB_BUS>,
- <&audrst JH7100_AUDRSTN_DMA1P_AHB>,
- <&audrst JH7100_AUDRSTN_PWMDAC_APB>;
- reset-names = "apb_bus", "dma1p_ahb", "apb_pwmdac";
- dmas = <&dma2p 23>;
- dma-names = "tx";
- #sound-dai-cells = <0>;
- };
-
- i2sdac0: i2sdac0@10450000 {
- compatible = "snps,designware-i2sdac0";
- reg = <0x0 0x10450000 0x0 0x1000>;
- clocks = <&audclk JH7100_AUDCLK_DAC_MCLK>,
- <&audclk JH7100_AUDCLK_I2SDAC_BCLK>,
- <&audclk JH7100_AUDCLK_I2SDAC_LRCLK>,
- <&audclk JH7100_AUDCLK_I2SDAC_APB>;
- clock-names = "dac_mclk", "i2sdac0_bclk", "i2sdac0_lrclk", "i2sdac_apb";
- resets = <&audrst JH7100_AUDRSTN_I2SDAC_APB>,
- <&audrst JH7100_AUDRSTN_I2SDAC_SRST>;
- reset-names = "apb_i2sdac", "i2sdac_srst";
- #sound-dai-cells = <0>;
- dmas = <&dma2p 30>;
- dma-names = "tx";
- };
-
- i2sdac1: i2sdac1@10460000 {
- compatible = "snps,designware-i2sdac1";
- reg = <0x0 0x10460000 0x0 0x1000>;
- clocks = <&audclk JH7100_AUDCLK_DAC_MCLK>,
- <&audclk JH7100_AUDCLK_I2S1_BCLK>,
- <&audclk JH7100_AUDCLK_I2S1_LRCLK>,
- <&audclk JH7100_AUDCLK_I2S1_APB>;
- clock-names = "dac_mclk", "i2sdac1_bclk", "i2sdac1_lrclk", "i2s1_apb";
- resets = <&audrst JH7100_AUDRSTN_I2S1_APB>,
- <&audrst JH7100_AUDRSTN_I2S1_SRST>;
- #sound-dai-cells = <0>;
- dmas = <&dma2p 31>;
- dma-names = "tx";
- };
-
- i2sdac16k: i2sdac16k@10470000 {
- compatible = "snps,designware-i2sdac16k";
- reg = <0x0 0x10470000 0x0 0x1000>;
- clocks = <&clkgen JH7100_CLK_APB1_BUS>;
- clock-names = "i2sclk";
- #sound-dai-cells = <0>;
- dmas = <&dma2p 29>;
- dma-names = "tx";
- };
-
- audclk: clock-controller@10480000 {
- compatible = "starfive,jh7100-audclk";
- reg = <0x0 0x10480000 0x0 0x10000>;
- clocks = <&clkgen JH7100_CLK_AUDIO_SRC>,
- <&clkgen JH7100_CLK_AUDIO_12288>,
- <&clkgen JH7100_CLK_DOM7AHB_BUS>;
- clock-names = "audio_src", "audio_12288", "dom7ahb_bus";
- #clock-cells = <1>;
- };
-
- audrst: reset-controller@10490000 {
- compatible = "starfive,jh7100-audrst";
- reg = <0x0 0x10490000 0x0 0x10000>;
- #reset-cells = <1>;
- };
-
- spdif_transmitter: spdif-transmitter {
- compatible = "linux,spdif-dit";
- #sound-dai-cells = <0>;
- };
-
- spdif_receiver: spdif-receiver {
- compatible = "linux,spdif-dir";
- #sound-dai-cells = <0>;
- };
-
- pwmdac_codec: pwmdac-transmitter {
- compatible = "linux,pwmdac-dit";
- #sound-dai-cells = <0>;
- };
-
- dmic_codec: dmic {
- compatible = "dmic-codec";
- #sound-dai-cells = <0>;
- };
-
- sound: snd-card {
- compatible = "simple-audio-card";
- simple-audio-card,name = "Starfive-Multi-Sound-Card";
- #address-cells = <1>;
- #size-cells = <0>;
-
- /* pwmdac */
- simple-audio-card,dai-link@0 {
- reg = <0>;
- status = "okay";
- format = "left_j";
- bitclock-master = <&sndcpu0>;
- frame-master = <&sndcpu0>;
-
- sndcpu0: cpu {
- sound-dai = <&pwmdac>;
- };
-
- codec {
- sound-dai = <&pwmdac_codec>;
- };
- };
- };
-
usb3: usb@104c0000 {
compatible = "cdns,usb3";
reg = <0x0 0x104c0000 0x0 0x10000>, // memory area for HOST registers
@@ -802,5 +653,170 @@
dsp@0 {
};
};
+
+ wm8960_mclk: wm8960_mclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24576000>;
+ };
+
+ i2sadc0: i2sadc0@10400000 {
+ compatible = "snps,designware-i2sadc0";
+ reg = <0x0 0x10400000 0x0 0x1000>;
+ interrupt-parent = <&plic>;
+ clocks = <&clkgen JH7100_CLK_AUDIO_ROOT>,
+ <&clkgen JH7100_CLK_AUDIO_SRC>,
+ <&clkgen JH7100_CLK_AUDIO_12288>,
+ <&audclk JH7100_AUDCLK_DMA1P_AHB>,
+ <&audclk JH7100_AUDCLK_ADC_MCLK>,
+ <&audclk JH7100_AUDCLK_I2SADC_APB>,
+ <&audclk JH7100_AUDCLK_I2SVAD_APB>,
+ <&audclk JH7100_AUDCLK_I2SADC_BCLK>,
+ <&audclk JH7100_AUDCLK_I2SADC_LRCLK>,
+ <&audclk JH7100_AUDCLK_I2SADC_BCLK_IOPAD>,
+ <&audclk JH7100_AUDCLK_I2SADC_LRCLK_IOPAD>;
+ clock-names = "audio_root", "audio_src",
+ "audio_12288", "dma1p_ahb",
+ "adc_mclk", "i2sadc_apb",
+ "i2svad_apb", "i2sadc0_bclk", "i2sadc0_lrclk",
+ "i2sadc_bclk_iopad", "i2sadc_lrclk_iopad";
+ resets = <&audrst JH7100_AUDRSTN_APB_BUS>,
+ <&audrst JH7100_AUDRSTN_DMA1P_AHB>,
+ <&audrst JH7100_AUDRSTN_I2SADC_APB>,
+ <&audrst JH7100_AUDRSTN_I2SADC_SRST>,
+ <&audrst JH7100_AUDRSTN_I2SVAD_APB>,
+ <&audrst JH7100_AUDRSTN_I2SVAD_SRST>;
+ reset-names = "apb_bus", "dma1p_ahb", "apb_i2sadc",
+ "i2sadc_srst", "apb_i2svad", "i2svad_srst";
+ #sound-dai-cells = <0>;
+ dmas = <&dma2p 28>;
+ dma-names = "rx";
+ };
+
+ i2svad: i2svad@10420000 {
+ compatible = "sf,sf-i2svad";
+ reg = <0x0 0x10420000 0x0 0x1000> ;
+ interrupt-parent = <&plic>;
+ interrupts = <60>, <61>;
+ interrupt-names = "spintr", "slintr";
+ clocks = <&clkgen JH7100_CLK_APB1_BUS>;
+ clock-names = "i2sclk";
+ #sound-dai-cells = <0>;
+ };
+ i2sdac0: i2sdac0@10450000 {
+ compatible = "snps,designware-i2sdac0";
+ reg = <0x0 0x10450000 0x0 0x1000>;
+ interrupt-parent = <&plic>;
+ clocks = <&audclk JH7100_AUDCLK_DAC_MCLK>,
+ <&audclk JH7100_AUDCLK_I2SDAC_BCLK>,
+ <&audclk JH7100_AUDCLK_I2SDAC_LRCLK>,
+ <&audclk JH7100_AUDCLK_I2SDAC_APB>,
+ <&audclk JH7100_AUDCLK_I2SDAC_BCLK_IOPAD>,
+ <&audclk JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD>;
+ clock-names = "dac_mclk", "i2sdac0_bclk", "i2sdac0_lrclk",
+ "i2sdac_apb", "i2sdac_bclk_iopad", "i2sdac_lrclk_iopad";
+ resets = <&audrst JH7100_AUDRSTN_I2SDAC_APB>,
+ <&audrst JH7100_AUDRSTN_I2SDAC_SRST>;
+ reset-names = "apb_i2sdac", "i2sdac_srst";
+ #sound-dai-cells = <0>;
+ dmas = <&dma2p 30>;
+ dma-names = "tx";
+ };
+
+ i2sdac16k: i2sdac16k@10470000 {
+ compatible = "snps,designware-i2sdac16k";
+ reg = <0x0 0x10470000 0x0 0x1000>;
+ interrupt-parent = <&plic>;
+ /* interrupts = <68>; */
+ /* interrupt-names = "tx"; */
+ clocks = <&clkgen JH7100_CLK_APB1_BUS>;
+ clock-names = "i2sclk";
+ #sound-dai-cells = <0>;
+ dmas = <&dma2p 29>;
+ dma-names = "tx";
+ };
+
+ audclk: clock-controller@10480000 {
+ compatible = "starfive,jh7100-audclk";
+ reg = <0x0 0x10480000 0x0 0x10000>;
+ clocks = <&clkgen JH7100_CLK_AUDIO_SRC>,
+ <&clkgen JH7100_CLK_AUDIO_12288>,
+ <&clkgen JH7100_CLK_DOM7AHB_BUS>;
+ clock-names = "audio_src", "audio_12288", "dom7ahb_bus";
+ #clock-cells = <1>;
+ };
+
+ audrst: reset-controller@10490000 {
+ compatible = "starfive,jh7100-audrst";
+ reg = <0x0 0x10490000 0x0 0x10000>;
+ #reset-cells = <1>;
+ };
+
+ spdif_transmitter: spdif_transmitter {
+ compatible = "linux,spdif-dit";
+ #sound-dai-cells = <0>;
+ };
+
+ spdif_receiver: spdif_receiver {
+ compatible = "linux,spdif-dir";
+ #sound-dai-cells = <0>;
+ };
+
+ pwmdac: pwmdac@10440000 {
+ compatible = "starfive,pwmdac";
+ reg = <0x0 0x10440000 0x0 0x1000>;
+ clocks = <&clkgen JH7100_CLK_AUDIO_ROOT>,
+ <&clkgen JH7100_CLK_AUDIO_SRC>,
+ <&clkgen JH7100_CLK_AUDIO_12288>,
+ <&audclk JH7100_AUDCLK_DMA1P_AHB>,
+ <&audclk JH7100_AUDCLK_PWMDAC_APB>,
+ <&audclk JH7100_AUDCLK_DAC_MCLK>;
+ clock-names = "audio_root",
+ "audio_src",
+ "audio_12288",
+ "dma1p_ahb",
+ "pwmdac_apb",
+ "dac_mclk";
+ resets = <&audrst JH7100_AUDRSTN_APB_BUS>,
+ <&audrst JH7100_AUDRSTN_DMA1P_AHB>,
+ <&audrst JH7100_AUDRSTN_PWMDAC_APB>;
+ reset-names = "apb_bus", "dma1p_ahb", "apb_pwmdac";
+ dmas = <&dma2p 23>;
+ dma-names = "tx";
+ #sound-dai-cells = <0>;
+ };
+
+ pwmdac_codec: pwmdac-transmitter {
+ compatible = "linux,pwmdac-dit";
+ #sound-dai-cells = <0>;
+ };
+
+ dmic_codec: dmic_codec {
+ compatible = "dmic-codec";
+ #sound-dai-cells = <0>;
+ };
+
+ sound:snd-card{
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "Starfive-Multi-Sound-Card";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ simple-audio-card,dai-link@0 {
+ reg = <0>;
+ status = "okay";
+ format = "left_j";
+ bitclock-master = <&sndcpu0>;
+ frame-master = <&sndcpu0>;
+
+ sndcpu0: cpu {
+ sound-dai = <&pwmdac>;
+ };
+
+ codec {
+ sound-dai = <&pwmdac_codec>;
+ };
+ };
+ };
};
};
diff --git a/arch/riscv/configs/starfive_jh7100_fedora_defconfig b/arch/riscv/configs/starfive_jh7100_fedora_defconfig
index 86da9efe705e..217aaa1c23e7 100644
--- a/arch/riscv/configs/starfive_jh7100_fedora_defconfig
+++ b/arch/riscv/configs/starfive_jh7100_fedora_defconfig
@@ -41,6 +41,7 @@ CONFIG_SLAB_FREELIST_RANDOM=y
CONFIG_SLAB_FREELIST_HARDENED=y
CONFIG_SHUFFLE_PAGE_ALLOCATOR=y
CONFIG_PROFILING=y
+CONFIG_SOC_SIFIVE=y
CONFIG_SOC_STARFIVE=y
CONFIG_SOC_VIRT=y
CONFIG_SMP=y
@@ -2049,8 +2050,8 @@ CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
+CONFIG_SOUND=y
+CONFIG_SND=y
CONFIG_SND_OSSEMUL=y
CONFIG_SND_MIXER_OSS=m
CONFIG_SND_PCM_OSS=m
@@ -2153,7 +2154,7 @@ CONFIG_SND_FIREWIRE_TASCAM=m
CONFIG_SND_FIREWIRE_MOTU=m
CONFIG_SND_FIREFACE=m
# CONFIG_SND_PCMCIA is not set
-CONFIG_SND_SOC=m
+CONFIG_SND_SOC=y
CONFIG_SND_SOC_AMD_ACP=m
CONFIG_SND_SOC_AMD_CZ_RT5645_MACH=m
CONFIG_SND_DESIGNWARE_I2S=m
@@ -2161,6 +2162,7 @@ CONFIG_SND_DESIGNWARE_PCM=y
CONFIG_SND_I2S_HI6210_I2S=m
CONFIG_SND_SOC_SOF_TOPLEVEL=y
CONFIG_SND_SOC_SOF_PCI=m
+CONFIG_SND_STARFIVE_PWMDAC=y
CONFIG_SND_SOC_AC97_CODEC=m
CONFIG_SND_SOC_ADAU1761_I2C=m
CONFIG_SND_SOC_ADAU1761_SPI=m
@@ -3069,6 +3071,7 @@ CONFIG_SECONDARY_TRUSTED_KEYRING=y
CONFIG_SYSTEM_BLACKLIST_KEYRING=y
# CONFIG_RAID6_PQ_BENCHMARK is not set
CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=32
CONFIG_PRINTK_TIME=y
CONFIG_CONSOLE_LOGLEVEL_QUIET=3
CONFIG_BOOT_PRINTK_DELAY=y
diff --git a/drivers/clk/starfive/clk-starfive-jh7100-audio.c b/drivers/clk/starfive/clk-starfive-jh7100-audio.c
index e5a59bccda60..0808aac4f64b 100644
--- a/drivers/clk/starfive/clk-starfive-jh7100-audio.c
+++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c
@@ -3,10 +3,12 @@
* StarFive JH7100 Audio Clock Driver
*
* Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
+ * Copyright (C) 2021 Walker Chen <walker.chen@starfivetech.com>
*/
#include <linux/bits.h>
#include <linux/clk-provider.h>
+#include <linux/io.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
@@ -22,11 +24,7 @@
#define JH7100_AUDCLK_AUDIO_SRC (JH7100_AUDCLK_END + 0)
#define JH7100_AUDCLK_AUDIO_12288 (JH7100_AUDCLK_END + 1)
#define JH7100_AUDCLK_DOM7AHB_BUS (JH7100_AUDCLK_END + 2)
-#define JH7100_AUDCLK_I2SADC_BCLK_IOPAD (JH7100_AUDCLK_END + 3)
-#define JH7100_AUDCLK_I2SADC_LRCLK_IOPAD (JH7100_AUDCLK_END + 4)
-#define JH7100_AUDCLK_I2SDAC_BCLK_IOPAD (JH7100_AUDCLK_END + 5)
-#define JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD (JH7100_AUDCLK_END + 6)
-#define JH7100_AUDCLK_VAD_INTMEM (JH7100_AUDCLK_END + 7)
+#define JH7100_AUDCLK_VAD_INTMEM (JH7100_AUDCLK_END + 3)
static const struct jh7100_clk_data jh7100_audclk_data[] = {
JH7100__GMD(JH7100_AUDCLK_ADC_MCLK, "adc_mclk", 0, 15, 2,
@@ -62,9 +60,10 @@ static const struct jh7100_clk_data jh7100_audclk_data[] = {
JH7100_AUDCLK_DAC_MCLK,
JH7100_AUDCLK_I2SDAC_BCLK_IOPAD),
JH7100__INV(JH7100_AUDCLK_I2SDAC_BCLK_N, "i2sdac_bclk_n", JH7100_AUDCLK_I2SDAC_BCLK),
- JH7100_MDIV(JH7100_AUDCLK_I2SDAC_LRCLK, "i2sdac_lrclk", 31, 2,
- JH7100_AUDCLK_I2S1_MCLK,
- JH7100_AUDCLK_I2SDAC_BCLK_IOPAD),
+ JH7100_MDIV(JH7100_AUDCLK_I2SDAC_LRCLK, "i2sdac_lrclk", 63, 3,
+ JH7100_AUDCLK_I2SDAC_BCLK_N,
+ JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD,
+ JH7100_AUDCLK_I2SDAC_BCLK),
JH7100_GATE(JH7100_AUDCLK_I2S1_APB, "i2s1_apb", 0, JH7100_AUDCLK_APB0_BUS),
JH7100_MDIV(JH7100_AUDCLK_I2S1_BCLK, "i2s1_bclk", 31, 2,
JH7100_AUDCLK_I2S1_MCLK,
@@ -72,7 +71,8 @@ static const struct jh7100_clk_data jh7100_audclk_data[] = {
JH7100__INV(JH7100_AUDCLK_I2S1_BCLK_N, "i2s1_bclk_n", JH7100_AUDCLK_I2S1_BCLK),
JH7100_MDIV(JH7100_AUDCLK_I2S1_LRCLK, "i2s1_lrclk", 63, 3,
JH7100_AUDCLK_I2S1_BCLK_N,
- JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD),
+ JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD,
+ JH7100_AUDCLK_I2S1_BCLK),
JH7100_GATE(JH7100_AUDCLK_I2SDAC16K_APB, "i2s1dac16k_apb", 0, JH7100_AUDCLK_APB0_BUS),
JH7100__DIV(JH7100_AUDCLK_APB0_BUS, "apb0_bus", 8, JH7100_AUDCLK_DOM7AHB_BUS),
JH7100_GATE(JH7100_AUDCLK_DMA1P_AHB, "dma1p_ahb", 0, JH7100_AUDCLK_DOM7AHB_BUS),
@@ -85,14 +85,33 @@ static const struct jh7100_clk_data jh7100_audclk_data[] = {
JH7100_AUDCLK_AUDIO_12288),
};
+static void jh7100_clk_set_divider(struct jh7100_clk_priv *priv,
+ unsigned int idx,
+ unsigned int mask,
+ unsigned int div)
+{
+ unsigned long flags;
+ unsigned int value;
+ void __iomem *reg = priv->base + 4 * idx;
+
+ spin_lock_irqsave(&priv->rmw_lock, flags);
+ value = readl_relaxed(reg) & ~mask;
+ value |= div;
+ writel_relaxed(value, reg);
+ spin_unlock_irqrestore(&priv->rmw_lock, flags);
+}
+
static struct clk_hw *jh7100_audclk_get(struct of_phandle_args *clkspec, void *data)
{
struct jh7100_clk_priv *priv = data;
unsigned int idx = clkspec->args[0];
- if (idx < JH7100_AUDCLK_END)
+ if (idx < JH7100_AUDCLK_I2SADC_BCLK_IOPAD)
return &priv->reg[idx].hw;
+ if (idx < JH7100_AUDCLK_END)
+ return priv->pll[idx - JH7100_AUDCLK_I2SADC_BCLK_IOPAD];
+
return ERR_PTR(-EINVAL);
}
@@ -102,7 +121,7 @@ static int jh7100_audclk_probe(struct platform_device *pdev)
unsigned int idx;
int ret;
- priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg, JH7100_AUDCLK_END), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg, JH7100_AUDCLK_I2SADC_BCLK_IOPAD), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -112,7 +131,18 @@ static int jh7100_audclk_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- for (idx = 0; idx < JH7100_AUDCLK_END; idx++) {
+ priv->pll[0] = clk_hw_register_fixed_rate(priv->dev, "i2sadc_bclk_iopad", NULL, 0, 12288000);
+ priv->pll[1] = clk_hw_register_fixed_rate(priv->dev, "i2sadc_lrclk_iopad", NULL, 0, 12288000);
+ priv->pll[2] = clk_hw_register_fixed_rate(priv->dev, "i2sdac_bclk_iopad", NULL, 0, 12288000);
+ priv->pll[3] = clk_hw_register_fixed_rate(priv->dev, "i2sdac_lrclk_iopad", NULL, 0, 12288000);
+
+ // for special initialization
+ jh7100_clk_set_divider(priv, JH7100_AUDCLK_I2SADC_BCLK, 0x1f, 0x1);
+ jh7100_clk_set_divider(priv, JH7100_AUDCLK_I2SADC_LRCLK, 0x3f, 0x1);
+ jh7100_clk_set_divider(priv, JH7100_AUDCLK_I2SDAC_BCLK, 0x1f, 0x1);
+ jh7100_clk_set_divider(priv, JH7100_AUDCLK_I2SDAC_LRCLK, 0x3f, 0x1);
+
+ for (idx = 0; idx < JH7100_AUDCLK_I2SADC_BCLK_IOPAD; idx++) {
u32 max = jh7100_audclk_data[idx].max;
struct clk_parent_data parents[4] = {};
struct clk_init_data init = {
@@ -128,8 +158,10 @@ static int jh7100_audclk_probe(struct platform_device *pdev)
for (i = 0; i < init.num_parents; i++) {
unsigned int pidx = jh7100_audclk_data[idx].parents[i];
- if (pidx < JH7100_AUDCLK_END)
+ if (pidx < JH7100_AUDCLK_I2SADC_BCLK_IOPAD)
parents[i].hw = &priv->reg[pidx].hw;
+ else if (pidx < JH7100_AUDCLK_END)
+ parents[i].hw = priv->pll[pidx - JH7100_AUDCLK_I2SADC_BCLK_IOPAD];
else if (pidx == JH7100_AUDCLK_AUDIO_SRC)
parents[i].fw_name = "audio_src";
else if (pidx == JH7100_AUDCLK_AUDIO_12288)
@@ -166,5 +198,6 @@ static struct platform_driver jh7100_audclk_driver = {
module_platform_driver(jh7100_audclk_driver);
MODULE_AUTHOR("Emil Renner Berthing");
+MODULE_AUTHOR("Walker Chen");
MODULE_DESCRIPTION("StarFive JH7100 audio clock driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/clk/starfive/clk-starfive-jh7100.c b/drivers/clk/starfive/clk-starfive-jh7100.c
index 831938baac05..57ff561a186d 100644
--- a/drivers/clk/starfive/clk-starfive-jh7100.c
+++ b/drivers/clk/starfive/clk-starfive-jh7100.c
@@ -321,6 +321,22 @@ static int jh7100_clk_is_enabled(struct clk_hw *hw)
return !!(jh7100_clk_reg_get(clk) & JH7100_CLK_ENABLE);
}
+static void jh7100_clk_set_divider(struct jh7100_clk_priv *priv,
+ unsigned int idx,
+ unsigned int mask,
+ unsigned int div)
+{
+ unsigned long flags;
+ unsigned int value;
+ void __iomem *reg = priv->base + 4 * idx;
+
+ spin_lock_irqsave(&priv->rmw_lock, flags);
+ value = readl_relaxed(reg) & ~mask;
+ value |= div;
+ writel_relaxed(value, reg);
+ spin_unlock_irqrestore(&priv->rmw_lock, flags);
+}
+
static unsigned long jh7100_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -634,6 +650,8 @@ static int __init clk_starfive_jh7100_probe(struct platform_device *pdev)
if (IS_ERR(priv->pll[2]))
return PTR_ERR(priv->pll[2]);
+ jh7100_clk_set_divider(priv, JH7100_CLK_AHB_BUS, 0xf, 0x4);
+
for (idx = 0; idx < JH7100_CLK_PLL0_OUT; idx++) {
u32 max = jh7100_clk_data[idx].max;
struct clk_parent_data parents[4] = {};
diff --git a/drivers/clk/starfive/clk-starfive-jh7100.h b/drivers/clk/starfive/clk-starfive-jh7100.h
index 5c9812c58392..c2d594c8ce5b 100644
--- a/drivers/clk/starfive/clk-starfive-jh7100.h
+++ b/drivers/clk/starfive/clk-starfive-jh7100.h
@@ -109,7 +109,7 @@ struct jh7100_clk_priv {
spinlock_t rmw_lock;
struct device *dev;
void __iomem *base;
- struct clk_hw *pll[3];
+ struct clk_hw *pll[4];
struct jh7100_clk reg[];
};
diff --git a/include/dt-bindings/clock/starfive-jh7100-audio.h b/include/dt-bindings/clock/starfive-jh7100-audio.h
index fbb4eae6572b..929f37ad1107 100644
--- a/include/dt-bindings/clock/starfive-jh7100-audio.h
+++ b/include/dt-bindings/clock/starfive-jh7100-audio.h
@@ -36,6 +36,11 @@
#define JH7100_AUDCLK_APB_EN 27
#define JH7100_AUDCLK_VAD_MEM 28
-#define JH7100_AUDCLK_END 29
+#define JH7100_AUDCLK_I2SADC_BCLK_IOPAD 29
+#define JH7100_AUDCLK_I2SADC_LRCLK_IOPAD 30
+#define JH7100_AUDCLK_I2SDAC_BCLK_IOPAD 31
+#define JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD 32
+
+#define JH7100_AUDCLK_END 33
#endif /* __DT_BINDINGS_CLOCK_STARFIVE_JH7100_AUDIO_H__ */
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 499604f1e178..b090b4012f5d 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -25,6 +25,8 @@
#include "wm8960.h"
+#define WM8960_MCLK 24000000
+
/* R25 - Power 1 */
#define WM8960_VMID_MASK 0x180
#define WM8960_VREF 0x40
@@ -742,16 +744,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;
}
@@ -1287,6 +1282,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_PLL;
switch (clk_id) {
case WM8960_SYSCLK_MCLK:
@@ -1302,7 +1298,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
default:
return -EINVAL;
}
-
+ wm8960->freq_in = WM8960_MCLK;
wm8960->sysclk = freq;
wm8960->clk_id = clk_id;
@@ -1354,6 +1350,22 @@ static int wm8960_probe(struct snd_soc_component *component)
else
wm8960->set_bias_level = wm8960_set_bias_level_out3;
+#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);
+ snd_soc_component_update_bits(component, WM8960_ROUT1, 0x100, 0x100);
+ snd_soc_component_update_bits(component, WM8960_LOUT2, 0x100, 0x100);
+ snd_soc_component_update_bits(component, WM8960_ROUT2, 0x100, 0x100);
+ snd_soc_component_update_bits(component, WM8960_POWER2, 0x1fB, 0x198);
+ snd_soc_component_update_bits(component, WM8960_LOUTMIX, 0x1F0, 0x100);
+ snd_soc_component_update_bits(component, WM8960_ROUTMIX, 0x1F0, 0x100);
+ snd_soc_component_update_bits(component, WM8960_LOUT1, 0x7f, 0x6f);
+ 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
+
snd_soc_add_component_controls(component, wm8960_snd_controls,
ARRAY_SIZE(wm8960_snd_controls));
wm8960_add_widgets(component);
@@ -1413,6 +1425,8 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
if (wm8960 == NULL)
return -ENOMEM;
+ wm8960->clk_id = WM8960_SYSCLK_PLL;
+
wm8960->mclk = devm_clk_get(&i2c->dev, "mclk");
if (IS_ERR(wm8960->mclk)) {
if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER)
@@ -1456,6 +1470,13 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
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 71a58f7ac13a..ec5dd5e44452 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 33ce257ae198..dc51ec841052 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,7 +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))
@@ -197,13 +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;
}
@@ -233,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)
{
@@ -306,9 +626,11 @@ 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)
+ 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,
@@ -383,7 +705,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,
+ .shutdown = dw_i2s_shutdown,
.hw_params = dw_i2s_hw_params,
.prepare = dw_i2s_prepare,
.trigger = dw_i2s_trigger,
@@ -617,9 +939,20 @@ 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);
+
+ 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,14 +968,24 @@ 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
- dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ 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;
- irq = platform_get_irq_optional(pdev, 0);
+ irq = platform_get_irq(pdev, 0);
if (irq >= 0) {
ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0,
pdev->name, dev);
@@ -688,6 +1031,34 @@ static int dw_i2s_probe(struct platform_device *pdev)
return ret;
}
+ 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);
@@ -714,6 +1085,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
}
pm_runtime_enable(&pdev->dev);
+
return 0;
err_clk_disable:
@@ -735,7 +1107,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", },
{},
};
@@ -759,6 +1133,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 1c361eb6127e..4a05357728c6 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;
int active;
unsigned int capability;
@@ -99,6 +145,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;