From patchwork Sun Dec 3 20:41:55 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vasily Khoruzhick X-Patchwork-Id: 10089405 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 6212F6035E for ; Sun, 3 Dec 2017 20:45:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6A21A28DD1 for ; Sun, 3 Dec 2017 20:45:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5CE2628DE5; Sun, 3 Dec 2017 20:45:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, DKIM_VALID, FREEMAIL_FROM, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 7091E28DD1 for ; Sun, 3 Dec 2017 20:45:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=N6h+2tS+QdJeJKYuBi65oWAqAlz6ZKBU/v5LX8mKfwc=; b=GFD/FzBVVed/9vx7PAhnwXshGb gf6B3+whVjS0gsV/WqZRXkUqyXrY1iOy1P+BPMIYvT3QQoQCPlaMU9MflQj+j3NPqbpOegakNa+DK llnNaHorPQ/PbFL7W+qKr0LfZNtu5LkxATESyPMurytujKD/5uAl3AfxnHOQckmI15gJbQwXcwYJ8 Yh1bPv3BiK0zpBZEJABc1XAYabnzkJU0KJLspOPjsJWvLkn5U+CRZpL6SnUMml65wXQAc8stwoM3R yLd1ClQrnaULIwANTx1aJp0gGReHMgDIN/KXoi5ab/H+DSDQ4WzAZkF6ZXq8aKOFxTKMeggGTeQGA f3MOcA4Q==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1eLb8F-0000wX-Gr; Sun, 03 Dec 2017 20:44:59 +0000 Received: from mail-pg0-x244.google.com ([2607:f8b0:400e:c05::244]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1eLb5p-00070K-Uq for linux-arm-kernel@lists.infradead.org; Sun, 03 Dec 2017 20:42:41 +0000 Received: by mail-pg0-x244.google.com with SMTP id w7so6748691pgv.6 for ; Sun, 03 Dec 2017 12:42:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=vo4H+B1ZKP8Jv4d/Fd0OwCaUF1tWfbhuzd2gayhdUsk=; b=TTzk1MnDCV6v0dnIxJotHUZ0ELVxdKvthVFFVu0BHA48yNaYfD3OKmYu2V6OBtVO1s XHRBvTrJ2oQlYRdVOzHt/LRlg007HQT7FGKiMO0d5/Ff5qWaXJ1p5uWFQvKj9znzEULX zd3NjVJjIlFwNEhlljIcd/QB5BSVWPf9AOwtQ+wQKkTyCqKFNtk10G59KZG0j5Zs0whf 8HHe0HtSrQHp6GNLnzQJHAoW/lVSpVX1XKB/3phUgMvuZRfieB6JIts0y4ycJN+Nmlev QqKdkqpNHzDHJuYPdjEZK+ZKWFq8z8ORhAvPyj93yHWcECEwpSkCVfVOUMGdh1fI1oQt HGTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=vo4H+B1ZKP8Jv4d/Fd0OwCaUF1tWfbhuzd2gayhdUsk=; b=g1LNeKfnZZ3JTRPWMQfTihwDhSWzDt8lzQt4GCNgb96gmorGMSvgvcoR79qmqUB9Dm pRGKZrUPvXlRdtPiO210FoDz9gYkQuBvhOV7NlZ9XLi2cNjDLhUGlIJztw3f/v18r5B+ XvKrAvQbC5HOYcUN4hk0GbF62HmpoqdE2aoOuQyKOeRvyrOZcylwzUNL/yHBVJzwRytU MqyLUwk1hnW2Xy3fgXUYaoTA6cxV8n8bm9QnlJKI6L0qUc5LRvK55+AsGk5N6nwzMimd eUOoKzTpEWfaY1g1/qfGq+fEqKVi0rqHgH1vogDoFgmGG4qi8KYQ/RIfbTrIkM60va+J Vebg== X-Gm-Message-State: AJaThX4wVvKqPKsZnn7lSVTk8BDEKFFv4Kzj/G3NGN85swWqgtyiDkh5 wCNDgaH+wlfV9EdAgntnMYY= X-Google-Smtp-Source: AGs4zMbE3vS7rJbbW0FRT7jorACoI2z/Gz0+6J73Ozb4ACSTXlB8GWcNQ5Sp3vG3RHTHuf4dSP5xmQ== X-Received: by 10.84.138.1 with SMTP id 1mr12308553plo.156.1512333728874; Sun, 03 Dec 2017 12:42:08 -0800 (PST) Received: from anarsoul-thinkpad.lan (216-71-193-140.dyn.novuscom.net. [216.71.193.140]) by smtp.gmail.com with ESMTPSA id z25sm19264929pfe.121.2017.12.03.12.42.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 03 Dec 2017 12:42:08 -0800 (PST) From: Vasily Khoruzhick To: Liam Girdwood , Mark Brown , Maxime Ripard , Chen-Yu Tsai , Marcus Cooper , =?UTF-8?q?Myl=C3=A8ne=20Josserand?= , alsa-devel@alsa-project.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH 7/9] ASoC: sun8i-codec-analog: Add support for A64 SoC Date: Sun, 3 Dec 2017 12:41:55 -0800 Message-Id: <20171203204157.20829-8-anarsoul@gmail.com> X-Mailer: git-send-email 2.15.0 In-Reply-To: <20171203204157.20829-1-anarsoul@gmail.com> References: <20171203204157.20829-1-anarsoul@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20171203_124230_164426_28CB89FC X-CRM114-Status: GOOD ( 19.42 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Vasily Khoruzhick MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Marcus Cooper Analog part of audiocodec is very similar to other codecs supports by this driver, but has different registers Signed-off-by: Marcus Cooper Signed-off-by: Vasily Khoruzhick --- .../bindings/sound/sun8i-codec-analog.txt | 1 + sound/soc/sunxi/Kconfig | 2 +- sound/soc/sunxi/sun8i-codec-analog.c | 227 +++++++++++++++++++++ 3 files changed, 229 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt index 07356758bd91..f38896850e4d 100644 --- a/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt +++ b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt @@ -5,6 +5,7 @@ Required properties: - "allwinner,sun8i-a23-codec-analog" - "allwinner,sun8i-h3-codec-analog" - "allwinner,sun8i-v3s-codec-analog" + - "allwinner,sun50i-a64-codec-analog" Required properties if not a sub-node of the PRCM node: - reg: must contain the registers location and length diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 22408bc2d6ec..26072b74e47f 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -12,7 +12,7 @@ config SND_SUN4I_CODEC config SND_SUN8I_CODEC tristate "Allwinner SUN8I audio codec" depends on OF - depends on MACH_SUN8I || COMPILE_TEST + depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST select REGMAP_MMIO help This option enables the digital part of the internal audio codec for diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 4e39d2668286..adb7fe087c73 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -30,6 +30,7 @@ /* Codec analog control register offsets and bit fields */ #define SUN8I_ADDA_HP_VOLC 0x00 #define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7 +#define SUN50I_ADDA_HP_VOLC_HPPAEN 6 #define SUN8I_ADDA_HP_VOLC_HP_VOL 0 #define SUN8I_ADDA_LOMIXSC 0x01 #define SUN8I_ADDA_LOMIXSC_MIC1 6 @@ -48,6 +49,7 @@ #define SUN8I_ADDA_ROMIXSC_DACR 1 #define SUN8I_ADDA_ROMIXSC_DACL 0 #define SUN8I_ADDA_DAC_PA_SRC 0x03 +#define SUN50I_ADDA_DAC_PA_SRC 0x0a #define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7 #define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6 #define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5 @@ -62,9 +64,16 @@ #define SUN8I_ADDA_LINEIN_GCTRL 0x05 #define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4 #define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0 +#define SUN50I_ADDA_LINEOUT_CTRL0 0x05 +#define SUN50I_ADDA_LINEOUT_CTRL0_LEN 7 +#define SUN50I_ADDA_LINEOUT_CTRL0_REN 6 +#define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL 5 +#define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL 4 #define SUN8I_ADDA_MICIN_GCTRL 0x06 #define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4 #define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0 +#define SUN50I_ADDA_LINEOUT_CTRL1 0x06 +#define SUN50I_ADDA_LINEOUT_CTRL1_VOL 0 #define SUN8I_ADDA_PAEN_HP_CTRL 0x07 #define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7 #define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */ @@ -364,6 +373,61 @@ static const struct snd_soc_dapm_widget sun8i_v3s_codec_mixer_widgets[] = { ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)), }; +static const struct snd_soc_dapm_widget sun50i_codec_common_widgets[] = { + /* ADC */ + SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0), + SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0), + + /* DAC */ + SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0), + SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0), + /* + * Due to this component and the codec belonging to separate DAPM + * contexts, we need to manually link the above widgets to their + * stream widgets at the card level. + */ + + /* Line In */ + SND_SOC_DAPM_INPUT("LINEIN"), + + /* Microphone inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN, + 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0), + + /* Mixers */ + SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, + sun8i_codec_mixer_controls, + ARRAY_SIZE(sun8i_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0, + sun8i_codec_mixer_controls, + ARRAY_SIZE(sun8i_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0, + sun8i_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0, + sun8i_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), +}; + static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { /* Microphone Routes */ { "Mic1 Amplifier", NULL, "MIC1"}, @@ -408,6 +472,17 @@ static const struct snd_kcontrol_new sun8i_a23_codec_hp_ctrls[] = { SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0), }; +static const struct snd_kcontrol_new sun50i_a64_codec_hp_ctrls[] = { + SOC_SINGLE_TLV("Headphone Playback Volume", + SUN8I_ADDA_HP_VOLC, + SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0, + sun8i_codec_hp_vol_scale), + SOC_DOUBLE("Headphone Playback Switch", + SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE, + SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0), +}; + static const char * const sun8i_codec_hp_src_enum_text[] = { "DAC", "Mixer", }; @@ -461,6 +536,14 @@ static const struct snd_soc_dapm_widget sun8i_a23_codec_hp_widgets[] = { SND_SOC_DAPM_OUTPUT("HP"), }; +static const struct snd_soc_dapm_widget sun50i_a64_codec_hp_widgets[] = { + SND_SOC_DAPM_MUX("Headphone Source Playback Route", + SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src), + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_HP_VOLC, + SUN50I_ADDA_HP_VOLC_HPPAEN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("HP"), +}; + static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = { { "Headphone Source Playback Route", "DAC", "Left DAC" }, { "Headphone Source Playback Route", "DAC", "Right DAC" }, @@ -471,6 +554,15 @@ static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = { { "HP", NULL, "Headphone Amp" }, }; +static const struct snd_soc_dapm_route sun50i_codec_headphone_routes[] = { + { "Headphone Source Playback Route", "DAC", "Left DAC" }, + { "Headphone Source Playback Route", "DAC", "Right DAC" }, + { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, + { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, + { "Headphone Amp", NULL, "Headphone Source Playback Route" }, + { "HP", NULL, "Headphone Amp" }, +}; + static int sun8i_a23_codec_add_headphone(struct snd_soc_component *cmpnt) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); @@ -525,6 +617,41 @@ static int sun8i_codec_add_mbias(struct snd_soc_component *cmpnt) return ret; } +static int sun50i_a64_codec_add_headphone(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun50i_a64_codec_hp_ctrls, + ARRAY_SIZE( + sun50i_a64_codec_hp_ctrls)); + if (ret) { + dev_err(dev, "Failed to add Headphone controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, + sun50i_a64_codec_hp_widgets, + ARRAY_SIZE( + sun50i_a64_codec_hp_widgets)); + if (ret) { + dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun50i_codec_headphone_routes, + ARRAY_SIZE( + sun50i_codec_headphone_routes)); + if (ret) { + dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + /* hmic specific widget */ static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = { SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, @@ -618,6 +745,17 @@ static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = { SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0), }; +static const struct snd_kcontrol_new sun50i_codec_lineout_ctrls[] = { + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN50I_ADDA_LINEOUT_CTRL1, + SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0, + sun8i_codec_lineout_vol_scale), + SOC_DOUBLE("Line Out Playback Switch", + SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_REN, + SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0), +}; + static const char * const sun8i_codec_lineout_src_enum_text[] = { "Stereo", "Mono Differential", }; @@ -628,11 +766,22 @@ static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum, SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC, sun8i_codec_lineout_src_enum_text); +static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum, + SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL, + SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL, + sun8i_codec_lineout_src_enum_text); + static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = { SOC_DAPM_ENUM("Line Out Source Playback Route", sun8i_codec_lineout_src_enum), }; +static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun50i_codec_lineout_src_enum), +}; + static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = { SND_SOC_DAPM_MUX("Line Out Source Playback Route", SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src), @@ -642,6 +791,17 @@ static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = { SND_SOC_DAPM_OUTPUT("LINEOUT"), }; +static const struct snd_soc_dapm_widget sun50i_codec_lineout_widgets[] = { + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src), + /* It is unclear if this is a buffer or gate, model it as a supply */ + SND_SOC_DAPM_SUPPLY("Left Line Out Enable", SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_LEN, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Right Line Out Enable", SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_REN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("LINEOUT"), +}; + static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = { { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, @@ -651,6 +811,17 @@ static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = { { "LINEOUT", NULL, "Line Out Enable", }, }; +static const struct snd_soc_dapm_route sun50i_codec_lineout_routes[] = { + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", + "Right Mixer" }, + { "LINEOUT", NULL, "Line Out Source Playback Route" }, + { "LINEOUT", NULL, "Left Line Out Enable", }, + { "LINEOUT", NULL, "Right Line Out Enable", }, +}; + static int sun8i_h3_codec_add_lineout(struct snd_soc_component *cmpnt) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); @@ -747,6 +918,39 @@ static int sun8i_codec_add_mic2(struct snd_soc_component *cmpnt) return 0; } +static int sun50i_a64_codec_add_lineout(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun50i_codec_lineout_ctrls, + ARRAY_SIZE( + sun50i_codec_lineout_ctrls)); + if (ret) { + dev_err(dev, "Failed to add Line Out controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, sun50i_codec_lineout_widgets, + ARRAY_SIZE( + sun50i_codec_lineout_widgets)); + if (ret) { + dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun50i_codec_lineout_routes, + ARRAY_SIZE(sun50i_codec_lineout_routes)); + if (ret) { + dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + struct sun8i_codec_analog_quirks { bool has_headphone; bool has_hmic; @@ -868,6 +1072,16 @@ static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = { .probe = sun8i_codec_analog_cmpnt_probe, }; +static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { + .controls = sun8i_codec_common_controls, + .num_controls = ARRAY_SIZE(sun8i_codec_common_controls), + .dapm_widgets = sun50i_codec_common_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun50i_codec_common_widgets), + .dapm_routes = sun8i_codec_common_routes, + .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes), + .probe = sun8i_codec_analog_cmpnt_probe, +}; + static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { .has_headphone = true, .has_hmic = true, @@ -893,6 +1107,15 @@ static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = { .cmpnt_drv = &sun8i_codec_analog_cmpnt_drv, }; +static const struct sun8i_codec_analog_quirks sun50i_a64_quirks = { + .has_headphone = true, + .has_hmic = false, + .has_lineout = true, + .add_headphone = sun50i_a64_codec_add_headphone, + .add_lineout = sun50i_a64_codec_add_lineout, + .cmpnt_drv = &sun50i_codec_analog_cmpnt_drv, +}; + static const struct of_device_id sun8i_codec_analog_of_match[] = { { .compatible = "allwinner,sun8i-a23-codec-analog", @@ -906,6 +1129,10 @@ static const struct of_device_id sun8i_codec_analog_of_match[] = { .compatible = "allwinner,sun8i-v3s-codec-analog", .data = &sun8i_v3s_quirks, }, + { + .compatible = "allwinner,sun50i-a64-codec-analog", + .data = &sun50i_a64_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);