From f6e11697b0f2f6e9954dd5dfbf5db24f2f6e5173 Mon Sep 17 00:00:00 2001 From: Xing Wang Date: Wed, 26 Apr 2017 20:24:13 +0800 Subject: [PATCH] audio: config audio for m8b PD#141217: audio: config audio for m8b Change-Id: If837cf19bf3da0e54830fefd2267fd14445ca6f1 Signed-off-by: Xing Wang --- MAINTAINERS | 21 + arch/arm/boot/dts/amlogic/meson8b.dtsi | 26 + arch/arm/boot/dts/amlogic/meson8b_m200.dts | 144 ++++ arch/arm/configs/meson32_defconfig | 11 + arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts | 4 +- arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts | 4 +- arch/arm64/boot/dts/amlogic/gxl_p400_2g.dts | 4 +- arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts | 4 +- arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts | 4 +- arch/arm64/boot/dts/amlogic/gxm_skt.dts | 4 +- drivers/amlogic/clk/m8b/clk_misc.c | 20 + drivers/amlogic/pinctrl/pinctrl-meson8b.c | 9 +- include/dt-bindings/clock/meson8b-clkc.h | 3 +- sound/soc/amlogic/aml_meson.c | 2 +- sound/soc/amlogic/aml_pcm_dai.c | 2 +- sound/soc/codecs/amlogic/Kconfig | 11 +- sound/soc/codecs/amlogic/Makefile | 4 +- sound/soc/codecs/amlogic/aml_pmu3.c | 984 ++++++++++++++++++++++++++++ sound/soc/codecs/amlogic/aml_pmu3.h | 52 ++ 19 files changed, 1295 insertions(+), 18 deletions(-) create mode 100644 sound/soc/codecs/amlogic/aml_pmu3.c create mode 100644 sound/soc/codecs/amlogic/aml_pmu3.h diff --git a/MAINTAINERS b/MAINTAINERS index 91cbb7f..c34b94b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13845,3 +13845,24 @@ AMLOGIC AXG ADD PXP DTS M: Yun Cai F: arch/arm64/boot/dts/amlogic/axg_pxp.dts F: arch/arm64/boot/dts/amlogic/mesonaxg.dtsi + +AMLOGIC S805 audio +M: Xing Wang +F: arch/arm/boot/dts/amlogic/meson8b.dtsi +F: arch/arm/boot/dts/amlogic/meson8b_m200.dts +F: arch/arm/configs/meson32_defconfig +F: arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts +F: arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts +F: arch/arm64/boot/dts/amlogic/gxl_p400_2g.dts +F: arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts +F: arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts +F: arch/arm64/boot/dts/amlogic/gxm_skt.dts +F: drivers/amlogic/clk/m8b/clk_misc.c +F: drivers/amlogic/pinctrl/pinctrl-meson8b.c +F: include/dt-bindings/clock/meson8b-clkc.h +F: sound/soc/amlogic/aml_meson.c +F: sound/soc/amlogic/aml_pcm_dai.c +F: sound/soc/codecs/amlogic/Kconfig +F: sound/soc/codecs/amlogic/Makefile +F: sound/soc/codecs/amlogic/aml_pmu3.c +F: sound/soc/codecs/amlogic/aml_pmu3.h diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi index 0e2f788..f1aaaf6 100644 --- a/arch/arm/boot/dts/amlogic/meson8b.dtsi +++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi @@ -562,6 +562,16 @@ function = "uart_b"; }; }; + + audio_pcm_pins:audio_pcm { + mux { + groups = "pcm_out_a", + "pcm_in_a", + "pcm_fs_a", + "pcm_clk_a"; + function = "pcm_a"; + }; + }; }; pinctrl_aobus: pinctrl@c8100084 { compatible = "amlogic,meson8b-aobus-pinctrl"; @@ -608,6 +618,22 @@ function = "hdmi_cec"; }; }; + audio_i2s_pins:audio_i2s { + mux { + groups = "i2s_am_clk_out", + "i2s_ao_clk_out", + "i2s_lr_clk_out", + "i2s_in_ch01", + "i2s_out_01"; + function = "i2s"; + }; + }; + audio_spdif_pins:audio_spdif { + mux { + groups = "spdif_out_2"; + function = "spdif_2"; + }; + }; }; dwc2_b { compatible = "amlogic,dwc2"; diff --git a/arch/arm/boot/dts/amlogic/meson8b_m200.dts b/arch/arm/boot/dts/amlogic/meson8b_m200.dts index c13ce35..850ff06 100644 --- a/arch/arm/boot/dts/amlogic/meson8b_m200.dts +++ b/arch/arm/boot/dts/amlogic/meson8b_m200.dts @@ -328,6 +328,150 @@ }; }; }; + + /* AUDIO MESON DEVICES */ + i2s_dai: I2S { + #sound-dai-cells = <0>; + compatible = "amlogic, aml-i2s-dai"; + clocks = + <&clkc CLKID_MPLL2>, + <&clkc CLKID_AMCLK_COMP>, + <&clkc CLKID_AIU_GLUE>, + <&clkc CLKID_IEC958>, + <&clkc CLKID_I2S_OUT>, + <&clkc CLKID_AMCLK>, + <&clkc CLKID_AIFIFO2>, + <&clkc CLKID_MIXER>, + <&clkc CLKID_MIXER_IFACE>, + <&clkc CLKID_ADC>, + <&clkc CLKID_AIU>, + <&clkc CLKID_AOCLK_GATE>, + <&clkc CLKID_I2S_SPDIF>; + clock-names = + "mpll2", + "mclk", + "top_glue", + "aud_buf", + "i2s_out", + "amclk_measure", + "aififo2", + "aud_mixer", + "mixer_reg", + "adc", + "top_level", + "aoclk", + "aud_in"; + /*DMIC;*/ /* I2s Mic or Dmic, default for I2S mic */ + }; + spdif_dai: SPDIF { + #sound-dai-cells = <0>; + compatible = "amlogic, aml-spdif-dai"; + clocks = + <&clkc CLKID_MPLL1>, + <&clkc CLKID_I958_COMP>, + <&clkc CLKID_AMCLK_COMP>, + <&clkc CLKID_I958_COMP_SPDIF>, + <&clkc CLKID_CLK81>, + <&clkc CLKID_IEC958>, + <&clkc CLKID_IEC958_GATE>; + clock-names = + "mpll1", + "i958", + "mclk", + "spdif", + "clk_81", + "iec958", + "iec958_amclk"; + }; + pcm_dai: PCM { + #sound-dai-cells = <0>; + compatible = "amlogic, aml-pcm-dai"; + pinctrl-names = "aml_audio_pcm"; + pinctrl-0 = <&audio_pcm_pins>; + clocks = + <&clkc CLKID_MPLL0>, + <&clkc CLKID_PCM_MCLK_COMP>, + <&clkc CLKID_PCM_SCLK_GATE>; + clock-names = + "mpll0", + "pcm_mclk", + "pcm_sclk"; + pcm_mode = <1>; /* 0=slave mode, 1=master mode */ + }; + i2s_plat: i2s_platform { + compatible = "amlogic, aml-i2s"; + interrupts = <0 29 1>; + }; + pcm_plat: pcm_platform { + compatible = "amlogic, aml-pcm"; + }; + spdif_codec: spdif_codec { + #sound-dai-cells = <0>; + compatible = "amlogic, aml-spdif-codec"; + pinctrl-names = "aml_audio_spdif"; + pinctrl-0 = <&audio_spdif_pins>; + }; + pcm_codec: pcm_codec { + #sound-dai-cells = <0>; + compatible = "amlogic, pcm2BT-codec"; + }; + /* endof AUDIO MESON DEVICES */ + + /* AUDIO board specific */ + dummy_codec:dummy { + #sound-dai-cells = <0>; + compatible = "amlogic, aml_dummy_codec"; + status = "disabled"; + }; + amlogic_codec:t9015 { + #sound-dai-cells = <0>; + compatible = "amlogic, aml_codec_T9015"; + reg = <0x0 0xc8832000 0x0 0x14>; + status = "disabled"; + }; + audio_pmu3_codec:aml_pmu3 { + #sound-dai-cells = <0>; + compatible = "amlogic, aml_pmu3_codec"; + status = "okay"; + }; + aml_sound_meson { + compatible = "aml, meson-snd-card"; + status = "okay"; + aml-sound-card,format = "i2s"; + aml_sound_card,name = "AML-MESONAUDIO"; + aml,audio-routing = + "Ext Spk","LOUTL", + "Ext Spk","LOUTR"; + + mute_gpio-gpios = <&gpio GPIOH_5 0>; + mute_inv; + hp_disable; + hp_paraments = <800 300 0 5 1>; + pinctrl-names = "aml_audio_i2s"; + pinctrl-0 = <&audio_i2s_pins>; + cpu_list = <&cpudai0 &cpudai1 &cpudai2>; + codec_list = <&codec0 &codec1 &codec2>; + plat_list = <&i2s_plat &i2s_plat &pcm_plat>; + cpudai0: cpudai0 { + sound-dai = <&i2s_dai>; + }; + cpudai1: cpudai1 { + sound-dai = <&spdif_dai>; + }; + cpudai2: cpudai2 { + sound-dai = <&pcm_dai>; + }; + codec0: codec0 { + sound-dai = <&audio_pmu3_codec>; + }; + codec1: codec1 { + sound-dai = <&spdif_codec>; + }; + codec2: codec2 { + sound-dai = <&pcm_codec>; + }; + }; + /* END OF AUDIO board specific */ }; &uart_AO { diff --git a/arch/arm/configs/meson32_defconfig b/arch/arm/configs/meson32_defconfig index 1de9fe0..c858d86 100644 --- a/arch/arm/configs/meson32_defconfig +++ b/arch/arm/configs/meson32_defconfig @@ -126,6 +126,17 @@ CONFIG_FB_SIMPLE=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_AMLOGIC_SND_SOC_CODECS=y +CONFIG_AMLOGIC_SND_CODEC_DUMMY_CODEC=y +CONFIG_AMLOGIC_SND_CODEC_PCM2BT=y +CONFIG_AMLOGIC_SND_CODEC_AMLT9015=y +CONFIG_AMLOGIC_SND_CODEC_PMU3=y +CONFIG_AMLOGIC_SND_SOC=y +CONFIG_AMLOGIC_SND_SPLIT_MODE=y CONFIG_USB_HIDDEV=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts index ea844f4..7e3f4a7 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts @@ -779,7 +779,7 @@ pcm_dai: PCM { #sound-dai-cells = <0>; compatible = "amlogic, aml-pcm-dai"; - pinctrl-names = "aml_audio_btpcm"; + pinctrl-names = "aml_audio_pcm"; pinctrl-0 = <&audio_pcm_pins>; clocks = <&clkc CLKID_MPLL0>, @@ -835,7 +835,7 @@ mute_inv; hp_disable; hp_paraments = <800 300 0 5 1>; - pinctrl-names = "audio_i2s_pins"; + pinctrl-names = "aml_audio_i2s"; pinctrl-0 = <&audio_i2s_pins>; cpu_list = <&cpudai0 &cpudai1 &cpudai2>; codec_list = <&codec0 &codec1 &codec2>; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts index 984da7b..a417a97 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts @@ -780,7 +780,7 @@ pcm_dai: PCM { #sound-dai-cells = <0>; compatible = "amlogic, aml-pcm-dai"; - pinctrl-names = "aml_audio_btpcm"; + pinctrl-names = "aml_audio_pcm"; pinctrl-0 = <&audio_pcm_pins>; clocks = <&clkc CLKID_MPLL0>, @@ -836,7 +836,7 @@ mute_inv; hp_disable; hp_paraments = <800 300 0 5 1>; - pinctrl-names = "audio_i2s_pins"; + pinctrl-names = "aml_audio_i2s"; pinctrl-0 = <&audio_i2s_pins>; cpu_list = <&cpudai0 &cpudai1 &cpudai2>; codec_list = <&codec0 &codec1 &codec2>; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p400_2g.dts b/arch/arm64/boot/dts/amlogic/gxl_p400_2g.dts index 32468bd..71af223 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p400_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p400_2g.dts @@ -550,7 +550,7 @@ pcm_dai: PCM { #sound-dai-cells = <0>; compatible = "amlogic, aml-pcm-dai"; - pinctrl-names = "aml_audio_btpcm"; + pinctrl-names = "aml_audio_pcm"; pinctrl-0 = <&audio_pcm_pins>; clocks = <&clkc CLKID_MPLL0>, @@ -606,7 +606,7 @@ mute_inv; hp_disable; hp_paraments = <800 300 0 5 1>; - pinctrl-names = "audio_i2s_pins"; + pinctrl-names = "aml_audio_i2s"; pinctrl-0 = <&audio_i2s_pins>; cpu_list = <&cpudai0 &cpudai1 &cpudai2>; codec_list = <&codec0 &codec1 &codec2>; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts b/arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts index 0dc3a6c..5869480 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts @@ -612,7 +612,7 @@ pcm_dai: PCM { #sound-dai-cells = <0>; compatible = "amlogic, aml-pcm-dai"; - pinctrl-names = "aml_audio_btpcm"; + pinctrl-names = "aml_audio_pcm"; pinctrl-0 = <&audio_pcm_pins>; clocks = <&clkc CLKID_MPLL0>, @@ -668,7 +668,7 @@ mute_inv; hp_disable; hp_paraments = <800 300 0 5 1>; - pinctrl-names = "audio_i2s_pins"; + pinctrl-names = "aml_audio_i2s"; pinctrl-0 = <&audio_i2s_pins>; cpu_list = <&cpudai0 &cpudai1 &cpudai2>; codec_list = <&codec0 &codec1 &codec2>; diff --git a/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts b/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts index ef4fa30..7893e3b 100644 --- a/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts @@ -792,7 +792,7 @@ pcm_dai: PCM { #sound-dai-cells = <0>; compatible = "amlogic, aml-pcm-dai"; - pinctrl-names = "aml_audio_btpcm"; + pinctrl-names = "aml_audio_pcm"; pinctrl-0 = <&audio_pcm_pins>; clocks = <&clkc CLKID_MPLL0>, @@ -848,7 +848,7 @@ mute_inv; hp_disable; hp_paraments = <800 300 0 5 1>; - pinctrl-names = "audio_i2s_pins"; + pinctrl-names = "aml_audio_i2s"; pinctrl-0 = <&audio_i2s_pins>; cpu_list = <&cpudai0 &cpudai1 &cpudai2>; codec_list = <&codec0 &codec1 &codec2>; diff --git a/arch/arm64/boot/dts/amlogic/gxm_skt.dts b/arch/arm64/boot/dts/amlogic/gxm_skt.dts index e2a657e..fcdada8 100644 --- a/arch/arm64/boot/dts/amlogic/gxm_skt.dts +++ b/arch/arm64/boot/dts/amlogic/gxm_skt.dts @@ -706,7 +706,7 @@ pcm_dai: PCM { #sound-dai-cells = <0>; compatible = "amlogic, aml-pcm-dai"; - pinctrl-names = "aml_audio_btpcm"; + pinctrl-names = "aml_audio_pcm"; pinctrl-0 = <&audio_pcm_pins>; clocks = <&clkc CLKID_MPLL0>, @@ -762,7 +762,7 @@ mute_inv; hp_disable; hp_paraments = <800 300 0 5 1>; - pinctrl-names = "audio_i2s_pins"; + pinctrl-names = "aml_audio_i2s"; pinctrl-0 = <&audio_i2s_pins>; cpu_list = <&cpudai0 &cpudai1 &cpudai2>; codec_list = <&codec0 &codec1 &codec2>; diff --git a/drivers/amlogic/clk/m8b/clk_misc.c b/drivers/amlogic/clk/m8b/clk_misc.c index 309dcaa..04d1768 100644 --- a/drivers/amlogic/clk/m8b/clk_misc.c +++ b/drivers/amlogic/clk/m8b/clk_misc.c @@ -130,6 +130,7 @@ static struct clk_hw *amclk_hws[] = { /* cts_clk_i958 */ const char *i958_parent_names[] = { "ddr_pll_clk", "mpll0", "mpll1", "mpll2"}; +const char *i958_ext_parent_names[] = {"amclk_composite", "i958_composite"}; static struct clk_mux i958_mux = { .reg = (void *)HHI_AUD_CLK_CNTL2, @@ -172,6 +173,20 @@ static struct clk_gate i958_gate = { }, }; +static struct clk_mux i958_comp_spdif = { + .reg = (void *)HHI_AUD_CLK_CNTL2, + .mask = 0x1, + .shift = 27, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "i958_comp_spdif", + .ops = &clk_mux_ops, + .parent_names = i958_ext_parent_names, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED), + }, +}; + static struct clk_hw *i958_hws[] = { [CLKID_I958_MUX - CLKID_I958_MUX] = &i958_mux.hw, [CLKID_I958_DIV - CLKID_I958_MUX] = &i958_div.hw, @@ -274,6 +289,8 @@ void amlogic_init_misc(void) i958_div.reg = clk_base + (u32)(i958_div.reg); i958_gate.reg = clk_base + (u32)(i958_gate.reg); + /*clk_i958 spdif*/ + i958_comp_spdif.reg = clk_base + (u32)(i958_comp_spdif.reg); /* cts_pclk_mclk */ pcm_mclk_mux.reg = clk_base + (u32)(pcm_mclk_mux.reg); pcm_mclk_div.reg = clk_base + (u32)(pcm_mclk_div.reg); @@ -343,6 +360,9 @@ void amlogic_init_misc(void) clks[CLKID_PCM_SCLK_GATE] = clk_register(NULL, &pcm_sclk_gate.hw); WARN_ON(IS_ERR(clks[CLKID_PCM_SCLK_GATE])); + clks[CLKID_I958_COMP_SPDIF] = clk_register(NULL, &i958_comp_spdif.hw); + WARN_ON(IS_ERR(clks[CLKID_I958_COMP_SPDIF])); + pr_info("%s: register meson misc clk\n", __func__); }; diff --git a/drivers/amlogic/pinctrl/pinctrl-meson8b.c b/drivers/amlogic/pinctrl/pinctrl-meson8b.c index d0e74e4..89e2b1a 100644 --- a/drivers/amlogic/pinctrl/pinctrl-meson8b.c +++ b/drivers/amlogic/pinctrl/pinctrl-meson8b.c @@ -333,6 +333,7 @@ static const unsigned int uart_rts_ao_b_pins[] = { PIN(GPIOAO_3, AO_OFF) }; static const unsigned int uart_tx_ao_b1_pins[] = { PIN(GPIOAO_4, AO_OFF) }; static const unsigned int uart_rx_ao_b1_pins[] = { PIN(GPIOAO_5, AO_OFF) }; static const unsigned int spdif_out_1_pins[] = { PIN(GPIOAO_6, AO_OFF) }; +static const unsigned int spdif_out_2_pins[] = { PIN(GPIOAO_13, AO_OFF) }; static const unsigned int i2s_in_ch01_pins[] = { PIN(GPIOAO_6, AO_OFF) }; static const unsigned int i2s_ao_clk_in_pins[] = { PIN(GPIOAO_9, AO_OFF) }; @@ -616,7 +617,8 @@ static struct meson_pmx_group meson8b_aobus_groups[] = { GROUP(uart_tx_ao_b1, 0, 24), GROUP(uart_rx_ao_b1, 0, 23), GROUP(spdif_out_1, 0, 16), - GROUP(i2s_in_ch01, 0, 13), + GROUP(spdif_out_2, 0, 3), + GROUP(i2s_in_ch01, 1, 13), GROUP(i2s_ao_clk_in, 0, 15), GROUP(i2s_lr_clk_in, 0, 14), }; @@ -808,6 +810,10 @@ static const char * const spdif_1_groups[] = { "spdif_out_1" }; +static const char * const spdif_2_groups[] = { + "spdif_out_2" +}; + static const char * const i2s_groups[] = { "i2s_am_clk_out", "i2s_ao_clk_out", "i2s_lr_clk_out", "i2s_out_01", "i2s_in_ch01", "i2s_ao_clk_in", @@ -902,6 +908,7 @@ static struct meson_pmx_func meson8b_aobus_functions[] = { FUNCTION(clk_32k), FUNCTION(pwm_c_ao), FUNCTION(spdif_1), + FUNCTION(spdif_2), FUNCTION(hdmi_cec), }; diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h index 8d71d31..d507af3 100644 --- a/include/dt-bindings/clock/meson8b-clkc.h +++ b/include/dt-bindings/clock/meson8b-clkc.h @@ -187,8 +187,9 @@ #define CLKID_PCM_MCLK_COMP (CLKID_MISC_BASE + 15) #define CLKID_PCM_SCLK_DIV (CLKID_MISC_BASE + 16) #define CLKID_PCM_SCLK_GATE (CLKID_MISC_BASE + 17) +#define CLKID_I958_COMP_SPDIF (CLKID_MISC_BASE + 18) -#define NR_CLKS 164 /*96+4+9+36+18*/ +#define NR_CLKS 165 /*96+4+9+36+18*/ #endif /* __MESON8B_CLKC_H */ diff --git a/sound/soc/amlogic/aml_meson.c b/sound/soc/amlogic/aml_meson.c index 20be66f..cf71284 100644 --- a/sound/soc/amlogic/aml_meson.c +++ b/sound/soc/amlogic/aml_meson.c @@ -553,7 +553,7 @@ static void aml_pinmux_init(struct snd_soc_card *card) #endif p_aml_audio->pin_ctl = devm_pinctrl_get_select( - card->dev, "audio_i2s_pins"); + card->dev, "aml_audio_i2s"); if (IS_ERR(p_aml_audio->pin_ctl)) { pr_info("%s,aml_pinmux_init error!\n", __func__); return; diff --git a/sound/soc/amlogic/aml_pcm_dai.c b/sound/soc/amlogic/aml_pcm_dai.c index 1416c6d7b..69223e6 100644 --- a/sound/soc/amlogic/aml_pcm_dai.c +++ b/sound/soc/amlogic/aml_pcm_dai.c @@ -271,7 +271,7 @@ static int aml_pcm_dai_probe(struct platform_device *pdev) pr_debug("enter %s\n", __func__); - pin_ctl = devm_pinctrl_get_select(&pdev->dev, "aml_audio_btpcm"); + pin_ctl = devm_pinctrl_get_select(&pdev->dev, "aml_audio_pcm"); if (IS_ERR(pin_ctl)) { pin_ctl = NULL; pr_err("aml audio pcm dai pinmux set error!\n"); diff --git a/sound/soc/codecs/amlogic/Kconfig b/sound/soc/codecs/amlogic/Kconfig index 2e38b13..4dbe0cf 100644 --- a/sound/soc/codecs/amlogic/Kconfig +++ b/sound/soc/codecs/amlogic/Kconfig @@ -38,4 +38,13 @@ config AMLOGIC_SND_CODEC_AMLT9015 AMLT9015 codec, this codec is internal -#endif #AMLOGIC_SND_SOC_CODECS \ No newline at end of file +config AMLOGIC_SND_CODEC_PMU3 + bool "Amlogic Audio AML PMU3 codec" + depends on AMLOGIC_SND_SOC_CODECS + default n + help + Amlogic Audio codec, + AML PMU3 codec, + AML PMU3 codec, + this codec is internal +#endif #AMLOGIC_SND_SOC_CODECS diff --git a/sound/soc/codecs/amlogic/Makefile b/sound/soc/codecs/amlogic/Makefile index 817b59c..8496871 100644 --- a/sound/soc/codecs/amlogic/Makefile +++ b/sound/soc/codecs/amlogic/Makefile @@ -2,8 +2,10 @@ snd-soc-dummy_codec-objs := dummy_codec.o snd-soc-pcm2bt-objs := pcm2bt.o snd-soc-aml_t9015-objs := aml_codec_t9015.o +snd-soc-pmu3-objs := aml_pmu3.o # Amlogic obj-$(CONFIG_AMLOGIC_SND_CODEC_DUMMY_CODEC) += snd-soc-dummy_codec.o obj-$(CONFIG_AMLOGIC_SND_CODEC_PCM2BT) += snd-soc-pcm2bt.o -obj-$(CONFIG_AMLOGIC_SND_CODEC_AMLT9015) += snd-soc-aml_t9015.o \ No newline at end of file +obj-$(CONFIG_AMLOGIC_SND_CODEC_AMLT9015) += snd-soc-aml_t9015.o +obj-$(CONFIG_AMLOGIC_SND_CODEC_PMU3) += snd-soc-pmu3.o diff --git a/sound/soc/codecs/amlogic/aml_pmu3.c b/sound/soc/codecs/amlogic/aml_pmu3.c new file mode 100644 index 0000000..8b2b4b1 --- /dev/null +++ b/sound/soc/codecs/amlogic/aml_pmu3.c @@ -0,0 +1,984 @@ +/* + * aml_pmu3.c -- AML_PMU3 ALSA Soc Codec driver + * + * Copyright 2013 AMLOGIC. + * + * Author: Shuai Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aml_pmu3.h" +#include +#include + + +static u16 pmu3_reg_defaults[] = { + 0x0000, /* R00h - SW Reset */ + 0x0000, /* R01h - Block Enable1 */ + 0x0000, /* R02h - Block Enable2 */ + 0x0000, /* R03h - PGAIN */ + 0x0000, /* R04h - MIXINL */ + 0x0000, /* R05h - MIXINR */ + 0x0000, /* R06h - MiXOUTL */ + 0x0000, /* R07h - MiXOUTR */ + 0x0000, /* R08h - RXV TO MIXOUT */ + 0x0000, /* R09h - Lineout&HP Driver */ + 0x0000, /* R0Ah - HP DC Offset */ + 0x2000, /* R0Bh - ADC & DAC */ + 0x00A8, /* R0Ch - HP & MIC Detect */ + 0x5050, /* R0Dh - ADC Digital Volume */ + 0xC0C0, /* R0Eh - DAC Digital Volume */ + 0xA000, /* R0Fh - Soft Mute and Unmute */ + 0x0000, /* R10h - Digital Sidetone & Mixing */ + 0x0000, /* R11h - DMIC & GPIO_AUDIO */ + 0x0000, /* R12h - Monitor register */ +}; + +static void pmu3_reset(struct snd_soc_codec *codec) +{ + snd_soc_write(codec, PMU3_SOFTWARE_RESET, 0x500); + msleep(20); +} + +static int pmu3_adc_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->dapm->component->codec; + u16 val = snd_soc_read(codec, PMU3_BLOCK_ENABLE_2); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val |= 0x2; + break; + + case SND_SOC_DAPM_PRE_PMD: + val &= ~0x2; + break; + + default: + break; + } + + snd_soc_write(codec, PMU3_BLOCK_ENABLE_2, val); + + return 0; +} + +static int pmu3_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->dapm->component->codec; + u16 val = snd_soc_read(codec, PMU3_BLOCK_ENABLE_2); + unsigned int mask = 1 << w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + val |= 0x1; + val |= mask; + break; + + case SND_SOC_DAPM_POST_PMD: + /*val &= ~0x1;*/ + break; + + default: + break; + } + + snd_soc_write(codec, PMU3_BLOCK_ENABLE_2, val); + + return 0; +} + +static int pmu3_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->dapm->component->codec; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + break; + + case SND_SOC_DAPM_POST_PMU: + /* Enable the input stage of HP driver + * and start the HP DC offset cancellation process + */ + snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_2, 0x1800, 0x1800); + + msleep(20); + + /* Finish the HP DC offset cancellation process */ + snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_2, 0x1000, 0); + + /* Remove shorting the HP driver + * output and enable its output stage + */ + snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_2, 0x400, 0x400); + snd_soc_update_bits(codec, PMU3_LINEOUT_HP_DRV, 0x2, 0x2); + + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, PMU3_LINEOUT_HP_DRV, 0x2, 0x0); + snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_2, 0x400, 0x0); + snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_2, 0x1800, 0x0); + + break; + + case SND_SOC_DAPM_POST_PMD: + break; + + default: + break; + } + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -4000, 200, 1); +static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(adc_tlv, -3000, 37, 1); +static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 37, 1); +static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3750, 250, 1); + +static const DECLARE_TLV_DB_SCALE(pga_in_tlv, -250, 250, 1); +static const DECLARE_TLV_DB_SCALE(pga2mixin_tlv, -1600, 150, 1); +static const DECLARE_TLV_DB_SCALE(xx2mixout_tlv, -5400, 200, 1); +static const DECLARE_TLV_DB_SCALE(xx2mixin_tlv, -1600, 150, 1); + +static const char * const mic_bias_level_txt[] = { + "0.72*CPAVDD25", "0.85*CPAVDD25" +}; + +/* ADC HPF Mode*/ +static const char * const adc_hpf_mode_txt[] = { + "Voice", "Hi-fi" }; + +static const char * const lr_txt[] = { + "Left", "Right" }; + +static const char * const rl_txt[] = { + "Right", "Left" }; + +static const char * const sidetone_txt[] = { + "Disabled", "Left ADC", "Right ADC" }; + +static const char * const dac_mute_rate_txt[] = { "Fast", "Slow" }; + +static const char * const pmu3_lol1_in_texts[] = { + "Off", "MIXOUTL", "MIXOUTR", "Inverted MIXOUTR" +}; + +static const char * const pmu3_lol2_in_texts[] = { + "Off", "MIXOUTL", "Inverted MIXOUTL", "Inverted MIXOUTR" +}; + +static const char * const pmu3_lor1_in_texts[] = { + "Off", "MIXOUTR", "MIXOUTL", "Inverted MIXOUTL" +}; + +static const char * const pmu3_lor2_in_texts[] = { + "Off", "MIXOUTR", "Inverted MIXOUTR", "Inverted MIXOUTL" +}; + +static const struct soc_enum pmu3_lineout_enum[] = { + SOC_ENUM_SINGLE(PMU3_LINEOUT_HP_DRV, 14, + ARRAY_SIZE(pmu3_lol1_in_texts), + pmu3_lol1_in_texts), + SOC_ENUM_SINGLE(PMU3_LINEOUT_HP_DRV, 12, + ARRAY_SIZE(pmu3_lol2_in_texts), + pmu3_lol2_in_texts), + SOC_ENUM_SINGLE(PMU3_LINEOUT_HP_DRV, 10, + ARRAY_SIZE(pmu3_lor1_in_texts), + pmu3_lor1_in_texts), + SOC_ENUM_SINGLE(PMU3_LINEOUT_HP_DRV, 8, + ARRAY_SIZE(pmu3_lor2_in_texts), + pmu3_lor2_in_texts), +}; + +static const SOC_ENUM_SINGLE_DECL( + mic_bias1_enum, PMU3_HP_MIC_DET, + PMU3_MIC_BIAS1_SHIFT, mic_bias_level_txt); + +static const SOC_ENUM_SINGLE_DECL( + mic_bias2_enum, PMU3_HP_MIC_DET, + PMU3_MIC_BIAS2_SHIFT, mic_bias_level_txt); + +static const SOC_ENUM_SINGLE_DECL( + adc_hpf_mode, PMU3_ADC_DAC, + PMU3_ADC_HPF_MODE_SHIFT, adc_hpf_mode_txt); +static const SOC_ENUM_SINGLE_DECL( + aifl_src, PMU3_SIDETONE_MIXING, + PMU3_ADCDATL_SRC_SHIFT, lr_txt); +static const SOC_ENUM_SINGLE_DECL( + aifr_src, PMU3_SIDETONE_MIXING, + PMU3_ADCDATR_SRC_SHIFT, rl_txt); +static const SOC_ENUM_SINGLE_DECL( + dacl_src, PMU3_SIDETONE_MIXING, + PMU3_DACDATL_SRC_SHIFT, lr_txt); +static const SOC_ENUM_SINGLE_DECL( + dacr_src, PMU3_SIDETONE_MIXING, + PMU3_DACDATR_SRC_SHIFT, rl_txt); +static const SOC_ENUM_SINGLE_DECL( + dacl_sidetone, PMU3_SIDETONE_MIXING, + PMU3_DACL_ST_SRC_SHIFT, sidetone_txt); +static const SOC_ENUM_SINGLE_DECL( + dacr_sidetone, PMU3_SIDETONE_MIXING, + PMU3_DACR_ST_SRC_SHIFT, sidetone_txt); + +static const SOC_ENUM_SINGLE_DECL( + dac_mute_rate, PMU3_SOFT_MUTE, + PMU3_DAC_RAMP_RATE_SHIFT, dac_mute_rate_txt); + +static const struct snd_kcontrol_new pmu3_snd_controls[] = { + /* MIC */ + SOC_ENUM("Mic Bias1 Level", mic_bias1_enum), + SOC_ENUM("Mic Bias2 Level", mic_bias2_enum), + + SOC_SINGLE_TLV("PGAIN Left Gain", PMU3_PGA_IN, 12, 0xf, 0, pga_in_tlv), + SOC_SINGLE_TLV("PGAIN Right Gain", PMU3_PGA_IN, 4, 0xf, 0, pga_in_tlv), + + /* ADC */ + SOC_SINGLE_TLV("Left ADC Sidetone Volume", + PMU3_SIDETONE_MIXING, 12, 0xf, 0, + adc_svol_tlv), + SOC_SINGLE_TLV("Right ADC Sidetone Volume", + PMU3_SIDETONE_MIXING, 8, 0xf, 0, + adc_svol_tlv), + + SOC_DOUBLE_TLV("Digital Capture Volume", + PMU3_ADC_VOLUME_CTL, 8, 0, 0x7f, 0, adc_tlv), + + SOC_SINGLE("ADC HPF Switch", PMU3_ADC_DAC, 11, 1, 0), + SOC_ENUM("ADC HPF Mode", adc_hpf_mode), + + SOC_ENUM("Left Digital Audio Source", aifl_src), + SOC_ENUM("Right Digital Audio Source", aifr_src), + SOC_SINGLE_TLV("DACL to MIXOUTL Volume", PMU3_MIXOUT_L, 11, 0x1f, 0, + xx2mixout_tlv), + SOC_SINGLE_TLV("DACR to MIXOUTR Volume", PMU3_MIXOUT_R, 11, 0x1f, 0, + xx2mixout_tlv), + + SOC_ENUM("DACL DATA Source", dacl_src), + SOC_ENUM("DACR DATA Source", dacr_src), + SOC_ENUM("DACL Sidetone Source", dacl_sidetone), + SOC_ENUM("DACR Sidetone Source", dacr_sidetone), + SOC_DOUBLE("DAC Invert Switch", PMU3_SOFT_MUTE, 8, 7, 1, 0), + SOC_DOUBLE("ADC Invert Switch", PMU3_SOFT_MUTE, 10, 9, 1, 0), + + SOC_SINGLE("DAC Soft Mute Switch", PMU3_SOFT_MUTE, 15, 1, 0), + SOC_ENUM("DAC Mute Rate", dac_mute_rate), + + SOC_DOUBLE_TLV("Digital Playback Volume", + PMU3_DAC_VOLUME_CTL, 8, 0, 0xff, 0, dac_tlv), +}; + +static const struct snd_kcontrol_new pmu3_dapm_mixer_out_l_controls[] = { + SOC_DAPM_SINGLE_TLV("DACL to MIXOUTL Volume", + PMU3_MIXOUT_L, 11, 0x1f, 0, xx2mixout_tlv), + SOC_DAPM_SINGLE_TLV("PGAINL to MIXOUTL Volume", + PMU3_MIXOUT_L, 6, 0x1f, 0, xx2mixout_tlv), + SOC_DAPM_SINGLE_TLV("PGAINR to MIXOUTL Volume", + PMU3_MIXOUT_L, 1, 0x1f, 0, xx2mixout_tlv), + SOC_DAPM_SINGLE_TLV("RXV to MIXOUTL Volume", + PMU3_RXV_TO_MIXOUT, 11, 0x1f, 0, xx2mixout_tlv), + SOC_DAPM_SINGLE("DACR Mono Switch", + PMU3_SIDETONE_MIXING, 5, 1, 0), +}; + +static const struct snd_kcontrol_new pmu3_dapm_mixer_out_r_controls[] = { + SOC_DAPM_SINGLE_TLV("DACR to MIXOUTR Volume", + PMU3_MIXOUT_R, 11, 0x1f, 0, xx2mixout_tlv), + SOC_DAPM_SINGLE_TLV("PGAINR to MIXOUTR Volume", + PMU3_MIXOUT_R, 6, 0x1f, 0, xx2mixout_tlv), + SOC_DAPM_SINGLE_TLV("PGAINL to MIXOUTR Volume", + PMU3_MIXOUT_R, 1, 0x1f, 0, xx2mixout_tlv), + SOC_DAPM_SINGLE_TLV("RXV to MIXOUTR Volume", + PMU3_RXV_TO_MIXOUT, 6, 0x1f, 0, xx2mixout_tlv), + SOC_DAPM_SINGLE("DACL Mono Switch", + PMU3_SIDETONE_MIXING, 5, 1, 0), +}; + +static const struct snd_kcontrol_new pmu3_dapm_mixer_in_l_controls[] = { +SOC_DAPM_SINGLE_TLV("PGAINL to MIXINL Volume", PMU3_MIXIN_L, 12, 0xf, 0, + xx2mixin_tlv), +SOC_DAPM_SINGLE_TLV("RXV to MIXINL Volume", PMU3_MIXIN_L, 8, 0xf, 0, + xx2mixin_tlv), +SOC_DAPM_SINGLE_TLV("RECL to MIXINL Volume", PMU3_MIXIN_L, 4, 0xf, 0, + xx2mixin_tlv), +}; +static const struct snd_kcontrol_new pmu3_dapm_mixer_in_r_controls[] = { +SOC_DAPM_SINGLE_TLV("PGAINR to MIXINR Volume", PMU3_MIXIN_R, 12, 0xf, 0, + xx2mixin_tlv), +SOC_DAPM_SINGLE_TLV("RXV to MIXINR Volume", PMU3_MIXIN_R, 8, 0xf, 0, + xx2mixin_tlv), +SOC_DAPM_SINGLE_TLV("RECR to MIXINR Volume", PMU3_MIXIN_R, 4, 0xf, 0, + xx2mixin_tlv), +}; + +static const struct snd_kcontrol_new lol1_mux_controls = + SOC_DAPM_ENUM("Route", pmu3_lineout_enum[0]); + +static const struct snd_kcontrol_new lol2_mux_controls = + SOC_DAPM_ENUM("Route", pmu3_lineout_enum[1]); + +static const struct snd_kcontrol_new lor1_mux_controls = + SOC_DAPM_ENUM("Route", pmu3_lineout_enum[2]); + +static const struct snd_kcontrol_new lor2_mux_controls = + SOC_DAPM_ENUM("Route", pmu3_lineout_enum[3]); + +static const struct snd_kcontrol_new pmu3_dapm_hpin_mixer_l_controls[] = { + SOC_DAPM_SINGLE("DACL Switch", PMU3_LINEOUT_HP_DRV, 7, 1, 0), + SOC_DAPM_SINGLE("MIXOUTL Switch", PMU3_LINEOUT_HP_DRV, 6, 1, 0), + SOC_DAPM_SINGLE("MIXOUTR Switch", PMU3_LINEOUT_HP_DRV, 5, 1, 0), +}; + +static const struct snd_kcontrol_new pmu3_dapm_hpin_mixer_r_controls[] = { + SOC_DAPM_SINGLE("DACR Switch", PMU3_LINEOUT_HP_DRV, 4, 1, 0), + SOC_DAPM_SINGLE("MIXOUTR Switch", PMU3_LINEOUT_HP_DRV, 3, 1, 0), + SOC_DAPM_SINGLE("MIXOUTL Switch", PMU3_LINEOUT_HP_DRV, 2, 1, 0), +}; + +static const struct snd_kcontrol_new pgain_lp_switch_controls = + SOC_DAPM_SINGLE("Switch", PMU3_PGA_IN, 10, 1, 0); + +static const struct snd_kcontrol_new pgain_rp_switch_controls = + SOC_DAPM_SINGLE("Switch", PMU3_PGA_IN, 2, 1, 0); + +static const char * const plin_text[] = { "None", "AINL2", "AINL1" }; +static const struct soc_enum pgainl_enum = + SOC_ENUM_SINGLE(PMU3_PGA_IN, 8, ARRAY_SIZE(plin_text), plin_text); +static const struct snd_kcontrol_new pgain_ln_mux[] = { + SOC_DAPM_ENUM("route", pgainl_enum), +}; +static const char * const prin_text[] = { "None", "AINR2", "AINR1" }; +static const struct soc_enum pgainr_enum = + SOC_ENUM_SINGLE(PMU3_PGA_IN, 0, ARRAY_SIZE(prin_text), prin_text); +static const struct snd_kcontrol_new pgain_rn_mux[] = { + SOC_DAPM_ENUM("route", pgainr_enum), +}; + +static const struct snd_soc_dapm_widget pmu3_dapm_widgets[] = { + /* Externally visible pins */ + SND_SOC_DAPM_OUTPUT("LINEOUTL1"), + SND_SOC_DAPM_OUTPUT("LINEOUTR1"), + SND_SOC_DAPM_OUTPUT("LINEOUTL2"), + SND_SOC_DAPM_OUTPUT("LINEOUTR2"), + SND_SOC_DAPM_OUTPUT("HP_L"), + SND_SOC_DAPM_OUTPUT("HP_R"), + /* SND_SOC_DAPM_OUTPUT("AUXOUT"), */ + /* SND_SOC_DAPM_INPUT("RXV"), */ + + SND_SOC_DAPM_INPUT("LINEINLP"), + SND_SOC_DAPM_INPUT("LINEINLN1"), + SND_SOC_DAPM_INPUT("LINEINLN2"), + SND_SOC_DAPM_INPUT("LINEINRP"), + SND_SOC_DAPM_INPUT("LINEINRN1"), + SND_SOC_DAPM_INPUT("LINEINRN2"), + + /* Input */ + SND_SOC_DAPM_PGA("PGAIN LEFT", PMU3_BLOCK_ENABLE_1, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGAIN RIGHT", PMU3_BLOCK_ENABLE_1, 4, 0, NULL, 0), + SND_SOC_DAPM_SWITCH("PGAIN LEFT Pos", SND_SOC_NOPM, 0, 0, + &pgain_lp_switch_controls), + SND_SOC_DAPM_SWITCH("PGAIN RIGHT Pos", SND_SOC_NOPM, 0, 0, + &pgain_rp_switch_controls), + SND_SOC_DAPM_MUX("PGAIN LEFT Neg", SND_SOC_NOPM, 0, 0, pgain_ln_mux), + SND_SOC_DAPM_MUX("PGAIN RIGHT Neg", SND_SOC_NOPM, 0, 0, pgain_rn_mux), + + SND_SOC_DAPM_MIXER("MIXINL", PMU3_BLOCK_ENABLE_1, 7, 0, + &pmu3_dapm_mixer_in_l_controls[0], + ARRAY_SIZE(pmu3_dapm_mixer_in_l_controls)), + SND_SOC_DAPM_MIXER("MIXINR", PMU3_BLOCK_ENABLE_1, 6, 0, + &pmu3_dapm_mixer_in_r_controls[0], + ARRAY_SIZE(pmu3_dapm_mixer_in_r_controls)), + + SND_SOC_DAPM_MICBIAS("Mic Bias1", PMU3_BLOCK_ENABLE_2, 15, 0), + SND_SOC_DAPM_MICBIAS("Mic Bias2", PMU3_BLOCK_ENABLE_2, 14, 0), + + SND_SOC_DAPM_ADC_E("ADCL", "Capture", PMU3_BLOCK_ENABLE_2, 5, 0, + pmu3_adc_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADCR", "Capture", PMU3_BLOCK_ENABLE_2, 4, 0, + pmu3_adc_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), + + /* Output */ + SND_SOC_DAPM_DAC_E("DACL", "Playback", SND_SOC_NOPM, 3, 0, + pmu3_dac_event, + SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("DACR", "Playback", SND_SOC_NOPM, 2, 0, + pmu3_dac_event, + SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("MIXOUTL", PMU3_BLOCK_ENABLE_1, 3, 0, + &pmu3_dapm_mixer_out_l_controls[0], + ARRAY_SIZE(pmu3_dapm_mixer_out_l_controls)), + SND_SOC_DAPM_MIXER("MIXOUTR", PMU3_BLOCK_ENABLE_1, 2, 0, + &pmu3_dapm_mixer_out_r_controls[0], + ARRAY_SIZE(pmu3_dapm_mixer_out_r_controls)), + + SND_SOC_DAPM_MUX("Lineout1 Left in", + SND_SOC_NOPM, 0, 0, &lol1_mux_controls), + SND_SOC_DAPM_MUX("Lineout2 Left in", + SND_SOC_NOPM, 0, 0, &lol2_mux_controls), + SND_SOC_DAPM_MUX("Lineout1 Right in", + SND_SOC_NOPM, 0, 0, &lor1_mux_controls), + SND_SOC_DAPM_MUX("Lineout2 Right in", + SND_SOC_NOPM, 0, 0, &lor2_mux_controls), + + SND_SOC_DAPM_MIXER("HPINL Mixer", SND_SOC_NOPM, 0, 0, + &pmu3_dapm_hpin_mixer_l_controls[0], + ARRAY_SIZE(pmu3_dapm_hpin_mixer_l_controls)), + + SND_SOC_DAPM_MIXER("HPINR Mixer", SND_SOC_NOPM, 0, 0, + &pmu3_dapm_hpin_mixer_r_controls[0], + ARRAY_SIZE(pmu3_dapm_hpin_mixer_r_controls)), + + SND_SOC_DAPM_OUT_DRV("LINEOUT1 Left driver", + PMU3_BLOCK_ENABLE_1, 11, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV("LINEOUT2 Left driver", + PMU3_BLOCK_ENABLE_1, 10, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV("LINEOUT1 Right driver", + PMU3_BLOCK_ENABLE_1, 9, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV("LINEOUT2 Right driver", + PMU3_BLOCK_ENABLE_1, 8, 0, NULL, 0), + + SND_SOC_DAPM_PGA_E("Headphone Amplifier", + PMU3_BLOCK_ENABLE_2, 13, 0, NULL, 0, + pmu3_hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA("RXV", SND_SOC_NOPM, 8, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route pmu3_intercon[] = { + /* Inputs */ + {"PGAIN LEFT Pos", "Switch", "LINEINLP"}, + {"PGAIN LEFT Neg", "AINL1", "LINEINLN1"}, + {"PGAIN LEFT Neg", "AINL2", "LINEINLN2"}, + + {"PGAIN RIGHT Pos", "Switch", "LINEINRP"}, + {"PGAIN RIGHT Neg", "AINR1", "LINEINRN1"}, + {"PGAIN RIGHT Neg", "AINR2", "LINEINRN2"}, + + {"PGAIN LEFT", NULL, "PGAIN LEFT Pos"}, + {"PGAIN LEFT", NULL, "PGAIN LEFT Neg"}, + + {"PGAIN RIGHT", NULL, "PGAIN RIGHT Pos"}, + {"PGAIN RIGHT", NULL, "PGAIN RIGHT Neg"}, + + {"RXV", NULL, "LINEINLN2"}, + {"RXV", NULL, "LINEINRN2"}, + + {"MIXINL", "PGAINL to MIXINL Volume", "PGAIN LEFT"}, + {"MIXINL", "RXV to MIXINL Volume", "RXV"}, + {"MIXINL", "RECL to MIXINL Volume", "MIXOUTL"}, + + {"MIXINR", "PGAINR to MIXINR Volume", "PGAIN RIGHT"}, + {"MIXINR", "RXV to MIXINR Volume", "RXV"}, + {"MIXINR", "RECR to MIXINR Volume", "MIXOUTR"}, + + {"ADCL", NULL, "MIXINL"}, + {"ADCR", NULL, "MIXINR"}, + + /* Outputs */ + /* LINEOUTL1 */ + {"LINEOUTL1", NULL, "LINEOUT1 Left driver"}, + {"LINEOUT1 Left driver", NULL, "Lineout1 Left in"}, + + {"Lineout1 Left in", "MIXOUTL", "MIXOUTL"}, + {"Lineout1 Left in", "MIXOUTR", "MIXOUTR"}, + {"Lineout1 Left in", "Inverted MIXOUTR", "MIXOUTR"}, + + /* LINEOUTR1 */ + {"LINEOUTR1", NULL, "LINEOUT1 Right driver"}, + {"LINEOUT1 Right driver", NULL, "Lineout1 Right in"}, + + {"Lineout1 Right in", "MIXOUTR", "MIXOUTL"}, + {"Lineout1 Right in", "MIXOUTL", "MIXOUTR"}, + {"Lineout1 Right in", "Inverted MIXOUTL", "MIXOUTL"}, + + /* LINEOUTL2 */ + {"LINEOUTL2", NULL, "LINEOUT2 Left driver"}, + {"LINEOUT2 Left driver", NULL, "Lineout2 Left in"}, + + {"Lineout2 Left in", "MIXOUTL", "MIXOUTL"}, + {"Lineout2 Left in", "Inverted MIXOUTL", "MIXOUTL"}, + {"Lineout2 Left in", "Inverted MIXOUTR", "MIXOUTR"}, + + /* LINEOUTR2 */ + {"LINEOUTR2", NULL, "LINEOUT2 Right driver"}, + {"LINEOUT2 Right driver", NULL, "Lineout2 Right in"}, + + {"Lineout2 Right in", "MIXOUTR", "MIXOUTR"}, + {"Lineout2 Right in", "Inverted MIXOUTR", "MIXOUTR"}, + {"Lineout2 Right in", "Inverted MIXOUTL", "MIXOUTL"}, + + /* MIXOUT */ + {"MIXOUTL", "DACL to MIXOUTL Volume", "DACL"}, + {"MIXOUTL", "PGAINL to MIXOUTL Volume", "PGAIN LEFT"}, + {"MIXOUTL", "PGAINR to MIXOUTL Volume", "PGAIN RIGHT"}, + {"MIXOUTL", "RXV to MIXOUTL Volume", "RXV"}, + {"MIXOUTL", "DACR Mono Switch", "DACR"}, + + {"MIXOUTR", "DACR to MIXOUTR Volume", "DACR"}, + {"MIXOUTR", "PGAINR to MIXOUTR Volume", "PGAIN RIGHT"}, + {"MIXOUTR", "PGAINL to MIXOUTR Volume", "PGAIN LEFT"}, + {"MIXOUTR", "RXV to MIXOUTR Volume", "RXV"}, + {"MIXOUTR", "DACL Mono Switch", "DACL"}, + + /* Headphone */ + + {"HPINL Mixer", "DACL Switch", "DACL"}, + {"HPINL Mixer", "MIXOUTL Switch", "MIXOUTL"}, + {"HPINL Mixer", "MIXOUTR Switch", "MIXOUTR"}, + + {"HPINR Mixer", "DACR Switch", "DACR"}, + {"HPINR Mixer", "MIXOUTR Switch", "MIXOUTR"}, + {"HPINR Mixer", "MIXOUTL Switch", "MIXOUTL"}, + + {"Headphone Amplifier", NULL, "HPINL Mixer"}, + {"Headphone Amplifier", NULL, "HPINR Mixer"}, + {"HP_L", NULL, "Headphone Amplifier"}, + {"HP_R", NULL, "Headphone Amplifier"}, +}; + +static int pmu3_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + int value = 0; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + if (codec->component.dapm.bias_level == + SND_SOC_BIAS_STANDBY) { + value = snd_soc_read(codec, + PMU3_SIDETONE_MIXING); + if (value & 0x20) + snd_soc_write(codec, + PMU3_BLOCK_ENABLE_1, 0xbc00); + else + snd_soc_write(codec, + PMU3_BLOCK_ENABLE_1, 0xbf00); + } + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->component.dapm.bias_level == SND_SOC_BIAS_OFF) { + /* VMID Gen & Bias Current & Refp Buf */ + snd_soc_update_bits(codec, + PMU3_BLOCK_ENABLE_1, + 0xf000, 0xf000); + msleep(200); + /* Clear Fast Charge */ + snd_soc_update_bits(codec, + PMU3_BLOCK_ENABLE_1, + 0x4000, 0x0); + value = snd_soc_read(codec, + PMU3_SIDETONE_MIXING); + if (value & 0x20) + snd_soc_write(codec, + PMU3_BLOCK_ENABLE_1, 0xbc00); + else + snd_soc_write(codec, + PMU3_BLOCK_ENABLE_1, 0xbf00); + } + break; + + case SND_SOC_BIAS_OFF: + snd_soc_write(codec, PMU3_BLOCK_ENABLE_1, 0); + + break; + } + + codec->component.dapm.bias_level = level; + + return 0; +} + +static int pmu3_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + return 0; +} + + +static int pmu3_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = 0; + + iface = snd_soc_read(codec, PMU3_ADC_DAC); + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + iface |= (0x1 << 14); + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + } + + snd_soc_write(codec, PMU3_ADC_DAC, iface); + + return 0; +} + +static int pmu3_digital_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 reg; + + reg = snd_soc_read(codec, PMU3_SOFT_MUTE); + + if (mute) + reg |= 0x8000; + else + reg &= ~0x8000; + + snd_soc_write(codec, PMU3_SOFT_MUTE, reg); + + return 0; +} + +static int pmu3_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + u16 reg; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + reg = snd_soc_read(codec, PMU3_SOFT_MUTE); + if (mute) + reg |= 0x8000; + else + reg &= ~0x8000; + snd_soc_write(codec, PMU3_SOFT_MUTE, reg); + } + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + if (mute) + snd_soc_write(codec, PMU3_ADC_VOLUME_CTL, 0); + else { + msleep(300); + snd_soc_write(codec, PMU3_ADC_VOLUME_CTL, 0x6a6a); + } + } + return 0; +} + + +static struct { + int rate; + int value; +} sample_rates[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 3 }, + { 22050, 4 }, + { 24000, 5 }, + { 32000, 6 }, + { 44100, 7 }, + { 48000, 8 }, +}; + +static int pmu3_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + int fs = params_rate(params); + u16 reg = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(sample_rates); i++) { + if (sample_rates[i].rate == fs) + reg = sample_rates[i].value; + } + pr_info("pmu3_hw_params(rate)%x\n", reg); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_update_bits(codec, PMU3_ADC_DAC, 0xf0, reg << 4); + else + snd_soc_update_bits(codec, PMU3_ADC_DAC, 0xf, reg); + + return 0; +} + +#define AML_PMU3_PLAYBACK_RATES SNDRV_PCM_RATE_8000_48000 +#define AML_PMU3_CAPTURE_RATES SNDRV_PCM_RATE_8000_48000 +#define AML_PMU3_FORMATS (SNDRV_PCM_FMTBIT_S16_LE \ + | SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops pmu3_dai_ops = { + .hw_params = pmu3_hw_params, + .digital_mute = pmu3_digital_mute, + .mute_stream = pmu3_mute_stream, + .set_fmt = pmu3_set_dai_fmt, + .set_sysclk = pmu3_set_dai_sysclk, +}; + +static struct snd_soc_dai_driver pmu3_dai = { + .name = "pmu3-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = AML_PMU3_PLAYBACK_RATES, + .formats = AML_PMU3_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = AML_PMU3_CAPTURE_RATES, + .formats = AML_PMU3_FORMATS, + }, + .ops = &pmu3_dai_ops, + .symmetric_rates = 1, +}; + +static int pmu3_suspend(struct snd_soc_codec *codec) +{ + pmu3_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int pmu3_resume(struct snd_soc_codec *codec) +{ + snd_soc_cache_sync(codec); + + /* Bring the codec back up to standby + * first to minimise pop/clicks + */ + pmu3_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +static int pmu3_audio_power_init(struct snd_soc_codec *codec) +{ + uint8_t val = 0; + + // LDO1v8 for audio + aml1218_read(0x010e, &val); + val |= 0x1; + aml1218_write(0x010e, val); + // LDO2v5 for audio + aml1218_write(0x0139, 0x1f); + val = 0; + aml1218_read(0x010f, &val); + val |= 0x1; + aml1218_write(0x010f, val); + + return 0; +} + +static int pmu3_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + uint32_t addr; + + addr = PMU3_AUDIO_BASE + (reg<<1); + pr_info("pmu3_write,addr=0x%x, reg=0x%x, value=0x%x\n", + addr, + reg, + value); + aml1218_write16(addr, value); + + return 0; +} + +static unsigned int pmu3_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + uint32_t addr; + uint16_t val = 0; + + addr = PMU3_AUDIO_BASE + (reg<<1); + aml1218_read16(addr, &val); + + return val; +} + + +static int pmu3_probe(struct snd_soc_codec *codec) +{ + int ret = 0; + + pr_info("aml pmu3 codec probe\n"); + pmu3_audio_power_init(codec); + pmu3_reset(codec); + /* power on device */ + pmu3_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* Enable DAC soft mute by default */ + snd_soc_update_bits(codec, PMU3_SOFT_MUTE, 0x7800, 0x7800); + + /* Enable ZC */ + snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_2, 0x3c0, 0x0); + + snd_soc_add_codec_controls(codec, pmu3_snd_controls, + ARRAY_SIZE(pmu3_snd_controls)); + /* ADC high pass filter Hi-fi mode */ + snd_soc_update_bits(codec, PMU3_ADC_DAC, 0xc00, 0xc00); + + snd_soc_write(codec, PMU3_MIXOUT_L, 0xe000); + snd_soc_write(codec, PMU3_MIXOUT_R, 0xe000); + snd_soc_write(codec, PMU3_MIXIN_L, 0xf000); + snd_soc_write(codec, PMU3_MIXIN_R, 0xf000); + snd_soc_write(codec, PMU3_PGA_IN, 0x1616); + + + snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_1, 0xf0c, 0xf0c); + snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_2, 0xf, 0xf); + + snd_soc_update_bits(codec, PMU3_LINEOUT_HP_DRV, 0x90, 0x90); + snd_soc_write(codec, PMU3_DAC_VOLUME_CTL, 0xb9b9); + snd_soc_write(codec, PMU3_ADC_VOLUME_CTL, 0x6a6a); + + return ret; +} + +/* power down chip */ +static int pmu3_remove(struct snd_soc_codec *codec) +{ + pmu3_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_pmu3 = { + .probe = pmu3_probe, + .remove = pmu3_remove, + .suspend = pmu3_suspend, + .resume = pmu3_resume, + .read = pmu3_read, + .write = pmu3_write, + .set_bias_level = pmu3_set_bias_level, + .reg_cache_size = ARRAY_SIZE(pmu3_reg_defaults), + .reg_word_size = sizeof(u16), + .reg_cache_step = 1, + .reg_cache_default = pmu3_reg_defaults, + .component_driver = { + .dapm_widgets = pmu3_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pmu3_dapm_widgets), + .dapm_routes = pmu3_intercon, + .num_dapm_routes = ARRAY_SIZE(pmu3_intercon), + } +}; + + +static int pmu3_audio_codec_mute(void) +{ + uint32_t addr; + unsigned int value = 0x8000; + unsigned int reg = PMU3_SOFT_MUTE; + + pr_info("pmu3_audio_codec_mute\n"); + + addr = PMU3_AUDIO_BASE + (reg<<1); + + aml1218_write16(addr, value); + + return 0; +} + + + +static int aml_pmu3_audio_reboot_work(struct notifier_block *nb, + unsigned long state, void *cmd) +{ + pr_info("\n%s\n", __func__); + + pmu3_audio_codec_mute(); + + return NOTIFY_DONE; +} + +static struct notifier_block aml_pmu3_audio_reboot_nb = { + .notifier_call = aml_pmu3_audio_reboot_work, + .priority = 0, +}; + +static int aml_pmu3_codec_probe(struct platform_device *pdev) +{ + int ret = snd_soc_register_codec(&pdev->dev, + &soc_codec_dev_pmu3, &pmu3_dai, 1); + + register_reboot_notifier(&aml_pmu3_audio_reboot_nb); + + return ret; +} + + + +static int aml_pmu3_codec_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +#ifdef CONFIG_USE_OF +static const struct of_device_id amlogic_pmu3_codec_dt_match[] = { + { .compatible = "amlogic, aml_pmu3_codec", }, + {}, +}; +#else +#define amlogic_audio_dt_match NULL +#endif +static struct platform_driver aml_pmu3_codec_platform_driver = { + .driver = { + .name = "aml_pmu3_codec", + .owner = THIS_MODULE, + .of_match_table = amlogic_pmu3_codec_dt_match, + }, + .probe = aml_pmu3_codec_probe, + .remove = aml_pmu3_codec_remove, +}; + +static int __init aml_pmu3_modinit(void) +{ + int ret = 0; + + ret = platform_driver_register(&aml_pmu3_codec_platform_driver); + if (ret != 0) { + pr_err("Failed to register AML PMU3 codec platform driver: %d\n", + ret); + } + + return ret; +} +module_init(aml_pmu3_modinit); + +static void __exit aml_pmu3_exit(void) +{ + platform_driver_unregister(&aml_pmu3_codec_platform_driver); +} +module_exit(aml_pmu3_exit); + +MODULE_DESCRIPTION("ASoC AML_PUM3 driver"); +MODULE_AUTHOR("Shuai Li "); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/codecs/amlogic/aml_pmu3.h b/sound/soc/codecs/amlogic/aml_pmu3.h new file mode 100644 index 0000000..77b8660 --- /dev/null +++ b/sound/soc/codecs/amlogic/aml_pmu3.h @@ -0,0 +1,52 @@ +/* + * aml_pmu3.h -- AML PMU3 Soc Audio codec driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _AML_PMU3_H +#define _AML_PMU3_H + +#define PMU3_ADDR 0x35 +#define PMU3_AUDIO_BASE 0x220 + +#define PMU3_SOFTWARE_RESET 0x0 +#define PMU3_BLOCK_ENABLE_1 0x1 +#define PMU3_BLOCK_ENABLE_2 0x2 +#define PMU3_PGA_IN 0x3 +#define PMU3_MIXIN_L 0x4 +#define PMU3_MIXIN_R 0x5 +#define PMU3_MIXOUT_L 0x6 +#define PMU3_MIXOUT_R 0x7 +#define PMU3_RXV_TO_MIXOUT 0x8 +#define PMU3_LINEOUT_HP_DRV 0x9 +#define PMU3_HP_DC_OFFSET 0xA +#define PMU3_ADC_DAC 0xB +#define PMU3_HP_MIC_DET 0xC +#define PMU3_ADC_VOLUME_CTL 0xD +#define PMU3_DAC_VOLUME_CTL 0xE +#define PMU3_SOFT_MUTE 0xF +#define PMU3_SIDETONE_MIXING 0x10 +#define PMU3_DMIC_GPIO 0x11 +#define PMU3_MONITOR_REG 0x12 + +/* R0Ch PMU3_HP_MIC_DET */ +#define PMU3_MIC_BIAS1_SHIFT 15 +#define PMU3_MIC_BIAS2_SHIFT 14 + +/* R0Bh PMU3_ADC_DAC */ +#define PMU3_ADC_HPF_MODE_SHIFT 10 + +/* R0FH PMU3_SOFT_MUTE */ +#define PMU3_DAC_RAMP_RATE_SHIFT 11 + +/* R10h PMU3_SIDETONE_MIXING */ +#define PMU3_DACL_ST_SRC_SHIFT 7 +#define PMU3_DACR_ST_SRC_SHIFT 6 +#define PMU3_ADCDATL_SRC_SHIFT 4 +#define PMU3_ADCDATR_SRC_SHIFT 3 +#define PMU3_DACDATL_SRC_SHIFT 2 +#define PMU3_DACDATR_SRC_SHIFT 1 + +#endif -- 2.7.4