Linux_SDK_V1.2.1

Signed-off-by: thead_admin <occ_thead@service.alibaba.com>
This commit is contained in:
thead_admin
2023-08-07 11:23:02 +08:00
committed by Han Gao
parent a26b2d282c
commit afef388b8e
84 changed files with 7359 additions and 634 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -523,7 +523,7 @@
>;
};
pinctrl_audio_i2s0: i2s0grp {
pinctrl_light_i2s0: i2s0grp {
thead,pins = <
FM_QSPI0_SCLK 0x2 0x208
FM_QSPI0_CSN0 0x2 0x238

View 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";
};

View File

@@ -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

View File

@@ -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>;

View File

@@ -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

View File

@@ -63,7 +63,7 @@
sound-dai = <&light_i2s 1>;
};
codec {
sound-dai = <&dummy_codec 2>;
sound-dai = <&dummy_codec>;
};
};
};

View File

@@ -48,11 +48,11 @@
sound-dai = <&light_i2s 1>;
};
codec {
sound-dai = <&dummy_codec 2>;
sound-dai = <&dummy_codec>;
};
};
};
&light_i2s {
status = "okay";
};
};

View 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>;
};

View 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>;
};
};
};

View File

@@ -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";
};

View File

@@ -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";
};

View File

@@ -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";
};

View File

@@ -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";
};

View File

@@ -48,7 +48,7 @@
sound-dai = <&light_i2s 1>;
};
codec {
sound-dai = <&dummy_codec 2>;
sound-dai = <&dummy_codec>;
};
};
};

View File

@@ -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";
};

View File

@@ -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";
};

View File

@@ -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";
};

View File

@@ -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 = <

View File

@@ -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";
};

View File

@@ -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";
};

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
/dts-v1/;
#include "light-b-product.dts"
#include "light-b-audio-hdmi.dts"

View File

@@ -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 {

View File

@@ -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";
};

View File

@@ -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";
};

View File

@@ -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>;

View File

@@ -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>;
};
};
};

View File

@@ -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 {

View File

@@ -11,3 +11,8 @@
&light_iopmp {
status = "disabled";
};
&qspi1 {
status = "disabled";
};

View File

@@ -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]
};

View File

@@ -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>;

View File

@@ -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";
};
};
};

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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" \

View File

@@ -13,7 +13,6 @@
#include <linux/types.h>
#include <linux/pgtable.h>
#include <asm/mmiowb.h>
#include <asm/early_ioremap.h>
/*

View File

@@ -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; })

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View 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");

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View 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;
}

View 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);

View File

@@ -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

View File

@@ -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);
/*0x320SMPLDL_CNFG
0x540AT_CTRL
0x544AT_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")) {

View File

@@ -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_*/

View File

@@ -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);

View File

@@ -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

View File

@@ -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
View 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");

View File

@@ -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 = {

View File

@@ -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.

View File

@@ -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))

View File

@@ -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;

View File

@@ -53,6 +53,7 @@
#define __WRITE_ONCE(x, val) \
do { \
*(volatile typeof(x) *)&(x) = (val); \
smp_mb(); \
} while (0)
#define WRITE_ONCE(x, val) \

View 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

View 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__

View File

@@ -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

View 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__*/

View File

@@ -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

View File

@@ -94,7 +94,7 @@ struct qnode {
* progress.
*/
#ifndef _Q_PENDING_LOOPS
#define _Q_PENDING_LOOPS 1
#define _Q_PENDING_LOOPS 9
#endif
/*

View File

@@ -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,

View File

@@ -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)

View File

@@ -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,

View File

@@ -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,

View File

@@ -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

View 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 */

View File

@@ -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,
},
},
};

View 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");

View File

@@ -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);

View File

@@ -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;

View 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");

View 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

View File

@@ -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");
}