mirror of
https://github.com/revyos/thead-kernel.git
synced 2026-06-21 09:12:26 +02:00
Linux_SDK_V1.2.1
Signed-off-by: thead_admin <occ_thead@service.alibaba.com>
This commit is contained in:
@@ -21,7 +21,6 @@ config RISCV
|
||||
select ARCH_HAS_GCOV_PROFILE_ALL
|
||||
select ARCH_HAS_GIGANTIC_PAGE
|
||||
select ARCH_HAS_KCOV
|
||||
select ARCH_HAS_MMIOWB
|
||||
select ARCH_HAS_PTE_SPECIAL
|
||||
select ARCH_HAS_SET_DIRECT_MAP
|
||||
select ARCH_HAS_SET_MEMORY
|
||||
@@ -35,6 +34,7 @@ config RISCV
|
||||
select ARCH_KEEP_MEMBLOCK
|
||||
select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX
|
||||
select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
|
||||
select ARCH_USE_QUEUED_SPINLOCKS
|
||||
select ARCH_USE_QUEUED_RWLOCKS
|
||||
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
|
||||
select ARCH_WANT_FRAME_POINTERS
|
||||
|
||||
@@ -12,8 +12,9 @@ dtb-$(CONFIG_SOC_THEAD) += light-a-val-ddr2G.dtb light-a-val-ddr1G.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-npu-fce.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-iso7816.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-nand.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-audio.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-audio.dtb light-a-val-audio-i2s-8ch.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-audio-tdm.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-audio-spdif.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-dsi0.dtb light-a-val-dsi1.dtb light-a-val-hdmi.dtb light-a-val-dsi0-dsi1.dtb light-a-val-dsi0-hdmi.dtb light-a-val-dsi0-hdmi-audio.dtb light-a-val-dpi0.dtb light-a-val-dpi0-dpi1.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-wcn.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-gpio-keys.dtb
|
||||
@@ -21,7 +22,7 @@ dtb-$(CONFIG_SOC_THEAD) += light-a-val-khv.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-sec.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-miniapp-hdmi.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-product.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-b-product.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-b-product.dtb light-b-product-sec.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-b-product-ddr1G.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-b-product-miniapp-hdmi.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += light-a-val-full.dtb
|
||||
@@ -38,3 +39,4 @@ dtb-$(CONFIG_SOC_THEAD) += light-a-val-android.dtb
|
||||
|
||||
dtb-$(CONFIG_SOC_THEAD) += fire-emu.dtb fire-emu-crash.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += fire-emu-soc-base.dtb fire-emu-soc-c910x4.dtb fire-emu-gpu-dpu-dsi0.dtb fire-emu-vi-dsp-vo.dtb fire-emu-vi-vp-vo.dtb
|
||||
dtb-$(CONFIG_SOC_THEAD) += fire-emu-soc-base-sec.dtb
|
||||
|
||||
@@ -523,7 +523,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
|
||||
13
arch/riscv/boot/dts/thead/fire-emu-soc-base-sec.dts
Normal file
13
arch/riscv/boot/dts/thead/fire-emu-soc-base-sec.dts
Normal file
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/* #include "fire-emu.dts" */
|
||||
#include "fire-emu-soc-base.dts"
|
||||
|
||||
&light_iopmp {
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -338,16 +338,18 @@
|
||||
clock-frequency = <100000>;
|
||||
status = "disabled";
|
||||
|
||||
es8156_audio_codec: es8156@8 {
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
};
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -488,7 +490,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
|
||||
@@ -1430,7 +1430,7 @@
|
||||
compatible = "light,light-i2s";
|
||||
reg = <0xff 0xe7034000 0x0 0x4000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audio_i2s0>;
|
||||
pinctrl-0 = <&pinctrl_light_i2s0>;
|
||||
light,mode = "i2s-master";
|
||||
light,sel = "ap_i2s";
|
||||
interrupt-parent = <&intc>;
|
||||
|
||||
@@ -687,6 +687,7 @@
|
||||
no-mmc;
|
||||
non-removable;
|
||||
io_fixed_1v8;
|
||||
rxclk-sample-delay = <80>;
|
||||
post-power-on-delay-ms = <50>;
|
||||
wprtn_ignore;
|
||||
cap-sd-highspeed;
|
||||
@@ -729,7 +730,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
sound-dai = <&light_i2s 1>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&dummy_codec 2>;
|
||||
sound-dai = <&dummy_codec>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -48,11 +48,11 @@
|
||||
sound-dai = <&light_i2s 1>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&dummy_codec 2>;
|
||||
sound-dai = <&dummy_codec>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&light_i2s {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
100
arch/riscv/boot/dts/thead/light-a-val-audio-i2s-8ch.dts
Normal file
100
arch/riscv/boot/dts/thead/light-a-val-audio-i2s-8ch.dts
Normal file
@@ -0,0 +1,100 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
||||
*/
|
||||
|
||||
#include "light-a-val-audio.dts"
|
||||
|
||||
/ {
|
||||
model = "T-HEAD Light FM Audio VAL board";
|
||||
compatible = "thead,light-val-audio-i2s-8ch", "thead,light";
|
||||
};
|
||||
|
||||
|
||||
&lightsound {
|
||||
status = "okay";
|
||||
|
||||
simple-audio-card,dai-link@1 { /* I2S - AUDIO SYS CODEC 7210*/
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
mclk-fs = <512>;
|
||||
sound-dai = <&es7210_audio_codec_adc0>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@2 { /* I2S - AUDIO SYS CODEC 7210*/
|
||||
reg = <2>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s_8ch_sd3 3>;
|
||||
};
|
||||
codec {
|
||||
mclk-fs = <512>;
|
||||
sound-dai = <&es7210_audio_codec_adc0>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@3 { /* I2S - AUDIO SYS CODEC 7210_1*/
|
||||
reg = <3>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s_8ch_sd0 0>;
|
||||
};
|
||||
codec {
|
||||
mclk-fs = <512>;
|
||||
sound-dai = <&es7210_audio_codec_adc1>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@4 { /* I2S - AUDIO SYS CODEC 7210_1*/
|
||||
reg = <4>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s_8ch_sd1 1>;
|
||||
};
|
||||
codec {
|
||||
mclk-fs = <512>;
|
||||
sound-dai = <&es7210_audio_codec_adc1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&i2s_8ch_sd0 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa4>,
|
||||
<&pinctrl_audio_i2s_8ch_sd0>,
|
||||
<&pinctrl_audiopa2>,
|
||||
<&pinctrl_audiopa3>,
|
||||
<&pinctrl_audiopa8>,
|
||||
<&pinctrl_audio_i2s_8ch_bus>;
|
||||
};
|
||||
|
||||
&i2s_8ch_sd1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa0>,
|
||||
<&pinctrl_audio_i2s_8ch_sd2>;
|
||||
};
|
||||
|
||||
&i2s_8ch_sd3 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&es7210_audio_codec_adc0 {
|
||||
status = "okay";
|
||||
channels-max = <8>;
|
||||
};
|
||||
|
||||
&es7210_audio_codec_adc1 {
|
||||
status = "okay";
|
||||
channels-max = <8>;
|
||||
};
|
||||
42
arch/riscv/boot/dts/thead/light-a-val-audio-spdif.dts
Normal file
42
arch/riscv/boot/dts/thead/light-a-val-audio-spdif.dts
Normal file
@@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
||||
*/
|
||||
|
||||
#include "light-a-val.dts"
|
||||
|
||||
&spdif0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audio_spdif0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spdif1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audio_spdif1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&lightsound {
|
||||
status = "okay";
|
||||
simple-audio-card,dai-link@0 { /* SPDIF0 */
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&spdif0>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&dummy_codec>;
|
||||
};
|
||||
};
|
||||
simple-audio-card,dai-link@1 { /* SPDIF1 */
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&spdif1>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&dummy_codec>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "light-a-val.dts"
|
||||
|
||||
&tdm_slot1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audio_tdm>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -45,19 +47,26 @@
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x42>;
|
||||
work-mode = "ES7210_TDM_1LRCK_DSPB";
|
||||
work-mode = "ES7210_TDM_1LRCK_DSPB";
|
||||
channels-max = <8>;
|
||||
sound-name-prefix = "ES7210_ADC2";
|
||||
MVDD-supply = <&soc_aud_adc_3v3_en_reg>;
|
||||
AVDD-supply = <&soc_aud_adc_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
PVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
};
|
||||
|
||||
es7210_adc3: es7210@43 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_1";
|
||||
reg = <0x43>;
|
||||
work-mode = "ES7210_TDM_1LRCK_DSPB";
|
||||
work-mode = "ES7210_TDM_1LRCK_DSPB";
|
||||
channels-max = <8>;
|
||||
sound-name-prefix = "ES7210_ADC3";
|
||||
status = "okay";
|
||||
MVDD-supply = <&soc_aud_adc_3v3_en_reg>;
|
||||
AVDD-supply = <&soc_aud_adc_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
PVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -65,8 +74,8 @@
|
||||
status = "okay";
|
||||
simple-audio-card,widgets = "Speaker", "Speaker";
|
||||
simple-audio-card,routing =
|
||||
"Speaker", "AW87519 VO",
|
||||
"AW87519 IN", "ES8156 ROUT";
|
||||
"AW87519 IN", "ES8156 ROUT",
|
||||
"Speaker", "AW87519 VO";
|
||||
simple-audio-card,aux-devs = <&audio_aw87519_pa>;
|
||||
simple-audio-card,dai-link@0 { /* I2S - AUDIO SYS CODEC 8156*/
|
||||
reg = <0>;
|
||||
@@ -82,29 +91,85 @@
|
||||
simple-audio-card,dai-link@1 { /* TDM - AUDIO SYS CODEC 7210*/
|
||||
reg = <1>;
|
||||
format = "dsp_b";
|
||||
cpu@0 {
|
||||
sound-dai = <&tdm_slot1 0>;
|
||||
cpu {
|
||||
sound-dai = <&tdm_slot1>;
|
||||
};
|
||||
cpu@1 {
|
||||
sound-dai = <&tdm_slot2 1>;
|
||||
codec {
|
||||
sound-dai = <&es7210_adc2>;
|
||||
};
|
||||
cpu@2 {
|
||||
sound-dai = <&tdm_slot3 2>;
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@2 {
|
||||
reg = <1>;
|
||||
format = "dsp_b";
|
||||
cpu {
|
||||
sound-dai = <&tdm_slot2>;
|
||||
};
|
||||
cpu@3 {
|
||||
sound-dai = <&tdm_slot4 3>;
|
||||
codec {
|
||||
sound-dai = <&es7210_adc2>;
|
||||
};
|
||||
cpu@4 {
|
||||
sound-dai = <&tdm_slot5 4>;
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@3 {
|
||||
reg = <1>;
|
||||
format = "dsp_b";
|
||||
cpu {
|
||||
sound-dai = <&tdm_slot3>;
|
||||
};
|
||||
cpu@5 {
|
||||
sound-dai = <&tdm_slot6 5>;
|
||||
codec {
|
||||
sound-dai = <&es7210_adc2>;
|
||||
};
|
||||
cpu@6 {
|
||||
sound-dai = <&tdm_slot7 6>;
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@4 {
|
||||
reg = <1>;
|
||||
format = "dsp_b";
|
||||
cpu {
|
||||
sound-dai = <&tdm_slot4>;
|
||||
};
|
||||
cpu@7 {
|
||||
sound-dai = <&tdm_slot8 7>;
|
||||
codec {
|
||||
sound-dai = <&es7210_adc2>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@5 {
|
||||
reg = <1>;
|
||||
format = "dsp_b";
|
||||
cpu {
|
||||
sound-dai = <&tdm_slot5>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_adc2>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@6 {
|
||||
reg = <1>;
|
||||
format = "dsp_b";
|
||||
cpu {
|
||||
sound-dai = <&tdm_slot6>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_adc2>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@7 {
|
||||
reg = <1>;
|
||||
format = "dsp_b";
|
||||
cpu {
|
||||
sound-dai = <&tdm_slot7>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_adc2>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@8 {
|
||||
reg = <1>;
|
||||
format = "dsp_b";
|
||||
cpu {
|
||||
sound-dai = <&tdm_slot8>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_adc2>;
|
||||
@@ -112,14 +177,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
&light_i2s {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -10,18 +10,6 @@
|
||||
compatible = "thead,light-val-audio", "thead,light";
|
||||
};
|
||||
|
||||
&audio_i2c0 {
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
sound-name-prefix = "ES7210";
|
||||
};
|
||||
};
|
||||
|
||||
&lightsound {
|
||||
status = "okay";
|
||||
simple-audio-card,widgets = "Speaker", "Speaker";
|
||||
@@ -44,22 +32,24 @@
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s3 0>;
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_audio_codec>;
|
||||
sound-dai = <&es7210_audio_codec_adc0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&light_i2s {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&es7210_audio_codec_adc0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -7,17 +7,6 @@
|
||||
|
||||
#include "light-a-val-dsi0-hdmi.dts"
|
||||
|
||||
&audio_i2c0 {
|
||||
status = "okay";
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
sound-name-prefix = "ES7210";
|
||||
};
|
||||
};
|
||||
|
||||
&lightsound {
|
||||
status = "okay";
|
||||
simple-audio-card,widgets = "Speaker", "Speaker";
|
||||
@@ -35,14 +24,15 @@
|
||||
sound-dai = <&es8156_audio_codec>;
|
||||
};
|
||||
};
|
||||
|
||||
simple-audio-card,dai-link@1 { /* I2S - AUDIO SYS CODEC 7210*/
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s3 0>;
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_audio_codec>;
|
||||
sound-dai = <&es7210_audio_codec_adc0>;
|
||||
};
|
||||
};
|
||||
simple-audio-card,dai-link@2 { /* I2S - HDMI */
|
||||
@@ -58,14 +48,17 @@
|
||||
};
|
||||
|
||||
&light_i2s {
|
||||
status = "okay";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&es7210_audio_codec_adc0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -93,18 +93,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
&audio_i2c0 {
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
sound-name-prefix = "ES7210";
|
||||
};
|
||||
};
|
||||
|
||||
&lightsound {
|
||||
status = "okay";
|
||||
simple-audio-card,widgets = "Speaker", "Speaker";
|
||||
@@ -122,31 +110,35 @@
|
||||
sound-dai = <&es8156_audio_codec>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
simple-audio-card,dai-link@1 { /* I2S - AUDIO SYS CODEC 7210*/
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s3 0>;
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_audio_codec>;
|
||||
sound-dai = <&es7210_audio_codec_adc0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
&light_i2s {
|
||||
status = "okay";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
&i2s0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&es7210_audio_codec_adc0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&qspi0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
sound-dai = <&light_i2s 1>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&dummy_codec 2>;
|
||||
sound-dai = <&dummy_codec>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -74,6 +74,26 @@
|
||||
};
|
||||
};
|
||||
|
||||
&padctrl_audiosys {
|
||||
status = "okay";
|
||||
|
||||
light-audio-padctrl {
|
||||
/*
|
||||
* Pin Configuration Node:
|
||||
* Format: <pin_id mux_node config>
|
||||
*/
|
||||
|
||||
pinctrl_audio_i2s_8ch: audio_i2s_8ch_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA0 0x2 0x008
|
||||
FM_AUDIO_IO_PA2 0x2 0x008
|
||||
FM_AUDIO_IO_PA3 0x2 0x008
|
||||
FM_AUDIO_IO_PA8 0x2 0x008
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&lightsound {
|
||||
status = "okay";
|
||||
|
||||
@@ -92,15 +112,14 @@
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s3 0>;
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_audio_codec>;
|
||||
sound-dai = <&es7210_audio_codec_adc0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
&light_i2s {
|
||||
status = "okay";
|
||||
};
|
||||
@@ -109,7 +128,11 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&es7210_audio_codec_adc0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -38,18 +38,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
&audio_i2c0 {
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
sound-name-prefix = "ES7210";
|
||||
};
|
||||
};
|
||||
|
||||
&lightsound {
|
||||
status = "okay";
|
||||
|
||||
@@ -68,10 +56,10 @@
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s3 0>;
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_audio_codec>;
|
||||
sound-dai = <&es7210_audio_codec_adc0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -85,7 +73,11 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&es7210_audio_codec_adc0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "light-a-val-dsi0-hdmi-audio.dts"
|
||||
#include "light-a-val-audio-hdmi.dts"
|
||||
|
||||
|
||||
&light_iopmp {
|
||||
status = "disabled";
|
||||
};
|
||||
&qspi1 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
@@ -179,7 +179,8 @@
|
||||
compatible = "thead,light-mbox-client";
|
||||
mbox-names = "906";
|
||||
mboxes = <&mbox_910t 2 0>;
|
||||
status = "disabled";
|
||||
audio-mbox-regmap = <&audio_mbox>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
lightsound: lightsound@1 {
|
||||
@@ -192,6 +193,20 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
light_rpmsg: light_rpmsg {
|
||||
compatible = "light,rpmsg-bus", "simple-bus";
|
||||
memory-region = <&rpmsgmem>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
rpmsg: rpmsg{
|
||||
vdev-nums = <1>;
|
||||
reg = <0x0 0x1E000000 0 0x10000>;
|
||||
compatible = "light,light-rpmsg";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
dummy_codec: dummy_codec {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "thead,light-dummy-pcm";
|
||||
@@ -263,6 +278,24 @@
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
soc_aud_adc_3v3_en_reg: soc-aud-adc-3v3-en {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "soc_aud_adc_3v3_en";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
gpio = <&pcal6408ahk_b 1 1>;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
soc_aud_dac_3v3_en_reg: soc-aud-dac-3v3-en {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "soc_aud_dac_3v3_en";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
gpio = <&pcal6408ahk_b 2 1>;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
wcn_wifi: wireless-wlan {
|
||||
compatible = "wlan-platdata";
|
||||
clock-names = "clk_wifi";
|
||||
@@ -513,7 +546,14 @@
|
||||
reg = <0x0 0x22000000 0x0 0x10000000>;
|
||||
no-map;
|
||||
};
|
||||
|
||||
audio_mem: memory@32000000 {
|
||||
reg = <0x0 0x32000000 0x0 0x6400000>;
|
||||
no-map;
|
||||
};
|
||||
rpmsgmem: memory@1E000000 {
|
||||
reg = <0x0 0x1E000000 0x0 0x10000>;
|
||||
no-map;
|
||||
};
|
||||
};
|
||||
|
||||
&adc {
|
||||
@@ -557,13 +597,51 @@
|
||||
&audio_i2c0 {
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa6>,
|
||||
<&pinctrl_audiopa7>,
|
||||
<&pinctrl_audio_i2c0>;
|
||||
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
};
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
AVDD-supply = <&soc_aud_dac_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
PVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
mclk-sclk-ratio = <4>;
|
||||
};
|
||||
|
||||
es7210_audio_codec_adc0: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
status = "disabled";
|
||||
work-mode = "ES7210_NORMAL_I2S";
|
||||
channels-max = <2>;
|
||||
mclk-sclk-ratio = <4>;
|
||||
sound-name-prefix = "ES7210_ADC0";
|
||||
MVDD-supply = <&soc_aud_adc_3v3_en_reg>;
|
||||
AVDD-supply = <&soc_aud_adc_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
PVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
};
|
||||
|
||||
es7210_audio_codec_adc1: es7210@41 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_1";
|
||||
reg = <0x41>;
|
||||
status = "disabled";
|
||||
work-mode = "ES7210_NORMAL_I2S";
|
||||
channels-max = <2>;
|
||||
mclk-sclk-ratio = <4>;
|
||||
sound-name-prefix = "ES7210_ADC1";
|
||||
MVDD-supply = <&soc_aud_adc_3v3_en_reg>;
|
||||
AVDD-supply = <&soc_aud_adc_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
PVDD-supply = <&soc_dvdd18_aon_reg>;
|
||||
};
|
||||
|
||||
audio_aw87519_pa: amp@58 {
|
||||
compatible = "awinic,aw87519_pa";
|
||||
@@ -577,6 +655,10 @@
|
||||
&audio_i2c1 {
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa13>,
|
||||
<&pinctrl_audiopa16>,
|
||||
<&pinctrl_audio_i2c1>;
|
||||
|
||||
pcal6408ahk_b: gpio@20 {
|
||||
compatible = "nxp,pcal9554b";
|
||||
@@ -733,6 +815,7 @@
|
||||
no-mmc;
|
||||
non-removable;
|
||||
io_fixed_1v8;
|
||||
rxclk-sample-delay = <80>;
|
||||
post-power-on-delay-ms = <50>;
|
||||
wprtn_ignore;
|
||||
cap-sd-highspeed;
|
||||
@@ -775,7 +858,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
@@ -850,16 +933,59 @@
|
||||
* Format: <pin_id mux_node config>
|
||||
*/
|
||||
|
||||
pinctrl_audiopa1: audiopa1_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_PA1 0x3 0x72
|
||||
>;
|
||||
pinctrl_audiopa0: audiopa0 {
|
||||
thead,pins = < FM_AUDIO_PA0 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
|
||||
pinctrl_audiopa2: audiopa2_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_PA2 0x0 0x72
|
||||
>;
|
||||
pinctrl_audiopa1: audiopa1 {
|
||||
thead,pins = < FM_AUDIO_PA1 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa2: audiopa2 {
|
||||
thead,pins = < FM_AUDIO_PA2 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa3: audiopa3 {
|
||||
thead,pins = < FM_AUDIO_PA3 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa4: audiopa4 {
|
||||
thead,pins = < FM_AUDIO_PA4 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa5: audiopa5 {
|
||||
thead,pins = < FM_AUDIO_PA5 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa6: audiopa6 {
|
||||
thead,pins = < FM_AUDIO_PA6 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa7: audiopa7 {
|
||||
thead,pins = < FM_AUDIO_PA7 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa8: audiopa8 {
|
||||
thead,pins = < FM_AUDIO_PA8 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa9: audiopa9 {
|
||||
thead,pins = < FM_AUDIO_PA9 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa10: audiopa10 {
|
||||
thead,pins = < FM_AUDIO_PA10 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa11: audiopa11 {
|
||||
thead,pins = < FM_AUDIO_PA11 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa12: audiopa12 {
|
||||
thead,pins = < FM_AUDIO_PA12 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa13: audiopa13 {
|
||||
thead,pins = < FM_AUDIO_PA13 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa14: audiopa14 {
|
||||
thead,pins = < FM_AUDIO_PA14 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa15: audiopa15 {
|
||||
thead,pins = < FM_AUDIO_PA15 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa16: audiopa16 {
|
||||
thead,pins = < FM_AUDIO_PA16 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa17: audiopa17 {
|
||||
thead,pins = < FM_AUDIO_PA17 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
|
||||
pinctrl_volume: volume_grp {
|
||||
@@ -881,10 +1007,77 @@
|
||||
* Format: <pin_id mux_node config>
|
||||
*/
|
||||
|
||||
pinctrl_audio_i2c0: audio_i2c0_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA6 LIGHT_PIN_FUNC_0 0x004
|
||||
FM_AUDIO_IO_PA7 LIGHT_PIN_FUNC_0 0x004
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2c1: audio_i2c1_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA6 0x2 0x008
|
||||
FM_AUDIO_IO_PA7 0x2 0x008
|
||||
FM_AUDIO_IO_PA13 LIGHT_PIN_FUNC_1 0x004
|
||||
FM_AUDIO_IO_PA16 LIGHT_PIN_FUNC_3 0x004
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s0: audio_i2s0_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA9 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA10 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA11 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA12 LIGHT_PIN_FUNC_0 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s1: audio_i2s1_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA14 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA15 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA17 LIGHT_PIN_FUNC_0 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s_8ch_bus: audio_i2s_8ch_bus_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA2 LIGHT_PIN_FUNC_3 0x008
|
||||
FM_AUDIO_IO_PA3 LIGHT_PIN_FUNC_3 0x008
|
||||
FM_AUDIO_IO_PA8 LIGHT_PIN_FUNC_3 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s_8ch_sd0: audio_i2s_8ch_sd0_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA4 LIGHT_PIN_FUNC_3 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s_8ch_sd1: audio_i2s_8ch_sd1_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA5 LIGHT_PIN_FUNC_3 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s_8ch_sd2: audio_i2s_8ch_sd2_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA0 LIGHT_PIN_FUNC_3 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s_8ch_sd3: audio_i2s_8ch_sd3_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA1 LIGHT_PIN_FUNC_3 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_tdm: audio_tdm_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA27 LIGHT_PIN_FUNC_1 0x007
|
||||
FM_AUDIO_IO_PA28 LIGHT_PIN_FUNC_1 0x007
|
||||
FM_AUDIO_IO_PA29 LIGHT_PIN_FUNC_1 0x000
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_spdif0: audio_spdif0_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA21 LIGHT_PIN_FUNC_1 0x000
|
||||
FM_AUDIO_IO_PA22 LIGHT_PIN_FUNC_1 0x007
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_spdif1: audio_spdif1_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA23 LIGHT_PIN_FUNC_1 0x007
|
||||
FM_AUDIO_IO_PA24 LIGHT_PIN_FUNC_1 0x000
|
||||
>;
|
||||
};
|
||||
};
|
||||
@@ -1024,6 +1217,24 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
&vvcam_sensor1 {
|
||||
sensor_name = "OV5693";
|
||||
sensor_regulators = "DOVDD18_RGB", "DVDD12_RGB", "AVDD28_RGB";
|
||||
sensor_regulator_voltage_uV = <1800000 1200000 2800000>;
|
||||
sensor_regulator_timing_us = <70 50 20>;
|
||||
sensor_rst = <&gpio1_porta 16 0>;
|
||||
sensor_pdn_delay_us = <4000>; //powerdown pin / shutdown pin actived till I2C ready
|
||||
DOVDD18_RGB-supply = <&soc_dovdd18_rgb_reg>;
|
||||
DVDD12_RGB-supply = <&soc_dvdd12_rgb_reg>;
|
||||
AVDD28_RGB-supply = <&soc_avdd28_rgb_reg>;
|
||||
i2c_reg_width = /bits/ 8 <2>;
|
||||
i2c_data_width = /bits/ 8 <1>;
|
||||
i2c_addr = /bits/ 8 <0x36>;
|
||||
i2c_bus = /bits/ 8 <3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&vvcam_sensor2 {
|
||||
sensor_name = "GC5035";
|
||||
sensor_regulators = "DOVDD18_SCAN", "DVDD12_SCAN", "AVDD28_SCAN";
|
||||
@@ -1108,6 +1319,22 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&vvcam_sensor7 {
|
||||
sensor_name = "IMX334";
|
||||
sensor_regulators = "DOVDD18_RGB", "DVDD12_RGB", "AVDD28_RGB";
|
||||
sensor_regulator_timing_us = <70 50 20>;
|
||||
sensor_rst = <&gpio1_porta 16 0>;
|
||||
sensor_pdn_delay_us = <1000>; //powerdown pin / shutdown pin actived till I2C ready
|
||||
DOVDD18_RGB-supply = <&soc_dovdd18_rgb_reg>;
|
||||
DVDD12_RGB-supply = <&soc_dvdd12_rgb_reg>;
|
||||
AVDD28_RGB-supply = <&soc_avdd28_rgb_reg>;
|
||||
i2c_reg_width = /bits/ 8 <2>;
|
||||
i2c_data_width = /bits/ 8 <1>;
|
||||
i2c_addr = /bits/ 8 <0x1a>;
|
||||
i2c_bus = /bits/ 8 <3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&video0{
|
||||
vi_mem_pool_region = <2>; // vi_mem: framebuffer, region[2]
|
||||
channel0 {
|
||||
@@ -1314,13 +1541,20 @@
|
||||
mode_idx = <0>;
|
||||
path_type = "SENSOR_1600x1200_RAW10_LINER";
|
||||
};
|
||||
sensor2 {
|
||||
subdev_name = "vivcam";
|
||||
idx = <7>; //imx334
|
||||
csi_idx = <0>; //<0>=CSI2
|
||||
mode_idx = <0>;
|
||||
path_type = "SENSOR_3840x2180_RAW12_LINER";
|
||||
};
|
||||
isp {
|
||||
subdev_name = "isp";
|
||||
idx = <1>;
|
||||
path_type = "ISP_MI_PATH_MP";
|
||||
output {
|
||||
max_width = <1920>;
|
||||
max_height = <1088>;
|
||||
max_width = <3840>;
|
||||
max_height = <2180>;
|
||||
bit_per_pixel = <16>;
|
||||
frame_count = <3>;
|
||||
};
|
||||
@@ -2173,6 +2407,44 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa9>,
|
||||
<&pinctrl_audiopa10>,
|
||||
<&pinctrl_audiopa11>,
|
||||
<&pinctrl_audiopa12>,
|
||||
<&pinctrl_audio_i2s0>;
|
||||
};
|
||||
|
||||
&i2s_8ch_sd0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa4>,
|
||||
<&pinctrl_audio_i2s_8ch_sd0>;
|
||||
};
|
||||
|
||||
&i2s_8ch_sd1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa5>,
|
||||
<&pinctrl_audio_i2s_8ch_sd1>;
|
||||
};
|
||||
|
||||
&i2s_8ch_sd2 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa0>,
|
||||
<&pinctrl_audio_i2s_8ch_sd2>,
|
||||
<&pinctrl_audiopa2>,
|
||||
<&pinctrl_audiopa3>,
|
||||
<&pinctrl_audiopa8>,
|
||||
<&pinctrl_audio_i2s_8ch_bus>;
|
||||
};
|
||||
|
||||
&i2s_8ch_sd3 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa1>,
|
||||
<&pinctrl_audio_i2s_8ch_sd3>;
|
||||
};
|
||||
|
||||
|
||||
&cpus {
|
||||
c910_0: cpu@0 {
|
||||
operating-points = <
|
||||
|
||||
@@ -582,27 +582,31 @@
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
};
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
AVDD-supply = <&soc_aud_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
PVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
};
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
sound-name-prefix = "ES7210";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
audio_aw87519_pa: amp@58 {
|
||||
compatible = "awinic,aw87519_pa";
|
||||
reg = <0x58>;
|
||||
reset-gpio = <&ao_gpio4_porta 9 0x1>;
|
||||
sound-name-prefix = "AW87519";
|
||||
status = "okay";
|
||||
};
|
||||
audio_aw87519_pa: amp@58 {
|
||||
compatible = "awinic,aw87519_pa";
|
||||
reg = <0x58>;
|
||||
reset-gpio = <&ao_gpio4_porta 9 0x1>;
|
||||
sound-name-prefix = "AW87519";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
@@ -735,6 +739,7 @@
|
||||
no-mmc;
|
||||
non-removable;
|
||||
io_fixed_1v8;
|
||||
rxclk-sample-delay = <80>;
|
||||
post-power-on-delay-ms = <50>;
|
||||
wprtn_ignore;
|
||||
cap-sd-highspeed;
|
||||
@@ -777,7 +782,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
@@ -2114,7 +2119,7 @@
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s3 0>;
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_audio_codec>;
|
||||
@@ -2144,7 +2149,7 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -590,27 +590,31 @@
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
};
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
AVDD-supply = <&soc_aud_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
PVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
};
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
sound-name-prefix = "ES7210";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
audio_aw87519_pa: amp@58 {
|
||||
compatible = "awinic,aw87519_pa";
|
||||
reg = <0x58>;
|
||||
reset-gpio = <&ao_gpio4_porta 9 0x1>;
|
||||
sound-name-prefix = "AW87519";
|
||||
status = "okay";
|
||||
};
|
||||
audio_aw87519_pa: amp@58 {
|
||||
compatible = "awinic,aw87519_pa";
|
||||
reg = <0x58>;
|
||||
reset-gpio = <&ao_gpio4_porta 9 0x1>;
|
||||
sound-name-prefix = "AW87519";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
@@ -743,6 +747,7 @@
|
||||
no-mmc;
|
||||
non-removable;
|
||||
io_fixed_1v8;
|
||||
rxclk-sample-delay = <80>;
|
||||
post-power-on-delay-ms = <50>;
|
||||
wprtn_ignore;
|
||||
cap-sd-highspeed;
|
||||
@@ -785,7 +790,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
@@ -2295,7 +2300,7 @@
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s3 0>;
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_audio_codec>;
|
||||
@@ -2325,7 +2330,7 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
2515
arch/riscv/boot/dts/thead/light-b-audio-hdmi.dts
Normal file
2515
arch/riscv/boot/dts/thead/light-b-audio-hdmi.dts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "light-b-product.dts"
|
||||
#include "light-b-audio-hdmi.dts"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -180,7 +180,8 @@
|
||||
compatible = "thead,light-mbox-client";
|
||||
mbox-names = "906";
|
||||
mboxes = <&mbox_910t 2 0>;
|
||||
status = "disabled";
|
||||
audio-mbox-regmap = <&audio_mbox>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
lightsound: lightsound@1 {
|
||||
@@ -193,6 +194,20 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
light_rpmsg: light_rpmsg {
|
||||
compatible = "light,rpmsg-bus", "simple-bus";
|
||||
memory-region = <&rpmsgmem>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
rpmsg: rpmsg{
|
||||
vdev-nums = <1>;
|
||||
reg = <0x0 0x1E000000 0 0x10000>;
|
||||
compatible = "light,light-rpmsg";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
dummy_codec: dummy_codec {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "thead,light-dummy-pcm";
|
||||
@@ -271,6 +286,8 @@
|
||||
regulator-name = "soc_aud_3v3_en";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audio_3v3_en>;
|
||||
gpio = <&ao_gpio_porta 7 1>;
|
||||
enable-active-high;
|
||||
regulator-always-on;
|
||||
@@ -281,6 +298,8 @@
|
||||
regulator-name = "soc_aud_1v8_en";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audio_1v8_en>;
|
||||
gpio = <&ao_gpio_porta 8 1>;
|
||||
enable-active-high;
|
||||
regulator-always-on;
|
||||
@@ -570,7 +589,14 @@
|
||||
reg = <0x0 0x17000000 0 0x02000000>;
|
||||
no-map;
|
||||
};
|
||||
|
||||
audio_mem: memory@32000000 {
|
||||
reg = <0x0 0x32000000 0x0 0x6400000>;
|
||||
no-map;
|
||||
};
|
||||
rpmsgmem: memory@1E000000 {
|
||||
reg = <0x0 0x1E000000 0x0 0x10000>;
|
||||
no-map;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -601,24 +627,41 @@
|
||||
&audio_i2c0 {
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa6>,
|
||||
<&pinctrl_audiopa7>,
|
||||
<&pinctrl_audio_i2c0>;
|
||||
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
};
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
AVDD-supply = <&soc_aud_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
PVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
mclk-sclk-ratio = <4>;
|
||||
};
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
sound-name-prefix = "ES7210";
|
||||
work-mode = "ES7210_NORMAL_I2S";
|
||||
channels-max = <2>;
|
||||
mclk-sclk-ratio = <4>;
|
||||
sound-name-prefix = "ES7210_ADC0";
|
||||
MVDD-supply = <&soc_aud_3v3_en_reg>;
|
||||
AVDD-supply = <&soc_aud_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
PVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
};
|
||||
|
||||
audio_aw87519_pa: amp@58 {
|
||||
compatible = "awinic,aw87519_pa";
|
||||
reg = <0x58>;
|
||||
pingctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audio_pa_rst0>;
|
||||
reset-gpio = <&ao_gpio4_porta 9 0x1>;
|
||||
sound-name-prefix = "AW87519";
|
||||
status = "okay";
|
||||
@@ -754,6 +797,7 @@
|
||||
no-mmc;
|
||||
non-removable;
|
||||
io_fixed_1v8;
|
||||
rxclk-sample-delay = <80>;
|
||||
post-power-on-delay-ms = <50>;
|
||||
wprtn_ignore;
|
||||
cap-sd-highspeed;
|
||||
@@ -796,7 +840,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
@@ -870,16 +914,47 @@
|
||||
* Format: <pin_id mux_node config>
|
||||
*/
|
||||
|
||||
pinctrl_audiopa1: audiopa1_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_PA1 0x3 0x72
|
||||
>;
|
||||
pinctrl_audiopa0: audiopa0 {
|
||||
thead,pins = < FM_AUDIO_PA0 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
|
||||
pinctrl_audiopa2: audiopa2_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_PA2 0x0 0x72
|
||||
>;
|
||||
pinctrl_audiopa1: audiopa1 {
|
||||
thead,pins = < FM_AUDIO_PA1 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa2: audiopa2 {
|
||||
thead,pins = < FM_AUDIO_PA2 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa3: audiopa3 {
|
||||
thead,pins = < FM_AUDIO_PA3 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa6: audiopa6 {
|
||||
thead,pins = < FM_AUDIO_PA6 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa7: audiopa7 {
|
||||
thead,pins = < FM_AUDIO_PA7 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa8: audiopa8 {
|
||||
thead,pins = < FM_AUDIO_PA8 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audio_pa_rst0: audio_pa_rst0 {
|
||||
thead,pins = < FM_AUDIO_PA9 LIGHT_PIN_FUNC_3 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa13: audiopa13 {
|
||||
thead,pins = < FM_AUDIO_PA13 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa14: audiopa14 {
|
||||
thead,pins = < FM_AUDIO_PA14 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa15: audiopa15 {
|
||||
thead,pins = < FM_AUDIO_PA15 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa17: audiopa17 {
|
||||
thead,pins = < FM_AUDIO_PA17 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audio_3v3_en: audio_3v3_en {
|
||||
thead,pins = < FM_AOGPIO_7 LIGHT_PIN_FUNC_3 0x008 >;
|
||||
};
|
||||
pinctrl_audio_1v8_en: audio_1v8_en {
|
||||
thead,pins = < FM_AOGPIO_8 LIGHT_PIN_FUNC_3 0x008 >;
|
||||
};
|
||||
|
||||
pinctrl_volume: volume_grp {
|
||||
@@ -891,6 +966,51 @@
|
||||
};
|
||||
};
|
||||
|
||||
&padctrl_audiosys {
|
||||
|
||||
status = "okay";
|
||||
|
||||
light-audio-padctrl {
|
||||
/*
|
||||
* Pin Configuration Node:
|
||||
* Format: <pin_id mux_node config>
|
||||
*/
|
||||
|
||||
pinctrl_audio_i2c0: audio_i2c0_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA6 LIGHT_PIN_FUNC_0 0x004
|
||||
FM_AUDIO_IO_PA7 LIGHT_PIN_FUNC_0 0x004
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s1: audio_i2s1_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA13 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA14 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA15 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA17 LIGHT_PIN_FUNC_0 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s_8ch_bus: audio_i2s_8ch_bus_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA2 LIGHT_PIN_FUNC_3 0x008
|
||||
FM_AUDIO_IO_PA3 LIGHT_PIN_FUNC_3 0x008
|
||||
FM_AUDIO_IO_PA8 LIGHT_PIN_FUNC_3 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s_8ch_sd2: audio_i2s_8ch_sd2_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA0 LIGHT_PIN_FUNC_3 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s_8ch_sd3: audio_i2s_8ch_sd3_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA1 LIGHT_PIN_FUNC_3 0x008
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
&i2c0 {
|
||||
clock-frequency = <400000>;
|
||||
status = "okay";
|
||||
@@ -1004,30 +1124,21 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/*
|
||||
&vvcam_sensor0 {
|
||||
sensor_name = "IMX334";
|
||||
sensor_regulators = "DOVDD18_RGB", "DVDD12_RGB", "AVDD28_RGB";
|
||||
sensor_regulator_timing_us = <70 50 20>;
|
||||
sensor_rst = <&gpio1_porta 16 0>;
|
||||
sensor_pdn_delay_us = <1000>; //powerdown pin / shutdown pin actived till I2C ready
|
||||
DOVDD18_RGB-supply = <&soc_dovdd18_rgb_reg>;
|
||||
DVDD12_RGB-supply = <&soc_dvdd12_rgb_reg>;
|
||||
AVDD28_RGB-supply = <&soc_avdd28_rgb_reg>;
|
||||
&vvcam_sensor1 {
|
||||
sensor_name = "OV5693";
|
||||
sensor_regulators = "DOVDD18_RGB", "DVDD12_RGB", "AVDD28_RGB";
|
||||
sensor_regulator_voltage_uV = <1800000 1200000 2800000>;
|
||||
sensor_regulator_timing_us = <70 50 20>;
|
||||
sensor_rst = <&gpio1_porta 16 0>;
|
||||
sensor_pdn_delay_us = <4000>; //powerdown pin / shutdown pin actived till I2C ready
|
||||
DOVDD18_RGB-supply = <&soc_dovdd18_rgb_reg>;
|
||||
DVDD12_RGB-supply = <&soc_dvdd12_rgb_reg>;
|
||||
AVDD28_RGB-supply = <&soc_avdd28_rgb_reg>;
|
||||
i2c_reg_width = /bits/ 8 <2>;
|
||||
i2c_data_width = /bits/ 8 <1>;
|
||||
i2c_addr = /bits/ 8 <0x1a>;
|
||||
i2c_bus = /bits/ 8 <3>;
|
||||
status = "okay";
|
||||
};
|
||||
*/
|
||||
|
||||
&vvcam_sensor1 {
|
||||
sensor_name = "OV5693";
|
||||
i2c_bus = /bits/ 8 <3>;
|
||||
i2c_reg_width = /bits/ 8 <1>;
|
||||
i2c_data_width = /bits/ 8 <1>;
|
||||
status = "disabled";
|
||||
i2c_addr = /bits/ 8 <0x36>;
|
||||
i2c_bus = /bits/ 8 <3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&vvcam_sensor2 {
|
||||
@@ -1112,6 +1223,22 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&vvcam_sensor7 {
|
||||
sensor_name = "IMX334";
|
||||
sensor_regulators = "DOVDD18_RGB", "DVDD12_RGB", "AVDD28_RGB";
|
||||
sensor_regulator_timing_us = <70 50 20>;
|
||||
sensor_rst = <&gpio1_porta 16 0>;
|
||||
sensor_pdn_delay_us = <1000>; //powerdown pin / shutdown pin actived till I2C ready
|
||||
DOVDD18_RGB-supply = <&soc_dovdd18_rgb_reg>;
|
||||
DVDD12_RGB-supply = <&soc_dvdd12_rgb_reg>;
|
||||
AVDD28_RGB-supply = <&soc_avdd28_rgb_reg>;
|
||||
i2c_reg_width = /bits/ 8 <2>;
|
||||
i2c_data_width = /bits/ 8 <1>;
|
||||
i2c_addr = /bits/ 8 <0x1a>;
|
||||
i2c_bus = /bits/ 8 <3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&video0{
|
||||
vi_mem_pool_region = <2>; // vi_mem: framebuffer, region[2]
|
||||
channel0 {
|
||||
@@ -1318,13 +1445,20 @@
|
||||
mode_idx = <0>;
|
||||
path_type = "SENSOR_1600x1200_RAW10_LINER";
|
||||
};
|
||||
sensor2 {
|
||||
subdev_name = "vivcam";
|
||||
idx = <7>; //imx334
|
||||
csi_idx = <0>; //<0>=CSI2
|
||||
mode_idx = <0>;
|
||||
path_type = "SENSOR_3840x2180_RAW12_LINER";
|
||||
};
|
||||
isp {
|
||||
subdev_name = "isp";
|
||||
idx = <1>;
|
||||
path_type = "ISP_MI_PATH_MP";
|
||||
output {
|
||||
max_width = <1920>;
|
||||
max_height = <1088>;
|
||||
max_width = <3840>;
|
||||
max_height = <2180>;
|
||||
bit_per_pixel = <16>;
|
||||
frame_count = <3>;
|
||||
};
|
||||
@@ -2336,7 +2470,7 @@
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s3 0>;
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_audio_codec>;
|
||||
@@ -2364,10 +2498,29 @@
|
||||
|
||||
&i2s1 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa13>,
|
||||
<&pinctrl_audiopa14>,
|
||||
<&pinctrl_audiopa15>,
|
||||
<&pinctrl_audiopa17>,
|
||||
<&pinctrl_audio_i2s1>;
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa0>,
|
||||
<&pinctrl_audio_i2s_8ch_sd2>,
|
||||
<&pinctrl_audiopa2>,
|
||||
<&pinctrl_audiopa3>,
|
||||
<&pinctrl_audiopa8>,
|
||||
<&pinctrl_audio_i2s_8ch_bus>;
|
||||
};
|
||||
|
||||
&i2s_8ch_sd3 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa1>,
|
||||
<&pinctrl_audio_i2s_8ch_sd3>;
|
||||
};
|
||||
|
||||
&cpus {
|
||||
|
||||
@@ -570,27 +570,34 @@
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
};
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
AVDD-supply = <&soc_aud_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
PVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
};
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
sound-name-prefix = "ES7210";
|
||||
MVDD-supply = <&soc_aud_3v3_en_reg>;
|
||||
AVDD-supply = <&soc_aud_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
PVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
};
|
||||
|
||||
audio_aw87519_pa: amp@58 {
|
||||
compatible = "awinic,aw87519_pa";
|
||||
reg = <0x58>;
|
||||
reset-gpio = <&ao_gpio4_porta 9 0x1>;
|
||||
sound-name-prefix = "AW87519";
|
||||
status = "okay";
|
||||
};
|
||||
audio_aw87519_pa: amp@58 {
|
||||
compatible = "awinic,aw87519_pa";
|
||||
reg = <0x58>;
|
||||
reset-gpio = <&ao_gpio4_porta 9 0x1>;
|
||||
sound-name-prefix = "AW87519";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
@@ -723,6 +730,7 @@
|
||||
no-mmc;
|
||||
non-removable;
|
||||
io_fixed_1v8;
|
||||
rxclk-sample-delay = <80>;
|
||||
post-power-on-delay-ms = <50>;
|
||||
wprtn_ignore;
|
||||
cap-sd-highspeed;
|
||||
@@ -765,7 +773,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
@@ -2272,7 +2280,7 @@
|
||||
reg = <1>;
|
||||
format = "i2s";
|
||||
cpu {
|
||||
sound-dai = <&i2s3 0>;
|
||||
sound-dai = <&i2s_8ch_sd2 2>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&es7210_audio_codec>;
|
||||
@@ -2302,7 +2310,7 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
&i2s_8ch_sd2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -343,6 +343,7 @@
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
@@ -350,6 +351,7 @@
|
||||
compatible = "MicArray_0";
|
||||
reg = <0x40>;
|
||||
sound-name-prefix = "ES7210";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
audio_aw87519_pa: amp@58 {
|
||||
@@ -492,6 +494,7 @@
|
||||
no-mmc;
|
||||
non-removable;
|
||||
io_fixed_1v8;
|
||||
rxclk-sample-delay = <80>;
|
||||
post-power-on-delay-ms = <50>;
|
||||
wprtn_ignore;
|
||||
cap-sd-highspeed;
|
||||
@@ -534,7 +537,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
@@ -866,22 +869,6 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&light_i2s {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&khvhost {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -1299,7 +1299,7 @@
|
||||
compatible = "light,light-i2s";
|
||||
reg = <0xff 0xe7034000 0x0 0x4000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audio_i2s0>;
|
||||
pinctrl-0 = <&pinctrl_light_i2s0>;
|
||||
light,mode = "i2s-master";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <70>;
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
sound-dai = <&light_i2s 0>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&dummy_codec 2>;
|
||||
sound-dai = <&dummy_codec>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
sound-dai = <&light_i2s 1>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&dummy_codec 2>;
|
||||
sound-dai = <&dummy_codec>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -172,7 +172,8 @@
|
||||
compatible = "thead,light-mbox-client";
|
||||
mbox-names = "906";
|
||||
mboxes = <&mbox_910t 2 0>;
|
||||
status = "disabled";
|
||||
audio-mbox-regmap = <&audio_mbox>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
lightsound: lightsound@1 {
|
||||
@@ -185,6 +186,20 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
light_rpmsg: light_rpmsg {
|
||||
compatible = "light,rpmsg-bus", "simple-bus";
|
||||
memory-region = <&rpmsgmem>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
rpmsg: rpmsg{
|
||||
vdev-nums = <1>;
|
||||
reg = <0x0 0x1E000000 0 0x10000>;
|
||||
compatible = "light,light-rpmsg";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
dummy_codec: dummy_codec {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "thead,light-dummy-pcm";
|
||||
@@ -367,6 +382,7 @@
|
||||
regulator-min-microvolt = <2800000>;
|
||||
regulator-max-microvolt = <2800000>;
|
||||
gpio = <&pcal6408ahk_b 1 1>;
|
||||
regulator-always-on;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
@@ -376,6 +392,7 @@
|
||||
regulator-min-microvolt = <2800000>;
|
||||
regulator-max-microvolt = <2800000>;
|
||||
gpio = <&pcal6408ahk_b 2 1>;
|
||||
regulator-always-on;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
@@ -385,6 +402,7 @@
|
||||
regulator-min-microvolt = <2800000>;
|
||||
regulator-max-microvolt = <2800000>;
|
||||
gpio = <&pcal6408ahk_b 0 1>;
|
||||
regulator-always-on;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
@@ -642,6 +660,14 @@
|
||||
reg = <0x0 0x17000000 0 0x02000000>;
|
||||
no-map;
|
||||
};
|
||||
audio_mem: memory@32000000 {
|
||||
reg = <0x0 0x32000000 0x0 0x6400000>;
|
||||
no-map;
|
||||
};
|
||||
rpmsgmem: memory@1E000000 {
|
||||
reg = <0x0 0x1E000000 0x0 0x10000>;
|
||||
no-map;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -654,12 +680,19 @@
|
||||
&audio_i2c0 {
|
||||
clock-frequency = <100000>;
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa29>,
|
||||
<&pinctrl_audiopa30>,
|
||||
<&pinctrl_audio_i2c0>;
|
||||
|
||||
es8156_audio_codec: es8156@8 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "everest,es8156";
|
||||
reg = <0x08>;
|
||||
sound-name-prefix = "ES8156";
|
||||
AVDD-supply = <&soc_aud_3v3_en_reg>;
|
||||
DVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
PVDD-supply = <&soc_aud_1v8_en_reg>;
|
||||
};
|
||||
|
||||
es7210_audio_codec: es7210@40 {
|
||||
@@ -882,7 +915,7 @@
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_audio_i2s0: i2s0grp {
|
||||
pinctrl_light_i2s0: i2s0grp {
|
||||
thead,pins = <
|
||||
FM_QSPI0_SCLK 0x2 0x208
|
||||
FM_QSPI0_CSN0 0x2 0x238
|
||||
@@ -970,10 +1003,87 @@
|
||||
FM_AUDIO_PA2 0x0 0x72
|
||||
>;
|
||||
};
|
||||
pinctrl_audiopa6: audiopa6 {
|
||||
thead,pins = < FM_AUDIO_PA6 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa7: audiopa7 {
|
||||
thead,pins = < FM_AUDIO_PA7 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa14: audiopa14 {
|
||||
thead,pins = < FM_AUDIO_PA14 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa15: audiopa15 {
|
||||
thead,pins = < FM_AUDIO_PA15 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa16: audiopa16 {
|
||||
thead,pins = < FM_AUDIO_PA16 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa17: audiopa17 {
|
||||
thead,pins = < FM_AUDIO_PA17 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa18: audiopa18 {
|
||||
thead,pins = < FM_AOGPIO_7 LIGHT_PIN_FUNC_1 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa19: audiopa19 {
|
||||
thead,pins = < FM_AOGPIO_8 LIGHT_PIN_FUNC_1 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa21: audiopa21 {
|
||||
thead,pins = < FM_AOGPIO_10 LIGHT_PIN_FUNC_1 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa22: audiopa22 {
|
||||
thead,pins = < FM_AOGPIO_11 LIGHT_PIN_FUNC_1 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa29: audiopa29 {
|
||||
thead,pins = < FM_AUDIO_PA29 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
pinctrl_audiopa30: audiopa30 {
|
||||
thead,pins = < FM_AUDIO_PA30 LIGHT_PIN_FUNC_0 0x000 >;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
&padctrl_audiosys {
|
||||
|
||||
status = "okay";
|
||||
|
||||
light-audio-padctrl {
|
||||
/*
|
||||
* Pin Configuration Node:
|
||||
* Format: <pin_id mux_node config>
|
||||
*/
|
||||
|
||||
pinctrl_audio_i2c0: audio_i2c0_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA29 LIGHT_PIN_FUNC_2 0x004
|
||||
FM_AUDIO_IO_PA30 LIGHT_PIN_FUNC_2 0x004
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2c1: audio_i2c1_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA6 LIGHT_PIN_FUNC_2 0x004
|
||||
FM_AUDIO_IO_PA7 LIGHT_PIN_FUNC_2 0x004
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s1: audio_i2s1_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA14 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA15 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA16 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA17 LIGHT_PIN_FUNC_0 0x008
|
||||
>;
|
||||
};
|
||||
pinctrl_audio_i2s2: audio_i2s2_grp {
|
||||
thead,pins = <
|
||||
FM_AUDIO_IO_PA18 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA19 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA21 LIGHT_PIN_FUNC_0 0x008
|
||||
FM_AUDIO_IO_PA22 LIGHT_PIN_FUNC_0 0x008
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
clock-frequency = <400000>;
|
||||
status = "okay";
|
||||
@@ -1134,6 +1244,24 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&vvcam_sensor3 {//cam3 csi0 modified
|
||||
sensor_name = "OV5693";
|
||||
sensor_regulators = "soc_dovdd18_rgb", "soc_dvdd12_rgb", "soc_avdd28_rgb";
|
||||
sensor_regulator_voltage_uV = <1800000 1200000 2800000>;
|
||||
sensor_regulator_timing_us = <70 50 20>;
|
||||
sensor_pdn = <&gpio1_porta 28 0>; //powerdown pin / shutdown pin
|
||||
sensor_rst = <&pcal6408ahk_c 1 0>;
|
||||
sensor_pdn_delay_us = <4000>; //powerdown pin / shutdown pin actived till I2C ready
|
||||
DOVDD18_RGB-supply = <&soc_dovdd18_rgb_reg>;
|
||||
DVDD12_RGB-supply = <&soc_dvdd12_rgb_reg>;
|
||||
AVDD28_RGB-supply = <&soc_avdd28_rgb_reg>;
|
||||
i2c_reg_width = /bits/ 8 <2>;
|
||||
i2c_data_width = /bits/ 8 <1>;
|
||||
i2c_addr = /bits/ 8 <0x36>;
|
||||
i2c_bus = /bits/ 8 <0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&video2 {
|
||||
vi_mem_pool_region = <0>; // vi_mem: framebuffer, region[0]
|
||||
status = "okay";
|
||||
@@ -1142,11 +1270,18 @@
|
||||
status = "okay";
|
||||
sensor0 {
|
||||
subdev_name = "vivcam";
|
||||
idx = <0>;
|
||||
idx = <0>;
|
||||
csi_idx = <0>;
|
||||
mode_idx = <0>;
|
||||
path_type = "SENSOR_VGA_RAW12_LINER";
|
||||
};
|
||||
sensor1 {
|
||||
subdev_name = "vivcam";
|
||||
idx = <3>;
|
||||
csi_idx = <0>;
|
||||
mode_idx = <1>;
|
||||
path_type = "SENSOR_2592x1944_LINER";
|
||||
};
|
||||
dma {
|
||||
subdev_name = "vipre";
|
||||
idx = <0>;
|
||||
@@ -1157,8 +1292,8 @@
|
||||
idx = <1>;
|
||||
path_type = "ISP_MI_PATH_MP";
|
||||
output {
|
||||
max_width = <1920>;
|
||||
max_height = <1088>;
|
||||
max_width = <2600>;
|
||||
max_height = <2000>;
|
||||
bit_per_pixel = <12>;
|
||||
frame_count = <3>;
|
||||
};
|
||||
@@ -1179,6 +1314,13 @@
|
||||
path_type = "SENSOR_VGA_RAW12_LINER";
|
||||
|
||||
};
|
||||
sensor1 {
|
||||
subdev_name = "vivcam";
|
||||
idx = <3>;
|
||||
csi_idx = <0>;
|
||||
mode_idx = <1>;
|
||||
path_type = "SENSOR_2592x1944_LINER";
|
||||
};
|
||||
dma {
|
||||
subdev_name = "vipre";
|
||||
idx = <0>;
|
||||
@@ -1316,15 +1458,22 @@
|
||||
status = "okay";
|
||||
sensor0 {
|
||||
subdev_name = "vivcam";
|
||||
idx = <2>;
|
||||
csi_idx = <1>; //csi_b
|
||||
idx = <0>;
|
||||
csi_idx = <0>;
|
||||
mode_idx = <0>;
|
||||
path_type = "SENSOR_1080X1280_30FPS_RAW10_LINER";
|
||||
path_type = "SENSOR_VGA_RAW12_LINER";
|
||||
};
|
||||
sensor1 {
|
||||
subdev_name = "vivcam";
|
||||
idx = <3>;
|
||||
csi_idx = <0>;
|
||||
mode_idx = <1>;
|
||||
path_type = "SENSOR_2592x1944_LINER";
|
||||
};
|
||||
dma {
|
||||
subdev_name = "vipre";
|
||||
idx = <0>;
|
||||
path_type = "VIPRE_CSI1_DDR";
|
||||
path_type = "VIPRE_CSI0_DDR";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1438,14 +1587,22 @@
|
||||
&i2s1 {
|
||||
status = "okay";
|
||||
dmas = <&dmac2 11>, <&dmac2 10>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa14>,
|
||||
<&pinctrl_audiopa15>,
|
||||
<&pinctrl_audiopa16>,
|
||||
<&pinctrl_audiopa17>,
|
||||
<&pinctrl_audio_i2s1>;
|
||||
};
|
||||
|
||||
&i2s2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s3 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audiopa18>,
|
||||
<&pinctrl_audiopa19>,
|
||||
<&pinctrl_audiopa21>,
|
||||
<&pinctrl_audiopa22>,
|
||||
<&pinctrl_audio_i2s2>;
|
||||
};
|
||||
|
||||
&usb_1 {
|
||||
|
||||
@@ -11,3 +11,8 @@
|
||||
&light_iopmp {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&qspi1 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
};
|
||||
|
||||
&cmamem {
|
||||
alloc-ranges = <0x1 0xe4000000 0 0x14000000>; // [0x1E400_0000 ~ 0x1F800_0000]
|
||||
alloc-ranges = <0 0xe4000000 0 0x14000000>; // [0x0E400_0000 ~ 0x0F800_0000]
|
||||
};
|
||||
|
||||
@@ -199,6 +199,12 @@
|
||||
csi_idx = <0xff>;
|
||||
path_type = "SENSOR_VGA_RAW10_LINER";
|
||||
};
|
||||
sensor2 {
|
||||
subdev_name = "vivcam";
|
||||
idx = <0xff>; // invalid
|
||||
csi_idx = <0xff>;
|
||||
path_type = "SENSOR_VGA_RAW10_LINER";
|
||||
};
|
||||
dma {
|
||||
subdev_name = "vipre";
|
||||
idx = <0>;
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
#include <dt-bindings/pinctrl/light-fm-right-pinctrl.h>
|
||||
#include <dt-bindings/pinctrl/light-fm-aon-pinctrl.h>
|
||||
#include <dt-bindings/pinctrl/light-fm-audio-pinctrl.h>
|
||||
#include <dt-bindings/pinctrl/light-fm-pinctrl-def.h>
|
||||
#include <dt-bindings/clock/light-fm-ap-clock.h>
|
||||
#include <dt-bindings/clock/light-vpsys.h>
|
||||
#include <dt-bindings/clock/light-vosys.h>
|
||||
#include <dt-bindings/clock/light-visys.h>
|
||||
#include <dt-bindings/clock/light-dspsys.h>
|
||||
#include <dt-bindings/clock/light-audiosys.h>
|
||||
#include <dt-bindings/firmware/thead/rsrc.h>
|
||||
#include <dt-bindings/soc/thead,light-iopmp.h>
|
||||
#include <dt-bindings/thermal/thermal.h>
|
||||
@@ -35,7 +37,7 @@
|
||||
i2c3 = &i2c3;
|
||||
i2c4 = &i2c4;
|
||||
audio_i2c0 = &audio_i2c0;
|
||||
audio_i2c1 = &audio_i2c1;
|
||||
audio_i2c1 = &audio_i2c1;
|
||||
mmc0 = &emmc;
|
||||
mmc1 = &sdhci0;
|
||||
serial0 = &uart0;
|
||||
@@ -56,6 +58,7 @@
|
||||
vivcam4 = &vvcam_sensor4;
|
||||
vivcam5 = &vvcam_sensor5;
|
||||
vivcam6 = &vvcam_sensor6;
|
||||
vivcam7 = &vvcam_sensor7;
|
||||
|
||||
viv_video0 = &video0;
|
||||
viv_video1 = &video1;
|
||||
@@ -95,11 +98,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
aon_iram: aon-iram@ffffef8000 {
|
||||
compatible = "syscon";
|
||||
reg = <0xff 0xffef8000 0x0 0x10000>;
|
||||
};
|
||||
|
||||
aon_iram: aon-iram@ffffef8000 {
|
||||
compatible = "syscon";
|
||||
reg = <0xff 0xffef8000 0x0 0x10000>;
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
cpu-thermal-zone {
|
||||
@@ -641,6 +643,12 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
audio_mbox: audio_mbox@0xffefc48000 {
|
||||
compatible = "thead,light-audio-mbox-reg", "syscon";
|
||||
reg = <0xff 0xefc48000 0x0 0x1000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
nvmem_controller: efuse@ffff210000 {
|
||||
compatible = "thead,light-fm-efuse", "syscon";
|
||||
reg = <0xff 0xff210000 0x0 0x10000>;
|
||||
@@ -1261,6 +1269,13 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
vpsys_rst: vpsys-reset-controller@ffecc30000 {
|
||||
compatible = "thead,light-vpsys-reset-src","syscon";
|
||||
reg = <0xff 0xecc30000 0x0 0x1000>;
|
||||
#reset-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sys_reg: sys_reg@ffef010100 {
|
||||
compatible = "thead,light_sys_reg";
|
||||
reg = <0xff 0xef010100 0x0 0x100>;
|
||||
@@ -1413,7 +1428,8 @@
|
||||
clock-names = "pclk", "aclk";
|
||||
vha_clk_rate = <1000000000>;
|
||||
ldo_vha-supply = <&npu>;
|
||||
dma-mask = <0xf 0xffffffff>;
|
||||
dma-mask = <0xff 0xffffffff>;
|
||||
resets = <&rst LIGHT_RESET_NPU>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -1442,6 +1458,7 @@
|
||||
clocks = <&vpsys_clk_gate LIGHT_VPSYS_FCE_ACLK>,
|
||||
<&vpsys_clk_gate LIGHT_VPSYS_FCE_PCLK>;
|
||||
clock-names = "aclk", "pclk";
|
||||
resets = <&vpsys_rst LIGHT_RESET_FCE>;
|
||||
dma-mask = <0xf 0xffffffff>;
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -1491,7 +1508,7 @@
|
||||
compatible = "light,light-i2s";
|
||||
reg = <0xff 0xe7034000 0x0 0x4000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_audio_i2s0>;
|
||||
pinctrl-0 = <&pinctrl_light_i2s0>;
|
||||
light,mode = "i2s-master";
|
||||
light,sel = "ap_i2s";
|
||||
interrupt-parent = <&intc>;
|
||||
@@ -1516,7 +1533,7 @@
|
||||
light,sel = "i2s0";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <174>;
|
||||
dmas = <&dmac2 9>, <&dmac2 16>;
|
||||
dmas = <&dmac2 9>, <&dmac2 8>;
|
||||
dma-names = "tx", "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
@@ -1565,16 +1582,74 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
i2s3: audio_i2s3@0xffcb017000 {
|
||||
i2s_8ch_sd0: audio_i2s_8ch_sd0@0xffcb017000 {
|
||||
#sound-dai-cells = <1>;
|
||||
compatible = "light,light-i2s";
|
||||
compatible = "light,light-i2s-8ch";
|
||||
reg = <0xff 0xcb017000 0x0 0x1000>;
|
||||
audio-cpr-regmap = <&audio_cpr>;
|
||||
pinctrl-names = "default";
|
||||
light,mode = "i2s-master";
|
||||
light,sel = "i2s3";
|
||||
light,sel = "i2s_8ch_sd0";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <177>;
|
||||
dmas = <&dmac2 14>, <&dmac2 16>;
|
||||
dmas = <&dmac2 36>, <&dmac2 14>;
|
||||
dma-names = "tx", "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
i2s_8ch_sd1: audio_i2s_8ch_sd1@0xffcb017000 {
|
||||
#sound-dai-cells = <1>;
|
||||
compatible = "light,light-i2s-8ch";
|
||||
reg = <0xff 0xcb017000 0x0 0x1000>;
|
||||
audio-cpr-regmap = <&audio_cpr>;
|
||||
pinctrl-names = "default";
|
||||
light,mode = "i2s-master";
|
||||
light,sel = "i2s_8ch_sd1";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <177>;
|
||||
dmas = <&dmac2 37>, <&dmac2 15>;
|
||||
dma-names = "tx", "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
i2s_8ch_sd2: audio_i2s_8ch_sd2@0xffcb017000 {
|
||||
#sound-dai-cells = <1>;
|
||||
compatible = "light,light-i2s-8ch";
|
||||
reg = <0xff 0xcb017000 0x0 0x1000>;
|
||||
audio-cpr-regmap = <&audio_cpr>;
|
||||
pinctrl-names = "default";
|
||||
light,mode = "i2s-master";
|
||||
light,sel = "i2s_8ch_sd2";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <177>;
|
||||
dmas = <&dmac2 38>, <&dmac2 16>;
|
||||
dma-names = "tx", "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
i2s_8ch_sd3: audio_i2s_8ch_sd3@0xffcb017000 {
|
||||
#sound-dai-cells = <1>;
|
||||
compatible = "light,light-i2s-8ch";
|
||||
reg = <0xff 0xcb017000 0x0 0x1000>;
|
||||
audio-cpr-regmap = <&audio_cpr>;
|
||||
pinctrl-names = "default";
|
||||
light,mode = "i2s-master";
|
||||
light,sel = "i2s_8ch_sd3";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <177>;
|
||||
dmas = <&dmac2 39>, <&dmac2 17>;
|
||||
dma-names = "tx", "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
@@ -1584,7 +1659,7 @@
|
||||
};
|
||||
|
||||
tdm_slot1: audio_tdm_slot1@0xffcb012000 {
|
||||
#sound-dai-cells = <1>;
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-tdm";
|
||||
reg = <0xff 0xcb012000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
@@ -1599,13 +1674,13 @@
|
||||
dma-names = "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_TDM>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
tdm_slot2: audio_tdm_slot2@0xffcb012000 {
|
||||
#sound-dai-cells = <1>;
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-tdm";
|
||||
reg = <0xff 0xcb012000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
@@ -1620,13 +1695,13 @@
|
||||
dma-names = "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_TDM>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
tdm_slot3: audio_tdm_slot3@0xffcb012000 {
|
||||
#sound-dai-cells = <1>;
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-tdm";
|
||||
reg = <0xff 0xcb012000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
@@ -1641,13 +1716,13 @@
|
||||
dma-names = "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_TDM>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
tdm_slot4: audio_tdm_slot4@0xffcb012000 {
|
||||
#sound-dai-cells = <1>;
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-tdm";
|
||||
reg = <0xff 0xcb012000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
@@ -1662,13 +1737,13 @@
|
||||
dma-names = "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_TDM>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
tdm_slot5: audio_tdm_slot5@0xffcb012000 {
|
||||
#sound-dai-cells = <1>;
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-tdm";
|
||||
reg = <0xff 0xcb012000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
@@ -1683,13 +1758,13 @@
|
||||
dma-names = "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_TDM>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
tdm_slot6: audio_tdm_slot6@0xffcb012000 {
|
||||
#sound-dai-cells = <1>;
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-tdm";
|
||||
reg = <0xff 0xcb012000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
@@ -1704,13 +1779,13 @@
|
||||
dma-names = "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_TDM>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
tdm_slot7: audio_tdm_slot7@0xffcb012000 {
|
||||
#sound-dai-cells = <1>;
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-tdm";
|
||||
reg = <0xff 0xcb012000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
@@ -1725,13 +1800,13 @@
|
||||
dma-names = "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_TDM>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
tdm_slot8: audio_tdm_slot8@0xffcb012000 {
|
||||
#sound-dai-cells = <1>;
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-tdm";
|
||||
reg = <0xff 0xcb012000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
@@ -1746,7 +1821,43 @@
|
||||
dma-names = "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_TDM>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spdif0: audio_spdif0@0xffcb018000 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-spdif";
|
||||
reg = <0xff 0xcb018000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
audio-cpr-regmap = <&audio_cpr>;
|
||||
pinctrl-names = "default";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <179>;
|
||||
dmas = <&dmac2 25>, <&dmac2 24>;
|
||||
dma-names = "tx", "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_SPDIF0>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spdif1: audio_spdif1@0xffcb019000 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "light,light-spdif";
|
||||
reg = <0xff 0xcb019000 0x0 0x1000>;
|
||||
audio-pin-regmap = <&audio_ioctrl>;
|
||||
audio-cpr-regmap = <&audio_cpr>;
|
||||
pinctrl-names = "default";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <180>;
|
||||
dmas = <&dmac2 27>, <&dmac2 26>;
|
||||
dma-names = "tx", "rx";
|
||||
light,dma_maxburst = <4>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&audiosys_clk_gate LIGHT_CLKGEN_AUDIO_SPDIF1>;
|
||||
clock-names = "pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -1770,6 +1881,10 @@
|
||||
interrupts = <44>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-frequency = <100000>;
|
||||
i2c_mode = "dma";
|
||||
dmas = <&dmac0 12>, <&dmac0 13>;
|
||||
dma-names = "tx", "rx";
|
||||
#dma-cells = <1>;
|
||||
ss_hcnt = /bits/ 16 <0x104>;
|
||||
ss_lcnt = /bits/ 16 <0xec>;
|
||||
fs_hcnt = /bits/ 16 <0x37>;
|
||||
@@ -1789,6 +1904,10 @@
|
||||
interrupts = <45>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-frequency = <100000>;
|
||||
i2c_mode = "dma";
|
||||
dmas = <&dmac0 14>, <&dmac0 15>;
|
||||
dma-names = "tx", "rx";
|
||||
#dma-cells = <1>;
|
||||
ss_hcnt = /bits/ 16 <0x104>;
|
||||
ss_lcnt = /bits/ 16 <0xec>;
|
||||
fs_hcnt = /bits/ 16 <0x37>;
|
||||
@@ -1808,6 +1927,10 @@
|
||||
interrupts = <46>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-frequency = <100000>;
|
||||
i2c_mode = "dma";
|
||||
dmas = <&dmac0 16>, <&dmac0 17>;
|
||||
dma-names = "tx", "rx";
|
||||
#dma-cells = <1>;
|
||||
ss_hcnt = /bits/ 16 <0x104>;
|
||||
ss_lcnt = /bits/ 16 <0xec>;
|
||||
fs_hcnt = /bits/ 16 <0x37>;
|
||||
@@ -1829,6 +1952,10 @@
|
||||
interrupts = <47>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-frequency = <100000>;
|
||||
i2c_mode = "dma";
|
||||
dmas = <&dmac0 18>, <&dmac0 19>;
|
||||
dma-names = "tx", "rx";
|
||||
#dma-cells = <1>;
|
||||
ss_hcnt = /bits/ 16 <0x104>;
|
||||
ss_lcnt = /bits/ 16 <0xec>;
|
||||
fs_hcnt = /bits/ 16 <0x37>;
|
||||
@@ -1850,6 +1977,10 @@
|
||||
interrupts = <48>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-frequency = <100000>;
|
||||
i2c_mode = "dma";
|
||||
dmas = <&dmac0 20>, <&dmac0 21>;
|
||||
dma-names = "tx", "rx";
|
||||
#dma-cells = <1>;
|
||||
ss_hcnt = /bits/ 16 <0x104>;
|
||||
ss_lcnt = /bits/ 16 <0xec>;
|
||||
fs_hcnt = /bits/ 16 <0x37>;
|
||||
@@ -1871,6 +2002,10 @@
|
||||
interrupts = <182>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-frequency = <100000>;
|
||||
i2c_mode = "dma";
|
||||
dmas = <&dmac2 21>, <&dmac2 20>;
|
||||
dma-names = "tx", "rx";
|
||||
#dma-cells = <1>;
|
||||
ss_hcnt = /bits/ 16 <0x82>;
|
||||
ss_lcnt = /bits/ 16 <0x78>;
|
||||
fs_hcnt = /bits/ 16 <0x37>;
|
||||
@@ -1883,26 +2018,30 @@
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
audio_i2c1: i2c@0xffcb01b000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0xff 0xcb01b000 0x0 0x1000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <183>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-frequency = <100000>;
|
||||
ss_hcnt = /bits/ 16 <0x82>;
|
||||
ss_lcnt = /bits/ 16 <0x78>;
|
||||
fs_hcnt = /bits/ 16 <0x37>;
|
||||
fs_lcnt = /bits/ 16 <0x42>;
|
||||
fp_hcnt = /bits/ 16 <0x14>;
|
||||
fp_lcnt = /bits/ 16 <0x1a>;
|
||||
hs_hcnt = /bits/ 16 <0x5>;
|
||||
hs_lcnt = /bits/ 16 <0x15>;
|
||||
status = "disabled";
|
||||
audio_i2c1: i2c@0xffcb01b000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0xff 0xcb01b000 0x0 0x1000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <183>;
|
||||
clocks = <&dummy_clock_apb>;
|
||||
clock-frequency = <100000>;
|
||||
i2c_mode = "dma";
|
||||
dmas = <&dmac2 23>, <&dmac2 22>;
|
||||
dma-names = "tx", "rx";
|
||||
#dma-cells = <1>;
|
||||
ss_hcnt = /bits/ 16 <0x82>;
|
||||
ss_lcnt = /bits/ 16 <0x78>;
|
||||
fs_hcnt = /bits/ 16 <0x37>;
|
||||
fs_lcnt = /bits/ 16 <0x42>;
|
||||
fp_hcnt = /bits/ 16 <0x14>;
|
||||
fp_lcnt = /bits/ 16 <0x1a>;
|
||||
hs_hcnt = /bits/ 16 <0x5>;
|
||||
hs_lcnt = /bits/ 16 <0x15>;
|
||||
status = "disabled";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
isp0: isp@ffe4100000 {
|
||||
compatible = "thead,light-isp";
|
||||
@@ -2183,6 +2322,11 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
vvcam_sensor7: vvcam_sensor@7 {
|
||||
compatible = "thead,light-vvcam-sensor";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
xtensa_dsp: dsp@01{
|
||||
compatible = "thead,dsp-hw-common";
|
||||
reg = <0xff 0xef040000 0x0 0x001000 >; /*DSP_SYSREG(0x0000-0xFFF) */
|
||||
@@ -2332,11 +2476,11 @@
|
||||
interrupts = <215>; /* TEE INT SRC_7 */
|
||||
};
|
||||
|
||||
light_event: light-event {
|
||||
compatible = "thead,light-event";
|
||||
aon-iram-regmap = <&aon_iram>;
|
||||
status = "okay";
|
||||
};
|
||||
light_event: light-event {
|
||||
compatible = "thead,light-event";
|
||||
aon-iram-regmap = <&aon_iram>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
visys_clk_gate: visys-clk-gate { /* VI_SYSREG_R */
|
||||
compatible = "thead,visys-gate-controller";
|
||||
@@ -2365,6 +2509,13 @@
|
||||
#clock-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
audiosys_clk_gate: audiosys-clk-gate {
|
||||
compatible = "thead,audiosys-gate-controller";
|
||||
audiosys-regmap = <&audio_cpr>;
|
||||
#clock-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -251,6 +251,7 @@ CONFIG_HWSPINLOCK=y
|
||||
CONFIG_HWSPINLOCK_LIGHT=y
|
||||
CONFIG_HWSPINLOCK_LIGHT_TEST=m
|
||||
CONFIG_MAILBOX=y
|
||||
CONFIG_EXTCON=y
|
||||
CONFIG_IIO=y
|
||||
CONFIG_IIO_SW_DEVICE=y
|
||||
CONFIG_PWM=y
|
||||
|
||||
@@ -252,6 +252,7 @@ CONFIG_HWSPINLOCK=y
|
||||
CONFIG_HWSPINLOCK_LIGHT=y
|
||||
CONFIG_HWSPINLOCK_LIGHT_TEST=m
|
||||
CONFIG_MAILBOX=y
|
||||
CONFIG_EXTCON=y
|
||||
CONFIG_IIO=y
|
||||
CONFIG_IIO_SW_DEVICE=y
|
||||
CONFIG_PWM=y
|
||||
|
||||
@@ -20,7 +20,6 @@ CONFIG_SOC_THEAD=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_VECTOR=y
|
||||
CONFIG_VECTOR_0_7=y
|
||||
CONFIG_THEAD_ISA=y
|
||||
CONFIG_KEXEC=y
|
||||
CONFIG_CRASH_DUMP=y
|
||||
CONFIG_CPU_IDLE=y
|
||||
@@ -267,6 +266,10 @@ CONFIG_HWSPINLOCK=y
|
||||
CONFIG_HWSPINLOCK_LIGHT=y
|
||||
CONFIG_HWSPINLOCK_LIGHT_TEST=m
|
||||
CONFIG_MAILBOX=y
|
||||
CONFIG_RPMSG=y
|
||||
CONFIG_RPMSG_CHAR=y
|
||||
CONFIG_RPMSG_VIRTIO=y
|
||||
CONFIG_RPMSG_THEAD_LIGHT=y
|
||||
CONFIG_EXTCON=y
|
||||
CONFIG_IIO=y
|
||||
CONFIG_IIO_SW_DEVICE=y
|
||||
|
||||
@@ -3,7 +3,8 @@ generic-y += early_ioremap.h
|
||||
generic-y += extable.h
|
||||
generic-y += flat.h
|
||||
generic-y += kvm_para.h
|
||||
generic-y += mcs_spinlock.h
|
||||
generic-y += qspinlock.h
|
||||
generic-y += qrwlock.h
|
||||
generic-y += qrwlock_types.h
|
||||
generic-y += user.h
|
||||
generic-y += vmlinux.lds.h
|
||||
|
||||
@@ -11,12 +11,36 @@
|
||||
#include <asm/barrier.h>
|
||||
#include <asm/fence.h>
|
||||
|
||||
static inline ulong __xchg16_relaxed(ulong new, void *ptr)
|
||||
{
|
||||
ulong ret, tmp;
|
||||
ulong shif = ((ulong)ptr & 2) ? 16 : 0;
|
||||
ulong mask = 0xffff << shif;
|
||||
ulong *__ptr = (ulong *)((ulong)ptr & ~2);
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"0: lr.w %0, %2\n"
|
||||
" and %1, %0, %z3\n"
|
||||
" or %1, %1, %z4\n"
|
||||
" sc.w %1, %1, %2\n"
|
||||
" bnez %1, 0b\n"
|
||||
: "=&r" (ret), "=&r" (tmp), "+A" (*__ptr)
|
||||
: "rJ" (~mask), "rJ" (new << shif)
|
||||
: "memory");
|
||||
|
||||
return (ulong)((ret & mask) >> shif);
|
||||
}
|
||||
|
||||
#define __xchg_relaxed(ptr, new, size) \
|
||||
({ \
|
||||
__typeof__(ptr) __ptr = (ptr); \
|
||||
__typeof__(new) __new = (new); \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
switch (size) { \
|
||||
case 2: { \
|
||||
__ret = (__typeof__(*(ptr))) \
|
||||
__xchg16_relaxed((ulong)__new, __ptr); \
|
||||
break;} \
|
||||
case 4: \
|
||||
__asm__ __volatile__ ( \
|
||||
" amoswap.w %0, %2, %1\n" \
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <asm/mmiowb.h>
|
||||
#include <asm/early_ioremap.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -133,7 +133,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
|
||||
#define __io_br() do {} while (0)
|
||||
#define __io_ar(v) __asm__ __volatile__ ("fence i,r" : : : "memory")
|
||||
#define __io_bw() __asm__ __volatile__ ("fence w,o" : : : "memory")
|
||||
#define __io_aw() mmiowb_set_pending()
|
||||
#define __io_aw() __asm__ __volatile__ ("fence o,w" : : : "memory")
|
||||
|
||||
#define readb(c) ({ u8 __v; __io_br(); __v = readb_cpu(c); __io_ar(__v); __v; })
|
||||
#define readw(c) ({ u16 __v; __io_br(); __v = readw_cpu(c); __io_ar(__v); __v; })
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _ASM_RISCV_MMIOWB_H
|
||||
#define _ASM_RISCV_MMIOWB_H
|
||||
|
||||
/*
|
||||
* "o,w" is sufficient to ensure that all writes to the device have completed
|
||||
* before the write to the spinlock is allowed to commit.
|
||||
*/
|
||||
#define mmiowb() __asm__ __volatile__ ("fence o,w" : : : "memory");
|
||||
|
||||
#include <linux/smp.h>
|
||||
#include <asm-generic/mmiowb.h>
|
||||
|
||||
#endif /* _ASM_RISCV_MMIOWB_H */
|
||||
@@ -1,92 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/*
|
||||
* 'Generic' ticket-lock implementation.
|
||||
*
|
||||
* It relies on atomic_fetch_add() having well defined forward progress
|
||||
* guarantees under contention. If your architecture cannot provide this, stick
|
||||
* to a test-and-set lock.
|
||||
*
|
||||
* It also relies on atomic_fetch_add() being safe vs smp_store_release() on a
|
||||
* sub-word of the value. This is generally true for anything LL/SC although
|
||||
* you'd be hard pressed to find anything useful in architecture specifications
|
||||
* about this. If your architecture cannot do this you might be better off with
|
||||
* a test-and-set.
|
||||
*
|
||||
* It further assumes atomic_*_release() + atomic_*_acquire() is RCpc and hence
|
||||
* uses atomic_fetch_add() which is RCsc to create an RCsc hot path, along with
|
||||
* a full fence after the spin to upgrade the otherwise-RCpc
|
||||
* atomic_cond_read_acquire().
|
||||
*
|
||||
* The implementation uses smp_cond_load_acquire() to spin, so if the
|
||||
* architecture has WFE like instructions to sleep instead of poll for word
|
||||
* modifications be sure to implement that (see ARM64 for example).
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ASM_GENERIC_SPINLOCK_H
|
||||
#define __ASM_GENERIC_SPINLOCK_H
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/spinlock_types.h>
|
||||
|
||||
static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
|
||||
{
|
||||
u32 val = atomic_fetch_add(1<<16, lock);
|
||||
u16 ticket = val >> 16;
|
||||
|
||||
if (ticket == (u16)val)
|
||||
return;
|
||||
|
||||
/*
|
||||
* atomic_cond_read_acquire() is RCpc, but rather than defining a
|
||||
* custom cond_read_rcsc() here we just emit a full fence. We only
|
||||
* need the prior reads before subsequent writes ordering from
|
||||
* smb_mb(), but as atomic_cond_read_acquire() just emits reads and we
|
||||
* have no outstanding writes due to the atomic_fetch_add() the extra
|
||||
* orderings are free.
|
||||
*/
|
||||
atomic_cond_read_acquire(lock, ticket == (u16)VAL);
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
static __always_inline bool arch_spin_trylock(arch_spinlock_t *lock)
|
||||
{
|
||||
u32 old = atomic_read(lock);
|
||||
|
||||
if ((old >> 16) != (old & 0xffff))
|
||||
return false;
|
||||
|
||||
return atomic_try_cmpxchg(lock, &old, old + (1<<16)); /* SC, for RCsc */
|
||||
}
|
||||
|
||||
static __always_inline void arch_spin_unlock(arch_spinlock_t *lock)
|
||||
{
|
||||
u16 *ptr = (u16 *)lock + IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
|
||||
u32 val = atomic_read(lock);
|
||||
|
||||
smp_store_release(ptr, (u16)val + 1);
|
||||
}
|
||||
|
||||
static __always_inline int arch_spin_is_locked(arch_spinlock_t *lock)
|
||||
{
|
||||
u32 val = atomic_read(lock);
|
||||
|
||||
return ((val >> 16) != (val & 0xffff));
|
||||
}
|
||||
|
||||
static __always_inline int arch_spin_is_contended(arch_spinlock_t *lock)
|
||||
{
|
||||
u32 val = atomic_read(lock);
|
||||
|
||||
return (s16)((val >> 16) - (val & 0xffff)) > 1;
|
||||
}
|
||||
|
||||
static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock)
|
||||
{
|
||||
return !arch_spin_is_locked(&lock);
|
||||
}
|
||||
|
||||
#include <asm-generic/qspinlock.h>
|
||||
#include <asm/qrwlock.h>
|
||||
|
||||
#endif /* __ASM_GENERIC_SPINLOCK_H */
|
||||
|
||||
@@ -3,15 +3,7 @@
|
||||
#ifndef __ASM_GENERIC_SPINLOCK_TYPES_H
|
||||
#define __ASM_GENERIC_SPINLOCK_TYPES_H
|
||||
|
||||
#include <linux/types.h>
|
||||
typedef atomic_t arch_spinlock_t;
|
||||
|
||||
/*
|
||||
* qrwlock_types depends on arch_spinlock_t, so we must typedef that before the
|
||||
* include.
|
||||
*/
|
||||
#include <asm/qrwlock_types.h>
|
||||
|
||||
#define __ARCH_SPIN_LOCK_UNLOCKED ATOMIC_INIT(0)
|
||||
#include <asm-generic/qspinlock_types.h>
|
||||
#include <asm-generic/qrwlock_types.h>
|
||||
|
||||
#endif /* __ASM_GENERIC_SPINLOCK_TYPES_H */
|
||||
|
||||
@@ -38,11 +38,10 @@ riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api)
|
||||
RISCV_INSN_REJECTED(c_ebreak, insn);
|
||||
#endif
|
||||
|
||||
RISCV_INSN_REJECTED(auipc, insn);
|
||||
RISCV_INSN_REJECTED(branch, insn);
|
||||
|
||||
RISCV_INSN_SET_SIMULATE(jal, insn);
|
||||
RISCV_INSN_SET_SIMULATE(jalr, insn);
|
||||
RISCV_INSN_SET_SIMULATE(auipc, insn);
|
||||
RISCV_INSN_SET_SIMULATE(branch, insn);
|
||||
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
||||
@@ -83,3 +83,115 @@ bool __kprobes simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *reg
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define auipc_rd_idx(opcode) \
|
||||
((opcode >> 7) & 0x1f)
|
||||
|
||||
#define auipc_imm(opcode) \
|
||||
((((opcode) >> 12) & 0xfffff) << 12)
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
#define auipc_offset(opcode) sign_extend64(auipc_imm(opcode), 31)
|
||||
#elif __riscv_xlen == 32
|
||||
#define auipc_offset(opcode) auipc_imm(opcode)
|
||||
#else
|
||||
#error "Unexpected __riscv_xlen"
|
||||
#endif
|
||||
|
||||
bool __kprobes simulate_auipc(u32 opcode, unsigned long addr, struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* auipc instruction:
|
||||
* 31 12 11 7 6 0
|
||||
* | imm[31:12] | rd | opcode |
|
||||
* 20 5 7
|
||||
*/
|
||||
|
||||
u32 rd_idx = auipc_rd_idx(opcode);
|
||||
unsigned long rd_val = addr + auipc_offset(opcode);
|
||||
|
||||
if (!rv_insn_reg_set_val(regs, rd_idx, rd_val))
|
||||
return false;
|
||||
|
||||
instruction_pointer_set(regs, addr + 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define branch_rs1_idx(opcode) \
|
||||
(((opcode) >> 15) & 0x1f)
|
||||
|
||||
#define branch_rs2_idx(opcode) \
|
||||
(((opcode) >> 20) & 0x1f)
|
||||
|
||||
#define branch_funct3(opcode) \
|
||||
(((opcode) >> 12) & 0x7)
|
||||
|
||||
#define branch_imm(opcode) \
|
||||
(((((opcode) >> 8) & 0xf ) << 1) | \
|
||||
((((opcode) >> 25) & 0x3f) << 5) | \
|
||||
((((opcode) >> 7) & 0x1 ) << 11) | \
|
||||
((((opcode) >> 31) & 0x1 ) << 12))
|
||||
|
||||
#define branch_offset(opcode) \
|
||||
sign_extend32((branch_imm(opcode)), 12)
|
||||
|
||||
#define BRANCH_BEQ 0x0
|
||||
#define BRANCH_BNE 0x1
|
||||
#define BRANCH_BLT 0x4
|
||||
#define BRANCH_BGE 0x5
|
||||
#define BRANCH_BLTU 0x6
|
||||
#define BRANCH_BGEU 0x7
|
||||
|
||||
bool __kprobes simulate_branch(u32 opcode, unsigned long addr, struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* branch instructions:
|
||||
* 31 30 25 24 20 19 15 14 12 11 8 7 6 0
|
||||
* | imm[12] | imm[10:5] | rs2 | rs1 | funct3 | imm[4:1] | imm[11] | opcode |
|
||||
* 1 6 5 5 3 4 1 7
|
||||
* imm[12|10:5] rs2 rs1 000 imm[4:1|11] 1100011 BEQ
|
||||
* imm[12|10:5] rs2 rs1 001 imm[4:1|11] 1100011 BNE
|
||||
* imm[12|10:5] rs2 rs1 100 imm[4:1|11] 1100011 BLT
|
||||
* imm[12|10:5] rs2 rs1 101 imm[4:1|11] 1100011 BGE
|
||||
* imm[12|10:5] rs2 rs1 110 imm[4:1|11] 1100011 BLTU
|
||||
* imm[12|10:5] rs2 rs1 111 imm[4:1|11] 1100011 BGEU
|
||||
*/
|
||||
|
||||
s32 offset;
|
||||
s32 offset_tmp;
|
||||
unsigned long rs1_val;
|
||||
unsigned long rs2_val;
|
||||
|
||||
if (!rv_insn_reg_get_val(regs, branch_rs1_idx(opcode), &rs1_val) ||
|
||||
!rv_insn_reg_get_val(regs, branch_rs2_idx(opcode), &rs2_val))
|
||||
return false;
|
||||
|
||||
offset_tmp = branch_offset(opcode);
|
||||
switch (branch_funct3(opcode)) {
|
||||
case BRANCH_BEQ:
|
||||
offset = (rs1_val == rs2_val) ? offset_tmp : 4;
|
||||
break;
|
||||
case BRANCH_BNE:
|
||||
offset = (rs1_val != rs2_val) ? offset_tmp : 4;
|
||||
break;
|
||||
case BRANCH_BLT:
|
||||
offset = ((long)rs1_val < (long)rs2_val) ? offset_tmp : 4;
|
||||
break;
|
||||
case BRANCH_BGE:
|
||||
offset = ((long)rs1_val >= (long)rs2_val) ? offset_tmp : 4;
|
||||
break;
|
||||
case BRANCH_BLTU:
|
||||
offset = (rs1_val < rs2_val) ? offset_tmp : 4;
|
||||
break;
|
||||
case BRANCH_BGEU:
|
||||
offset = (rs1_val >= rs2_val) ? offset_tmp : 4;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
instruction_pointer_set(regs, addr + offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_CLK_LIGHT_FM) += thead-gate.o visys-gate.o vpsys-gate.o vosys-gate.o dspsys-gate.o
|
||||
obj-$(CONFIG_CLK_LIGHT_FM) += thead-gate.o visys-gate.o vpsys-gate.o vosys-gate.o dspsys-gate.o audiosys-gate.o
|
||||
|
||||
124
drivers/clk/thead/gate/audiosys-gate.c
Normal file
124
drivers/clk/thead/gate/audiosys-gate.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2022 Alibaba Group Holding Limited.
|
||||
*/
|
||||
|
||||
#include <dt-bindings/clock/light-fm-ap-clock.h>
|
||||
#include <dt-bindings/clock/light-audiosys.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
#include "clk-gate.h"
|
||||
#include "../clk.h"
|
||||
|
||||
static struct clk *gates[LIGHT_CLKGEN_AUDIO_CLK_END];
|
||||
static struct clk_onecell_data clk_gate_data;
|
||||
|
||||
static int light_audiosys_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct regmap *audiosys_regmap;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
int ret;
|
||||
|
||||
audiosys_regmap = syscon_regmap_lookup_by_phandle(np, "audiosys-regmap");
|
||||
if (IS_ERR(audiosys_regmap)) {
|
||||
dev_err(&pdev->dev, "cannot find regmap for vi system register\n");
|
||||
return PTR_ERR(audiosys_regmap);
|
||||
}
|
||||
|
||||
printk("%s audiosys_regmap=0x%px\n", __func__, audiosys_regmap);
|
||||
|
||||
/* we assume that the gate clock is a root clock */
|
||||
gates[LIGHT_CLKGEN_AUDIO_CPU] = thead_gate_clk_register("clkgen_audiosys_cpu_clk", NULL,
|
||||
audiosys_regmap, 0x10, 0, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_SRAM0] = thead_gate_clk_register("clkgen_audiosys_sram0_clk", NULL,
|
||||
audiosys_regmap, 0x10, 1, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_SRAM1] = thead_gate_clk_register("clkgen_audiosys_sram1_clk", NULL,
|
||||
audiosys_regmap, 0x10, 2, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_DMA] = thead_gate_clk_register("clkgen_audiosys_dma_clk", NULL,
|
||||
audiosys_regmap, 0x10, 3, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_BSM] = thead_gate_clk_register("clkgen_audiosys_bsm_clk", NULL,
|
||||
audiosys_regmap, 0x10, 4, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_TIMER] = thead_gate_clk_register("clkgen_audiosys_timer_clk", NULL,
|
||||
audiosys_regmap, 0x10, 8, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_TIMER_CNT1] = thead_gate_clk_register("clkgen_audiosys_timer_cnt1_clk", NULL,
|
||||
audiosys_regmap, 0x10, 9, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_TIMER_CNT2] = thead_gate_clk_register("clkgen_audiosys_timer_cnt2_clk", NULL,
|
||||
audiosys_regmap, 0x10, 10, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_TIMER_CNT3] = thead_gate_clk_register("clkgen_audiosys_timer_cnt3_clk", NULL,
|
||||
audiosys_regmap, 0x10, 11, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_TIMER_CNT4] = thead_gate_clk_register("clkgen_audiosys_timer_cnt4_clk", NULL,
|
||||
audiosys_regmap, 0x10, 12, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_WDR] = thead_gate_clk_register("clkgen_audiosys_wdr_clk", NULL,
|
||||
audiosys_regmap, 0x10, 13, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_I2C0] = thead_gate_clk_register("clkgen_audiosys_i2c0_clk", NULL,
|
||||
audiosys_regmap, 0x10, 14, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_I2C1] = thead_gate_clk_register("clkgen_audiosys_i2c1_clk", NULL,
|
||||
audiosys_regmap, 0x10, 15, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_UART] = thead_gate_clk_register("clkgen_audiosys_uart_clk", NULL,
|
||||
audiosys_regmap, 0x10, 16, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_I2S0] = thead_gate_clk_register("clkgen_audiosys_i2s0_clk", NULL,
|
||||
audiosys_regmap, 0x10, 17, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_I2S1] = thead_gate_clk_register("clkgen_audiosys_i2s1_clk", NULL,
|
||||
audiosys_regmap, 0x10, 18, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_I2S2] = thead_gate_clk_register("clkgen_audiosys_i2s2_clk", NULL,
|
||||
audiosys_regmap, 0x10, 19, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_I2S8CH] = thead_gate_clk_register("clkgen_audiosys_i2s8ch_clk", NULL,
|
||||
audiosys_regmap, 0x10, 20, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_TDM] = thead_gate_clk_register("clkgen_audiosys_tdm_clk", NULL,
|
||||
audiosys_regmap, 0x10, 21, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_GPIO] = thead_gate_clk_register("clkgen_audiosys_gpio_clk", NULL,
|
||||
audiosys_regmap, 0x10, 22, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_SPDIF0] = thead_gate_clk_register("clkgen_audiosys_spdif0_clk", NULL,
|
||||
audiosys_regmap, 0x10, 23, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_SPDIF1] = thead_gate_clk_register("clkgen_audiosys_spdif1_clk", NULL,
|
||||
audiosys_regmap, 0x10, 24, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_VAD] = thead_gate_clk_register("clkgen_audiosys_vad_clk", NULL,
|
||||
audiosys_regmap, 0x10, 25, GATE_NOT_SHARED, NULL, dev);
|
||||
gates[LIGHT_CLKGEN_AUDIO_IOMUX] = thead_gate_clk_register("clkgen_audiosys_iomux_clk", NULL,
|
||||
audiosys_regmap, 0x10, 26, GATE_NOT_SHARED, NULL, dev);
|
||||
|
||||
clk_gate_data.clks = gates;
|
||||
clk_gate_data.clk_num = ARRAY_SIZE(gates);
|
||||
|
||||
ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register gate clks for light audiosys\n");
|
||||
goto unregister_clks;
|
||||
}
|
||||
|
||||
dev_info(dev, "succeed to register audiosys gate clock provider\n");
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_clks:
|
||||
thead_unregister_clocks(gates, ARRAY_SIZE(gates));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id audiosys_clk_gate_of_match[] = {
|
||||
{ .compatible = "thead,audiosys-gate-controller" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, audiosys_clk_gate_of_match);
|
||||
|
||||
static struct platform_driver light_audiosys_clk_driver = {
|
||||
.probe = light_audiosys_clk_probe,
|
||||
.driver = {
|
||||
.name = "audiosys-clk-gate-provider",
|
||||
.of_match_table = of_match_ptr(audiosys_clk_gate_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(light_audiosys_clk_driver);
|
||||
MODULE_AUTHOR("nanli.yd <nanli.yd@linux.alibaba.com>");
|
||||
MODULE_DESCRIPTION("Thead Light Fullmask audiosys clock gate provider");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -50,6 +50,7 @@ obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
|
||||
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
|
||||
i2c-designware-core-y := i2c-designware-common.o
|
||||
i2c-designware-core-y += i2c-designware-master_dma.o
|
||||
i2c-designware-core-y += i2c-designware-master.o
|
||||
i2c-designware-core-$(CONFIG_I2C_DESIGNWARE_SLAVE) += i2c-designware-slave.o
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
|
||||
I2C_FUNC_SMBUS_BYTE | \
|
||||
@@ -234,6 +235,18 @@ struct reset_control;
|
||||
* values than the one computed based only on the input clock frequency.
|
||||
* Leave them to be %0 if not used.
|
||||
*/
|
||||
struct i2c_dw_dma {
|
||||
struct dma_chan *dma_chan;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
dma_cookie_t cookie;
|
||||
dma_addr_t dma_addr; //phy addr
|
||||
u32 *buf; //Store the virtual address of the data to be transferred by dma
|
||||
u32 buf_size;
|
||||
u32 transfer_len; //dma transfer data num
|
||||
//volatile int dma_complete;
|
||||
struct completion dma_complete;
|
||||
};
|
||||
|
||||
struct dw_i2c_dev {
|
||||
struct device *dev;
|
||||
struct regmap *map;
|
||||
@@ -257,6 +270,7 @@ struct dw_i2c_dev {
|
||||
u8 *rx_buf;
|
||||
int msg_err;
|
||||
unsigned int status;
|
||||
unsigned int tx_status;
|
||||
u32 abort_source;
|
||||
int irq;
|
||||
u32 flags;
|
||||
@@ -287,6 +301,10 @@ struct dw_i2c_dev {
|
||||
int mode;
|
||||
struct i2c_bus_recovery_info rinfo;
|
||||
bool suspended;
|
||||
struct i2c_dw_dma dma;
|
||||
u32 laststat;
|
||||
u32 laststatus;
|
||||
int dw_i2c_enable_dma;
|
||||
};
|
||||
|
||||
#define ACCESS_INTR_MASK 0x00000001
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "i2c-designware-core.h"
|
||||
#include "i2c-designware-master_dma.h"
|
||||
|
||||
static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
@@ -257,7 +258,13 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
||||
|
||||
/* Clear and enable interrupts */
|
||||
regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK);
|
||||
|
||||
if (dev->dw_i2c_enable_dma) {
|
||||
i2c_dw_xfer_dma_init(dev);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK & (~DW_IC_INTR_TX_EMPTY));
|
||||
} else {
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -289,9 +296,9 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
||||
* adapter when we are done with this transfer.
|
||||
*/
|
||||
if (msgs[dev->msg_write_idx].addr != addr) {
|
||||
dev_err(dev->dev,
|
||||
"%s: invalid target address\n", __func__);
|
||||
dev->msg_err = -EINVAL;
|
||||
dev_err(dev->dev,
|
||||
"%s: invalid target address\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -476,6 +483,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
dev->msg_read_idx = 0;
|
||||
dev->msg_err = 0;
|
||||
dev->status = STATUS_IDLE;
|
||||
dev->tx_status = STATUS_IDLE;
|
||||
dev->abort_source = 0;
|
||||
dev->rx_outstanding = 0;
|
||||
|
||||
@@ -491,6 +499,16 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
i2c_dw_xfer_init(dev);
|
||||
|
||||
/* Wait for tx to complete */
|
||||
if (dev->dw_i2c_enable_dma) {
|
||||
if(i2c_dw_dma_tx_transfer(dev, adap->timeout) != 0) {
|
||||
dev_err(dev->dev, "i2c dw dma transfer error\n");
|
||||
i2c_recover_bus(&dev->adapter);
|
||||
i2c_dw_init_master(dev);
|
||||
ret = -ETIMEDOUT;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
/* i2c_dw_init implicitly disables the adapter */
|
||||
@@ -527,15 +545,21 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (dev->status)
|
||||
dev_err(dev->dev,
|
||||
"transfer terminated early - interrupt latency too high?\n");
|
||||
if (dev->status || dev->tx_status) {
|
||||
dev_err(dev->dev, "transfer terminated early - interrupt latency too high? sta 0x%x\n", dev->status);
|
||||
|
||||
dev_err(dev->dev, "laststa 0x%x, laststatus 0x%x\n", dev->laststat, dev->laststatus);
|
||||
dev_err(dev->dev, "dev->tx_status 0x%x\n", dev->tx_status);
|
||||
dev_err(dev->dev, "dev->rx_outstanding %d\n", dev->rx_outstanding);
|
||||
}
|
||||
|
||||
ret = -EIO;
|
||||
|
||||
done:
|
||||
if (dev->dw_i2c_enable_dma) {
|
||||
i2c_dw_xfer_dma_deinit(dev);
|
||||
}
|
||||
i2c_dw_release_lock(dev);
|
||||
|
||||
done_nolock:
|
||||
pm_runtime_mark_last_busy(dev->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
@@ -631,8 +655,9 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
|
||||
if (stat & DW_IC_INTR_RX_FULL)
|
||||
i2c_dw_read(dev);
|
||||
|
||||
if (stat & DW_IC_INTR_TX_EMPTY)
|
||||
if (stat & DW_IC_INTR_TX_EMPTY) {
|
||||
i2c_dw_xfer_msg(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* No need to modify or disable the interrupt mask here.
|
||||
@@ -645,9 +670,11 @@ tx_aborted:
|
||||
if ((stat & DW_IC_INTR_TX_ABRT) || dev->msg_err ||
|
||||
((status & DW_IC_STATUS_TFE) &&
|
||||
(!(status & DW_IC_STATUS_RFNE)) &&
|
||||
(!(status & DW_IC_STATUS_MASTER_ACTIVITY))))
|
||||
(!(status & DW_IC_STATUS_MASTER_ACTIVITY)))) {
|
||||
complete(&dev->cmd_complete);
|
||||
else if (unlikely(dev->flags & ACCESS_INTR_MASK)) {
|
||||
dev->laststat = stat;
|
||||
dev->laststatus = status;
|
||||
} else if (unlikely(dev->flags & ACCESS_INTR_MASK)) {
|
||||
/* Workaround to trigger pending interrupt */
|
||||
regmap_read(dev->map, DW_IC_INTR_MASK, &stat);
|
||||
i2c_dw_disable_int(dev);
|
||||
@@ -747,9 +774,25 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_adapter *adap = &dev->adapter;
|
||||
unsigned long irq_flags;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
const char *i2c_mode;
|
||||
|
||||
//default used interrupt mode
|
||||
dev->dw_i2c_enable_dma = 0;
|
||||
|
||||
np = dev->dev->of_node;
|
||||
ret = of_property_read_string(np, "i2c_mode", &i2c_mode);
|
||||
if (ret == 0) {
|
||||
if (strcmp(i2c_mode, "dma") == 0) {
|
||||
dev->dw_i2c_enable_dma = 1;
|
||||
}
|
||||
}
|
||||
|
||||
init_completion(&dev->cmd_complete);
|
||||
if (dev->dw_i2c_enable_dma) {
|
||||
init_completion(&dev->dma.dma_complete);
|
||||
}
|
||||
|
||||
dev->init = i2c_dw_init_master;
|
||||
dev->disable = i2c_dw_disable;
|
||||
@@ -787,10 +830,10 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
|
||||
|
||||
i2c_dw_disable_int(dev);
|
||||
ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
|
||||
dev_name(dev->dev), dev);
|
||||
dev_name(dev->dev), dev);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failure requesting irq %i: %d\n",
|
||||
dev->irq, ret);
|
||||
dev->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
318
drivers/i2c/busses/i2c-designware-master_dma.c
Normal file
318
drivers/i2c/busses/i2c-designware-master_dma.c
Normal file
@@ -0,0 +1,318 @@
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include "i2c-designware-core.h"
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#define DW_IC_DMA_CR (0x88)
|
||||
#define DW_IC_DMA_TDLR (0x8c)
|
||||
#define DW_IC_DMA_RDLR (0x90)
|
||||
#define DW_IC_DMA_CR_TXEN (0x2)
|
||||
#define DW_IC_DMA_CR_DIS (0x0)
|
||||
|
||||
//Because the fifo register bit width is 32bits, each transfer data is 4byte
|
||||
#define DW_IC_DMA_DATA_BLOCK_BYTES (0x4)
|
||||
|
||||
//#define __dev_vdgb dev_dbg
|
||||
#define __dev_vdgb(fmt, ...)
|
||||
|
||||
static int i2c_dw_hwparams_to_dma_slave_config(struct dw_i2c_dev *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dma_slave_config slave_config;
|
||||
struct i2c_dw_dma *dma = &dev->dma;
|
||||
struct platform_device *pdev;
|
||||
struct resource *iores_mem;
|
||||
phys_addr_t reg_addr;
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, enter\n", __func__, __LINE__);
|
||||
memset(&slave_config, 0, sizeof(slave_config));
|
||||
|
||||
//get i2c fifo addr
|
||||
pdev = to_platform_device(dev->dev);
|
||||
iores_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
reg_addr = iores_mem->start + DW_IC_DATA_CMD;
|
||||
slave_config.direction = DMA_MEM_TO_DEV;
|
||||
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
slave_config.dst_addr = reg_addr;
|
||||
//for light only support "false"
|
||||
slave_config.device_fc = false;
|
||||
|
||||
ret = dmaengine_slave_config(dma->dma_chan, &slave_config);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "dmaengine_slave_config failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, exit\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i2c_dw_dma_callback(void *data)
|
||||
{
|
||||
struct dw_i2c_dev *dev = (struct dw_i2c_dev *)data;
|
||||
struct i2c_dw_dma *dma = &dev->dma;
|
||||
|
||||
dev->tx_status &= ~STATUS_WRITE_IN_PROGRESS;
|
||||
complete(&dma->dma_complete);
|
||||
dmaengine_terminate_async(dma->dma_chan);
|
||||
}
|
||||
|
||||
static int get_msg_size(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_msg *msgs = dev->msgs;
|
||||
u32 addr = msgs[dev->msg_write_idx].addr;
|
||||
int i = 0;
|
||||
int len = 0;
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, enter\n", __func__, __LINE__);
|
||||
for (i = dev->msg_write_idx; i < dev->msgs_num; i++) {
|
||||
if (msgs[i].addr != addr) {
|
||||
dev_err(dev->dev, "%s: invalid target address\n", __func__);
|
||||
dev->msg_err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
len += msgs[i].len;
|
||||
}
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, exit\n", __func__, __LINE__);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int alloc_dma_buf(struct dw_i2c_dev *dev, int size)
|
||||
{
|
||||
struct i2c_dw_dma *dma = &dev->dma;
|
||||
__dev_vdgb(dev->dev, "%s, %d, enter\n", __func__, __LINE__);
|
||||
|
||||
dma->buf = dma_alloc_coherent(dev->dev, size, &dma->dma_addr, GFP_KERNEL);
|
||||
if (!dma->buf) {
|
||||
dev_err(dev->dev, "i2c alloc dma buf failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dma->buf_size = size;
|
||||
dma->transfer_len = 0;
|
||||
__dev_vdgb(dev->dev, "%s, %d, exit\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_dw_release_tx_packets(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_dw_dma *dma = &dev->dma;
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, enter\n", __func__, __LINE__);
|
||||
|
||||
if(dma->buf && dma->dma_addr && dma->buf_size) {
|
||||
dma_free_coherent(dev->dev, dma->buf_size, dma->buf, dma->dma_addr);
|
||||
}
|
||||
|
||||
dma->buf = 0;
|
||||
dma->dma_addr = 0;
|
||||
dma->buf_size = 0;
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, exit\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_dw_synthetic_tx_packets(struct dw_i2c_dev *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct i2c_dw_dma *dma = &dev->dma;
|
||||
struct i2c_msg *msgs = dev->msgs;
|
||||
bool need_restart = false;
|
||||
uint32_t *tx_buf;
|
||||
int dma_tx_buf_size;
|
||||
u32 addr = msgs[dev->msg_write_idx].addr;
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, enter\n", __func__, __LINE__);
|
||||
|
||||
dma_tx_buf_size = get_msg_size(dev) * 4;
|
||||
if (dma_tx_buf_size <= 0) {
|
||||
dev_err(dev->dev, "i2c get_msg_size size is error %d\n", dma_tx_buf_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = alloc_dma_buf(dev, dma_tx_buf_size);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "i2c alloc_dma_buf failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tx_buf = dma->buf;
|
||||
|
||||
for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
|
||||
unsigned char *buf;
|
||||
int buf_len;
|
||||
u32 flags = msgs[dev->msg_write_idx].flags;
|
||||
|
||||
if (msgs[dev->msg_write_idx].addr != addr) {
|
||||
dev_err(dev->dev, "%s: invalid target address\n", __func__);
|
||||
dev->msg_err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* new i2c_msg */
|
||||
buf = msgs[dev->msg_write_idx].buf;
|
||||
buf_len = msgs[dev->msg_write_idx].len;
|
||||
|
||||
if ((dev->master_cfg & DW_IC_CON_RESTART_EN) &&
|
||||
(dev->msg_write_idx > 0))
|
||||
need_restart = true;
|
||||
|
||||
//dev_err(dev->dev, " msg_buf_len %d\n", buf_len);
|
||||
while (buf_len > 0) {
|
||||
u32 cmd = 0;
|
||||
|
||||
if (dev->msg_write_idx == dev->msgs_num - 1 &&
|
||||
buf_len == 1 && !(flags & I2C_M_RECV_LEN))
|
||||
cmd |= BIT(9);
|
||||
|
||||
if (need_restart) {
|
||||
cmd |= BIT(10);
|
||||
need_restart = false;
|
||||
}
|
||||
|
||||
if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
|
||||
*tx_buf = cmd | 0x100;
|
||||
dev->rx_outstanding++;
|
||||
} else {
|
||||
*tx_buf = cmd | *buf++;
|
||||
}
|
||||
tx_buf++;
|
||||
dma->transfer_len++;
|
||||
buf_len--;
|
||||
}
|
||||
}
|
||||
|
||||
dma_sync_single_for_device(dev->dev, dma->dma_addr, dma->buf_size, DMA_TO_DEVICE);
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, exit\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_dw_xfer_dma_deinit(struct dw_i2c_dev *dev);
|
||||
|
||||
int i2c_dw_dma_tx_transfer(struct dw_i2c_dev *dev, unsigned int timeout)
|
||||
{
|
||||
int ret = 0;
|
||||
struct i2c_dw_dma *dma = &dev->dma;
|
||||
unsigned long start_jiffies = 0;
|
||||
u32 stat;
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, enter\n", __func__, __LINE__);
|
||||
if (dma->dma_chan == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = i2c_dw_hwparams_to_dma_slave_config(dev);
|
||||
if (ret != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
|
||||
if (stat & DW_IC_INTR_TX_ABRT) {
|
||||
dev->cmd_err |= DW_IC_ERR_TX_ABRT;
|
||||
dev->tx_status = STATUS_IDLE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = i2c_dw_synthetic_tx_packets(dev);
|
||||
if (ret != 0) {
|
||||
dev_err(dev->dev, "%s: i2c_dw_synthetic_tx_packets failed\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->tx_status |= STATUS_WRITE_IN_PROGRESS;
|
||||
dma->desc = dmaengine_prep_slave_single(dma->dma_chan, dma->dma_addr,
|
||||
dma->transfer_len * DW_IC_DMA_DATA_BLOCK_BYTES,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (dma->desc == NULL) {
|
||||
dev_err(dev->dev, "%s: dmaengine_prep_slave_single failed\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dma->desc->callback = i2c_dw_dma_callback;
|
||||
dma->desc->callback_param = dev;
|
||||
dma->cookie = dmaengine_submit(dma->desc);
|
||||
dma_async_issue_pending(dma->dma_chan);
|
||||
|
||||
//wait dma transfer complete
|
||||
if (!wait_for_completion_timeout(&dma->dma_complete, timeout)) {
|
||||
dev_err(dev->dev, "i2c dma_ch%d write timed out\n", dma->dma_chan->chan_id);
|
||||
ret = dmaengine_terminate_async(dma->dma_chan);
|
||||
if (ret !=0) {
|
||||
dev_err(dev->dev, "i2c dma dmaengine_terminate_async failed,\
|
||||
dma_ch is %d\n", dma->dma_chan->chan_id);
|
||||
}
|
||||
dmaengine_synchronize(dma->dma_chan);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dmaengine_synchronize(dma->dma_chan);
|
||||
|
||||
//Release the dma channel immediately after the dma transfer is completed,
|
||||
//reducing the dma occupation time
|
||||
//i2c_dw_xfer_dma_init(dev);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
//i2c_dw_xfer_dma_init(dev);
|
||||
__dev_vdgb(dev->dev, "%s, %d, exit\n", __func__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int i2c_dw_xfer_dma_init(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_dw_dma *dma = &dev->dma;
|
||||
__dev_vdgb(dev->dev, "%s, %d, enter\n", __func__, __LINE__);
|
||||
|
||||
// i2c dma set tx data level
|
||||
regmap_write(dev->map, DW_IC_DMA_TDLR, dev->tx_fifo_depth / 2);
|
||||
|
||||
// i2c dma tx enable
|
||||
regmap_write(dev->map, DW_IC_DMA_CR, DW_IC_DMA_CR_TXEN);
|
||||
|
||||
if (dma->dma_chan == NULL) {
|
||||
//Alloc i2c dma channel.
|
||||
//The function is to configure the handshake number in i2c dts into the channel
|
||||
dma->dma_chan = dma_request_slave_channel(dev->dev, "tx");
|
||||
if (!dma->dma_chan) {
|
||||
dev_err(dev->dev, "Failed to request dma channel");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
__dev_vdgb(dev->dev,"i2c request dma_ch %d\n", dma->dma_chan->chan_id);
|
||||
}
|
||||
|
||||
__dev_vdgb(dev->dev,"i2c dma_ch %d\n", dma->dma_chan->chan_id);
|
||||
reinit_completion(&dma->dma_complete);
|
||||
__dev_vdgb(dev->dev, "%s, %d, exit\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_dw_xfer_dma_deinit(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_dw_dma *dma = &dev->dma;
|
||||
|
||||
__dev_vdgb(dev->dev, "%s, %d, enter\n", __func__, __LINE__);
|
||||
|
||||
i2c_dw_release_tx_packets(dev);
|
||||
if (dma->dma_chan != NULL) {
|
||||
dma_release_channel(dma->dma_chan);
|
||||
}
|
||||
dma->dma_chan = NULL;
|
||||
|
||||
// i2c dma disable
|
||||
regmap_write(dev->map, DW_IC_DMA_CR, DW_IC_DMA_CR_DIS);
|
||||
__dev_vdgb(dev->dev, "%s, %d, exit\n", __func__, __LINE__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
6
drivers/i2c/busses/i2c-designware-master_dma.h
Normal file
6
drivers/i2c/busses/i2c-designware-master_dma.h
Normal file
@@ -0,0 +1,6 @@
|
||||
//#include "i2c-designware-core.h"
|
||||
|
||||
int i2c_dw_dma_tx_transfer(struct dw_i2c_dev *dev, unsigned int timeout);
|
||||
int i2c_dw_xfer_dma_init(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_xfer_dma_deinit(struct dw_i2c_dev *dev);
|
||||
|
||||
@@ -56,7 +56,7 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o
|
||||
obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o
|
||||
|
||||
obj-$(CONFIG_THEAD_LIGHT_MBOX) += light-mailbox.o
|
||||
obj-$(CONFIG_THEAD_LIGHT_MBOX) += light-mailbox-client.o
|
||||
#obj-$(CONFIG_THEAD_LIGHT_MBOX) += light-mailbox-client.o
|
||||
|
||||
obj-$(CONFIG_VIRTIO_MAILBOX) += virtio-mailbox.o
|
||||
obj-$(CONFIG_VIRTIO_MAILBOX_TEST) += virtio-mailbox-test.o
|
||||
|
||||
@@ -33,11 +33,15 @@ struct dwcmshc_priv {
|
||||
bool io_fixed_1v8;
|
||||
bool wprtn_ignore;
|
||||
long reset_cnt;
|
||||
uint32_t delay_line[MMC_TIMING_MMC_HS400+1];
|
||||
uint32_t clk_delay_set;
|
||||
bool rxclk_sw_tune_en;
|
||||
uint32_t rxclk_delay_set;
|
||||
};
|
||||
|
||||
#define HS400_DELAY_LINE 24
|
||||
|
||||
static uint32_t delay_line = 50;
|
||||
//static uint32_t delay_line = 50;
|
||||
|
||||
static void sdhci_phy_1_8v_init_no_pull(struct sdhci_host *host)
|
||||
{
|
||||
@@ -113,12 +117,13 @@ static void snps_phy_1_8v_init(struct sdhci_host *host)
|
||||
//disable delay lane
|
||||
sdhci_writeb(host, 1 << UPDATE_DC, PHY_SDCLKDL_CNFG_R);
|
||||
//set delay lane
|
||||
sdhci_writeb(host, delay_line, PHY_SDCLKDL_DC_R);
|
||||
sdhci_writeb(host, priv->clk_delay_set, PHY_SDCLKDL_DC_R);
|
||||
sdhci_writeb(host, 0xa, PHY_DLL_CNFG2_R);
|
||||
//enable delay lane
|
||||
val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
|
||||
val &= ~(1 << UPDATE_DC);
|
||||
sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
|
||||
pr_debug("%s: snps_phy_1_8v_init clk delay %d\n",host->hw_name,priv->clk_delay_set);
|
||||
|
||||
val = (1 << RXSEL) | (1 << WEAKPULL_EN) | (3 << TXSLEW_CTRL_P) | (3 << TXSLEW_CTRL_N);
|
||||
sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
|
||||
@@ -155,12 +160,13 @@ static void snps_phy_3_3v_init(struct sdhci_host *host)
|
||||
//disable delay lane
|
||||
sdhci_writeb(host, 1 << UPDATE_DC, PHY_SDCLKDL_CNFG_R);
|
||||
//set delay lane
|
||||
sdhci_writeb(host, delay_line, PHY_SDCLKDL_DC_R);
|
||||
sdhci_writeb(host, priv->clk_delay_set, PHY_SDCLKDL_DC_R);
|
||||
sdhci_writeb(host, 0xa, PHY_DLL_CNFG2_R);
|
||||
//enable delay lane
|
||||
val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
|
||||
val &= ~(1 << UPDATE_DC);
|
||||
sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
|
||||
pr_debug("%s: snps_phy_3_3v_init clk delay %d\n",host->hw_name,priv->clk_delay_set);
|
||||
|
||||
val = (2 << RXSEL) | (1 << WEAKPULL_EN) | (3 << TXSLEW_CTRL_P) | (3 << TXSLEW_CTRL_N);
|
||||
sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
|
||||
@@ -254,6 +260,61 @@ static int snps_execute_tuning(struct sdhci_host *host, u32 opcode)
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int snps_rxclk_sw_tuned_sample_delay_set(struct sdhci_host *host, u32 sample_delay,u32 timeout)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct dwcmshc_priv *priv;
|
||||
u32 reg_val;
|
||||
u32 tune_clk_set;
|
||||
u16 ctrl_2;
|
||||
u32 i=0;
|
||||
pltfm_host = sdhci_priv(host);
|
||||
priv = sdhci_pltfm_priv(pltfm_host);
|
||||
/*0x320:SMPLDL_CNFG
|
||||
0x540:AT_CTRL
|
||||
0x544:AT_STAT */
|
||||
reg_val = sdhci_readb(host, PHY_SMPLDL_CNFG_R);
|
||||
if(sample_delay >= 0x80){
|
||||
/*if larger than 128,DelayLine works with extended delay range setting*/
|
||||
reg_val |= (1 << SMPLDL_CNFG_EXTDLY_EN);
|
||||
}else{
|
||||
reg_val &= ~(1 << SMPLDL_CNFG_EXTDLY_EN);
|
||||
}
|
||||
sdhci_writeb(host, reg_val, PHY_SMPLDL_CNFG_R);
|
||||
|
||||
reg_val = sdhci_readl(host, AT_CTRL_R);
|
||||
reg_val |= (1 << TUNE_CLK_STOP_EN);
|
||||
reg_val |= (1 << SW_TUNE_EN);
|
||||
sdhci_writel(host, reg_val, AT_CTRL_R);
|
||||
|
||||
if(sample_delay >= 0x80){
|
||||
tune_clk_set = (sample_delay - 0x80) & 0xff;
|
||||
}
|
||||
else {
|
||||
tune_clk_set = sample_delay ;
|
||||
}
|
||||
reg_val = sdhci_readl(host, AT_STAT_R);
|
||||
reg_val &= ~(0xff<<AT_STAT_CENTER_PH_CODE);
|
||||
reg_val |= tune_clk_set;
|
||||
sdhci_writel(host,reg_val, AT_STAT_R);
|
||||
|
||||
for(i = 0; i < timeout; i += 10){
|
||||
ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||
if(ctrl_2 & SDHCI_CTRL_TUNED_CLK)
|
||||
return 0;
|
||||
udelay(10);
|
||||
}
|
||||
pr_warn("%s: _rxclk_sw_tuned_sample_delay_set timeout %d\n",host->hw_name,timeout);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void snps_rxclk_sw_tuned_sample_delay_dump(struct sdhci_host *host)
|
||||
{
|
||||
pr_info("PHY_SMPLDL_CNFG_R = %x\n",sdhci_readb(host, PHY_SMPLDL_CNFG_R));
|
||||
pr_info("AT_CTRL_R = %x\n", sdhci_readl(host, AT_CTRL_R));
|
||||
pr_info("AT_STAT_R = %x\n", sdhci_readl(host, AT_STAT_R));
|
||||
pr_info("SDHCI_HOST_CONTROL2 = %x\n",sdhci_readw(host, SDHCI_HOST_CONTROL2));
|
||||
}
|
||||
|
||||
static void snps_sdhci_set_phy(struct sdhci_host *host)
|
||||
{
|
||||
@@ -383,7 +444,7 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
|
||||
ctrl_2 |= SDHCI_CTRL_VDD_180;
|
||||
|
||||
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
||||
|
||||
pr_debug("%s: %s timing %d\n",host->hw_name,__func__,timing);
|
||||
if (timing == MMC_TIMING_MMC_HS400) {
|
||||
// //disable delay lane
|
||||
// sdhci_writeb(host, 1 << UPDATE_DC, PHY_SDCLKDL_CNFG_R);
|
||||
@@ -399,10 +460,18 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
|
||||
reg &= ~1;
|
||||
sdhci_writel(host, reg, AT_CTRL_R);
|
||||
|
||||
delay_line = HS400_DELAY_LINE;
|
||||
priv->clk_delay_set = priv->delay_line[MMC_TIMING_MMC_HS400];
|
||||
snps_sdhci_set_phy(host); /* update tx delay*/
|
||||
} else if(timing == MMC_TIMING_UHS_SDR104){
|
||||
priv->clk_delay_set = priv->delay_line[MMC_TIMING_UHS_SDR104];
|
||||
snps_sdhci_set_phy(host); /* update tx delay*/
|
||||
} else {
|
||||
sdhci_writeb(host, 0, PHY_DLLDL_CNFG_R);
|
||||
}else {
|
||||
sdhci_writeb(host, 0, PHY_DLLDL_CNFG_R);
|
||||
if(priv->rxclk_sw_tune_en && (timing == MMC_TIMING_SD_HS)){
|
||||
snps_rxclk_sw_tuned_sample_delay_set(host,priv->rxclk_delay_set,10000);
|
||||
//snps_rxclk_sw_tuned_sample_delay_dump(host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,7 +533,8 @@ static void dwcmshc_set_power_noreg(struct sdhci_host *host, unsigned char mode,
|
||||
unsigned short vdd)
|
||||
{
|
||||
u8 pwr = 0;
|
||||
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
if (mode != MMC_POWER_OFF) {
|
||||
switch (1 << vdd) {
|
||||
case MMC_VDD_165_195:
|
||||
@@ -502,6 +572,8 @@ static void dwcmshc_set_power_noreg(struct sdhci_host *host, unsigned char mode,
|
||||
return;
|
||||
|
||||
host->pwr = pwr;
|
||||
pr_debug("%s: %s set pwr %d\n",host->hw_name,__func__,pwr);
|
||||
priv->clk_delay_set = priv->delay_line[0];
|
||||
snps_sdhci_set_phy(host);
|
||||
|
||||
if (pwr == 0) {
|
||||
@@ -572,6 +644,20 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
||||
};
|
||||
|
||||
static int device_property_get_clk_delay(struct device *dev,
|
||||
const char *propname, u32 *val)
|
||||
{
|
||||
int ret = device_property_read_u32(dev, propname, val);
|
||||
if(ret < 0){
|
||||
return ret;
|
||||
}
|
||||
if(*val > 0xff){
|
||||
pr_info("Note: invalid clk delay property :%s, val: %u\n",propname,*val);
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwcmshc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
@@ -599,8 +685,29 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
|
||||
if (device_property_present(&pdev->dev, "is_emmc")) {
|
||||
priv->is_emmc_card = 1;
|
||||
|
||||
if(device_property_get_clk_delay(&pdev->dev, "clk-delay-default", &(priv->delay_line[0]) ) < 0 )
|
||||
priv->delay_line[0] = 50;
|
||||
if(device_property_get_clk_delay(&pdev->dev, "clk-delay-mmc-hs400", &(priv->delay_line[MMC_TIMING_MMC_HS400]) ) < 0 )
|
||||
priv->delay_line[MMC_TIMING_MMC_HS400] = HS400_DELAY_LINE;
|
||||
} else {
|
||||
priv->is_emmc_card = 0;
|
||||
|
||||
if(device_property_get_clk_delay(&pdev->dev, "clk-delay-default", &(priv->delay_line[0]) ) < 0 )
|
||||
priv->delay_line[0] = 0x7d;
|
||||
if(device_property_get_clk_delay(&pdev->dev, "clk-delay-uhs-sdr104", &(priv->delay_line[MMC_TIMING_UHS_SDR104]) ) < 0 )
|
||||
priv->delay_line[MMC_TIMING_UHS_SDR104] = 0x32;
|
||||
|
||||
|
||||
if(device_property_get_clk_delay(&pdev->dev, "rxclk-sample-delay", &(priv->rxclk_delay_set) ) == 0 ){
|
||||
priv->rxclk_sw_tune_en = 1;
|
||||
dev_info(&pdev->dev,"rxclk-sample-delay get val = 0x%x\n",priv->rxclk_delay_set);
|
||||
|
||||
}
|
||||
else {
|
||||
priv->rxclk_sw_tune_en = 0;
|
||||
priv->rxclk_delay_set = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (device_property_present(&pdev->dev, "pull_up")) {
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e)
|
||||
#define PHY_SMPLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x20)
|
||||
#define SMPLDL_CNFG_EXTDLY_EN 0x0 //1bit
|
||||
|
||||
#define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21)
|
||||
#define INPSEL_CNFG 2 //2bit
|
||||
|
||||
@@ -72,4 +74,6 @@
|
||||
#define POST_CHANGE_DLY 0x13 //2bit
|
||||
#define SWIN_TH_VAL 0x18 //9bit
|
||||
|
||||
#define AT_STAT_R (P_VENDOR_SPECIFIC_AREA + 0x44) // 32bit
|
||||
#define AT_STAT_CENTER_PH_CODE 0x0 //0-7bit
|
||||
#endif /* _SDHCI_OF_DWCMSHC_H_*/
|
||||
|
||||
@@ -34,6 +34,11 @@ struct light_src {
|
||||
enum light_src_registers {
|
||||
SRC_WDT0 = 0x0034,
|
||||
SRC_WDT1 = 0x0038,
|
||||
SRC_NPU = 0x01b0,
|
||||
};
|
||||
|
||||
enum light_vpsys_src_registers {
|
||||
SRC_FCE = 0x0004,
|
||||
};
|
||||
|
||||
static int light_reset_update(struct light_src *lightsrc,
|
||||
@@ -48,6 +53,11 @@ static int light_reset_update(struct light_src *lightsrc,
|
||||
static const struct light_src_signal light_src_signals[] = {
|
||||
[LIGHT_RESET_WDT0] = { SRC_WDT0, BIT(0) },
|
||||
[LIGHT_RESET_WDT1] = { SRC_WDT1, BIT(0) },
|
||||
[LIGHT_RESET_NPU] = { SRC_NPU, BIT(0) },
|
||||
};
|
||||
|
||||
static const struct light_src_signal light_vpsys_src_signals[] = {
|
||||
[LIGHT_RESET_FCE] = { SRC_FCE, BIT(0)|BIT(1)|BIT(4)|BIT(5) },
|
||||
};
|
||||
|
||||
static struct light_src *to_light_src(struct reset_controller_dev *rcdev)
|
||||
@@ -94,6 +104,15 @@ static const struct light_src_variant variant_light = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct light_src_variant variant_light_vpsys = {
|
||||
.signals = light_vpsys_src_signals,
|
||||
.signals_num = ARRAY_SIZE(light_vpsys_src_signals),
|
||||
.ops = {
|
||||
.assert = light_reset_assert,
|
||||
.deassert = light_reset_deassert,
|
||||
},
|
||||
};
|
||||
|
||||
static int light_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct light_src *lightsrc;
|
||||
@@ -123,6 +142,7 @@ static int light_reset_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id light_reset_dt_ids[] = {
|
||||
{ .compatible = "thead,light-reset-src", .data = &variant_light },
|
||||
{ .compatible = "thead,light-vpsys-reset-src", .data = &variant_light_vpsys },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, light_reset_dt_ids);
|
||||
|
||||
|
||||
@@ -58,6 +58,10 @@ config RPMSG_QCOM_SMD
|
||||
providing communication channels to remote processors in Qualcomm
|
||||
platforms.
|
||||
|
||||
config RPMSG_THEAD_LIGHT
|
||||
tristate "THEAD Light RPM Driver"
|
||||
depends on RPMSG
|
||||
|
||||
config RPMSG_VIRTIO
|
||||
tristate "Virtio RPMSG bus driver"
|
||||
depends on HAS_DMA
|
||||
|
||||
@@ -8,3 +8,4 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
|
||||
obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o
|
||||
obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o
|
||||
obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o
|
||||
obj-$(CONFIG_RPMSG_THEAD_LIGHT) += light_rpmsg.o
|
||||
|
||||
763
drivers/rpmsg/light_rpmsg.c
Normal file
763
drivers/rpmsg/light_rpmsg.c
Normal file
@@ -0,0 +1,763 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Alibaba Group Holding Limited.
|
||||
*
|
||||
* derived from the omap-rpmsg implementation.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rpmsg.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/virtio.h>
|
||||
#include <linux/virtio_config.h>
|
||||
#include <linux/virtio_ids.h>
|
||||
#include <linux/virtio_ring.h>
|
||||
#include <linux/light_rpmsg.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/light_rpmsg.h>
|
||||
|
||||
#define MBOX_MAX_MSG_LEN 28
|
||||
#define WJ_MBOX_SEND_MAX_MESSAGE_LENGTH 28
|
||||
#define HEXDUMP_BYTES_PER_LINE 28
|
||||
#define HEXDUMP_LINE_LEN ((HEXDUMP_BYTES_PER_LINE * 4) + 2)
|
||||
#define HEXDUMP_MAX_LEN (HEXDUMP_LINE_LEN * \
|
||||
(MBOX_MAX_MSG_LEN / HEXDUMP_BYTES_PER_LINE))
|
||||
|
||||
//extern struct light_rpmsg_vproc *pri_rpdev;
|
||||
static struct dentry *root_debugfs_dir;
|
||||
|
||||
struct mbox_client_light_device {
|
||||
struct device *dev;
|
||||
void __iomem *tx_mmio;
|
||||
void __iomem *rx_mmio;
|
||||
struct mbox_chan *tx_channel;
|
||||
struct mbox_chan *rx_channel;
|
||||
char *rx_buffer;
|
||||
struct regmap *audio_mbox_regmap;
|
||||
char *message;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct mbox_client_light_device *tdev_priv;
|
||||
|
||||
static volatile uint32_t *p_mbox_reg;
|
||||
static volatile uint32_t *p_mbox_reg1;
|
||||
static volatile uint32_t *p_mbox_reg2;
|
||||
|
||||
/*
|
||||
* For now, allocate 256 buffers of 512 bytes for each side. each buffer
|
||||
* will then have 16B for the msg header and 496B for the payload.
|
||||
* This will require a total space of 256KB for the buffers themselves, and
|
||||
* 3 pages for every vring (the size of the vring depends on the number of
|
||||
* buffers it supports).
|
||||
*/
|
||||
#define RPMSG_NUM_BUFS (512)
|
||||
//#define RPMSG_BUF_SIZE (512)
|
||||
//#define RPMSG_BUFS_SPACE (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
|
||||
|
||||
/*
|
||||
* The alignment between the consumer and producer parts of the vring.
|
||||
* Note: this is part of the "wire" protocol. If you change this, you need
|
||||
* to update your BIOS image as well
|
||||
*/
|
||||
#define RPMSG_VRING_ALIGN (4096)
|
||||
|
||||
/* With 256 buffers, our vring will occupy 3 pages */
|
||||
#define RPMSG_RING_SIZE ((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \
|
||||
RPMSG_VRING_ALIGN), PAGE_SIZE)) * PAGE_SIZE)
|
||||
|
||||
#define to_light_virdev(vd) container_of(vd, struct light_virdev, vdev)
|
||||
#define to_light_rpdev(vd, id) container_of(vd, struct light_rpmsg_vproc, ivdev[id])
|
||||
|
||||
struct light_rpmsg_vq_info {
|
||||
__u16 num; /* number of entries in the virtio_ring */
|
||||
__u16 vq_id; /* a globaly unique index of this virtqueue */
|
||||
void *addr; /* address where we mapped the virtio ring */
|
||||
struct light_rpmsg_vproc *rpdev;
|
||||
};
|
||||
|
||||
static u64 light_rpmsg_get_features(struct virtio_device *vdev)
|
||||
{
|
||||
/* VIRTIO_RPMSG_F_NS has been made private */
|
||||
return 1 << 0;
|
||||
}
|
||||
|
||||
static int light_rpmsg_finalize_features(struct virtio_device *vdev)
|
||||
{
|
||||
/* Give virtio_ring a chance to accept features */
|
||||
vring_transport_features(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* kick the remote processor, and let it know which virtqueue to poke at */
|
||||
static bool light_rpmsg_notify(struct virtqueue *vq)
|
||||
{
|
||||
unsigned int mu_rpmsg = 0;
|
||||
int ret;
|
||||
struct light_rpmsg_vq_info *rpvq = vq->priv;
|
||||
|
||||
mu_rpmsg = rpvq->vq_id << 16;
|
||||
mutex_lock(&rpvq->rpdev->lock);
|
||||
|
||||
//pr_info("light rpmsg: notify %d\n", rpvq->rpdev->first_notify);
|
||||
if (unlikely(rpvq->rpdev->first_notify > 0)) {
|
||||
rpvq->rpdev->first_notify--;
|
||||
if (!tdev_priv->tx_channel) {
|
||||
dev_err(tdev_priv->dev, "Channel cannot do Tx+++\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = mbox_send_message(tdev_priv->tx_channel, "Hello, Queue!");
|
||||
} else {
|
||||
*p_mbox_reg1 |= 1 << 0;
|
||||
*p_mbox_reg2 |= 1 << 0;
|
||||
}
|
||||
mutex_unlock(&rpvq->rpdev->lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int light_mu_rpmsg_callback(struct notifier_block *this,
|
||||
unsigned long index, void *data)
|
||||
{
|
||||
u32 mu_msg = (phys_addr_t) data;
|
||||
struct light_virdev *virdev;
|
||||
|
||||
virdev = container_of(this, struct light_virdev, nb);
|
||||
|
||||
pr_debug("light rpmsg: %s notifier_call mu_msg: 0x%x\n", __func__, mu_msg);
|
||||
/* ignore vq indices which are clearly not for us */
|
||||
mu_msg = mu_msg >> 16;
|
||||
if (mu_msg < virdev->base_vq_id || mu_msg > virdev->base_vq_id + 1) {
|
||||
pr_debug("light rpmsg: mu_msg 0x%x is invalid\n", mu_msg);
|
||||
//return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
mu_msg -= virdev->base_vq_id;
|
||||
pr_debug("%smu_msg 0x%xbase_vq_id 0x%xvirdev num_of_vqs0x%x\n", __func__, mu_msg, virdev->base_vq_id, virdev->num_of_vqs);
|
||||
|
||||
/*
|
||||
* Currently both PENDING_MSG and explicit-virtqueue-index
|
||||
* messaging are supported.
|
||||
* Whatever approach is taken, at this point 'mu_msg' contains
|
||||
* the index of the vring which was just triggered.
|
||||
*/
|
||||
//if (mu_msg < virdev->num_of_vqs)
|
||||
vring_interrupt(mu_msg, virdev->vq[mu_msg]);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int light_mu_rpmsg_register_nb(struct light_rpmsg_vproc *rpdev,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
if ((rpdev == NULL) || (nb == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
blocking_notifier_chain_register(&(rpdev->notifier), nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int light_mu_rpmsg_unregister_nb(struct light_rpmsg_vproc *rpdev,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
if ((rpdev == NULL) || (nb == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
blocking_notifier_chain_unregister(&(rpdev->notifier), nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
|
||||
unsigned int index,
|
||||
void (*callback)(struct virtqueue *vq),
|
||||
const char *name,
|
||||
bool ctx)
|
||||
{
|
||||
struct light_virdev *virdev = to_light_virdev(vdev);
|
||||
struct light_rpmsg_vproc *rpdev = to_light_rpdev(virdev,
|
||||
virdev->base_vq_id / 2);
|
||||
struct light_rpmsg_vq_info *rpvq;
|
||||
struct virtqueue *vq;
|
||||
int err;
|
||||
//static void __iomem *brd_io;
|
||||
|
||||
rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL);
|
||||
if (!rpvq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* ioremap'ing normal memory, so we cast away sparse's complaints */
|
||||
//rpvq->addr = (__force void *) ioremap_nocache(virdev->vring[index],
|
||||
// RPMSG_RING_SIZE);
|
||||
rpvq->addr = (__force void *) ioremap(virdev->vring[index],
|
||||
RPMSG_RING_SIZE);
|
||||
if (!rpvq->addr) {
|
||||
err = -ENOMEM;
|
||||
goto free_rpvq;
|
||||
}
|
||||
|
||||
p_mbox_reg = ioremap(0xffefc48000,25);
|
||||
p_mbox_reg1 = p_mbox_reg + 4;
|
||||
p_mbox_reg2 = p_mbox_reg + 5;
|
||||
|
||||
memset_io(rpvq->addr, 0, RPMSG_RING_SIZE);
|
||||
|
||||
pr_debug("vring%d: phys 0x%x, virt 0x%p\n", index, virdev->vring[index],
|
||||
rpvq->addr);
|
||||
|
||||
vq = vring_new_virtqueue(index, RPMSG_NUM_BUFS / 2, RPMSG_VRING_ALIGN,
|
||||
vdev, true, ctx,
|
||||
rpvq->addr,
|
||||
light_rpmsg_notify, callback,
|
||||
name);
|
||||
if (!vq) {
|
||||
pr_err("light rpmsg: vring_new_virtqueue failed\n");
|
||||
err = -ENOMEM;
|
||||
goto unmap_vring;
|
||||
}
|
||||
|
||||
virdev->vq[index] = vq;
|
||||
vq->priv = rpvq;
|
||||
/* system-wide unique id for this virtqueue */
|
||||
rpvq->vq_id = virdev->base_vq_id + index;
|
||||
rpvq->rpdev = rpdev;
|
||||
mutex_init(&rpdev->lock);
|
||||
|
||||
return vq;
|
||||
|
||||
unmap_vring:
|
||||
/* iounmap normal memory, so make sparse happy */
|
||||
iounmap((__force void __iomem *) rpvq->addr);
|
||||
free_rpvq:
|
||||
kfree(rpvq);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static void light_rpmsg_del_vqs(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtqueue *vq, *n;
|
||||
struct light_virdev *virdev = to_light_virdev(vdev);
|
||||
struct light_rpmsg_vproc *rpdev = to_light_rpdev(virdev,
|
||||
virdev->base_vq_id / 2);
|
||||
|
||||
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
|
||||
struct light_rpmsg_vq_info *rpvq = vq->priv;
|
||||
|
||||
iounmap(rpvq->addr);
|
||||
vring_del_virtqueue(vq);
|
||||
kfree(rpvq);
|
||||
}
|
||||
|
||||
if (&virdev->nb)
|
||||
light_mu_rpmsg_unregister_nb(rpdev, &virdev->nb);
|
||||
}
|
||||
|
||||
static int light_rpmsg_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
|
||||
struct virtqueue *vqs[],
|
||||
vq_callback_t *callbacks[],
|
||||
const char * const names[],
|
||||
const bool *ctx,
|
||||
struct irq_affinity *desc)
|
||||
{
|
||||
struct light_virdev *virdev = to_light_virdev(vdev);
|
||||
struct light_rpmsg_vproc *rpdev = to_light_rpdev(virdev,
|
||||
virdev->base_vq_id / 2);
|
||||
int i, err;
|
||||
|
||||
/* we maintain two virtqueues per remote processor (for RX and TX) */
|
||||
if (nvqs != 2)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < nvqs; ++i) {
|
||||
vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i],
|
||||
ctx ? ctx[i] : false);
|
||||
if (IS_ERR(vqs[i])) {
|
||||
err = PTR_ERR(vqs[i]);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
virdev->num_of_vqs = nvqs;
|
||||
|
||||
virdev->nb.notifier_call = light_mu_rpmsg_callback;
|
||||
light_mu_rpmsg_register_nb(rpdev, &virdev->nb);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
light_rpmsg_del_vqs(vdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void light_rpmsg_reset(struct virtio_device *vdev)
|
||||
{
|
||||
dev_dbg(&vdev->dev, "reset!\n");
|
||||
}
|
||||
|
||||
static u8 light_rpmsg_get_status(struct virtio_device *vdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void light_rpmsg_set_status(struct virtio_device *vdev, u8 status)
|
||||
{
|
||||
dev_dbg(&vdev->dev, "%s new status: %d\n", __func__, status);
|
||||
}
|
||||
|
||||
static void light_rpmsg_vproc_release(struct device *dev)
|
||||
{
|
||||
/* this handler is provided so driver core doesn't yell at us */
|
||||
}
|
||||
|
||||
static struct virtio_config_ops light_rpmsg_config_ops = {
|
||||
.get_features = light_rpmsg_get_features,
|
||||
.finalize_features = light_rpmsg_finalize_features,
|
||||
.find_vqs = light_rpmsg_find_vqs,
|
||||
.del_vqs = light_rpmsg_del_vqs,
|
||||
.reset = light_rpmsg_reset,
|
||||
.set_status = light_rpmsg_set_status,
|
||||
.get_status = light_rpmsg_get_status,
|
||||
};
|
||||
|
||||
static struct light_rpmsg_vproc light_rpmsg_vprocs[] = {
|
||||
{
|
||||
.rproc_name = "m4",
|
||||
},
|
||||
{
|
||||
.rproc_name = "m4",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id light_rpmsg_dt_ids[] = {
|
||||
{ .compatible = "light,light-rpmsg", .data = (void *)LIGHT_RPMSG, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, light_rpmsg_dt_ids);
|
||||
|
||||
static int set_vring_phy_buf(struct platform_device *pdev,
|
||||
struct light_rpmsg_vproc *rpdev, int vdev_nums)
|
||||
{
|
||||
struct resource *res;
|
||||
resource_size_t size;
|
||||
unsigned int start, end;
|
||||
int i, ret = 0;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res) {
|
||||
size = resource_size(res);
|
||||
start = res->start;
|
||||
end = res->start + size;
|
||||
for (i = 0; i < vdev_nums; i++) {
|
||||
rpdev->ivdev[i].vring[0] = start;
|
||||
rpdev->ivdev[i].vring[1] = start +
|
||||
0x8000;
|
||||
start += 0x10000;
|
||||
if (start > end) {
|
||||
pr_err("Too small memory size %x!\n",
|
||||
(u32)size);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rpmsg_work_handler(struct work_struct *work)
|
||||
{
|
||||
u32 message = 0;
|
||||
struct delayed_work *dwork = to_delayed_work(work);
|
||||
struct light_rpmsg_vproc *rpdev = container_of(dwork,
|
||||
struct light_rpmsg_vproc, rpmsg_work);
|
||||
|
||||
//spin_lock_irqsave(&rpdev->mu_lock, flags);
|
||||
blocking_notifier_call_chain(&(rpdev->notifier), 4,
|
||||
(void *)(phys_addr_t)message);
|
||||
//spin_unlock_irqrestore(&rpdev->mu_lock, flags);
|
||||
}
|
||||
|
||||
struct light_rpmsg_vproc *pri_rpdev;
|
||||
EXPORT_SYMBOL_GPL(pri_rpdev);
|
||||
|
||||
static int light_rpmsg_probe(struct platform_device *pdev)
|
||||
{
|
||||
int core_id, j, ret = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct light_rpmsg_vproc *rpdev;
|
||||
|
||||
if (of_property_read_u32(np, "multi-core-id", &core_id))
|
||||
core_id = 0;
|
||||
rpdev = &light_rpmsg_vprocs[core_id];
|
||||
rpdev->core_id = core_id;
|
||||
rpdev->variant = (enum light_rpmsg_variants)of_device_get_match_data(dev);
|
||||
|
||||
spin_lock_init(&rpdev->mu_lock);
|
||||
|
||||
pri_rpdev = rpdev;
|
||||
|
||||
INIT_DELAYED_WORK(&(rpdev->rpmsg_work), rpmsg_work_handler);
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&(rpdev->notifier));
|
||||
|
||||
pr_info("light rpmsg: Ready for cross core communication!\n");
|
||||
|
||||
ret = of_property_read_u32(np, "vdev-nums", &rpdev->vdev_nums);
|
||||
if (ret) {
|
||||
rpdev->vdev_nums = 1;
|
||||
}
|
||||
|
||||
if (rpdev->vdev_nums > MAX_VDEV_NUMS) {
|
||||
pr_err("light rpmsg: vdev-nums exceed the max %d\n", MAX_VDEV_NUMS);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rpdev->first_notify = rpdev->vdev_nums;
|
||||
|
||||
pr_info("light rpmsg: rproc_name = %s",rpdev->rproc_name);
|
||||
if (!strcmp(rpdev->rproc_name, "m4")) {
|
||||
ret = set_vring_phy_buf(pdev, rpdev,
|
||||
rpdev->vdev_nums);
|
||||
if (ret) {
|
||||
pr_err("light rpmsg: No vring buffer.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
pr_err("light rpmsg: No remote processor.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (j = 0; j < rpdev->vdev_nums; j++) {
|
||||
pr_debug("%s rpdev%d vdev%d: vring0 0x%x, vring1 0x%x\n",
|
||||
__func__, rpdev->core_id, rpdev->vdev_nums,
|
||||
rpdev->ivdev[j].vring[0],
|
||||
rpdev->ivdev[j].vring[1]);
|
||||
rpdev->ivdev[j].vdev.id.device = VIRTIO_ID_RPMSG;
|
||||
rpdev->ivdev[j].vdev.config = &light_rpmsg_config_ops;
|
||||
rpdev->ivdev[j].vdev.dev.parent = &pdev->dev;
|
||||
rpdev->ivdev[j].vdev.dev.release = light_rpmsg_vproc_release;
|
||||
rpdev->ivdev[j].base_vq_id = j * 2;
|
||||
|
||||
ret = register_virtio_device(&rpdev->ivdev[j].vdev);
|
||||
if (ret) {
|
||||
pr_err("light rpmsg: %s failed to register rpdev: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
platform_set_drvdata(pdev, rpdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int light_rpmsg_suspend(struct device *dev)
|
||||
{
|
||||
struct light_rpmsg_vproc *rpdev = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(rpdev->mu_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int light_rpmsg_resume(struct device *dev)
|
||||
{
|
||||
struct light_rpmsg_vproc *rpdev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(rpdev->mu_clk);
|
||||
if (ret) {
|
||||
pr_err("unable to enable mu clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(light_rpmsg_pm_ops, light_rpmsg_suspend, light_rpmsg_resume);
|
||||
|
||||
static struct platform_driver light_rpmsg_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "light-rpmsg",
|
||||
.of_match_table = light_rpmsg_dt_ids,
|
||||
.pm = &light_rpmsg_pm_ops,
|
||||
},
|
||||
.probe = light_rpmsg_probe,
|
||||
};
|
||||
|
||||
static int __init light_rpmsg_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&light_rpmsg_driver);
|
||||
if (ret)
|
||||
pr_err("light rpmsg: Unable to initialize\n");
|
||||
else
|
||||
pr_info("light rpmsg: driver is registered.\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR(",Inc.");
|
||||
MODULE_DESCRIPTION("remote processor messaging virtio device");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
late_initcall(light_rpmsg_init);
|
||||
|
||||
static ssize_t mbox_client_light_message_write(struct file *filp,
|
||||
const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mbox_client_light_device *tdev = filp->private_data;
|
||||
void *data;
|
||||
int ret;
|
||||
|
||||
if (!tdev->tx_channel) {
|
||||
dev_err(tdev->dev, "Channel cannot do Tx\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (count > WJ_MBOX_SEND_MAX_MESSAGE_LENGTH)
|
||||
count = WJ_MBOX_SEND_MAX_MESSAGE_LENGTH;
|
||||
|
||||
tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
|
||||
if (!tdev->message)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = copy_from_user(tdev->message, userbuf, count);
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = tdev->message;
|
||||
print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->message, MBOX_MAX_MSG_LEN, true);
|
||||
|
||||
ret = mbox_send_message(tdev->tx_channel, data);
|
||||
if (ret < 0)
|
||||
dev_err(tdev->dev, "Failed to send message via mailbox\n");
|
||||
|
||||
out:
|
||||
kfree(tdev->message);
|
||||
return ret < 0 ? ret : count;
|
||||
}
|
||||
|
||||
static ssize_t mbox_client_light_message_read(struct file *filp,
|
||||
char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mbox_client_light_device *tdev = filp->private_data;
|
||||
unsigned long flags;
|
||||
|
||||
print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true);
|
||||
spin_lock_irqsave(&tdev->lock, flags);
|
||||
memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN);
|
||||
spin_unlock_irqrestore(&tdev->lock, flags);
|
||||
|
||||
return MBOX_MAX_MSG_LEN;
|
||||
}
|
||||
|
||||
static const struct file_operations mbox_client_light_message_ops = {
|
||||
.write = mbox_client_light_message_write,
|
||||
.read = mbox_client_light_message_read,
|
||||
.open = simple_open,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
static int index_names = 0;
|
||||
static bool debugfs_dir_created = false;
|
||||
static const char* file_names[] = {"mbox-client0", "mbox-client1"};
|
||||
|
||||
static int mbox_client_light_add_debugfs(struct platform_device *pdev,
|
||||
struct mbox_client_light_device *tdev)
|
||||
{
|
||||
if (!debugfs_initialized())
|
||||
return 0;
|
||||
|
||||
if (index_names > 2) {
|
||||
dev_err(&pdev->dev, "Max device index is 2\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!debugfs_dir_created) {
|
||||
root_debugfs_dir = debugfs_create_dir("mailbox",NULL);
|
||||
if (!root_debugfs_dir) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to create mailbox debugfs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
debugfs_dir_created = true;
|
||||
}
|
||||
|
||||
debugfs_create_file(file_names[index_names], 0600, root_debugfs_dir,
|
||||
tdev, &mbox_client_light_message_ops);
|
||||
|
||||
index_names++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mbox_client_light_receive_message(struct mbox_client *client,
|
||||
void *message)
|
||||
{
|
||||
struct mbox_client_light_device *tdev = dev_get_drvdata(client->dev);
|
||||
char *data = message;
|
||||
|
||||
spin_lock(&tdev->lock);
|
||||
memcpy(tdev->rx_buffer, data, MBOX_MAX_MSG_LEN);
|
||||
spin_unlock(&tdev->lock);
|
||||
|
||||
//printk("mbox_client receive rpmsg_work\n");
|
||||
schedule_delayed_work(&(pri_rpdev->rpmsg_work), 0);
|
||||
|
||||
//print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true);
|
||||
}
|
||||
|
||||
static struct mbox_chan *
|
||||
mbox_client_light_request_channel(struct platform_device *pdev,
|
||||
const char *name)
|
||||
{
|
||||
struct mbox_client *client;
|
||||
struct mbox_chan *channel;
|
||||
|
||||
client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
client->dev = &pdev->dev;
|
||||
client->tx_block = true;
|
||||
client->knows_txdone = false;
|
||||
client->tx_tout = 500;
|
||||
client->rx_callback = mbox_client_light_receive_message;
|
||||
|
||||
channel = mbox_request_channel_byname(client, name);
|
||||
if (IS_ERR(channel)) {
|
||||
devm_kfree(&pdev->dev, client);
|
||||
dev_warn(&pdev->dev, "Failed to request %s channel\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
static int mbox_client_light_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mbox_client_light_device *tdev;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
static int chan_idx = 1;
|
||||
|
||||
tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
|
||||
if (!tdev)
|
||||
return -ENOMEM;
|
||||
|
||||
tdev_priv = tdev;
|
||||
|
||||
if (!chan_idx)
|
||||
tdev->tx_channel = mbox_client_light_request_channel(pdev, "902");
|
||||
else
|
||||
tdev->tx_channel = mbox_client_light_request_channel(pdev, "906");
|
||||
|
||||
if (!tdev->tx_channel) {
|
||||
dev_err(&pdev->dev, "Request channel failed\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
chan_idx++;
|
||||
|
||||
/* In fact, rx_channel is same with tx_channel in C-SKY's mailbox */
|
||||
tdev->rx_channel = tdev->tx_channel;
|
||||
|
||||
tdev->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, tdev);
|
||||
|
||||
tdev->audio_mbox_regmap = syscon_regmap_lookup_by_phandle(np, "audio-mbox-regmap");
|
||||
if (IS_ERR(tdev->audio_mbox_regmap)) {
|
||||
dev_err(&pdev->dev, "cannot find regmap for audio mbox register\n");
|
||||
} else {
|
||||
dev_dbg(&pdev->dev, "audio_mbox_regmap ok\n");
|
||||
}
|
||||
|
||||
spin_lock_init(&tdev->lock);
|
||||
|
||||
tdev->rx_buffer = devm_kzalloc(&pdev->dev,
|
||||
MBOX_MAX_MSG_LEN, GFP_KERNEL);
|
||||
if (!tdev->rx_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = mbox_client_light_add_debugfs(pdev, tdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_err(&pdev->dev, "Successfully registered\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mbox_client_light_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mbox_client_light_device *tdev = platform_get_drvdata(pdev);
|
||||
|
||||
debugfs_remove_recursive(root_debugfs_dir);
|
||||
|
||||
if (tdev->tx_channel)
|
||||
mbox_free_channel(tdev->tx_channel);
|
||||
|
||||
if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel)
|
||||
mbox_free_channel(tdev->rx_channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mbox_client_light_match[] = {
|
||||
{ .compatible = "thead,light-mbox-client" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver mbox_client_light_driver = {
|
||||
.driver = {
|
||||
.name = "thead,light-mbox-client",
|
||||
.of_match_table = mbox_client_light_match,
|
||||
},
|
||||
.probe = mbox_client_light_probe,
|
||||
.remove = mbox_client_light_remove,
|
||||
};
|
||||
module_platform_driver(mbox_client_light_driver);
|
||||
|
||||
MODULE_AUTHOR("Alibaba Group Holding Limited");
|
||||
MODULE_DESCRIPTION("Thead Light mailbox IPC client driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -521,7 +521,16 @@ static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
|
||||
put_device(&ctrldev->dev);
|
||||
}
|
||||
|
||||
static struct rpmsg_device_id rpmsg_driver_char_id_table[] = {
|
||||
{ .name = "rpmsg-virtual-char-channel-1" },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_char_id_table);
|
||||
|
||||
static struct rpmsg_driver rpmsg_chrdev_driver = {
|
||||
.id_table = rpmsg_driver_char_id_table,
|
||||
.probe = rpmsg_chrdev_probe,
|
||||
.remove = rpmsg_chrdev_remove,
|
||||
.drv = {
|
||||
|
||||
@@ -158,7 +158,7 @@ struct virtio_rpmsg_channel {
|
||||
* processor.
|
||||
*/
|
||||
#define MAX_RPMSG_NUM_BUFS (512)
|
||||
#define MAX_RPMSG_BUF_SIZE (512)
|
||||
#define MAX_RPMSG_BUF_SIZE (4096)
|
||||
|
||||
/*
|
||||
* Local addresses are dynamically allocated on-demand.
|
||||
|
||||
@@ -73,6 +73,14 @@
|
||||
#define USB3_DRD_PRST BIT(0)
|
||||
#define USB3_DRD_MASK GENMASK(2, 0)
|
||||
|
||||
/* USB as host or device*/
|
||||
#define USB_AS_HOST (true)
|
||||
#define USB_AS_DEVICE (false)
|
||||
|
||||
static bool usb_role = USB_AS_HOST;
|
||||
module_param(usb_role, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(usb_role, "USB role");
|
||||
|
||||
struct dwc3_thead {
|
||||
struct device *dev;
|
||||
struct platform_device *dwc3;
|
||||
@@ -255,9 +263,10 @@ static int dwc3_thead_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, thead);
|
||||
thead->dev = &pdev->dev;
|
||||
|
||||
thead->hubswitch = devm_gpiod_get(dev, "hubswitch", GPIOD_OUT_HIGH);
|
||||
thead->hubswitch = devm_gpiod_get(dev, "hubswitch", (usb_role == USB_AS_DEVICE) ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(thead->hubswitch))
|
||||
dev_dbg(dev, "no need to get hubswitch GPIO\n");
|
||||
dev_info(dev, "hubswitch usb_role = %d\n", usb_role);
|
||||
|
||||
thead->vbus = devm_regulator_get(dev, "vbus");
|
||||
if (IS_ERR(thead->vbus))
|
||||
|
||||
@@ -1226,6 +1226,12 @@ static int virtio_vdmabuf_create_dmabuf(struct virtio_vdmabuf *vdmabuf,
|
||||
exp_info.flags = O_RDWR;
|
||||
exp_info.priv = exp_buf;
|
||||
|
||||
unsigned int gfp = GFP_KERNEL;
|
||||
if(attr->flags & VIRTIO_VDAMBUF_DMA32)
|
||||
{
|
||||
gfp |= __GFP_DMA32;
|
||||
}
|
||||
|
||||
switch (heap_type) {
|
||||
case VIRTIO_VDMABUF_HEAP_TYPE_USER:
|
||||
return -EINVAL; /* Not support currently */
|
||||
@@ -1235,7 +1241,7 @@ static int virtio_vdmabuf_create_dmabuf(struct virtio_vdmabuf *vdmabuf,
|
||||
exp_buf->bp_num = npages;
|
||||
|
||||
for (i = 0; i < npages; i++) {
|
||||
page = alloc_page(GFP_KERNEL);
|
||||
page = alloc_page(gfp);
|
||||
if (!page) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc;
|
||||
@@ -1253,7 +1259,7 @@ static int virtio_vdmabuf_create_dmabuf(struct virtio_vdmabuf *vdmabuf,
|
||||
/* only need 1 bp to record Compound Page */
|
||||
exp_buf->bp_num = 1;
|
||||
|
||||
page = alloc_pages(GFP_KERNEL, get_order(exp_buf->size));
|
||||
page = alloc_pages(gfp, get_order(exp_buf->size));
|
||||
if (!page) {
|
||||
ret = -ENOMEM;
|
||||
goto err_exp;
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#define __WRITE_ONCE(x, val) \
|
||||
do { \
|
||||
*(volatile typeof(x) *)&(x) = (val); \
|
||||
smp_mb(); \
|
||||
} while (0)
|
||||
|
||||
#define WRITE_ONCE(x, val) \
|
||||
|
||||
35
include/dt-bindings/clock/light-audiosys.h
Normal file
35
include/dt-bindings/clock/light-audiosys.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2022 Alibaba Group Holding Limited.
|
||||
*/
|
||||
|
||||
#ifndef _LIGHT_AUDIOSYS_H_
|
||||
#define _LIGHT_AUDIOSYS_H_
|
||||
|
||||
#define LIGHT_CLKGEN_AUDIO_CPU 0
|
||||
#define LIGHT_CLKGEN_AUDIO_SRAM0 1
|
||||
#define LIGHT_CLKGEN_AUDIO_SRAM1 2
|
||||
#define LIGHT_CLKGEN_AUDIO_DMA 3
|
||||
#define LIGHT_CLKGEN_AUDIO_BSM 4
|
||||
#define LIGHT_CLKGEN_AUDIO_TIMER 5
|
||||
#define LIGHT_CLKGEN_AUDIO_TIMER_CNT1 6
|
||||
#define LIGHT_CLKGEN_AUDIO_TIMER_CNT2 7
|
||||
#define LIGHT_CLKGEN_AUDIO_TIMER_CNT3 8
|
||||
#define LIGHT_CLKGEN_AUDIO_TIMER_CNT4 9
|
||||
#define LIGHT_CLKGEN_AUDIO_WDR 10
|
||||
#define LIGHT_CLKGEN_AUDIO_I2C0 11
|
||||
#define LIGHT_CLKGEN_AUDIO_I2C1 12
|
||||
#define LIGHT_CLKGEN_AUDIO_UART 13
|
||||
#define LIGHT_CLKGEN_AUDIO_I2S0 14
|
||||
#define LIGHT_CLKGEN_AUDIO_I2S1 15
|
||||
#define LIGHT_CLKGEN_AUDIO_I2S2 16
|
||||
#define LIGHT_CLKGEN_AUDIO_I2S8CH 17
|
||||
#define LIGHT_CLKGEN_AUDIO_TDM 18
|
||||
#define LIGHT_CLKGEN_AUDIO_GPIO 19
|
||||
#define LIGHT_CLKGEN_AUDIO_SPDIF0 20
|
||||
#define LIGHT_CLKGEN_AUDIO_SPDIF1 21
|
||||
#define LIGHT_CLKGEN_AUDIO_VAD 22
|
||||
#define LIGHT_CLKGEN_AUDIO_IOMUX 23
|
||||
#define LIGHT_CLKGEN_AUDIO_CLK_END 24
|
||||
|
||||
#endif
|
||||
36
include/dt-bindings/pinctrl/light-fm-pinctrl-def.h
Normal file
36
include/dt-bindings/pinctrl/light-fm-pinctrl-def.h
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
#ifndef __DT_BINDINGS_LIGHT_FM_PINCTRL_DEF_H__
|
||||
#define __DT_BINDINGS_LIGHT_FM_PINCTRL_DEF_H__
|
||||
|
||||
#define LIGHT_PIN_PULL_NONE 0
|
||||
#define LIGHT_PIN_PULL_DOWN 1
|
||||
#define LIGHT_PIN_PULL_UP 2
|
||||
|
||||
#define LIGHT_PIN_DRV_LV0 0
|
||||
#define LIGHT_PIN_DRV_LV1 1
|
||||
#define LIGHT_PIN_DRV_LV2 2
|
||||
#define LIGHT_PIN_DRV_LV3 3
|
||||
#define LIGHT_PIN_DRV_LV4 4
|
||||
#define LIGHT_PIN_DRV_LV5 5
|
||||
#define LIGHT_PIN_DRV_LV6 6
|
||||
#define LIGHT_PIN_DRV_LV7 7
|
||||
#define LIGHT_PIN_DRV_LV8 8
|
||||
#define LIGHT_PIN_DRV_LV9 9
|
||||
#define LIGHT_PIN_DRV_LV10 10
|
||||
#define LIGHT_PIN_DRV_LV11 11
|
||||
#define LIGHT_PIN_DRV_LV12 12
|
||||
#define LIGHT_PIN_DRV_LV13 13
|
||||
#define LIGHT_PIN_DRV_LV14 14
|
||||
#define LIGHT_PIN_DRV_LV15 15
|
||||
|
||||
#define LIGHT_PIN_FUNC_0 0
|
||||
#define LIGHT_PIN_FUNC_1 1
|
||||
#define LIGHT_PIN_FUNC_2 2
|
||||
#define LIGHT_PIN_FUNC_3 3
|
||||
#define LIGHT_PIN_FUNC_4 4
|
||||
#define LIGHT_PIN_FUNC_5 5
|
||||
#define LIGHT_PIN_FUNC_6 6
|
||||
#define LIGHT_PIN_FUNC_7 7
|
||||
|
||||
#endif // __DT_BINDINGS_LIGHT_FM_PINCTRL_DEF_H__
|
||||
@@ -10,5 +10,10 @@
|
||||
|
||||
#define LIGHT_RESET_WDT0 0
|
||||
#define LIGHT_RESET_WDT1 1
|
||||
#define LIGHT_RESET_NPU 2
|
||||
|
||||
// vpsys reset
|
||||
#define LIGHT_RESET_FCE 100
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
88
include/linux/light_rpmsg.h
Normal file
88
include/linux/light_rpmsg.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Alibaba Group Holding Limited.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU Lesser General
|
||||
* Public License. You may obtain a copy of the GNU Lesser General
|
||||
* Public License Version 2.1 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/lgpl-license.html
|
||||
* http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* @file linux/light_rpmsg.h
|
||||
*
|
||||
* @brief Global header file for imx RPMSG
|
||||
*
|
||||
* @ingroup RPMSG
|
||||
*/
|
||||
#ifndef __LINUX_LIGHT_RPMSG_H__
|
||||
#define __LINUX_LIGHT_RPMSG_H__
|
||||
|
||||
#include <linux/rpmsg.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/virtio.h>
|
||||
#include <linux/virtio_config.h>
|
||||
#include <linux/virtio_ids.h>
|
||||
#include <linux/virtio_ring.h>
|
||||
|
||||
/* Category define */
|
||||
#define LIGHT_RMPSG_LIFECYCLE 1
|
||||
#define LIGHT_RPMSG_PMIC 2
|
||||
#define LIGHT_RPMSG_AUDIO 3
|
||||
#define LIGHT_RPMSG_KEY 4
|
||||
#define LIGHT_RPMSG_GPIO 5
|
||||
#define LIGHT_RPMSG_RTC 6
|
||||
#define LIGHT_RPMSG_SENSOR 7
|
||||
/* rpmsg version */
|
||||
#define LIGHT_RMPSG_MAJOR 1
|
||||
#define LIGHT_RMPSG_MINOR 0
|
||||
|
||||
enum light_rpmsg_variants {
|
||||
LIGHTA,
|
||||
LIGHTB,
|
||||
LIGHT_RPMSG,
|
||||
};
|
||||
|
||||
struct light_virdev {
|
||||
struct virtio_device vdev;
|
||||
unsigned int vring[2];
|
||||
struct virtqueue *vq[2];
|
||||
int base_vq_id;
|
||||
int num_of_vqs;
|
||||
struct notifier_block nb;
|
||||
};
|
||||
|
||||
struct light_rpmsg_vproc {
|
||||
char *rproc_name;
|
||||
struct mutex lock;
|
||||
struct clk *mu_clk;
|
||||
enum light_rpmsg_variants variant;
|
||||
int vdev_nums;
|
||||
int first_notify;
|
||||
#define MAX_VDEV_NUMS 8
|
||||
struct light_virdev ivdev[MAX_VDEV_NUMS];
|
||||
void __iomem *mu_base;
|
||||
struct delayed_work rpmsg_work;
|
||||
struct blocking_notifier_head notifier;
|
||||
#define MAX_NUM 10 /* enlarge it if overflow happen */
|
||||
u32 m4_message[MAX_NUM];
|
||||
u32 in_idx;
|
||||
u32 out_idx;
|
||||
u32 core_id;
|
||||
spinlock_t mu_lock;
|
||||
};
|
||||
|
||||
struct light_rpmsg_head {
|
||||
u8 cate;
|
||||
u8 major;
|
||||
u8 minor;
|
||||
u8 type;
|
||||
u8 cmd;
|
||||
u8 reserved[5];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* __LINUX_LIGHT_RPMSG_H__*/
|
||||
|
||||
@@ -17,7 +17,8 @@ _IOC(_IOC_NONE, 'G', 2, sizeof(struct virtio_vdmabuf_alloc))
|
||||
_IOC(_IOC_NONE, 'G', 3, sizeof(struct virtio_vdmabuf_import))
|
||||
|
||||
/* dmabuf flag */
|
||||
#define VIRTIO_VDAMBUF_NONCACHED 0x1
|
||||
#define VIRTIO_VDAMBUF_NONCACHED 0x1
|
||||
#define VIRTIO_VDAMBUF_DMA32 0x4
|
||||
|
||||
/*
|
||||
* Max single alloc size is (768 * PAGE_SIZE) only for
|
||||
|
||||
@@ -94,7 +94,7 @@ struct qnode {
|
||||
* progress.
|
||||
*/
|
||||
#ifndef _Q_PENDING_LOOPS
|
||||
#define _Q_PENDING_LOOPS 1
|
||||
#define _Q_PENDING_LOOPS 9
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@@ -435,7 +435,7 @@ static bool rcu_preempt_has_tasks(struct rcu_node *rnp)
|
||||
* be quite short, for example, in the case of the call from
|
||||
* rcu_read_unlock_special().
|
||||
*/
|
||||
static void
|
||||
static notrace void
|
||||
rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
|
||||
{
|
||||
bool empty_exp;
|
||||
@@ -556,7 +556,7 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
|
||||
* is disabled. This function cannot be expected to understand these
|
||||
* nuances, so the caller must handle them.
|
||||
*/
|
||||
static bool rcu_preempt_need_deferred_qs(struct task_struct *t)
|
||||
static notrace bool rcu_preempt_need_deferred_qs(struct task_struct *t)
|
||||
{
|
||||
return (__this_cpu_read(rcu_data.exp_deferred_qs) ||
|
||||
READ_ONCE(t->rcu_read_unlock_special.s)) &&
|
||||
@@ -570,7 +570,7 @@ static bool rcu_preempt_need_deferred_qs(struct task_struct *t)
|
||||
* evaluate safety in terms of interrupt, softirq, and preemption
|
||||
* disabling.
|
||||
*/
|
||||
static void rcu_preempt_deferred_qs(struct task_struct *t)
|
||||
static notrace void rcu_preempt_deferred_qs(struct task_struct *t)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@@ -897,11 +897,11 @@ static bool rcu_preempt_has_tasks(struct rcu_node *rnp)
|
||||
* Because there is no preemptible RCU, there can be no deferred quiescent
|
||||
* states.
|
||||
*/
|
||||
static bool rcu_preempt_need_deferred_qs(struct task_struct *t)
|
||||
static notrace bool rcu_preempt_need_deferred_qs(struct task_struct *t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static void rcu_preempt_deferred_qs(struct task_struct *t) { }
|
||||
static notrace void rcu_preempt_deferred_qs(struct task_struct *t) { }
|
||||
|
||||
/*
|
||||
* Because there is no preemptible RCU, there can be no readers blocked,
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/initval.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include "es7210.h"
|
||||
|
||||
|
||||
@@ -912,7 +913,20 @@ exit_i2c_check_id_failed:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void es7210_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct es7210_priv *es7210 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
/* power down the controller */
|
||||
if (es7210->pvdd)
|
||||
regulator_disable(es7210->pvdd);
|
||||
if (es7210->dvdd)
|
||||
regulator_disable(es7210->dvdd);
|
||||
if (es7210->avdd)
|
||||
regulator_disable(es7210->avdd);
|
||||
if (es7210->mvdd)
|
||||
regulator_disable(es7210->mvdd);
|
||||
}
|
||||
|
||||
static int es7210_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include "es8156.h"
|
||||
|
||||
#define INVALID_GPIO -1
|
||||
@@ -63,6 +64,9 @@ struct es8156_priv {
|
||||
unsigned int sysclk;
|
||||
struct snd_pcm_hw_constraint_list *sysclk_constraints;
|
||||
struct clk *mclk;
|
||||
struct regulator *avdd;
|
||||
struct regulator *dvdd;
|
||||
struct regulator *pvdd;
|
||||
int debounce_time;
|
||||
int hp_det_invert;
|
||||
struct delayed_work work;
|
||||
@@ -74,6 +78,7 @@ struct es8156_priv {
|
||||
bool spk_active_level;
|
||||
|
||||
int pwr_count;
|
||||
u32 mclk_sclk_ratio;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -143,6 +148,158 @@ static const struct snd_soc_dapm_widget es8156_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_OUTPUT("ROUT"),
|
||||
};
|
||||
|
||||
/*************** parameter define ***************/
|
||||
#define STATEconfirm 0x0C
|
||||
#define NORMAL_I2S 0x00
|
||||
#define NORMAL_LJ 0x01
|
||||
#define NORMAL_DSPA 0x03
|
||||
#define NORMAL_DSPB 0x07
|
||||
#define Format_Len24 0x00
|
||||
#define Format_Len20 0x01
|
||||
#define Format_Len18 0x02
|
||||
#define Format_Len16 0x03
|
||||
#define Format_Len32 0x04
|
||||
|
||||
#define VDDA_3V3 0x00
|
||||
#define VDDA_1V8 0x01
|
||||
#define MCLK_PIN 0x00
|
||||
#define SCLK_PIN 0x01
|
||||
|
||||
/**************************************************/
|
||||
#define MSMode_MasterSelOn 0 // SlaveMode:0, MasterMode:1
|
||||
static unsigned int Ratio = 64; // Ratio = MCLK/LRCK on board
|
||||
#define Format NORMAL_I2S
|
||||
#define Format_Len Format_Len16 // data format
|
||||
#define SCLK_DIV 8 // SCLK_DIV = MCLK/SCLK
|
||||
#define SCLK_INV 0
|
||||
static unsigned int MCLK_SOURCE; // select MCLK source, MCLK_PIN or SCLK_PIN
|
||||
#define EQ7bandOn 0
|
||||
#define VDDA_VOLTAGE VDDA_3V3
|
||||
#define DAC_Volume 191 // DAC digital gain
|
||||
#define DACHPModeOn 0 // disable:0, enable:1
|
||||
|
||||
/**************************************************/
|
||||
|
||||
static int es8156_init_regs(struct snd_soc_component *codec)
|
||||
{
|
||||
struct es8156_priv *priv = snd_soc_component_get_drvdata(codec);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
snd_soc_component_write(codec,0x02,(MCLK_SOURCE<<7) + (SCLK_INV<<4) + (EQ7bandOn<<3) + 0x04 + MSMode_MasterSelOn);
|
||||
snd_soc_component_write(codec,0x19,0x20);
|
||||
|
||||
if(DACHPModeOn == 0) // output from PA
|
||||
{
|
||||
snd_soc_component_write(codec,0x20,0x2A);
|
||||
snd_soc_component_write(codec,0x21,0x3C);
|
||||
snd_soc_component_write(codec,0x22,0x02);
|
||||
snd_soc_component_write(codec,0x24,0x07);
|
||||
snd_soc_component_write(codec,0x23,0x40 + (0x30*VDDA_VOLTAGE));
|
||||
}
|
||||
if(DACHPModeOn == 1) // output from headphone
|
||||
{
|
||||
snd_soc_component_write(codec,0x20,0x16);
|
||||
snd_soc_component_write(codec,0x21,0x3F);
|
||||
snd_soc_component_write(codec,0x22,0x0A);
|
||||
snd_soc_component_write(codec,0x24,0x01);
|
||||
snd_soc_component_write(codec,0x23,0xCA + (0x30*VDDA_VOLTAGE));
|
||||
}
|
||||
snd_soc_component_write(codec,0x0A,0x01);
|
||||
snd_soc_component_write(codec,0x0B,0x01);
|
||||
//snd_soc_component_write(codec,0x11,NORMAL_I2S + (Format_Len<<4));
|
||||
|
||||
if(Ratio == 1536) // Ratio=MCLK/LRCK=1536; 12M288/8K; 24M576/16K
|
||||
{
|
||||
snd_soc_component_write(codec,0x01,0x26 - (0x03*EQ7bandOn)); // 1536 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x09,0x00); // 1536 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x03,0x06); // LRCK H
|
||||
snd_soc_component_write(codec,0x04,0x00); // LRCK=MCLK/1536
|
||||
snd_soc_component_write(codec,0x05,SCLK_DIV); // BCLK=MCLK/4
|
||||
}
|
||||
if(Ratio == 1024) // Ratio=MCLK/LRCK=1024; 12M288/12K; 24M576/24K
|
||||
{
|
||||
snd_soc_component_write(codec,0x01,0x24 - (0x02*EQ7bandOn)); // 256 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x09,0x00); // 256 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x03,0x04); // LRCK H
|
||||
snd_soc_component_write(codec,0x04,0x00); // LRCK=MCLK/256
|
||||
snd_soc_component_write(codec,0x05,SCLK_DIV); // BCLK=MCLK/4
|
||||
}
|
||||
if(Ratio == 768) // Ratio=MCLK/LRCK=768; 12M288/16K; 24M576/32K
|
||||
{
|
||||
snd_soc_component_write(codec,0x01,0x23 + (0x40*EQ7bandOn)); // 768 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x09,0x00); // 768 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x03,0x03); // LRCK H
|
||||
snd_soc_component_write(codec,0x04,0x00); // LRCK=MCLK/768
|
||||
snd_soc_component_write(codec,0x05,SCLK_DIV); // BCLK=MCLK/4
|
||||
}
|
||||
if(Ratio == 512) // Ratio=MCLK/LRCK=512; 12M288/24K; 24M576/48K
|
||||
{
|
||||
snd_soc_component_write(codec,0x01,0xC0 + 0x22 - (0x01*EQ7bandOn)); // 512 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x09,0x00); // 512 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x03,0x02); // LRCK H
|
||||
snd_soc_component_write(codec,0x04,0x00); // LRCK=MCLK/512
|
||||
snd_soc_component_write(codec,0x05,SCLK_DIV); //BCLK=MCLK/4
|
||||
}
|
||||
if(Ratio == 400) // Ratio=MCLK/LRCK=400; 19M2/48K
|
||||
{ // DVDD must be 3.3V
|
||||
snd_soc_component_write(codec,0x01,0x21 + (0x40*EQ7bandOn)); // 384 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x09,0x00); // 400 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x10,0x64); // 400 OSR
|
||||
snd_soc_component_write(codec,0x03,0x01); // LRCK H
|
||||
snd_soc_component_write(codec,0x04,0x90); // LRCK=MCLK/400
|
||||
snd_soc_component_write(codec,0x05,SCLK_DIV); // BCLK=MCLK/4
|
||||
}
|
||||
if(Ratio == 384) // Ratio=MCLK/LRCK=384; 12M288/32K; 6M144/16K
|
||||
{
|
||||
snd_soc_component_write(codec,0x01,0x63 + (0x40*EQ7bandOn)); // 384 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x09,0x00); // 384 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x03,0x01); // LRCK H
|
||||
snd_soc_component_write(codec,0x04,0x80); // LRCK=MCLK/384
|
||||
snd_soc_component_write(codec,0x05,SCLK_DIV); // BCLK=MCLK/4
|
||||
}
|
||||
if(Ratio == 256) // Ratio=MCLK/LRCK=256; 12M288/48K
|
||||
{
|
||||
snd_soc_component_write(codec,0x01,0x21 + (0x40*EQ7bandOn)); // 256 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x09,0x00); // 256 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x03,0x01); // LRCK H
|
||||
snd_soc_component_write(codec,0x04,0x00); // LRCK=MCLK/256
|
||||
snd_soc_component_write(codec,0x05,SCLK_DIV); // BCLK=MCLK/4
|
||||
}
|
||||
if(Ratio == 128) // Ratio=MCLK/LRCK=128; 6M144/48K
|
||||
{
|
||||
snd_soc_component_write(codec,0x01,0x61 + (0x40*EQ7bandOn)); // 128 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x09,0x00); // 128 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x03,0x00); // LRCK H
|
||||
snd_soc_component_write(codec,0x04,0x80); // LRCK=MCLK/128
|
||||
snd_soc_component_write(codec,0x05,SCLK_DIV); // BCLK=MCLK/4
|
||||
}
|
||||
if(Ratio == 64) // Ratio=MCLK/LRCK=64; 3M072/48K
|
||||
{
|
||||
snd_soc_component_write(codec,0x01,0xE1); // 64 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x09,0x02); // 64 Ratio(MCLK/LRCK)
|
||||
snd_soc_component_write(codec,0x03,0x00); // LRCK H
|
||||
snd_soc_component_write(codec,0x04,0x40); // LRCK=MCLK/64
|
||||
snd_soc_component_write(codec,0x05,SCLK_DIV); // BCLK=MCLK/2
|
||||
}
|
||||
|
||||
snd_soc_component_write(codec,0x0D,0x14);
|
||||
snd_soc_component_write(codec,0x18,0x00);
|
||||
snd_soc_component_write(codec,0x08,0x3F);
|
||||
snd_soc_component_write(codec,0x00,0x02);
|
||||
snd_soc_component_write(codec,0x00,0x03);
|
||||
snd_soc_component_write(codec,0x25,0x20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es8156_init_sequence(struct snd_soc_component *codec)
|
||||
{
|
||||
es8156_init_regs(codec);
|
||||
snd_soc_component_write(codec, ES8156_VOLUME_CONTROL_REG14, DAC_Volume);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_route es8156_dapm_routes[] = {
|
||||
{"SDOUT TRISTATE",NULL,"SDIN"},
|
||||
{"SDOUT",NULL,"SDOUT TRISTATE"},
|
||||
@@ -392,7 +549,7 @@ static int es8156_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
static int es8156_set_bias_level(struct snd_soc_component *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
int ret;
|
||||
int ret, i;
|
||||
struct es8156_priv *priv = snd_soc_component_get_drvdata(codec);
|
||||
|
||||
switch (level)
|
||||
@@ -547,12 +704,23 @@ static void hp_work(struct work_struct *work)
|
||||
|
||||
static int es8156_probe(struct snd_soc_component *codec)
|
||||
{
|
||||
#if MCLK
|
||||
struct es8156_priv *es8156 = snd_soc_component_get_drvdata(codec);
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
es8156_codec = codec;
|
||||
|
||||
/* power up the controller */
|
||||
if (es8156->avdd)
|
||||
ret |= regulator_enable(es8156->avdd);
|
||||
if (es8156->dvdd)
|
||||
ret |= regulator_enable(es8156->dvdd);
|
||||
if (es8156->pvdd)
|
||||
ret |= regulator_enable(es8156->pvdd);
|
||||
if (ret) {
|
||||
pr_err("Failed to enable VDD regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if MCLK
|
||||
es8156->mclk = devm_clk_get(codec->dev, "mclk");
|
||||
if (PTR_ERR(es8156->mclk) == -EPROBE_DEFER)
|
||||
@@ -600,10 +768,10 @@ static int es8156_i2c_probe(struct i2c_client *i2c,
|
||||
{
|
||||
struct es8156_priv *es8156;
|
||||
int ret = -1;
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
#ifdef HP_DET_FUNTION
|
||||
int hp_irq;
|
||||
enum of_gpio_flags flags;
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
#endif
|
||||
es8156 = devm_kzalloc(&i2c->dev, sizeof(*es8156), GFP_KERNEL);
|
||||
if (!es8156)
|
||||
@@ -622,6 +790,35 @@ static int es8156_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
es8156->avdd = devm_regulator_get(&i2c->dev, "AVDD");
|
||||
if (IS_ERR(es8156->avdd)) {
|
||||
ret = PTR_ERR(es8156->avdd);
|
||||
dev_warn(&i2c->dev, "Failed to get AVDD regulator: %d\n", ret);
|
||||
es8156->avdd = NULL;
|
||||
}
|
||||
es8156->dvdd = devm_regulator_get(&i2c->dev, "DVDD");
|
||||
if (IS_ERR(es8156->dvdd)) {
|
||||
ret = PTR_ERR(es8156->dvdd);
|
||||
dev_warn(&i2c->dev, "Failed to get DVDD regulator: %d\n", ret);
|
||||
es8156->dvdd = NULL;
|
||||
}
|
||||
es8156->pvdd = devm_regulator_get(&i2c->dev, "PVDD");
|
||||
if (IS_ERR(es8156->pvdd)) {
|
||||
ret = PTR_ERR(es8156->pvdd);
|
||||
dev_warn(&i2c->dev, "Failed to get PVDD regulator: %d\n", ret);
|
||||
es8156->pvdd = NULL;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "mclk-sclk-ratio", &es8156->mclk_sclk_ratio) != 0) {
|
||||
es8156->mclk_sclk_ratio = 1;
|
||||
}
|
||||
Ratio *= es8156->mclk_sclk_ratio;
|
||||
if (es8156->mclk_sclk_ratio == 1) {
|
||||
MCLK_SOURCE = SCLK_PIN;
|
||||
} else {
|
||||
MCLK_SOURCE = MCLK_PIN;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, es8156);
|
||||
#ifdef HP_DET_FUNTION
|
||||
es8156->spk_ctl_gpio = of_get_named_gpio_flags(np,
|
||||
|
||||
@@ -145,19 +145,16 @@ EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name);
|
||||
|
||||
static int asoc_simple_clk_enable(struct asoc_simple_dai *dai)
|
||||
{
|
||||
if (dai) {
|
||||
if (!IS_ERR_OR_NULL(dai->clk))
|
||||
return clk_prepare_enable(dai->clk);
|
||||
}
|
||||
if (dai)
|
||||
return clk_prepare_enable(dai->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void asoc_simple_clk_disable(struct asoc_simple_dai *dai)
|
||||
{
|
||||
if (dai) {
|
||||
if (!IS_ERR_OR_NULL(dai->clk))
|
||||
clk_disable_unprepare(dai->clk);
|
||||
}
|
||||
if (dai)
|
||||
clk_disable_unprepare(dai->clk);
|
||||
}
|
||||
|
||||
int asoc_simple_parse_clk(struct device *dev,
|
||||
@@ -185,7 +182,6 @@ int asoc_simple_parse_clk(struct device *dev,
|
||||
clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
|
||||
if (!IS_ERR(clk))
|
||||
simple_dai->sysclk = clk_get_rate(clk);
|
||||
simple_dai->clk = NULL; // avoid invalid clk pointer like 0x00000000d
|
||||
}
|
||||
|
||||
if (of_property_read_bool(node, "system-clock-direction-out"))
|
||||
@@ -246,11 +242,7 @@ static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
|
||||
if (clk_get_rate(simple_dai->clk) == rate)
|
||||
return 0;
|
||||
|
||||
if (!IS_ERR_OR_NULL(simple_dai->clk)) {
|
||||
return clk_set_rate(simple_dai->clk, rate);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return clk_set_rate(simple_dai->clk, rate);
|
||||
}
|
||||
|
||||
int asoc_simple_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
obj-$(CONFIG_SND_SOC_THEAD_LIGHT) += light-i2s.o
|
||||
obj-$(CONFIG_SND_SOC_THEAD_LIGHT) += light-tdm.o
|
||||
obj-$(CONFIG_SND_SOC_THEAD_LIGHT) += light-i2s-8ch.o
|
||||
obj-$(CONFIG_SND_SOC_THEAD_LIGHT) += light-spdif.o
|
||||
obj-$(CONFIG_SND_SOC_THEAD_LIGHT) += light-pcm-dma.o
|
||||
obj-$(CONFIG_SND_SOC_THEAD_LIGHT) += light-dummy-pcm.o
|
||||
obj-$(CONFIG_SND_SOC_AW87519) += aw87519_audio.o
|
||||
|
||||
49
sound/soc/thead/light-audio-cpr.h
Normal file
49
sound/soc/thead/light-audio-cpr.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef _LIGHT_AUDIO_CPR_H
|
||||
#define _LIGHT_AUDIO_CPR_H
|
||||
|
||||
#define CPR_PERI_DIV_SEL_REG 0x004 /*audio sys i2s clock div Register*/
|
||||
#define CPR_PERI_CLK_SEL_REG 0x008 /*audio sys i2s clock selection Register*/
|
||||
#define CPR_PERI_CTRL_REG 0x00C /*Peripheral control signal configuration register*/
|
||||
|
||||
|
||||
/* AUDIO SYS DIV SEL REG, offset: 0x4 */
|
||||
#define CPR_AUDIO_DIV0_SEL_POS (4U)
|
||||
#define CPR_AUDIO_DIV0_SEL_MSK (0x1FU << CPR_AUDIO_DIV0_SEL_POS)
|
||||
#define CPR_AUDIO_DIV0_SEL(X) (X << CPR_AUDIO_DIV0_SEL_POS)
|
||||
#define CPR_AUDIO_DIV1_SEL_POS (12U)
|
||||
#define CPR_AUDIO_DIV1_SEL_MSK (0x1FU << CPR_AUDIO_DIV1_SEL_POS)
|
||||
#define CPR_AUDIO_DIV1_SEL(X) (X << CPR_AUDIO_DIV1_SEL_POS)
|
||||
|
||||
/* AUDIO SYS CLK SEL REG, offset: 0x8 */
|
||||
#define CPR_I2S0_SRC_SEL_POS (0U)
|
||||
#define CPR_I2S0_SRC_SEL_MSK (0x3U << CPR_I2S0_SRC_SEL_POS)
|
||||
#define CPR_I2S0_SRC_SEL(X) (X << CPR_I2S0_SRC_SEL_POS)
|
||||
#define CPR_I2S0_SRC_SEL_24M (0x1U << AUDIOSYS_I2S0_SRC_SEL_POS)
|
||||
#define CPR_I2S0_SRC_SEL_AUDIO_DIVCLK1 (0x2U << AUDIOSYS_I2S0_SRC_SEL_POS)
|
||||
|
||||
#define CPR_I2S1_SRC_SEL_POS (4U)
|
||||
#define CPR_I2S1_SRC_SEL_MSK (0x3U << CPR_I2S1_SRC_SEL_POS)
|
||||
#define CPR_I2S1_SRC_SEL(X) (X << CPR_I2S1_SRC_SEL_POS)
|
||||
#define CPR_I2S1_SRC_SEL_24M (0x1U << AUDIOSYS_I2S1_SRC_SEL_POS)
|
||||
#define CPR_I2S1_SRC_SEL_AUDIO_DIVCLK1 (0x2U << AUDIOSYS_I2S1_SRC_SEL_POS)
|
||||
|
||||
#define CPR_I2S2_SRC_SEL_POS (8U)
|
||||
#define CPR_I2S2_SRC_SEL_MSK (0x3U << CPR_I2S2_SRC_SEL_POS)
|
||||
#define CPR_I2S2_SRC_SEL(X) (X << CPR_I2S2_SRC_SEL_POS)
|
||||
#define CPR_I2S2_SRC_SEL_24M (0x1U << AUDIOSYS_I2S2_SRC_SEL_POS)
|
||||
#define CPR_I2S2_SRC_SEL_AUDIO_DIVCLK1 (0x2U << AUDIOSYS_I2S2_SRC_SEL_POS)
|
||||
|
||||
/* PERI_CTRL_REG, Offset: 0xC */
|
||||
#define CPR_VAD_I2SIN_SYNC_POS (12U)
|
||||
#define CPR_VAD_I2SIN_SYNC_MSK (0x1U << CPR_VAD_I2SIN_SYNC_POS)
|
||||
#define CPR_VAD_I2SIN_SYNC_EN (CPR_VAD_I2SIN_SYNC_MSK)
|
||||
#define CPR_I2S_SYNC_POS (13U)
|
||||
#define CPR_I2S_SYNC_MSK (0x1U << CPR_I2S_SYNC_POS)
|
||||
#define CPR_I2S_SYNC_EN (CPR_I2S_SYNC_MSK)
|
||||
#define CPR_SPDIF_SYNC_POS (14U)
|
||||
#define CPR_SPDIF_SYNC_MSK (0x1U << CPR_SPDIF_SYNC_POS)
|
||||
#define CPR_SPDIF_SYNC_EN (CPR_SPDIF_SYNC_MSK)
|
||||
|
||||
|
||||
#endif /* _LIGHT_AUDIO_CPR_H */
|
||||
|
||||
@@ -25,17 +25,17 @@ static struct snd_soc_dai_driver light_dummy_pcm_dai[] = {
|
||||
.name = "dummy-pcm",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
797
sound/soc/thead/light-i2s-8ch.c
Normal file
797
sound/soc/thead/light-i2s-8ch.c
Normal file
@@ -0,0 +1,797 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
||||
*/
|
||||
//#define DEBUG
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/sh_fsi.h>
|
||||
#include "light-i2s.h"
|
||||
#include "light-pcm.h"
|
||||
#include "light-audio-cpr.h"
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <dt-bindings/pinctrl/light-fm-aon-pinctrl.h>
|
||||
|
||||
#define IIS_SRC_CLK 294912000
|
||||
#define AUDIO_IIS_SRC0_CLK 49152000
|
||||
#define AUDIO_IIS_SRC1_CLK 135475200
|
||||
#define IIS_MCLK_SEL 256
|
||||
#define HDMI_DIV_VALUE 2
|
||||
#define DIV_DEFAULT 1
|
||||
#define MONO_SOURCE 1
|
||||
#define STEREO_CHANNEL 2
|
||||
|
||||
#define I2S_DMA_TX_THRESHOLD 16
|
||||
#define I2S_DMA_RX_THRESHOLD 16
|
||||
|
||||
#define AUDIO_I2S_8CH "i2s_8ch"
|
||||
#define AUDIO_I2S_8CH_SD0 "i2s_8ch_sd0"
|
||||
#define AUDIO_I2S_8CH_SD1 "i2s_8ch_sd1"
|
||||
#define AUDIO_I2S_8CH_SD2 "i2s_8ch_sd2"
|
||||
#define AUDIO_I2S_8CH_SD3 "i2s_8ch_sd3"
|
||||
|
||||
#define LIGHT_I2S_DMABUF_SIZE (64 * 1024 * 10)
|
||||
|
||||
#define LIGHT_RATES SNDRV_PCM_RATE_8000_384000
|
||||
#define LIGHT_FMTS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8)
|
||||
|
||||
#define LIGHT_AUDIO_PAD_CONFIG(idx) (priv->cfg_off + ((idx-25) >> 1) * 4)
|
||||
|
||||
static int i2s_8ch_probe_flag = 0;
|
||||
static u32 light_special_sample_rates[] = { 11025, 22050, 44100, 88200 };
|
||||
|
||||
static int light_audio_cpr_set(struct light_i2s_priv *chip, unsigned int cpr_off,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
if(!chip->audio_cpr_regmap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return regmap_update_bits(chip->audio_cpr_regmap,
|
||||
cpr_off, mask, val);
|
||||
}
|
||||
|
||||
static void light_i2s_8ch_set_div_sclk(struct light_i2s_priv *chip, u32 sample_rate, unsigned int div_val)
|
||||
{
|
||||
u32 div;
|
||||
u32 div0;
|
||||
u32 cpr_div = (IIS_SRC_CLK/AUDIO_IIS_SRC0_CLK)-1;
|
||||
if(!chip->regs) {
|
||||
return;
|
||||
}
|
||||
|
||||
div = AUDIO_IIS_SRC0_CLK / IIS_MCLK_SEL;
|
||||
div0 = (div + div % sample_rate) / sample_rate / div_val;
|
||||
writel(div0, chip->regs + I2S_DIV0_LEVEL);
|
||||
light_audio_cpr_set(chip, CPR_PERI_DIV_SEL_REG, CPR_AUDIO_DIV0_SEL_MSK, CPR_AUDIO_DIV0_SEL(cpr_div));
|
||||
}
|
||||
|
||||
static inline void light_snd_txctrl(struct light_i2s_priv *chip, bool on)
|
||||
{
|
||||
u32 dma_en = 0;
|
||||
u32 i2s_8ch_en = 0;
|
||||
u32 i2s_8ch_imr = 0;
|
||||
|
||||
if(!chip->regs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (on) {
|
||||
dma_en |= DMACR_TDMAE_EN;
|
||||
i2s_8ch_en |= IISEN_I2SEN;
|
||||
writel(dma_en, chip->regs + I2S_DMACR);
|
||||
writel(i2s_8ch_en, chip->regs + I2S_IISEN);
|
||||
} else {
|
||||
dma_en &= ~DMACR_TDMAE_EN;
|
||||
i2s_8ch_en &= ~IISEN_I2SEN;
|
||||
i2s_8ch_imr = readl(chip->regs + I2S_IMR);
|
||||
i2s_8ch_imr &= ~(IMR_TXUIRM_INTR_MSK);
|
||||
i2s_8ch_imr &= ~(IMR_TXEIM_INTR_MSK);
|
||||
writel(i2s_8ch_imr, chip->regs + I2S_IMR);
|
||||
writel(dma_en, chip->regs + I2S_DMACR);
|
||||
writel(i2s_8ch_en, chip->regs + I2S_IISEN);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void light_snd_rxctrl(struct light_i2s_priv *chip, bool on)
|
||||
{
|
||||
u32 dma_en = 0;
|
||||
u32 i2s_8ch_en = 0;
|
||||
|
||||
if(!chip->regs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (on) {
|
||||
dma_en |= DMACR_RDMAE_EN;
|
||||
i2s_8ch_en |= IISEN_I2SEN;
|
||||
writel(I2S_DMA_RX_THRESHOLD, chip->regs + I2S_DMARDLR);
|
||||
} else {
|
||||
dma_en &= ~DMACR_RDMAE_EN;
|
||||
i2s_8ch_en &= ~IISEN_I2SEN;
|
||||
}
|
||||
|
||||
writel(dma_en, chip->regs + I2S_DMACR);
|
||||
writel(i2s_8ch_en, chip->regs + I2S_IISEN);
|
||||
}
|
||||
|
||||
static int light_i2s_8ch_dai_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void light_i2s_8ch_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct light_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
light_snd_rxctrl(priv, 0);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
}
|
||||
|
||||
/**
|
||||
* light_i2s_8ch_dai_trigger: start and stop the DMA transfer.
|
||||
*
|
||||
* This function is called by ALSA to start, stop, pause, and resume the DMA
|
||||
* transfer of data.
|
||||
*/
|
||||
static int light_i2s_8ch_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct light_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (tx)
|
||||
light_snd_txctrl(priv, 1);
|
||||
else
|
||||
light_snd_rxctrl(priv, 1);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (tx) {
|
||||
dmaengine_terminate_async(snd_dmaengine_pcm_get_chan(substream)); // work around for DMAC stop issue
|
||||
light_snd_txctrl(priv, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int light_i2s_8ch_set_fmt_dai(struct snd_soc_dai *cpu_dai, unsigned int fmt)
|
||||
{
|
||||
struct light_i2s_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
u32 cnfout = 0;
|
||||
u32 cnfin = 0;
|
||||
|
||||
if(!priv->regmap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
cnfout |= IISCNFOUT_TSAFS_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
cnfout |= IISCNFOUT_TSAFS_RIGHT_JUSTIFIED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
cnfout |= IISCNFOUT_TSAFS_LEFT_JUSTIFIED;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown fmt dai\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->regmap, I2S_IISCNF_OUT,
|
||||
IISCNFOUT_TSAFS_MSK,
|
||||
cnfout);
|
||||
|
||||
cnfin |= CNFIN_I2S_RXMODE_MASTER_MODE;
|
||||
regmap_update_bits(priv->regmap, I2S_IISCNF_IN,
|
||||
CNFIN_I2S_RXMODE_Msk,
|
||||
cnfin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int light_i2s_8ch_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct light_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
u32 val;
|
||||
u32 len = 0;
|
||||
u32 sclk_sel = 0;
|
||||
u32 rate;
|
||||
u32 funcmode;
|
||||
u32 iiscnf_out;
|
||||
u32 iiscnf_in;
|
||||
u32 i2s_8ch_en;
|
||||
|
||||
u32 channels = params_channels(params);
|
||||
|
||||
if(!priv->regs || !priv->regmap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rate = params_rate(params);
|
||||
|
||||
iiscnf_out = readl(priv->regs + I2S_IISCNF_OUT);
|
||||
iiscnf_in = readl(priv->regs + I2S_IISCNF_IN);
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
val |= I2S_DATA_8BIT_WIDTH_32BIT;
|
||||
len = 32;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
val |= I2S_DATA_WIDTH_16BIT;
|
||||
len = 32;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
val |= I2S_DATA_WIDTH_24BIT;
|
||||
len = 32;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
val |= I2S_DATA_WIDTH_32BIT;
|
||||
len = 32;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown data format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sclk_sel = len*STEREO_CHANNEL;
|
||||
|
||||
switch (sclk_sel) {
|
||||
case 16:
|
||||
val |= FSSTA_SCLK_SEL_16;
|
||||
break;
|
||||
case 32:
|
||||
val |= FSSTA_SCLK_SEL_32;
|
||||
break;
|
||||
case 48:
|
||||
val |= FSSTA_SCLK_SEL_48;
|
||||
break;
|
||||
case 64:
|
||||
val |= FSSTA_SCLK_SEL_64;
|
||||
break;
|
||||
default:
|
||||
pr_err("Not support channel num %d\n", channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
i2s_8ch_en &= ~IISEN_I2SEN;
|
||||
writel(i2s_8ch_en, priv->regs + I2S_IISEN);
|
||||
|
||||
regmap_update_bits(priv->regmap, I2S_FSSTA,
|
||||
FSSTA_DATAWTH_Msk | FSSTA_SCLK_SEL_Msk,
|
||||
val);
|
||||
funcmode = readl(priv->regs + I2S_FUNCMODE);
|
||||
if (tx) {
|
||||
funcmode |= FUNCMODE_TMODE_WEN;
|
||||
funcmode &= ~FUNCMODE_CH1_ENABLE;
|
||||
funcmode |= FUNCMODE_RMODE_WEN;
|
||||
funcmode &= ~FUNCMODE_RMODE;
|
||||
funcmode &= ~FUNCMODE_TMODE;
|
||||
funcmode |= FUNCMODE_TMODE;
|
||||
} else {
|
||||
funcmode |= FUNCMODE_RMODE_WEN;
|
||||
funcmode |= FUNCMODE_CH0_ENABLE;
|
||||
funcmode |= FUNCMODE_CH1_ENABLE;
|
||||
funcmode |= FUNCMODE_CH2_ENABLE;
|
||||
funcmode |= FUNCMODE_CH3_ENABLE;
|
||||
funcmode |= FUNCMODE_TMODE_WEN;
|
||||
funcmode &= ~FUNCMODE_TMODE;
|
||||
funcmode &= ~FUNCMODE_RMODE;
|
||||
funcmode |= FUNCMODE_RMODE;
|
||||
}
|
||||
|
||||
writel(funcmode, priv->regs + I2S_FUNCMODE);
|
||||
|
||||
if (channels == MONO_SOURCE) {
|
||||
iiscnf_out |= IISCNFOUT_TX_VOICE_EN_MONO;
|
||||
iiscnf_in |= CNFIN_RX_CH_SEL_LEFT;
|
||||
iiscnf_in |= CNFIN_RVOICEEN_MONO;
|
||||
} else {
|
||||
iiscnf_out &= ~IISCNFOUT_TX_VOICE_EN_MONO;
|
||||
iiscnf_in &= ~CNFIN_RX_CH_SEL_LEFT;
|
||||
iiscnf_in &= ~CNFIN_RVOICEEN_MONO;
|
||||
}
|
||||
|
||||
if (tx)
|
||||
writel(iiscnf_out, priv->regs + I2S_IISCNF_OUT);
|
||||
else
|
||||
writel(iiscnf_in, priv->regs + I2S_IISCNF_IN);
|
||||
|
||||
light_i2s_8ch_set_div_sclk(priv, rate, DIV_DEFAULT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int light_hdmi_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct light_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
u32 val;
|
||||
u32 len = 0;
|
||||
u32 rate;
|
||||
u32 funcmode;
|
||||
u32 iiscnf_out;
|
||||
u32 i2s_8ch_en;
|
||||
|
||||
u32 channels = params_channels(params);
|
||||
|
||||
if(!priv->regs || !priv->regmap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rate = params_rate(params);
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
val |= I2S_DATA_WIDTH_16BIT;
|
||||
len = 16;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
val |= I2S_DATA_WIDTH_24BIT;
|
||||
len = 24;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown data format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val |= FSSTA_SCLK_SEL_64;
|
||||
|
||||
i2s_8ch_en &= ~IISEN_I2SEN;
|
||||
writel(i2s_8ch_en, priv->regs + I2S_IISEN);
|
||||
|
||||
regmap_update_bits(priv->regmap, I2S_FSSTA,
|
||||
FSSTA_DATAWTH_Msk | FSSTA_SCLK_SEL_Msk,
|
||||
val);
|
||||
funcmode = readl(priv->regs + I2S_FUNCMODE);
|
||||
if (tx) {
|
||||
funcmode |= FUNCMODE_TMODE_WEN;
|
||||
funcmode &= ~FUNCMODE_TMODE;
|
||||
funcmode |= FUNCMODE_TMODE;
|
||||
} else {
|
||||
funcmode |= FUNCMODE_RMODE_WEN;
|
||||
funcmode &= ~FUNCMODE_RMODE;
|
||||
funcmode |= FUNCMODE_RMODE;
|
||||
}
|
||||
|
||||
writel(funcmode, priv->regs + I2S_FUNCMODE);
|
||||
|
||||
iiscnf_out = readl(priv->regs + I2S_IISCNF_OUT);
|
||||
if (channels == MONO_SOURCE)
|
||||
iiscnf_out |= IISCNFOUT_TX_VOICE_EN_MONO;
|
||||
else
|
||||
iiscnf_out &= ~IISCNFOUT_TX_VOICE_EN_MONO;
|
||||
|
||||
writel(iiscnf_out, priv->regs + I2S_IISCNF_OUT);
|
||||
|
||||
light_i2s_8ch_set_div_sclk(priv, rate, DIV_DEFAULT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int light_i2s_8ch_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct light_i2s_priv *i2s_8ch = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if(i2s_8ch)
|
||||
snd_soc_dai_init_dma_data(dai, &i2s_8ch->dma_params_tx,
|
||||
&i2s_8ch->dma_params_rx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops light_i2s_8ch_dai_ops = {
|
||||
.startup = light_i2s_8ch_dai_startup,
|
||||
.shutdown = light_i2s_8ch_dai_shutdown,
|
||||
.trigger = light_i2s_8ch_dai_trigger,
|
||||
.set_fmt = light_i2s_8ch_set_fmt_dai,
|
||||
.hw_params = light_i2s_8ch_dai_hw_params,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops light_hdmi_dai_ops = {
|
||||
.startup = light_i2s_8ch_dai_startup,
|
||||
.shutdown = light_i2s_8ch_dai_shutdown,
|
||||
.trigger = light_i2s_8ch_dai_trigger,
|
||||
.set_fmt = light_i2s_8ch_set_fmt_dai,
|
||||
.hw_params = light_hdmi_dai_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver light_i2s_8ch_soc_dai[] = {
|
||||
{
|
||||
.probe = light_i2s_8ch_dai_probe,
|
||||
.name = "light-i2s-dai-8ch-sd0",
|
||||
.playback = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &light_i2s_8ch_dai_ops,
|
||||
},
|
||||
{
|
||||
.probe = light_i2s_8ch_dai_probe,
|
||||
.name = "light-i2s-dai-8ch-sd1",
|
||||
.playback = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &light_i2s_8ch_dai_ops,
|
||||
},
|
||||
{
|
||||
.probe = light_i2s_8ch_dai_probe,
|
||||
.name = "light-i2s-dai-8ch-sd2",
|
||||
.playback = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &light_i2s_8ch_dai_ops,
|
||||
},
|
||||
{
|
||||
.probe = light_i2s_8ch_dai_probe,
|
||||
.name = "light-i2s-dai-8ch-sd3",
|
||||
.playback = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &light_i2s_8ch_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static const struct snd_soc_component_driver light_i2s_8ch_soc_component = {
|
||||
.name = "light_i2s_8ch",
|
||||
};
|
||||
|
||||
static int light_pcm_probe(struct platform_device *pdev,struct light_i2s_priv *i2s_8ch)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = light_pcm_dma_init(pdev, LIGHT_I2S_DMABUF_SIZE);
|
||||
|
||||
if (ret) {
|
||||
pr_err("light_pcm_dma_init error\n");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool light_i2s_8ch_wr_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case I2S_IISEN:
|
||||
case I2S_FUNCMODE:
|
||||
case I2S_IISCNF_IN:
|
||||
case I2S_FSSTA:
|
||||
case I2S_IISCNF_OUT:
|
||||
case I2S_DMACR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool light_i2s_8ch_rd_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case I2S_IISEN:
|
||||
case I2S_FUNCMODE:
|
||||
case I2S_IISCNF_IN:
|
||||
case I2S_FSSTA:
|
||||
case I2S_IISCNF_OUT:
|
||||
case I2S_DMACR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config light_i2s_8ch_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = I2S_DR4,
|
||||
.writeable_reg = light_i2s_8ch_wr_reg,
|
||||
.readable_reg = light_i2s_8ch_rd_reg,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static int light_audio_pinconf_set(struct device *dev, unsigned int pin_id, unsigned int val)
|
||||
{
|
||||
struct light_i2s_priv *priv = dev_get_drvdata(dev);
|
||||
unsigned int shift;
|
||||
unsigned int mask = 0;
|
||||
|
||||
if(!priv->audio_pin_regmap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
priv->cfg_off = 0xC;
|
||||
|
||||
shift = (((pin_id-25) % 2) << 4);
|
||||
mask |= (0xFFFF << shift);
|
||||
val = (val << shift);
|
||||
|
||||
return regmap_update_bits(priv->audio_pin_regmap,
|
||||
LIGHT_AUDIO_PAD_CONFIG(pin_id),mask, val);
|
||||
}
|
||||
|
||||
static int light_audio_pinctrl(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int light_i2s_8ch_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct light_i2s_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if(!priv->regmap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
regcache_cache_only(priv->regmap, true);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int light_i2s_8ch_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct light_i2s_priv *priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if(!priv->regmap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "clock enable failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(priv->regmap, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id light_i2s_8ch_of_match[] = {
|
||||
{ .compatible = "light,light-i2s-8ch"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, light_i2s_8ch_of_match);
|
||||
|
||||
struct light_i2s_priv *host_priv;
|
||||
|
||||
static int light_audio_i2s_8ch_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
const char *sprop;
|
||||
const uint32_t *iprop;
|
||||
struct light_i2s_priv *priv;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned int irq;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
|
||||
sprop = of_get_property(np, "light,mode", NULL);
|
||||
if (sprop) {
|
||||
if (!strcmp(sprop, "i2s-master"))
|
||||
priv->dai_fmt = SND_SOC_DAIFMT_I2S;
|
||||
else
|
||||
printk("mode is not i2s-master");
|
||||
}
|
||||
|
||||
sprop = of_get_property(np, "light,sel", NULL);
|
||||
if (sprop) {
|
||||
strcpy(priv->name, sprop);
|
||||
}
|
||||
|
||||
iprop = of_get_property(np, "light,dma_maxburst", NULL);
|
||||
if (iprop)
|
||||
priv->dma_maxburst = be32_to_cpup(iprop);
|
||||
else
|
||||
priv->dma_maxburst = 8;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, priv);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
if(i2s_8ch_probe_flag) {
|
||||
printk("i2s_8ch already probe\n");
|
||||
priv->regs = NULL;
|
||||
priv->regmap = NULL;
|
||||
priv->audio_cpr_regmap = NULL;
|
||||
} else {
|
||||
printk("i2s_8ch probing\n");
|
||||
i2s_8ch_probe_flag = 1;
|
||||
host_priv = priv;
|
||||
|
||||
priv->regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->regs))
|
||||
return PTR_ERR(priv->regs);
|
||||
|
||||
priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->regs,
|
||||
&light_i2s_8ch_regmap_config);
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to initialise managed register map\n");
|
||||
return PTR_ERR(priv->regmap);
|
||||
}
|
||||
|
||||
priv->audio_cpr_regmap = syscon_regmap_lookup_by_phandle(np, "audio-cpr-regmap");
|
||||
if (IS_ERR(priv->audio_cpr_regmap)) {
|
||||
dev_err(dev, "cannot find regmap for audio cpr register\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// enable i2s sync
|
||||
light_audio_cpr_set(priv, CPR_PERI_CTRL_REG, CPR_VAD_I2SIN_SYNC_MSK, CPR_VAD_I2SIN_SYNC_EN);
|
||||
|
||||
priv->clk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (IS_ERR(priv->clk))
|
||||
return PTR_ERR(priv->clk);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||
ret = light_i2s_8ch_runtime_resume(&pdev->dev);
|
||||
if (ret)
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (!res || (int)irq <= 0) {
|
||||
dev_err(&pdev->dev, "Not enough light platform resources.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
priv->audio_pin_regmap = NULL;
|
||||
|
||||
priv->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
priv->dma_params_rx.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
priv->dma_params_tx.maxburst = priv->dma_maxburst;
|
||||
priv->dma_params_rx.maxburst = priv->dma_maxburst;
|
||||
|
||||
if (!strcmp(priv->name, AUDIO_I2S_8CH_SD0)) {
|
||||
priv->dma_params_tx.addr = res->start + I2S_DR;
|
||||
priv->dma_params_rx.addr = res->start + I2S_DR;
|
||||
} else if (!strcmp(priv->name, AUDIO_I2S_8CH_SD1)) {
|
||||
priv->dma_params_tx.addr = res->start + I2S_DR1;
|
||||
priv->dma_params_rx.addr = res->start + I2S_DR1;
|
||||
} else if (!strcmp(priv->name, AUDIO_I2S_8CH_SD2)) {
|
||||
priv->dma_params_tx.addr = res->start + I2S_DR2;
|
||||
priv->dma_params_rx.addr = res->start + I2S_DR2;
|
||||
} else if (!strcmp(priv->name, AUDIO_I2S_8CH_SD3)) {
|
||||
priv->dma_params_tx.addr = res->start + I2S_DR3;
|
||||
priv->dma_params_rx.addr = res->start + I2S_DR3;
|
||||
}
|
||||
|
||||
light_pcm_probe(pdev, priv);
|
||||
|
||||
ret = devm_snd_soc_register_component(&pdev->dev, &light_i2s_8ch_soc_component,
|
||||
light_i2s_8ch_soc_dai, ARRAY_SIZE(light_i2s_8ch_soc_dai));
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot snd component register\n");
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int light_i2s_8ch_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct light_i2s_priv *priv = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
light_i2s_8ch_runtime_suspend(&pdev->dev);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops light_i2s_8ch_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(light_i2s_8ch_runtime_suspend, light_i2s_8ch_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver light_i2s_8ch_driver = {
|
||||
.driver = {
|
||||
.name = "light-pcm-audio-8ch",
|
||||
.pm = &light_i2s_8ch_pm_ops,
|
||||
.of_match_table = light_i2s_8ch_of_match,
|
||||
},
|
||||
.probe = light_audio_i2s_8ch_probe,
|
||||
.remove = light_i2s_8ch_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(light_i2s_8ch_driver);
|
||||
|
||||
MODULE_AUTHOR("shuofeng.ren <shuofeng.rsf@linux.alibaba.com>");
|
||||
MODULE_DESCRIPTION("Thead Light audio driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <sound/sh_fsi.h>
|
||||
#include "light-i2s.h"
|
||||
#include "light-pcm.h"
|
||||
#include "light-audio-cpr.h"
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/core.h>
|
||||
@@ -54,6 +55,10 @@ static u32 light_special_sample_rates[] = { 11025, 22050, 44100, 88200 };
|
||||
static int light_audio_cpr_set(struct light_i2s_priv *chip, unsigned int cpr_off,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
if(!chip->audio_cpr_regmap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return regmap_update_bits(chip->audio_cpr_regmap,
|
||||
cpr_off, mask, val);
|
||||
}
|
||||
@@ -62,6 +67,7 @@ static void light_i2s_set_div_sclk(struct light_i2s_priv *chip, u32 sample_rate,
|
||||
{
|
||||
u32 div;
|
||||
u32 div0;
|
||||
u32 cpr_div = (IIS_SRC_CLK/AUDIO_IIS_SRC0_CLK)-1;
|
||||
int i;
|
||||
u32 i2s_src_clk = 0;
|
||||
|
||||
@@ -105,6 +111,7 @@ static void light_i2s_set_div_sclk(struct light_i2s_priv *chip, u32 sample_rate,
|
||||
|
||||
div0 = (div + div % sample_rate) / sample_rate / div_val;
|
||||
writel(div0, chip->regs + I2S_DIV0_LEVEL);
|
||||
light_audio_cpr_set(chip, CPR_PERI_DIV_SEL_REG, CPR_AUDIO_DIV0_SEL_MSK, CPR_AUDIO_DIV0_SEL(cpr_div));
|
||||
}
|
||||
|
||||
static inline void light_snd_txctrl(struct light_i2s_priv *chip, bool on)
|
||||
@@ -159,7 +166,8 @@ static void light_i2s_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct light_i2s_priv *i2s_private = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
light_snd_rxctrl(i2s_private, 0);
|
||||
|
||||
clk_disable_unprepare(i2s_private->clk);
|
||||
@@ -275,7 +283,7 @@ static int light_i2s_dai_hw_params(struct snd_pcm_substream *substream, struct s
|
||||
len = 32;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown data format\n");
|
||||
pr_err("Unknown data format: %d\n", params_format(params));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -371,7 +379,7 @@ static int light_hdmi_dai_hw_params(struct snd_pcm_substream *substream, struct
|
||||
len = 24;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown data format\n");
|
||||
pr_err("Unknown data format: %d\n", params_format(params));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -459,7 +467,7 @@ static struct snd_soc_dai_driver light_i2s_soc_dai[] = {
|
||||
.name = "light-hdmi-dai",
|
||||
.playback = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
},
|
||||
@@ -669,6 +677,9 @@ static int light_audio_i2s_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "cannot find regmap for audio cpr register\n");
|
||||
} else
|
||||
light_audio_cpr_set(i2s_priv, CPR_PERI_DIV_SEL_REG, CPR_AUDIO_DIV1_SEL_MSK, CPR_AUDIO_DIV1_SEL(5));
|
||||
|
||||
// enable i2s sync
|
||||
light_audio_cpr_set(i2s_priv, CPR_PERI_CTRL_REG, CPR_I2S_SYNC_MSK, CPR_I2S_SYNC_EN);
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
@@ -48,9 +48,6 @@
|
||||
#define I2S_DR3 0x068 /* CH3_Data Register */
|
||||
#define I2S_DR4 0x06C /* CH4_Data Register */
|
||||
|
||||
#define CPR_PERI_DIV_SEL_REG 0x004 /*audio sys i2s clock div Register*/
|
||||
#define CPR_PERI_CLK_SEL_REG 0x008 /*audio sys i2s clock selection Register*/
|
||||
|
||||
/* IISEN , offset: 0x00 */
|
||||
#define IISEN_I2SEN_POS (0U)
|
||||
#define IISEN_I2SEN_MSK (0x1U << IISEN_I2SEN_POS)
|
||||
@@ -459,30 +456,6 @@
|
||||
#define RXFIFO_IRQ_TH (0x20U)
|
||||
#define I2S_MAX_FIFO (0x20U)
|
||||
|
||||
/* AUDIO SYS DIV SEL REG, offset: 0x4 */
|
||||
#define CPR_AUDIO_DIV1_SEL_POS (12U)
|
||||
#define CPR_AUDIO_DIV1_SEL_MSK (0x1FU << CPR_AUDIO_DIV1_SEL_POS)
|
||||
#define CPR_AUDIO_DIV1_SEL(X) (X << CPR_AUDIO_DIV1_SEL_POS)
|
||||
|
||||
/* AUDIO SYS CLK SEL REG, offset: 0x8 */
|
||||
#define CPR_I2S0_SRC_SEL_POS (0U)
|
||||
#define CPR_I2S0_SRC_SEL_MSK (0x3U << CPR_I2S0_SRC_SEL_POS)
|
||||
#define CPR_I2S0_SRC_SEL(X) (X << CPR_I2S0_SRC_SEL_POS)
|
||||
#define CPR_I2S0_SRC_SEL_24M (0x1U << AUDIOSYS_I2S0_SRC_SEL_POS)
|
||||
#define CPR_I2S0_SRC_SEL_AUDIO_DIVCLK1 (0x2U << AUDIOSYS_I2S0_SRC_SEL_POS)
|
||||
|
||||
#define CPR_I2S1_SRC_SEL_POS (4U)
|
||||
#define CPR_I2S1_SRC_SEL_MSK (0x3U << CPR_I2S1_SRC_SEL_POS)
|
||||
#define CPR_I2S1_SRC_SEL(X) (X << CPR_I2S1_SRC_SEL_POS)
|
||||
#define CPR_I2S1_SRC_SEL_24M (0x1U << AUDIOSYS_I2S1_SRC_SEL_POS)
|
||||
#define CPR_I2S1_SRC_SEL_AUDIO_DIVCLK1 (0x2U << AUDIOSYS_I2S1_SRC_SEL_POS)
|
||||
|
||||
#define CPR_I2S2_SRC_SEL_POS (8U)
|
||||
#define CPR_I2S2_SRC_SEL_MSK (0x3U << CPR_I2S2_SRC_SEL_POS)
|
||||
#define CPR_I2S2_SRC_SEL(X) (X << CPR_I2S2_SRC_SEL_POS)
|
||||
#define CPR_I2S2_SRC_SEL_24M (0x1U << AUDIOSYS_I2S2_SRC_SEL_POS)
|
||||
#define CPR_I2S2_SRC_SEL_AUDIO_DIVCLK1 (0x2U << AUDIOSYS_I2S2_SRC_SEL_POS)
|
||||
|
||||
struct light_i2s_priv {
|
||||
void __iomem *base;
|
||||
phys_addr_t phys;
|
||||
|
||||
454
sound/soc/thead/light-spdif.c
Normal file
454
sound/soc/thead/light-spdif.c
Normal file
@@ -0,0 +1,454 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/sh_fsi.h>
|
||||
#include "light-pcm.h"
|
||||
#include "light-spdif.h"
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <dt-bindings/pinctrl/light-fm-aon-pinctrl.h>
|
||||
|
||||
#define LIGHT_RATES SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000
|
||||
|
||||
static int light_spdif_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct light_spdif_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (priv) {
|
||||
snd_soc_dai_init_dma_data(dai, &priv->dma_params_tx, &priv->dma_params_rx);
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int light_spdif_dai_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct light_spdif_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
pm_runtime_get_sync(dai->dev);
|
||||
regmap_update_bits(priv->regmap, SPDIF_EN,
|
||||
SPDIF_SPDIFEN_MSK, SPDIF_SPDIFEN_SEL(1));
|
||||
atomic_inc(&priv->spdif_ref_cnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void light_spdif_snd_txctrl(struct light_spdif_priv *priv, char on)
|
||||
{
|
||||
unsigned int reg[24];
|
||||
int i;
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_DMA_EN,
|
||||
SPDIF_TDMA_EN_MSK, SPDIF_TDMA_EN_SEL(on));
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_EN,
|
||||
SPDIF_TXEN_MSK, SPDIF_TXEN_SEL(on));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void light_spdif_snd_rxctrl(struct light_spdif_priv *priv, char on)
|
||||
{
|
||||
|
||||
regmap_update_bits(priv->regmap, SPDIF_RX_DMA_EN,
|
||||
SPDIF_RDMA_EN_MSK, SPDIF_RDMA_EN_SEL(on));
|
||||
regmap_update_bits(priv->regmap, SPDIF_RX_EN,
|
||||
SPDIF_RXEN_MSK, SPDIF_RXEN_SEL(on));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void light_spdif_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct light_spdif_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
light_spdif_snd_rxctrl(priv, 0);
|
||||
else
|
||||
light_spdif_snd_txctrl(priv, 0);
|
||||
|
||||
atomic_dec(&priv->spdif_ref_cnt);
|
||||
if (atomic_read(&priv->spdif_ref_cnt) == 0) {
|
||||
regmap_update_bits(priv->regmap, SPDIF_EN,
|
||||
SPDIF_SPDIFEN_MSK, SPDIF_SPDIFEN_SEL(0));
|
||||
}
|
||||
pm_runtime_put(dai->dev);
|
||||
}
|
||||
|
||||
static int light_spdif_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret = 0;
|
||||
struct light_spdif_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
|
||||
switch(cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (tx)
|
||||
light_spdif_snd_txctrl(priv, 1);
|
||||
else
|
||||
light_spdif_snd_rxctrl(priv, 1);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (tx) {
|
||||
dmaengine_terminate_async(snd_dmaengine_pcm_get_chan(substream)); // work around for DMAC stop issue
|
||||
light_spdif_snd_txctrl(priv, 0);
|
||||
}
|
||||
else
|
||||
light_spdif_snd_rxctrl(priv, 0);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 light_special_sample_rates[] = { 44100, 88200 };
|
||||
#define AUDIO_DIVCLK0 98304000 // 49152000
|
||||
#define AUDIO_DIVCLK1 135475200
|
||||
|
||||
static int light_spdif_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct light_spdif_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
u32 datawidth, chn_num, i;
|
||||
u32 sample_rate = params_rate(params);
|
||||
bool is_divclk1 = false; //audio_divclk1 for 44.1k...etc. audio_divclk0 for 48k....etc
|
||||
u32 src_clk, tx_div, rx_div;
|
||||
|
||||
switch (params_channels(params)) {
|
||||
case 1:
|
||||
chn_num = SPDIF_TX_DATAMODE_1CH;
|
||||
break;
|
||||
case 2:
|
||||
chn_num = SPDIF_TX_DATAMODE_2CH;
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "unsupported channel num\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
datawidth = SPDIF_TX_DATAMODE_16BIT_PACKED;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S20_LE:
|
||||
datawidth = SPDIF_TX_DATAMODE_20BIT;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
datawidth = SPDIF_TX_DATAMODE_24BIT;
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "unsupported data format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(light_special_sample_rates); i++) {
|
||||
if (light_special_sample_rates[i] == sample_rate) {
|
||||
is_divclk1 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_divclk1 == false) { // audio_divclk0=98304000 for 48k
|
||||
regmap_update_bits(priv->audio_cpr_regmap,
|
||||
CPR_PERI_CLK_SEL_REG, CPR_SPDIF_SRC_SEL_MSK, CPR_SPDIF_SRC_SEL(2));
|
||||
src_clk = AUDIO_DIVCLK0;
|
||||
} else { // audio_divclk1=135475200 for 44.1k
|
||||
regmap_update_bits(priv->audio_cpr_regmap,
|
||||
CPR_PERI_CLK_SEL_REG, CPR_SPDIF_SRC_SEL_MSK, CPR_SPDIF_SRC_SEL(1));
|
||||
src_clk = AUDIO_DIVCLK1;
|
||||
}
|
||||
//printk("selected src_clk=%d substream->stream=%d sample_rate=%d\n", src_clk, substream->stream, sample_rate);
|
||||
regmap_update_bits(priv->regmap, SPDIF_EN,
|
||||
SPDIF_SPDIFEN_MSK, SPDIF_SPDIFEN_SEL(1));
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
tx_div = src_clk / (sample_rate * (32 * 2) * 2);
|
||||
tx_div = tx_div / 2 - 1;
|
||||
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_CTL,
|
||||
SPDIF_TX_DIV_MSK, SPDIF_TX_DIV_SEL(tx_div));
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_CTL,
|
||||
SPDIF_TX_DIV_BYPASS_MSK, SPDIF_TX_DIV_BYPASS_SEL(1));
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_CTL,
|
||||
SPDIF_TX_CH_SEL_MSK, SPDIF_TX_CH_SEL_SEL(chn_num));
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_CTL,
|
||||
SPDIF_TX_DATAMODE_MSK, SPDIF_TX_DATAMODE_SEL(datawidth));
|
||||
// Channel Status
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_CS_A,
|
||||
SPDIF_TX_T_FS_SEL_MSK, SPDIF_TX_T_FS_SEL_SEL(2)); // 2 for 48k
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_CS_A,
|
||||
SPDIF_TX_T_CH_NUM_MSK, SPDIF_TX_T_CH_NUM_SEL(1)); // Left in 2 channel format
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_CS_B,
|
||||
SPDIF_TX_T_B_FS_SEL_MSK, SPDIF_TX_T_B_FS_SEL_SEL(2)); // 2 for 48k
|
||||
regmap_update_bits(priv->regmap, SPDIF_TX_CS_B,
|
||||
SPDIF_TX_T_B_CH_NUM_MSK, SPDIF_TX_T_B_CH_NUM_SEL(2)); // Right in 2 channel format
|
||||
} else {
|
||||
regmap_update_bits(priv->regmap, SPDIF_RX_CTL,
|
||||
SPDIF_RX_DIV_MSK, SPDIF_RX_DIV_SEL(0));
|
||||
regmap_update_bits(priv->regmap, SPDIF_RX_CTL,
|
||||
SPDIF_RX_DIV_BYPASS_MSK, SPDIF_RX_DIV_BYPASS_SEL(0)); // spdif_rx_clk = src_clk
|
||||
regmap_update_bits(priv->regmap, SPDIF_RX_CTL,
|
||||
SPDIF_RX_DATAMODE_MSK, SPDIF_RX_DATAMODE_SEL(datawidth));
|
||||
regmap_update_bits(priv->regmap, SPDIF_RX_DMA_TH,
|
||||
SPDIF_RDMA_TH_MSK, SPDIF_RDMA_TH_SEL(8));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops light_spdif_dai_ops = {
|
||||
.startup = light_spdif_dai_startup,
|
||||
.shutdown = light_spdif_dai_shutdown,
|
||||
.trigger = light_spdif_dai_trigger,
|
||||
.hw_params = light_spdif_dai_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver light_spdif_soc_dai = {
|
||||
.probe = light_spdif_dai_probe,
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S20_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &light_spdif_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver light_spdif_soc_component = {
|
||||
.name = "light_spdif",
|
||||
};
|
||||
|
||||
static void light_spdif_pinctrl(struct light_spdif_priv *priv)
|
||||
{
|
||||
//GPIO_SEL AUDIO_PA21~24
|
||||
regmap_update_bits(priv->audio_pin_regmap,
|
||||
0x0,0x1E00000, 0x1E00000);
|
||||
//MUX
|
||||
regmap_update_bits(priv->audio_pin_regmap,
|
||||
0x8,0x3FC00, 0x15400);
|
||||
//strength
|
||||
regmap_update_bits(priv->audio_pin_regmap,
|
||||
0x38,0xF000F, 0x70007); // AUDIO_PA22 SPDIF0_DOUT / AUDIO_PA23 SPDIF1_DOUT
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct regmap_config light_spdif_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = SPDIF_RX_USER_B5,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static int light_spdif_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct light_spdif_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
regcache_cache_only(priv->regmap, true);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int light_spdif_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct light_spdif_priv *priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "clock enable failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(priv->regmap, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id light_spdif_of_match[] = {
|
||||
{ .compatible = "light,light-spdif"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, light_spdif_of_match);
|
||||
|
||||
irqreturn_t spdif_interrupt(int irq, void* dev_id)
|
||||
{
|
||||
struct light_spdif_priv* priv = (struct light_spdif_priv*)dev_id;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int light_spdif_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const char *sprop;
|
||||
const uint32_t *iprop;
|
||||
struct light_spdif_priv *priv;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned int irq;
|
||||
int data_register, ret = 0;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(struct light_spdif_priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->dev = dev;
|
||||
|
||||
iprop = of_get_property(np, "light,dma_maxburst", NULL);
|
||||
if (iprop)
|
||||
priv->dma_maxburst = be32_to_cpup(iprop);
|
||||
else
|
||||
priv->dma_maxburst = 8;
|
||||
|
||||
dev_set_drvdata(dev, priv);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
priv->clk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (IS_ERR(priv->clk))
|
||||
return PTR_ERR(priv->clk);
|
||||
|
||||
priv->regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->regs)) {
|
||||
return PTR_ERR(priv->regs);
|
||||
}
|
||||
|
||||
priv->regmap = devm_regmap_init_mmio(dev, priv->regs,
|
||||
&light_spdif_regmap_config);
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
dev_err(dev, "Failed to initialise managed register map\n");
|
||||
return PTR_ERR(priv->regmap);
|
||||
}
|
||||
|
||||
priv->audio_pin_regmap = syscon_regmap_lookup_by_phandle(np, "audio-pin-regmap");
|
||||
if (IS_ERR(priv->audio_pin_regmap)) {
|
||||
dev_err(dev, "cannot find regmap for audio system register\n");
|
||||
return -EINVAL;
|
||||
} else {
|
||||
//light_spdif_pinctrl(priv);
|
||||
}
|
||||
|
||||
priv->audio_cpr_regmap = syscon_regmap_lookup_by_phandle(np, "audio-cpr-regmap");
|
||||
if (IS_ERR(priv->audio_cpr_regmap)) {
|
||||
dev_err(dev, "cannot find regmap for audio cpr register\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
//AUDIO_DIV1 set to 1/6. 812.8512MHz / 6 = 135.4752MHz
|
||||
regmap_update_bits(priv->audio_cpr_regmap,
|
||||
CPR_PERI_DIV_SEL_REG, CPR_AUDIO_DIV1_SEL_MSK, CPR_AUDIO_DIV1_SEL(5));
|
||||
regmap_update_bits(priv->audio_cpr_regmap,
|
||||
CPR_PERI_DIV_SEL_REG, CPR_AUDIO_DIV1_CG_MSK, CPR_AUDIO_DIV1_CG(1));
|
||||
//AUDIO_DIV0 set to 1/3. 294.912MHz / 3 = 98304000Hz
|
||||
regmap_update_bits(priv->audio_cpr_regmap,
|
||||
CPR_PERI_DIV_SEL_REG, CPR_AUDIO_DIV0_SEL_MSK, CPR_AUDIO_DIV0_SEL(2)); // 2=98304000 5=49152000
|
||||
regmap_update_bits(priv->audio_cpr_regmap,
|
||||
CPR_PERI_DIV_SEL_REG, CPR_AUDIO_DIV0_CG_MSK, CPR_AUDIO_DIV0_CG(1));
|
||||
//enable spdif0/1 sync
|
||||
regmap_update_bits(priv->audio_cpr_regmap,
|
||||
CPR_PERI_CTRL_REG, CPR_SPDIF_SYNC_MSK, CPR_SPDIF_SYNC_EN);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_resume_and_get(&pdev->dev); // clk gate is enabled by hardware as default register value
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
if (priv->irq== 0) {
|
||||
dev_err(dev, "could not map IRQ.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
//ret = request_irq(priv->irq , spdif_interrupt,
|
||||
// IRQF_SHARED|IRQF_TRIGGER_RISING, "AUDIO_TDM_IRQ", (char *)priv);
|
||||
//if (ret) {
|
||||
// dev_err(dev, "%s[%d]:request irq error!\n", __func__, __LINE__);
|
||||
// return ret;
|
||||
//}
|
||||
|
||||
priv->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
priv->dma_params_rx.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
priv->dma_params_tx.maxburst = priv->dma_maxburst;
|
||||
priv->dma_params_rx.maxburst = priv->dma_maxburst;
|
||||
priv->dma_params_tx.addr = res->start + SPDIF_TX_FIFO_DR;
|
||||
priv->dma_params_rx.addr = res->start + SPDIF_RX_FIFO_DR;
|
||||
|
||||
ret = light_pcm_dma_init(pdev, LIGHT_TDM_DMABUF_SIZE);
|
||||
if (ret) {
|
||||
dev_err(dev, "light_pcm_dma_init error\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &light_spdif_soc_component,
|
||||
&light_spdif_soc_dai, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot snd component register\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int light_spdif_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct light_spdif_priv *priv = dev_get_drvdata(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
light_spdif_runtime_suspend(&pdev->dev);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops light_spdif_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(light_spdif_runtime_suspend, light_spdif_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver light_spdif_driver = {
|
||||
.driver = {
|
||||
.name = "light-spdif-audio",
|
||||
.pm = &light_spdif_pm_ops,
|
||||
.of_match_table = light_spdif_of_match,
|
||||
},
|
||||
.probe = light_spdif_probe,
|
||||
.remove = light_spdif_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(light_spdif_driver);
|
||||
|
||||
MODULE_AUTHOR("nanli.yd <nanli.yd@linux.alibaba.com>");
|
||||
MODULE_DESCRIPTION("Thead Light spdif driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
209
sound/soc/thead/light-spdif.h
Normal file
209
sound/soc/thead/light-spdif.h
Normal file
@@ -0,0 +1,209 @@
|
||||
#ifndef _LIGHT_SPDIF_H_
|
||||
#define _LIGHT_SPDIF_H_
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include "light-pcm.h"
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define SPDIF_EN 0x00
|
||||
#define SPDIF_TX_EN 0x04
|
||||
#define SPDIF_TX_CTL 0x08
|
||||
#define SPDIF_TX_CS_A 0x0c
|
||||
#define SPDIF_TX_USER_A0 0x10
|
||||
#define SPDIF_TX_USER_A1 0x14
|
||||
#define SPDIF_TX_USER_A2 0x18
|
||||
#define SPDIF_TX_USER_A3 0x1C
|
||||
#define SPDIF_TX_USER_A4 0x20
|
||||
#define SPDIF_TX_USER_A5 0x24
|
||||
#define SPDIF_TX_FIFO_DR 0x28
|
||||
#define SPDIF_TX_FIFO_TH 0x2C
|
||||
#define SPDIF_TX_FIFO_DL 0x30
|
||||
#define SPDIF_TX_DMA_EN 0x34
|
||||
#define SPDIF_TX_DMA_TH 0x38
|
||||
#define SPDIF_SR 0x3C
|
||||
#define SPDIF_IMR 0x40
|
||||
#define SPDIF_ISR 0x44
|
||||
#define SPDIF_RISR 0x48
|
||||
#define SPDIF_ICR 0x4C
|
||||
#define SPDIF_RX_EN 0x50
|
||||
#define SPDIF_RX_CTL 0x54
|
||||
#define SPDIF_RX_CS_A 0x58
|
||||
#define SPDIF_RX_USER_A0 0x5C
|
||||
#define SPDIF_RX_USER_A1 0x60
|
||||
#define SPDIF_RX_USER_A2 0x64
|
||||
#define SPDIF_RX_USER_A3 0x68
|
||||
#define SPDIF_RX_USER_A4 0x6C
|
||||
#define SPDIF_RX_USER_A5 0x70
|
||||
#define SPDIF_RX_FIFO_DR 0x74
|
||||
#define SPDIF_RX_FIFO_TH 0x78
|
||||
#define SPDIF_RX_FIFO_DL 0x7C
|
||||
#define SPDIF_RX_DMA_EN 0x80
|
||||
#define SPDIF_RX_DMA_TH 0x84
|
||||
#define SPDIF_TX_CS_B 0x88
|
||||
#define SPDIF_TX_USER_B0 0x8C
|
||||
#define SPDIF_TX_USER_B1 0x90
|
||||
#define SPDIF_TX_USER_B2 0x94
|
||||
#define SPDIF_TX_USER_B3 0x98
|
||||
#define SPDIF_TX_USER_B4 0x9C
|
||||
#define SPDIF_TX_USER_B5 0xa0
|
||||
#define SPDIF_RX_CS_B 0xa4
|
||||
#define SPDIF_RX_USER_B0 0xa8
|
||||
#define SPDIF_RX_USER_B1 0xaC
|
||||
#define SPDIF_RX_USER_B2 0xb0
|
||||
#define SPDIF_RX_USER_B3 0xb4
|
||||
#define SPDIF_RX_USER_B4 0xb8
|
||||
#define SPDIF_RX_USER_B5 0xbC
|
||||
|
||||
/* SPDIF_EN */
|
||||
#define SPDIF_SPDIFEN_POS (0U)
|
||||
#define SPDIF_SPDIFEN_MSK (0x1U << SPDIF_SPDIFEN_POS)
|
||||
#define SPDIF_SPDIFEN_SEL(X) (X << SPDIF_SPDIFEN_POS)
|
||||
|
||||
/* SPDIF_TX_EN */
|
||||
#define SPDIF_TXEN_POS (0U)
|
||||
#define SPDIF_TXEN_MSK (0x1U << SPDIF_TXEN_POS)
|
||||
#define SPDIF_TXEN_SEL(X) (X << SPDIF_TXEN_POS)
|
||||
|
||||
/* SPDIF_TX_CTL */
|
||||
#define SPDIF_TX_DIV_POS (9U)
|
||||
#define SPDIF_TX_DIV_MSK (0x7FU << SPDIF_TX_DIV_POS)
|
||||
#define SPDIF_TX_DIV_SEL(X) (X << SPDIF_TX_DIV_POS)
|
||||
#define SPDIF_TX_DIV_BYPASS_POS (8U)
|
||||
#define SPDIF_TX_DIV_BYPASS_MSK (0x1U << SPDIF_TX_DIV_BYPASS_POS)
|
||||
#define SPDIF_TX_DIV_BYPASS_SEL(X) (X << SPDIF_TX_DIV_BYPASS_POS)
|
||||
#define SPDIF_TX_CH_SEL_POS (4U)
|
||||
#define SPDIF_TX_CH_SEL_MSK (0x1U << SPDIF_TX_CH_SEL_POS)
|
||||
#define SPDIF_TX_CH_SEL_SEL(X) (X << SPDIF_TX_CH_SEL_POS)
|
||||
#define SPDIF_TX_DATAMODE_POS (0U)
|
||||
#define SPDIF_TX_DATAMODE_MSK (0x3U << SPDIF_TX_DATAMODE_POS)
|
||||
#define SPDIF_TX_DATAMODE_SEL(X) (X << SPDIF_TX_DATAMODE_POS)
|
||||
|
||||
#define SPDIF_TX_DATAMODE_2CH 0x0
|
||||
#define SPDIF_TX_DATAMODE_1CH 0x1
|
||||
#define SPDIF_TX_DATAMODE_16BIT_PACKED 0x3
|
||||
#define SPDIF_TX_DATAMODE_16BIT 0x2
|
||||
#define SPDIF_TX_DATAMODE_20BIT 0x1
|
||||
#define SPDIF_TX_DATAMODE_24BIT 0x0
|
||||
|
||||
/* SPDIF_TX_CS_A */
|
||||
#define SPDIF_TX_T_FS_SEL_POS (24U)
|
||||
#define SPDIF_TX_T_FS_SEL_MSK (0xFU << SPDIF_TX_T_FS_SEL_POS)
|
||||
#define SPDIF_TX_T_FS_SEL_SEL(X) (X << SPDIF_TX_T_FS_SEL_POS)
|
||||
#define SPDIF_TX_T_CH_NUM_POS (20U)
|
||||
#define SPDIF_TX_T_CH_NUM_MSK (0xFU << SPDIF_TX_T_CH_NUM_POS)
|
||||
#define SPDIF_TX_T_CH_NUM_SEL(X) (X << SPDIF_TX_T_CH_NUM_POS)
|
||||
|
||||
/* SPDIF_RX_DMA_TH */
|
||||
#define SPDIF_RDMA_TH_POS (0U)
|
||||
#define SPDIF_RDMA_TH_MSK (0xFU << SPDIF_RDMA_TH_POS)
|
||||
#define SPDIF_RDMA_TH_SEL(X) (X << SPDIF_RDMA_TH_POS)
|
||||
|
||||
/* SPDIF_TX_CS_B */
|
||||
#define SPDIF_TX_T_B_FS_SEL_POS (24U)
|
||||
#define SPDIF_TX_T_B_FS_SEL_MSK (0xFU << SPDIF_TX_T_B_FS_SEL_POS)
|
||||
#define SPDIF_TX_T_B_FS_SEL_SEL(X) (X << SPDIF_TX_T_B_FS_SEL_POS)
|
||||
#define SPDIF_TX_T_B_CH_NUM_POS (20U)
|
||||
#define SPDIF_TX_T_B_CH_NUM_MSK (0xFU << SPDIF_TX_T_B_CH_NUM_POS)
|
||||
#define SPDIF_TX_T_B_CH_NUM_SEL(X) (X << SPDIF_TX_T_B_CH_NUM_POS)
|
||||
|
||||
/* SPDIF_TX_DMA_EN */
|
||||
#define SPDIF_TDMA_EN_POS (0U)
|
||||
#define SPDIF_TDMA_EN_MSK (0x1U << SPDIF_TDMA_EN_POS)
|
||||
#define SPDIF_TDMA_EN_SEL(X) (X << SPDIF_TDMA_EN_POS)
|
||||
|
||||
/* SPDIF_RX_EN */
|
||||
#define SPDIF_RXEN_POS (0U)
|
||||
#define SPDIF_RXEN_MSK (0x1U << SPDIF_RXEN_POS)
|
||||
#define SPDIF_RXEN_SEL(X) (X << SPDIF_RXEN_POS)
|
||||
|
||||
/* SPDIF_RX_CTL */
|
||||
#define SPDIF_RX_DIV_POS (13U)
|
||||
#define SPDIF_RX_DIV_MSK (0x7FU << SPDIF_RX_DIV_POS)
|
||||
#define SPDIF_RX_DIV_SEL(X) (X << SPDIF_RX_DIV_POS)
|
||||
#define SPDIF_RX_DIV_BYPASS_POS (12U)
|
||||
#define SPDIF_RX_DIV_BYPASS_MSK (0x1U << SPDIF_RX_DIV_BYPASS_POS)
|
||||
#define SPDIF_RX_DIV_BYPASS_SEL(X) (X << SPDIF_RX_DIV_BYPASS_POS)
|
||||
#define SPDIF_RX_VALID_EN_POS (8U)
|
||||
#define SPDIF_RX_VALID_EN_MSK (0x1U << SPDIF_RX_VALID_EN_POS)
|
||||
#define SPDIF_RX_VALID_EN_SEL(X) (X << SPDIF_RX_VALID_EN_POS)
|
||||
#define SPDIF_RX_PARITY_EN_POS (4U)
|
||||
#define SPDIF_RX_PARITY_EN_MSK (0x1U << SPDIF_RX_PARITY_EN_POS)
|
||||
#define SPDIF_RX_PARITY_EN_SEL(X) (X << SPDIF_RX_PARITY_EN_POS)
|
||||
#define SPDIF_RX_DATAMODE_POS (0U)
|
||||
#define SPDIF_RX_DATAMODE_MSK (0x3U << SPDIF_RX_DATAMODE_POS)
|
||||
#define SPDIF_RX_DATAMODE_SEL(X) (X << SPDIF_RX_DATAMODE_POS)
|
||||
|
||||
/* SPDIF_RX_DMA_EN */
|
||||
#define SPDIF_RDMA_EN_POS (0U)
|
||||
#define SPDIF_RDMA_EN_MSK (0x1U << SPDIF_RDMA_EN_POS)
|
||||
#define SPDIF_RDMA_EN_SEL(X) (X << SPDIF_RDMA_EN_POS)
|
||||
|
||||
|
||||
#define CPR_PERI_DIV_SEL_REG 0x004 /*audio sys clock div Register*/
|
||||
#define CPR_PERI_CLK_SEL_REG 0x008 /*audio sys clock selection Register*/
|
||||
#define CPR_PERI_CTRL_REG 0x00C /*Peripheral control signal configuration register*/
|
||||
#define CPR_IP_CG_REG 0x010 /* ip clock gate register */
|
||||
|
||||
/* AUDIO SYS DIV SEL REG, offset: 0x4 */
|
||||
#define CPR_AUDIO_DIV1_CG_POS (17U)
|
||||
#define CPR_AUDIO_DIV1_CG_MSK (0x1U << CPR_AUDIO_DIV1_CG_POS)
|
||||
#define CPR_AUDIO_DIV1_CG(X) (X << CPR_AUDIO_DIV1_CG_POS)
|
||||
#define CPR_AUDIO_DIV1_SEL_POS (12U)
|
||||
#define CPR_AUDIO_DIV1_SEL_MSK (0x1FU << CPR_AUDIO_DIV1_SEL_POS)
|
||||
#define CPR_AUDIO_DIV1_SEL(X) (X << CPR_AUDIO_DIV1_SEL_POS)
|
||||
#define CPR_AUDIO_DIV0_CG_POS (9U)
|
||||
#define CPR_AUDIO_DIV0_CG_MSK (0x1U << CPR_AUDIO_DIV0_CG_POS)
|
||||
#define CPR_AUDIO_DIV0_CG(X) (X << CPR_AUDIO_DIV0_CG_POS)
|
||||
#define CPR_AUDIO_DIV0_SEL_POS (4U)
|
||||
#define CPR_AUDIO_DIV0_SEL_MSK (0x1FU << CPR_AUDIO_DIV0_SEL_POS)
|
||||
#define CPR_AUDIO_DIV0_SEL(X) (X << CPR_AUDIO_DIV0_SEL_POS)
|
||||
/* CPR_PERI_CLK_SEL_REG 0x008 */
|
||||
#define CPR_SPDIF_SRC_SEL_POS (24U)
|
||||
#define CPR_SPDIF_SRC_SEL_MSK (0x3U << CPR_SPDIF_SRC_SEL_POS)
|
||||
#define CPR_SPDIF_SRC_SEL(X) (X << CPR_SPDIF_SRC_SEL_POS)
|
||||
/* PERI_CTRL_REG, Offset: 0xC */
|
||||
#define CPR_SPDIF_SYNC_POS (14U)
|
||||
#define CPR_SPDIF_SYNC_MSK (0x1U << CPR_SPDIF_SYNC_POS)
|
||||
#define CPR_SPDIF_SYNC_EN (CPR_SPDIF_SYNC_MSK)
|
||||
/* CPR_IP_CG_REG 0x010 */
|
||||
#define CPR_SPDIF0_CG_SEL_POS (23U)
|
||||
#define CPR_SPDIF0_CG_SEL_MSK (0x1U << CPR_SPDIF0_CG_SEL_POS)
|
||||
#define CPR_SPDIF0_CG_SEL(X) (X << CPR_SPDIF0_CG_SEL_POS)
|
||||
#define CPR_SPDIF1_CG_SEL_POS (24U)
|
||||
#define CPR_SPDIF1_CG_SEL_MSK (0x1U << CPR_SPDIF1_CG_SEL_POS)
|
||||
#define CPR_SPDIF1_CG_SEL(X) (X << CPR_SPDIF1_CG_SEL_POS)
|
||||
|
||||
|
||||
#define LIGHT_TDM_DMABUF_SIZE (64 * 1024)
|
||||
|
||||
struct light_spdif_priv {
|
||||
void __iomem *regs;
|
||||
struct regmap *regmap;
|
||||
struct regmap *audio_pin_regmap;
|
||||
struct regmap *audio_cpr_regmap;
|
||||
struct clk *clk;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_rx;
|
||||
unsigned int dai_fmt;
|
||||
u32 dma_maxburst;
|
||||
struct device *dev;
|
||||
unsigned int irq;
|
||||
atomic_t spdif_ref_cnt;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -46,7 +46,13 @@ static int light_tdm_dai_probe(struct snd_soc_dai *dai)
|
||||
static int light_tdm_dai_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
return 0;
|
||||
struct light_tdm_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (priv->slot_num != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pm_runtime_get_sync(dai->dev);
|
||||
}
|
||||
|
||||
static void light_tdm_snd_rxctrl(struct light_tdm_priv *priv, char on)
|
||||
@@ -72,10 +78,15 @@ static void light_tdm_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct light_tdm_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
if (priv->slot_num != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
light_tdm_snd_rxctrl(priv, 0);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
pm_runtime_put(dai->dev);
|
||||
return;
|
||||
}
|
||||
|
||||
static int light_tdm_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
|
||||
@@ -110,7 +121,6 @@ static int light_tdm_set_fmt_dai(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk("%s fmt=%d\n", __func__, fmt);
|
||||
switch(fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
break;
|
||||
@@ -131,8 +141,7 @@ static int light_tdm_set_fmt_dai(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
u32 dmadl;
|
||||
regmap_read(priv->regmap, TDM_TDMCTL, &tdmctl);
|
||||
regmap_read(priv->regmap, TDM_DMADL, &dmadl);
|
||||
printk("%s TDM_TDMCTL=0x%x TDM_DMADL=0x%x\n", __func__, tdmctl, dmadl);
|
||||
printk("%s %d\n", __func__, __LINE__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -253,95 +262,15 @@ static const struct snd_soc_dai_ops light_tdm_dai_ops = {
|
||||
.hw_params = light_tdm_dai_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver light_tdm_soc_dai[] = {
|
||||
{
|
||||
.probe = light_tdm_dai_probe,
|
||||
.name = "light-tdm-dai-slot1",
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &light_tdm_dai_ops,
|
||||
static struct snd_soc_dai_driver light_tdm_soc_dai = {
|
||||
.probe = light_tdm_dai_probe,
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
{
|
||||
.probe = light_tdm_dai_probe,
|
||||
.name = "light-tdm-dai-slot2",
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &light_tdm_dai_ops,
|
||||
},
|
||||
{
|
||||
.probe = light_tdm_dai_probe,
|
||||
.name = "light-tdm-dai-slot3",
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &light_tdm_dai_ops,
|
||||
},
|
||||
{
|
||||
.probe = light_tdm_dai_probe,
|
||||
.name = "light-tdm-dai-slot4",
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &light_tdm_dai_ops,
|
||||
},
|
||||
{
|
||||
.probe = light_tdm_dai_probe,
|
||||
.name = "light-tdm-dai-slot5",
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &light_tdm_dai_ops,
|
||||
},
|
||||
{
|
||||
.probe = light_tdm_dai_probe,
|
||||
.name = "light-tdm-dai-slot6",
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &light_tdm_dai_ops,
|
||||
},
|
||||
{
|
||||
.probe = light_tdm_dai_probe,
|
||||
.name = "light-tdm-dai-slot7",
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &light_tdm_dai_ops,
|
||||
},
|
||||
{
|
||||
.probe = light_tdm_dai_probe,
|
||||
.name = "light-tdm-dai-slot8",
|
||||
.capture = {
|
||||
.rates = LIGHT_RATES,
|
||||
.formats = LIGHT_FMTS,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &light_tdm_dai_ops,
|
||||
},
|
||||
.ops = &light_tdm_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver light_tdm_soc_component = {
|
||||
@@ -482,11 +411,13 @@ static int light_tdm_probe(struct platform_device *pdev)
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
tdm_priv->clk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (IS_ERR(tdm_priv->clk))
|
||||
return PTR_ERR(tdm_priv->clk);
|
||||
|
||||
|
||||
if (tdm_priv->slot_num == 1) {
|
||||
tdm_priv->clk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (IS_ERR(tdm_priv->clk))
|
||||
return PTR_ERR(tdm_priv->clk);
|
||||
|
||||
tdm_priv->regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(tdm_priv->regs)) {
|
||||
return PTR_ERR(tdm_priv->regs);
|
||||
@@ -504,7 +435,7 @@ static int light_tdm_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "cannot find regmap for audio system register\n");
|
||||
return -EINVAL;
|
||||
} else {
|
||||
light_tdm_pinctrl(tdm_priv);
|
||||
//light_tdm_pinctrl(tdm_priv);
|
||||
}
|
||||
|
||||
tdm_priv->audio_cpr_regmap = syscon_regmap_lookup_by_phandle(np, "audio-cpr-regmap");
|
||||
@@ -518,22 +449,10 @@ static int light_tdm_probe(struct platform_device *pdev)
|
||||
//AUDIO_DIV0 set to 1/6. 294.912MHz / 6 = 49.152MHz
|
||||
regmap_update_bits(tdm_priv->audio_cpr_regmap,
|
||||
CPR_PERI_DIV_SEL_REG, CPR_AUDIO_DIV0_SEL_MSK, CPR_AUDIO_DIV0_SEL(5));
|
||||
//enable clock gate
|
||||
regmap_update_bits(tdm_priv->audio_cpr_regmap,
|
||||
CPR_IP_CG_REG, CPR_TDM_CG_SEL_MSK, CPR_TDM_CG_SEL(1));
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||
ret = light_tdm_runtime_resume(&pdev->dev);
|
||||
if (ret) {
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(tdm_priv->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pm_runtime_resume_and_get(&pdev->dev); // clk gate is enabled by hardware as default register value
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
||||
tdm_priv->irq = platform_get_irq(pdev, 0);
|
||||
if (tdm_priv->irq== 0) {
|
||||
@@ -590,7 +509,7 @@ static int light_tdm_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &light_tdm_soc_component,
|
||||
light_tdm_soc_dai, ARRAY_SIZE(light_tdm_soc_dai));
|
||||
&light_tdm_soc_dai, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot snd component register\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user