From patchwork Mon Jul 23 15:53:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540537 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 912EC13BB for ; Mon, 23 Jul 2018 15:58:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7C0D528C33 for ; Mon, 23 Jul 2018 15:58:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6F7C628CE8; Mon, 23 Jul 2018 15:58:32 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A2FA828C33 for ; Mon, 23 Jul 2018 15:58:31 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 5C1AB2676CC; Mon, 23 Jul 2018 17:58:22 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 1AE812675D4; Mon, 23 Jul 2018 17:58:19 +0200 (CEST) Received: from mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65]) by alsa0.perex.cz (Postfix) with ESMTP id 6497226739D for ; Mon, 23 Jul 2018 17:58:17 +0200 (CEST) Received: by mail-wm0-f65.google.com with SMTP id o18-v6so1766221wmc.0 for ; Mon, 23 Jul 2018 08:58:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=usbvpM84D03PVtnGQhVCdxXJhk8fO01uK4ITF8UQWmY=; b=B5mF7Fyarhrc3QWrxoy2h4hQg7HRWWaOrV/VnRwXr7pEp9uUP6POsDTV2MU73Q9sLG Rl+gIMVkiH+EjPlhB7nhO5pTpcx0B0Swn1fhgwdxEo58GILaGooLBldbvCUU/M97HyYH zFZDxRV0HGkUcok5fc7YlIgdkZELDQn33/sHs= 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=usbvpM84D03PVtnGQhVCdxXJhk8fO01uK4ITF8UQWmY=; b=DaIOvRMyxcZ6rTsabWqTVrbGtN6VQoNBMvFciLRZZpdogD3PecSoixK6WunbqvdtYl /z/252qJvVATFBbTT5Mx+AVlBuYjGkOQOxG6aiUjvTtVNLWqvBWtbZ5Jl9rlKBcsRehb RfMqP3QJwTOt3CHewycpJwca36e4H2cUjOIn+Hb0d1Ve2xFYuiB5CDHtWAM4xZZpMZD3 ppS/cB2ptZEmPE287h0zywe5zBIazUgZzuMNtt+GTe3ByZ/fMfVtlXVPTSYhv9Bqe3Tj 5+zZN0Ht61yLfFXiiFUXDFdSXUwUcC0ulZy5UEtczzQDyn/BzOLsoZn0q5Oov+QgMKzH pLnw== X-Gm-Message-State: AOUpUlF1UlWYNVeE5KvLLvQykeGPVYzK3OTr9gkdRr8Nxv03NOCGILc0 PRRZ98ExLPtp8B/02O3KA/GuaQ== X-Google-Smtp-Source: AAOMgpfYZX79xog3eIdjZ67JmfH8gktXkLHw5HWqYZUQSvyJwrFMJ7Mjmdidwx9UAzM4dILYC/1IaQ== X-Received: by 2002:a1c:5e08:: with SMTP id s8-v6mr8293652wmb.88.1532361496869; Mon, 23 Jul 2018 08:58:16 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.15 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:16 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:53:59 +0100 Message-Id: <20180723155410.9494-2-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 01/12] mfd: dt-bindings: Add wcd9335 mfd bindings X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC, supports Qualcomm Technologies, Inc. (QTI) multimedia solutions, including the MSM8996, MSM8976, and MSM8956 chipsets. It has in-build Soundwire controller, interrupt mux. It supports both I2S/I2C and SLIMbus audio interfaces. Signed-off-by: Srinivas Kandagatla --- .../devicetree/bindings/mfd/qcom,wcd9335.txt | 130 +++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/qcom,wcd9335.txt diff --git a/Documentation/devicetree/bindings/mfd/qcom,wcd9335.txt b/Documentation/devicetree/bindings/mfd/qcom,wcd9335.txt new file mode 100644 index 000000000000..1f8c9e8d4e3d --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/qcom,wcd9335.txt @@ -0,0 +1,130 @@ +QCOM WCD9335 Codec + +Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC, supports +Qualcomm Technologies, Inc. (QTI) multimedia solutions, including +the MSM8996, MSM8976, and MSM8956 chipsets. It has in-build +Soundwire controller, interrupt mux. It supports both I2S/I2C and +SLIMbus audio interfaces. + +Required properties with SLIMbus Interface: + +- compatible: + Usage: required + Value type: + Definition: For SLIMbus interface it should be "slimMID,PID", + textual representation of Manufacturer ID, Product Code, + shall be in lower case hexadecimal with leading zeroes + suppressed. Refer to slimbus/bus.txt for details. + Should be: + "slim217,1a0" for MSM8996 and APQ8096 SoCs with SLIMbus. + +- reg + Usage: required + Value type: + Definition: Should be ('Device index', 'Instance ID') + +- interrupts + Usage: required + Value type: + Definition: Interrupts via WCD INTR1 and INTR2 pins + +- interrupt-names: + Usage: required + Value type: + Definition: Interrupt names of WCD INTR1 and INTR2 + Should be: "intr1", "intr2" + +- reset-gpio: + Usage: required + Value type: + Definition: Reset gpio line + +- qcom,ifd: + Usage: required + Value type: + Definition: SLIM interface device + +- clocks: + Usage: required + Value type: + Definition: See clock-bindings.txt section "consumers". List of + three clock specifiers for mclk, mclk2 and slimbus clock. + +- clock-names: + Usage: required + Value type: + Definition: Must contain "mclk", "mclk2" and "slimbus" strings. + +- vdd-buck-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V buck supply + +- vdd-buck-sido-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V SIDO buck supply + +- vdd-rx-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V rx supply + +- vdd-tx-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V tx supply + +- vdd-vbat-supply: + Usage: Optional + Value type: + Definition: Should contain a reference to the vbat supply + +- vdd-micbias-supply: + Usage: required + Value type: + Definition: Should contain a reference to the micbias supply + +- vdd-io-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V io supply + +- interrupt-controller: + Usage: required + Definition: Indicating that this is a interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: should be 1 + += WCD9335 Child devices +Each subnode of WCD9335 represents a functional blocks like +"audio codec", "soundwire Controller" of WCD. The name of the +nodes are not important. The properties of these nodes are +defined by the individual bindings for the specific device. + +Example: + +wcd9335@1 { + compatible = "slim217,1a0"; + reg = <1 0>; + interrupts = <&msmgpio 54 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "intr2" + reset-gpio = <&msmgpio 64 0>; + qcom,ifd = <&wc9335_ifd>; + clock-names = "mclk", "native"; + clocks = <&rpmcc RPM_SMD_DIV_CLK1>, + <&rpmcc RPM_SMD_BB_CLK1>; + vdd-buck-supply = <&pm8994_s4>; + vdd-rx-supply = <&pm8994_s4>; + vdd-buck-sido-supply = <&pm8994_s4>; + vdd-tx-supply = <&pm8994_s4>; + vdd-io-supply = <&pm8994_s4>; + + codec { + compatible = "qcom,wcd9335-codec"; + #sound-dai-cells = <1>; + }; +} From patchwork Mon Jul 23 15:54:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540541 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D7A06157A for ; Mon, 23 Jul 2018 15:58:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C42CF28CDC for ; Mon, 23 Jul 2018 15:58:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B8A6428CF3; Mon, 23 Jul 2018 15:58:53 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2B71E28CDC for ; Mon, 23 Jul 2018 15:58:51 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 129E12676D4; Mon, 23 Jul 2018 17:58:30 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id DE983267711; Mon, 23 Jul 2018 17:58:22 +0200 (CEST) Received: from mail-wm0-f68.google.com (mail-wm0-f68.google.com [74.125.82.68]) by alsa0.perex.cz (Postfix) with ESMTP id 7A26B26720C for ; Mon, 23 Jul 2018 17:58:19 +0200 (CEST) Received: by mail-wm0-f68.google.com with SMTP id c14-v6so1627649wmb.4 for ; Mon, 23 Jul 2018 08:58:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ddl1MOe/rzc/+YIVj0IUfcz5etd2b76frkriqo8cciM=; b=kBLMyNqc1LifWYvyDovY5//4bQnYos9GWDnYvN3CayX89F3hATkfureFaHo8KbZgtD E8cY5cvWjEPhofY+M3W5Zv0PYJkQEOFwxggxSH4JuXeO5ck9KSAazGBShYdj+seYmqz+ pfkld6vJlFfaEul8Eamc6z2Sb7pcPe6DCeHhU= 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=ddl1MOe/rzc/+YIVj0IUfcz5etd2b76frkriqo8cciM=; b=VfhQBUFgijYhqJorNOKnVbxB0mgYa8TfTrIU7hINqy/6g368QS0JR2ZXyimZHfho8U 6owsZrO+RcJTIRtAFTkn4qII4P++Y8faMlbz6GNfw7ngW6mYWjYWhbzZOBnyTeVFcn8x nzVrFGsSwe9Dop9aSZCkqaY0cCAOKTF/iQlpGKNEVnh+yJ3H4KCZxSyrexyXLf8pdpOa dp+PD8jBVr7dc7Zbr++6yIhOTlrmDlL6fH3pJJAjIiVBkNMnqbFGj+WPHIA7Iib3GZLA 1pJj0KM6m/NXFVWUPf3ZyD1Xl2OYXw8BIYWivVY5zb9PQ+QPsFVWHGFsPG1bUWDZRKaq cdwg== X-Gm-Message-State: AOUpUlHqNsHrW0cYvU58IN/pW9IH9gmXr5UBQ3txQx3dSWADVLyDdAz0 rUbtSvrRnHbdVybWMw0FSNcfhg== X-Google-Smtp-Source: AAOMgpfP+HZJ7aI4KTVsaUeoGOFEMOGMxr+m9rYBMYlC8oF2sDYStNuCOGv4xYN/PhbUdd7uth6DfQ== X-Received: by 2002:a1c:9755:: with SMTP id z82-v6mr8222753wmd.104.1532361498323; Mon, 23 Jul 2018 08:58:18 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:17 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:00 +0100 Message-Id: <20180723155410.9494-3-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 02/12] mfd: wcd9335: add support to wcd9335 core X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC, It has mulitple blocks like Soundwire controller, codec, Codec processing engine, ClassH controller, interrupt mux. It supports both I2S/I2C and SLIMbus audio interfaces. This patch adds support to SLIMbus audio interface. Signed-off-by: Srinivas Kandagatla --- drivers/mfd/Kconfig | 18 ++ drivers/mfd/Makefile | 4 + drivers/mfd/wcd9335-core.c | 269 ++++++++++++++++ include/linux/mfd/wcd9335/registers.h | 580 ++++++++++++++++++++++++++++++++++ include/linux/mfd/wcd9335/wcd9335.h | 40 +++ 5 files changed, 911 insertions(+) create mode 100644 drivers/mfd/wcd9335-core.c create mode 100644 include/linux/mfd/wcd9335/registers.h create mode 100644 include/linux/mfd/wcd9335/wcd9335.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f3fa516011ec..6e5b5f3cfe20 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1807,6 +1807,24 @@ config MFD_WM97xx support for the WM97xx, in order to use the actual functionaltiy of the device other drivers must be enabled. +config MFD_WCD9335 + tristate + select MFD_CORE + select REGMAP + select REGMAP_IRQ + +config MFD_WCD9335_SLIM + tristate "Qualcomm WCD9335 with SLIMbus" + select MFD_WCD9335 + select REGMAP_SLIMBUS + depends on SLIMBUS + help + The WCD9335 is a standalone Hi-Fi audio codec IC, supports + Qualcomm Technologies, Inc. (QTI) multimedia solutions, including + the MSM8996, MSM8976, and MSM8956 chipsets. It has inbuild + Soundwire controller, interrupt mux. It supports both I2S/I2C and + SLIMbus audio interfaces. This option selects SLIMbus audio interface. + config MFD_STW481X tristate "Support for ST Microelectronics STw481x" depends on I2C && (ARCH_NOMADIK || COMPILE_TEST) diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2852a6042ecf..a4697370640b 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -56,6 +56,10 @@ endif ifeq ($(CONFIG_MFD_CS47L24),y) obj-$(CONFIG_MFD_ARIZONA) += cs47l24-tables.o endif + +obj-$(CONFIG_MFD_WCD9335) += wcd9335.o +wcd9335-objs := wcd9335-core.o + obj-$(CONFIG_MFD_WM8400) += wm8400-core.o wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o wm831x-objs += wm831x-auxadc.o diff --git a/drivers/mfd/wcd9335-core.c b/drivers/mfd/wcd9335-core.c new file mode 100644 index 000000000000..ccdd27c3a351 --- /dev/null +++ b/drivers/mfd/wcd9335-core.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct regmap_range_cfg wcd9335_ranges[] = { + { .name = "WCD9335", + .range_min = 0x0, + .range_max = WCD9335_MAX_REGISTER, + .selector_reg = WCD9335_REG(0x0, 0), + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0x0, + .window_len = 0x1000, + }, +}; + +struct regmap_config wcd9335_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = WCD9335_MAX_REGISTER, + .can_multi_write = true, + .ranges = wcd9335_ranges, + .num_ranges = ARRAY_SIZE(wcd9335_ranges), +}; + +static const struct regmap_range_cfg wcd9335_ifd_ranges[] = { + { .name = "WCD9335-IFD", + .range_min = 0x0, + .range_max = WCD9335_REG(0, 0x7ff), + .selector_reg = WCD9335_REG(0, 0x0), + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0x0, + .window_len = 0x1000, + }, +}; + +struct regmap_config wcd9335_ifd_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .can_multi_write = true, + .max_register = WCD9335_REG(0, 0x7FF), + .ranges = wcd9335_ifd_ranges, + .num_ranges = ARRAY_SIZE(wcd9335_ifd_ranges), +}; + +static int wcd9335_parse_dt(struct wcd9335 *wcd) +{ + struct device *dev = wcd->dev; + struct device_node *np = dev->of_node; + int ret; + + wcd->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (wcd->reset_gpio < 0) { + dev_err(dev, "Reset gpio missing in DT\n"); + return wcd->reset_gpio; + } + + wcd->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(wcd->mclk)) { + dev_err(dev, "mclk not found\n"); + return PTR_ERR(wcd->mclk); + } + + wcd->native_clk = devm_clk_get(dev, "slimbus"); + if (IS_ERR(wcd->native_clk)) { + dev_err(dev, "slimbus clk not found\n"); + return PTR_ERR(wcd->native_clk); + } + + wcd->supplies[0].supply = "vdd-buck"; + wcd->supplies[1].supply = "vdd-buck-sido"; + wcd->supplies[2].supply = "vdd-tx"; + wcd->supplies[3].supply = "vdd-rx"; + wcd->supplies[4].supply = "vdd-io"; + + ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies); + if (ret != 0) { + dev_err(dev, "Failed to get supplies: err = %d\n", ret); + return ret; + } + + return 0; +} + +static int wcd9335_power_on_reset(struct wcd9335 *wcd) +{ + struct device *dev = wcd->dev; + int ret; + + ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, wcd->supplies); + if (ret != 0) { + dev_err(dev, "Failed to get supplies: err = %d\n", ret); + return ret; + } + + /* + * For WCD9335, it takes about 600us for the Vout_A and + * Vout_D to be ready after BUCK_SIDO is powered up. + * SYS_RST_N shouldn't be pulled high during this time + */ + usleep_range(600, 650); + + gpio_direction_output(wcd->reset_gpio, 0); + msleep(20); + gpio_set_value(wcd->reset_gpio, 1); + msleep(20); + + return 0; +} + +static int wcd9335_bring_up(struct wcd9335 *wcd) +{ + struct regmap *rm = wcd->regmap; + int val, byte0; + int ret = 0; + + regmap_read(rm, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val); + regmap_read(rm, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0); + + if ((val < 0) || (byte0 < 0)) { + dev_err(wcd->dev, "wcd9335 codec version detection fail!\n"); + return -EINVAL; + } + + if (byte0 == 0x1) { + dev_info(wcd->dev, "wcd9335 codec version is v2.0\n"); + wcd->version = WCD9335_VERSION_2_0; + regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x01); + regmap_write(rm, WCD9335_SIDO_SIDO_TEST_2, 0x00); + regmap_write(rm, WCD9335_SIDO_SIDO_CCL_8, 0x6F); + regmap_write(rm, WCD9335_BIAS_VBG_FINE_ADJ, 0x65); + regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5); + regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7); + regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3); + regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x3); + } else { + dev_err(wcd->dev, "wcd9335 codec version not supported\n"); + ret = -EINVAL; + } + + return ret; +} + +static int wcd9335_slim_probe(struct slim_device *slim) +{ + struct device *dev = &slim->dev; + struct wcd9335 *wcd; + int ret = 0; + + /* Interface device */ + if (slim->e_addr.dev_index == 0) + return 0; + + wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); + if (!wcd) + return -ENOMEM; + + wcd->dev = dev; + ret = wcd9335_parse_dt(wcd); + if (ret) { + dev_err(dev, "Error parsing DT (%d)\n", ret); + return ret; + } + + ret = wcd9335_power_on_reset(wcd); + if (ret) { + dev_err(dev, "Error Powering\n"); + return ret; + } + + wcd->regmap = regmap_init_slimbus(slim, &wcd9335_regmap_config); + if (IS_ERR(wcd->regmap)) { + ret = PTR_ERR(wcd->regmap); + dev_err(dev, "Failed to allocate register map:%d\n", ret); + return ret; + } + + dev_set_drvdata(dev, wcd); + wcd->slim = slim; + wcd->intf_type = WCD9335_INTERFACE_TYPE_SLIMBUS; + + return 0; +} + +static const struct mfd_cell wcd9335_devices[] = { + { + .name = "wcd9335-codec", + .of_compatible = "qcom,wcd9335-codec", + }, +}; + +static int wcd9335_slim_status(struct slim_device *sdev, + enum slim_device_status s) +{ + struct device_node *ifd_np; + struct wcd9335 *wcd; + struct device *dev; + int ret; + + /* Interface device */ + if (sdev->e_addr.dev_index == 0) + return 0; + + wcd = dev_get_drvdata(&sdev->dev); + dev = wcd->dev; + + ifd_np = of_parse_phandle(wcd->dev->of_node, "qcom,ifd", 0); + if (!ifd_np) { + dev_err(wcd->dev, "No Interface device found\n"); + return -EINVAL; + } + + wcd->slim_ifd = of_slim_get_device(sdev->ctrl, ifd_np); + if (!wcd->slim_ifd) { + dev_err(wcd->dev, "Unable to get SLIM Interface device\n"); + return -EINVAL; + } + + wcd->ifd_regmap = regmap_init_slimbus(wcd->slim_ifd, + &wcd9335_ifd_regmap_config); + if (IS_ERR(wcd->ifd_regmap)) { + dev_err(dev, "Failed to allocate register map\n"); + return PTR_ERR(wcd->ifd_regmap); + } + + ret = wcd9335_bring_up(wcd); + if (ret) { + dev_err(dev, "Failed to bringup WCD9335\n"); + return ret; + } + + wcd->slim_ifd = wcd->slim_ifd; + + return mfd_add_devices(wcd->dev, 0, wcd9335_devices, + ARRAY_SIZE(wcd9335_devices), NULL, 0, NULL); +} + +static const struct slim_device_id wcd9335_slim_id[] = { + {0x217, 0x1a0, 0x1, 0x0}, + {} +}; + +static struct slim_driver wcd9335_slim_driver = { + .driver = { + .name = "wcd9335-slim", + }, + .probe = wcd9335_slim_probe, + .device_status = wcd9335_slim_status, + .id_table = wcd9335_slim_id, +}; + +module_slim_driver(wcd9335_slim_driver); +MODULE_DESCRIPTION("WCD9335 slim driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/wcd9335/registers.h b/include/linux/mfd/wcd9335/registers.h new file mode 100644 index 000000000000..d6a81017c2b5 --- /dev/null +++ b/include/linux/mfd/wcd9335/registers.h @@ -0,0 +1,580 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _WCD9335_REGISTERS_H +#define _WCD9335_REGISTERS_H + +#define WCD9335_PAGE_SIZE 0x256 +#define WCD9335_NUM_PAGES 0x256 + +/* + * WCD9335 register base can change according to the mode it works in + * in slimbus mode the reg base starts from 0x800 + * in i2s/i2c mode the reg base is 0x0 + */ +#define WCD9335_REG(pg, r) ((pg << 12) | (r) | 0x800) +#define WCD9335_REG_OFFSET(r) (r & 0xFF) +#define WCD9335_PAGE_OFFSET(r) ((r >> 12) & 0xFF) + +/* Page-0 Registers */ +#define WCD9335_PAGE0_PAGE_REGISTER WCD9335_REG(0x00, 0x000) +#define WCD9335_CODEC_RPM_CLK_GATE WCD9335_REG(0x00, 0x002) +#define WCD9335_CODEC_RPM_CLK_GATE_MCLK_GATE_MASK GENMASK(1, 0) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG WCD9335_REG(0x00, 0x003) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ BIT(0) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ BIT(0) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK GENMASK(1, 0) +#define WCD9335_CODEC_RPM_RST_CTL WCD9335_REG(0x00, 0x009) +#define WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL WCD9335_REG(0x00, 0x011) +#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0 WCD9335_REG(0x00, 0x021) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_CTL WCD9335_REG(0x00, 0x025) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_SSTATE_MASK GENMASK(4, 1) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK BIT(0) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_ENABLE BIT(0) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0 WCD9335_REG(0x00, 0x029) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS WCD9335_REG(0x00, 0x039) +#define WCD9335_INTR_PIN1_MASK0 WCD9335_REG(0x00, 0x089) +#define WCD9335_INTR_PIN1_MASK1 WCD9335_REG(0x00, 0x08a) +#define WCD9335_INTR_PIN1_MASK2 WCD9335_REG(0x00, 0x08b) +#define WCD9335_INTR_PIN1_MASK3 WCD9335_REG(0x00, 0x08c) +#define WCD9335_INTR_PIN1_STATUS0 WCD9335_REG(0x00, 0x091) +#define WCD9335_INTR_PIN1_STATUS1 WCD9335_REG(0x00, 0x092) +#define WCD9335_INTR_PIN1_STATUS2 WCD9335_REG(0x00, 0x093) +#define WCD9335_INTR_PIN1_STATUS3 WCD9335_REG(0x00, 0x094) +#define WCD9335_INTR_PIN1_CLEAR0 WCD9335_REG(0x00, 0x099) +#define WCD9335_INTR_PIN1_CLEAR1 WCD9335_REG(0x00, 0x09a) +#define WCD9335_INTR_PIN1_CLEAR2 WCD9335_REG(0x00, 0x09b) +#define WCD9335_INTR_PIN1_CLEAR3 WCD9335_REG(0x00, 0x09c) +#define WCD9335_INTR_PIN2_MASK0 WCD9335_REG(0x00, 0x0a1) +#define WCD9335_INTR_PIN2_MASK1 WCD9335_REG(0x00, 0x0a2) +#define WCD9335_INTR_PIN2_MASK2 WCD9335_REG(0x00, 0x0a3) +#define WCD9335_INTR_PIN2_MASK3 WCD9335_REG(0x00, 0x0a4) +#define WCD9335_INTR_PIN2_STATUS0 WCD9335_REG(0x00, 0x0a9) +#define WCD9335_INTR_PIN2_STATUS1 WCD9335_REG(0x00, 0x0aa) +#define WCD9335_INTR_PIN2_STATUS2 WCD9335_REG(0x00, 0x0ab) +#define WCD9335_INTR_PIN2_STATUS3 WCD9335_REG(0x00, 0x0ac) +#define WCD9335_INTR_PIN2_CLEAR0 WCD9335_REG(0x00, 0x0b1) +#define WCD9335_INTR_PIN2_CLEAR1 WCD9335_REG(0x00, 0x0b2) +#define WCD9335_INTR_PIN2_CLEAR2 WCD9335_REG(0x00, 0x0b3) +#define WCD9335_INTR_PIN2_CLEAR3 WCD9335_REG(0x00, 0x0b4) +#define WCD9335_INTR_LEVEL0 WCD9335_REG(0x00, 0x0e1) +#define WCD9335_INTR_LEVEL1 WCD9335_REG(0x00, 0x0e2) +#define WCD9335_INTR_LEVEL2 WCD9335_REG(0x00, 0x0e3) +#define WCD9335_INTR_LEVEL3 WCD9335_REG(0x00, 0x0e4) + +/* Page-1 Registers */ +#define WCD9335_CPE_FLL_USER_CTL_0 WCD9335_REG(0x01, 0x001) +#define WCD9335_CPE_FLL_USER_CTL_1 WCD9335_REG(0x01, 0x002) +#define WCD9335_CPE_FLL_USER_CTL_2 WCD9335_REG(0x01, 0x003) +#define WCD9335_CPE_FLL_USER_CTL_3 WCD9335_REG(0x01, 0x004) +#define WCD9335_CPE_FLL_USER_CTL_4 WCD9335_REG(0x01, 0x005) +#define WCD9335_CPE_FLL_USER_CTL_5 WCD9335_REG(0x01, 0x006) +#define WCD9335_CPE_FLL_USER_CTL_6 WCD9335_REG(0x01, 0x007) +#define WCD9335_CPE_FLL_USER_CTL_7 WCD9335_REG(0x01, 0x008) +#define WCD9335_CPE_FLL_USER_CTL_8 WCD9335_REG(0x01, 0x009) +#define WCD9335_CPE_FLL_USER_CTL_9 WCD9335_REG(0x01, 0x00a) +#define WCD9335_CPE_FLL_L_VAL_CTL_0 WCD9335_REG(0x01, 0x00b) +#define WCD9335_CPE_FLL_L_VAL_CTL_1 WCD9335_REG(0x01, 0x00c) +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_0 WCD9335_REG(0x01, 0x00d) +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_1 WCD9335_REG(0x01, 0x00e) +#define WCD9335_CPE_FLL_CONFIG_CTL_0 WCD9335_REG(0x01, 0x00f) +#define WCD9335_CPE_FLL_CONFIG_CTL_1 WCD9335_REG(0x01, 0x010) +#define WCD9335_CPE_FLL_CONFIG_CTL_2 WCD9335_REG(0x01, 0x011) +#define WCD9335_CPE_FLL_CONFIG_CTL_3 WCD9335_REG(0x01, 0x012) +#define WCD9335_CPE_FLL_CONFIG_CTL_4 WCD9335_REG(0x01, 0x013) +#define WCD9335_CPE_FLL_TEST_CTL_0 WCD9335_REG(0x01, 0x014) +#define WCD9335_CPE_FLL_TEST_CTL_1 WCD9335_REG(0x01, 0x015) +#define WCD9335_CPE_FLL_TEST_CTL_2 WCD9335_REG(0x01, 0x016) +#define WCD9335_CPE_FLL_TEST_CTL_3 WCD9335_REG(0x01, 0x017) +#define WCD9335_CPE_FLL_TEST_CTL_4 WCD9335_REG(0x01, 0x018) +#define WCD9335_CPE_FLL_TEST_CTL_5 WCD9335_REG(0x01, 0x019) +#define WCD9335_CPE_FLL_TEST_CTL_6 WCD9335_REG(0x01, 0x01a) +#define WCD9335_CPE_FLL_TEST_CTL_7 WCD9335_REG(0x01, 0x01b) +#define WCD9335_CPE_FLL_FREQ_CTL_0 WCD9335_REG(0x01, 0x01c) +#define WCD9335_CPE_FLL_FREQ_CTL_1 WCD9335_REG(0x01, 0x01d) +#define WCD9335_CPE_FLL_FREQ_CTL_2 WCD9335_REG(0x01, 0x01e) +#define WCD9335_CPE_FLL_FREQ_CTL_3 WCD9335_REG(0x01, 0x01f) +#define WCD9335_CPE_FLL_SSC_CTL_0 WCD9335_REG(0x01, 0x020) +#define WCD9335_CPE_FLL_SSC_CTL_1 WCD9335_REG(0x01, 0x021) +#define WCD9335_CPE_FLL_SSC_CTL_2 WCD9335_REG(0x01, 0x022) +#define WCD9335_CPE_FLL_SSC_CTL_3 WCD9335_REG(0x01, 0x023) +#define WCD9335_CPE_FLL_FLL_MODE WCD9335_REG(0x01, 0x024) +#define WCD9335_CPE_FLL_STATUS_0 WCD9335_REG(0x01, 0x025) +#define WCD9335_CPE_FLL_STATUS_1 WCD9335_REG(0x01, 0x026) +#define WCD9335_CPE_FLL_STATUS_2 WCD9335_REG(0x01, 0x027) +#define WCD9335_CPE_FLL_STATUS_3 WCD9335_REG(0x01, 0x028) +#define WCD9335_I2S_FLL_USER_CTL_0 WCD9335_REG(0x01, 0x041) +#define WCD9335_I2S_FLL_USER_CTL_1 WCD9335_REG(0x01, 0x042) +#define WCD9335_I2S_FLL_USER_CTL_2 WCD9335_REG(0x01, 0x043) +#define WCD9335_I2S_FLL_USER_CTL_3 WCD9335_REG(0x01, 0x044) +#define WCD9335_I2S_FLL_USER_CTL_4 WCD9335_REG(0x01, 0x045) +#define WCD9335_I2S_FLL_USER_CTL_5 WCD9335_REG(0x01, 0x046) +#define WCD9335_I2S_FLL_USER_CTL_6 WCD9335_REG(0x01, 0x047) +#define WCD9335_I2S_FLL_USER_CTL_7 WCD9335_REG(0x01, 0x048) +#define WCD9335_I2S_FLL_USER_CTL_8 WCD9335_REG(0x01, 0x049) +#define WCD9335_I2S_FLL_USER_CTL_9 WCD9335_REG(0x01, 0x04a) +#define WCD9335_I2S_FLL_L_VAL_CTL_0 WCD9335_REG(0x01, 0x04b) +#define WCD9335_I2S_FLL_L_VAL_CTL_1 WCD9335_REG(0x01, 0x04c) +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_0 WCD9335_REG(0x01, 0x04d) +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_1 WCD9335_REG(0x01, 0x04e) +#define WCD9335_I2S_FLL_CONFIG_CTL_0 WCD9335_REG(0x01, 0x04f) +#define WCD9335_I2S_FLL_CONFIG_CTL_1 WCD9335_REG(0x01, 0x050) +#define WCD9335_I2S_FLL_CONFIG_CTL_2 WCD9335_REG(0x01, 0x051) +#define WCD9335_I2S_FLL_CONFIG_CTL_3 WCD9335_REG(0x01, 0x052) +#define WCD9335_I2S_FLL_CONFIG_CTL_4 WCD9335_REG(0x01, 0x053) +#define WCD9335_I2S_FLL_TEST_CTL_0 WCD9335_REG(0x01, 0x054) +#define WCD9335_I2S_FLL_TEST_CTL_1 WCD9335_REG(0x01, 0x055) +#define WCD9335_I2S_FLL_TEST_CTL_2 WCD9335_REG(0x01, 0x056) +#define WCD9335_I2S_FLL_TEST_CTL_3 WCD9335_REG(0x01, 0x057) +#define WCD9335_I2S_FLL_TEST_CTL_4 WCD9335_REG(0x01, 0x058) +#define WCD9335_I2S_FLL_TEST_CTL_5 WCD9335_REG(0x01, 0x059) +#define WCD9335_I2S_FLL_TEST_CTL_6 WCD9335_REG(0x01, 0x05a) +#define WCD9335_I2S_FLL_TEST_CTL_7 WCD9335_REG(0x01, 0x05b) +#define WCD9335_I2S_FLL_FREQ_CTL_0 WCD9335_REG(0x01, 0x05c) +#define WCD9335_I2S_FLL_FREQ_CTL_1 WCD9335_REG(0x01, 0x05d) +#define WCD9335_I2S_FLL_FREQ_CTL_2 WCD9335_REG(0x01, 0x05e) +#define WCD9335_I2S_FLL_FREQ_CTL_3 WCD9335_REG(0x01, 0x05f) +#define WCD9335_I2S_FLL_SSC_CTL_0 WCD9335_REG(0x01, 0x060) +#define WCD9335_I2S_FLL_SSC_CTL_1 WCD9335_REG(0x01, 0x061) +#define WCD9335_I2S_FLL_SSC_CTL_2 WCD9335_REG(0x01, 0x062) +#define WCD9335_I2S_FLL_SSC_CTL_3 WCD9335_REG(0x01, 0x063) +#define WCD9335_I2S_FLL_FLL_MODE WCD9335_REG(0x01, 0x064) +#define WCD9335_I2S_FLL_STATUS_0 WCD9335_REG(0x01, 0x065) +#define WCD9335_I2S_FLL_STATUS_1 WCD9335_REG(0x01, 0x066) +#define WCD9335_I2S_FLL_STATUS_2 WCD9335_REG(0x01, 0x067) +#define WCD9335_I2S_FLL_STATUS_3 WCD9335_REG(0x01, 0x068) +#define WCD9335_SB_FLL_USER_CTL_0 WCD9335_REG(0x01, 0x081) +#define WCD9335_SB_FLL_USER_CTL_1 WCD9335_REG(0x01, 0x082) +#define WCD9335_SB_FLL_USER_CTL_2 WCD9335_REG(0x01, 0x083) +#define WCD9335_SB_FLL_USER_CTL_3 WCD9335_REG(0x01, 0x084) +#define WCD9335_SB_FLL_USER_CTL_4 WCD9335_REG(0x01, 0x085) +#define WCD9335_SB_FLL_USER_CTL_5 WCD9335_REG(0x01, 0x086) +#define WCD9335_SB_FLL_USER_CTL_6 WCD9335_REG(0x01, 0x087) +#define WCD9335_SB_FLL_USER_CTL_7 WCD9335_REG(0x01, 0x088) +#define WCD9335_SB_FLL_USER_CTL_8 WCD9335_REG(0x01, 0x089) +#define WCD9335_SB_FLL_USER_CTL_9 WCD9335_REG(0x01, 0x08a) +#define WCD9335_SB_FLL_L_VAL_CTL_0 WCD9335_REG(0x01, 0x08b) +#define WCD9335_SB_FLL_L_VAL_CTL_1 WCD9335_REG(0x01, 0x08c) +#define WCD9335_SB_FLL_DSM_FRAC_CTL_0 WCD9335_REG(0x01, 0x08d) +#define WCD9335_SB_FLL_DSM_FRAC_CTL_1 WCD9335_REG(0x01, 0x08e) +#define WCD9335_SB_FLL_CONFIG_CTL_0 WCD9335_REG(0x01, 0x08f) +#define WCD9335_SB_FLL_CONFIG_CTL_1 WCD9335_REG(0x01, 0x090) +#define WCD9335_SB_FLL_CONFIG_CTL_2 WCD9335_REG(0x01, 0x091) +#define WCD9335_SB_FLL_CONFIG_CTL_3 WCD9335_REG(0x01, 0x092) +#define WCD9335_SB_FLL_CONFIG_CTL_4 WCD9335_REG(0x01, 0x093) +#define WCD9335_SB_FLL_TEST_CTL_0 WCD9335_REG(0x01, 0x094) +#define WCD9335_SB_FLL_TEST_CTL_1 WCD9335_REG(0x01, 0x095) +#define WCD9335_SB_FLL_TEST_CTL_2 WCD9335_REG(0x01, 0x096) +#define WCD9335_SB_FLL_TEST_CTL_3 WCD9335_REG(0x01, 0x097) +#define WCD9335_SB_FLL_TEST_CTL_4 WCD9335_REG(0x01, 0x098) +#define WCD9335_SB_FLL_TEST_CTL_5 WCD9335_REG(0x01, 0x099) +#define WCD9335_SB_FLL_TEST_CTL_6 WCD9335_REG(0x01, 0x09a) +#define WCD9335_SB_FLL_TEST_CTL_7 WCD9335_REG(0x01, 0x09b) +#define WCD9335_SB_FLL_FREQ_CTL_0 WCD9335_REG(0x01, 0x09c) +#define WCD9335_SB_FLL_FREQ_CTL_1 WCD9335_REG(0x01, 0x09d) +#define WCD9335_SB_FLL_FREQ_CTL_2 WCD9335_REG(0x01, 0x09e) +#define WCD9335_SB_FLL_FREQ_CTL_3 WCD9335_REG(0x01, 0x09f) +#define WCD9335_SB_FLL_SSC_CTL_0 WCD9335_REG(0x01, 0x0a0) +#define WCD9335_SB_FLL_SSC_CTL_1 WCD9335_REG(0x01, 0x0a1) +#define WCD9335_SB_FLL_SSC_CTL_2 WCD9335_REG(0x01, 0x0a2) +#define WCD9335_SB_FLL_SSC_CTL_3 WCD9335_REG(0x01, 0x0a3) +#define WCD9335_SB_FLL_FLL_MODE WCD9335_REG(0x01, 0x0a4) +#define WCD9335_SB_FLL_STATUS_0 WCD9335_REG(0x01, 0x0a5) +#define WCD9335_SB_FLL_STATUS_1 WCD9335_REG(0x01, 0x0a6) +#define WCD9335_SB_FLL_STATUS_2 WCD9335_REG(0x01, 0x0a7) +#define WCD9335_SB_FLL_STATUS_3 WCD9335_REG(0x01, 0x0a8) + +/* Page-2 Registers */ +#define WCD9335_PAGE2_PAGE_REGISTER WCD9335_REG(0x02, 0x000) +#define WCD9335_CPE_SS_DMIC0_CTL WCD9335_REG(0x02, 0x063) +#define WCD9335_CPE_SS_DMIC1_CTL WCD9335_REG(0x02, 0x064) +#define WCD9335_CPE_SS_DMIC2_CTL WCD9335_REG(0x02, 0x065) +#define WCD9335_CPE_SS_DMIC_CFG WCD9335_REG(0x02, 0x066) +#define WCD9335_SOC_MAD_AUDIO_CTL_2 WCD9335_REG(0x02, 0x084) + +/* Page-6 Registers */ +#define WCD9335_PAGE6_PAGE_REGISTER WCD9335_REG(0x06, 0x000) +#define WCD9335_ANA_BIAS WCD9335_REG(0x06, 0x001) +#define WCD9335_ANA_BIAS_EN_MASK BIT(7) +#define WCD9335_ANA_BIAS_ENABLE BIT(7) +#define WCD9335_ANA_BIAS_DISABLE 0 +#define WCD9335_ANA_BIAS_PRECHRG_EN_MASK BIT(6) +#define WCD9335_ANA_BIAS_PRECHRG_ENABLE BIT(6) +#define WCD9335_ANA_BIAS_PRECHRG_DISABLE 0 +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE BIT(5) +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_AUTO BIT(5) +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL 0 +#define WCD9335_ANA_CLK_TOP WCD9335_REG(0x06, 0x002) +#define WCD9335_ANA_CLK_MCLK_EN_MASK BIT(2) +#define WCD9335_ANA_CLK_MCLK_ENABLE BIT(2) +#define WCD9335_ANA_CLK_MCLK_DISABLE 0 +#define WCD9335_ANA_CLK_MCLK_SRC_MASK BIT(3) +#define WCD9335_ANA_CLK_MCLK_SRC_RCO BIT(3) +#define WCD9335_ANA_CLK_MCLK_SRC_EXTERNAL 0 +#define WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK BIT(7) +#define WCD9335_ANA_CLK_EXT_CLKBUF_ENABLE BIT(7) +#define WCD9335_ANA_CLK_EXT_CLKBUF_DISABLE 0 +#define WCD9335_ANA_RCO WCD9335_REG(0x06, 0x003) +#define WCD9335_ANA_RCO_BG_EN_MASK BIT(7) +#define WCD9335_ANA_RCO_BG_ENABLE BIT(7) +#define WCD9335_ANA_BUCK_VOUT_D WCD9335_REG(0x06, 0x005) +#define WCD9335_ANA_BUCK_VOUT_MASK GENMASK(7, 0) +#define WCD9335_ANA_BUCK_CTL WCD9335_REG(0x06, 0x006) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_MASK BIT(1) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_EXT BIT(1) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_INT 0 +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_MASK BIT(2) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT BIT(2) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_INT 0 +#define WCD9335_ANA_BUCK_CTL_RAMP_START_MASK BIT(7) +#define WCD9335_ANA_BUCK_CTL_RAMP_START_ENABLE BIT(7) +#define WCD9335_ANA_BUCK_CTL_RAMP_START_DISABLE 0 +#define WCD9335_ANA_RX_SUPPLIES WCD9335_REG(0x06, 0x008) +#define WCD9335_ANA_RX_BIAS_ENABLE_MASK BIT(0) +#define WCD9335_ANA_RX_BIAS_ENABLE BIT(0) +#define WCD9335_ANA_RX_BIAS_DISABLE 0 +#define WCD9335_ANA_HPH WCD9335_REG(0x06, 0x009) +#define WCD9335_ANA_EAR WCD9335_REG(0x06, 0x00a) +#define WCD9335_ANA_LO_1_2 WCD9335_REG(0x06, 0x00b) +#define WCD9335_ANA_LO_3_4 WCD9335_REG(0x06, 0x00c) +#define WCD9335_ANA_AMIC1 WCD9335_REG(0x06, 0x00e) +#define WCD9335_ANA_AMIC2 WCD9335_REG(0x06, 0x00f) +#define WCD9335_ANA_AMIC3 WCD9335_REG(0x06, 0x010) +#define WCD9335_ANA_AMIC4 WCD9335_REG(0x06, 0x011) +#define WCD9335_ANA_AMIC5 WCD9335_REG(0x06, 0x012) +#define WCD9335_ANA_AMIC6 WCD9335_REG(0x06, 0x013) +#define WCD9335_ANA_MICB1 WCD9335_REG(0x06, 0x022) +#define WCD9335_ANA_MICB2 WCD9335_REG(0x06, 0x023) +#define WCD9335_ANA_MICB2_RAMP WCD9335_REG(0x06, 0x024) +#define WCD9335_ANA_MICB3 WCD9335_REG(0x06, 0x025) +#define WCD9335_ANA_MICB4 WCD9335_REG(0x06, 0x026) +#define WCD9335_ANA_VBADC WCD9335_REG(0x06, 0x027) +#define WCD9335_BIAS_VBG_FINE_ADJ WCD9335_REG(0x06, 0x029) +#define WCD9335_RCO_CTRL_2 WCD9335_REG(0x06, 0x02f) +#define WCD9335_SIDO_SIDO_CCL_2 WCD9335_REG(0x06, 0x042) +#define WCD9335_SIDO_SIDO_CCL_4 WCD9335_REG(0x06, 0x044) +#define WCD9335_SIDO_SIDO_CCL_8 WCD9335_REG(0x06, 0x048) +#define WCD9335_SIDO_SIDO_CCL_10 WCD9335_REG(0x06, 0x04a) +#define WCD9335_SIDO_SIDO_CCL_10_ICHARG_PWR_SEL_C320FF 0x2 +/* Comparator 1 and 2 Bias current at 1P0UA with start pulse width of C320FF */ +#define WCD9335_SIDO_SIDO_CCL_DEF_VALUE 0x6e +#define WCD9335_SIDO_SIDO_TEST_2 WCD9335_REG(0x06, 0x055) +#define WCD9335_MBHC_ZDET_RAMP_CTL WCD9335_REG(0x06, 0x05a) +#define WCD9335_VBADC_IBIAS_FE WCD9335_REG(0x06, 0x05e) +#define WCD9335_FLYBACK_CTRL_1 WCD9335_REG(0x06, 0x0b1) +#define WCD9335_RX_BIAS_HPH_PA WCD9335_REG(0x06, 0x0bb) +#define WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK GENMASK(3, 0) +#define WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2 WCD9335_REG(0x06, 0x0bc) +#define WCD9335_RX_BIAS_HPH_RDAC_LDO WCD9335_REG(0x06, 0x0bd) +#define WCD9335_RX_BIAS_FLYB_BUFF WCD9335_REG(0x06, 0x0c7) +#define WCD9335_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0) +#define WCD9335_RX_BIAS_FLYB_I_0P0_UA 0 +#define WCD9335_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) +#define WCD9335_RX_BIAS_FLYB_MID_RST WCD9335_REG(0x06, 0x0c8) +#define WCD9335_HPH_CNP_WG_CTL WCD9335_REG(0x06, 0x0cc) +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK GENMASK(2, 0) +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500 0x2 +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000 0x3 +#define WCD9335_HPH_OCP_CTL WCD9335_REG(0x06, 0x0ce) +#define WCD9335_HPH_AUTO_CHOP WCD9335_REG(0x06, 0x0cf) +#define WCD9335_HPH_AUTO_CHOP_MASK BIT(5) +#define WCD9335_HPH_AUTO_CHOP_FORCE_ENABLE BIT(5) +#define WCD9335_HPH_AUTO_CHOP_ENABLE_BY_CMPDR_GAIN 0 +#define WCD9335_HPH_PA_CTL1 WCD9335_REG(0x06, 0x0d1) +#define WCD9335_HPH_PA_GM3_IB_SCALE_MASK GENMASK(3, 1) +#define WCD9335_HPH_PA_CTL2 WCD9335_REG(0x06, 0x0d2) +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK BIT(2) +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_ENABLE BIT(2) +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_DISABLE 0 +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK BIT(3) +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE BIT(3) +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE 0 +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK BIT(5) +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENABLE BIT(5) +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_DISABLE 0 +#define WCD9335_HPH_L_EN WCD9335_REG(0x06, 0x0d3) +#define WCD9335_HPH_CONST_SEL_L_MASK GENMASK(7, 6) +#define WCD9335_HPH_CONST_SEL_L_BYPASS 0 +#define WCD9335_HPH_CONST_SEL_L_LP_PATH 0x40 +#define WCD9335_HPH_CONST_SEL_L_HQ_PATH 0x80 +#define WCD9335_HPH_PA_GAIN_MASK GENMASK(4, 0) +#define WCD9335_HPH_GAIN_SRC_SEL_MASK BIT(5) +#define WCD9335_HPH_GAIN_SRC_SEL_COMPANDER 0 +#define WCD9335_HPH_GAIN_SRC_SEL_REGISTER BIT(5) +#define WCD9335_HPH_L_TEST WCD9335_REG(0x06, 0x0d4) +#define WCD9335_HPH_R_EN WCD9335_REG(0x06, 0x0d6) +#define WCD9335_HPH_R_TEST WCD9335_REG(0x06, 0x0d7) +#define WCD9335_HPH_R_ATEST WCD9335_REG(0x06, 0x0d8) +#define WCD9335_HPH_RDAC_LDO_CTL WCD9335_REG(0x06, 0x0db) +#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_MASK GENMASK(2, 0) +#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_V_N1P60 0x1 +#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_MASK GENMASK(6, 4) +#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_V_N1P60 0x10 +#define WCD9335_HPH_REFBUFF_LP_CTL WCD9335_REG(0x06, 0x0de) +#define WCD9335_HPH_L_DAC_CTL WCD9335_REG(0x06, 0x0df) +#define WCD9335_HPH_DAC_LDO_POWERMODE_MASK BIT(0) +#define WCD9335_HPH_DAC_LDO_POWERMODE_LOWPOWER 0 +#define WCD9335_HPH_DAC_LDO_POWERMODE_UHQA BIT(0) +#define WCD9335_HPH_DAC_LDO_UHQA_OV_MASK BIT(1) +#define WCD9335_HPH_DAC_LDO_UHQA_OV_ENABLE BIT(1) +#define WCD9335_HPH_DAC_LDO_UHQA_OV_DISABLE 0 + +#define WCD9335_EAR_CMBUFF WCD9335_REG(0x06, 0x0e2) +#define WCD9335_DIFF_LO_LO2_COMPANDER WCD9335_REG(0x06, 0x0ea) +#define WCD9335_DIFF_LO_LO1_COMPANDER WCD9335_REG(0x06, 0x0eb) +#define WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ WCD9335_REG(0x06, 0x0f1) +#define WCD9335_DIFF_LO_COM_PA_FREQ WCD9335_REG(0x06, 0x0f2) +#define WCD9335_SE_LO_LO3_GAIN WCD9335_REG(0x06, 0x0f8) +#define WCD9335_SE_LO_LO3_CTRL WCD9335_REG(0x06, 0x0f9) +#define WCD9335_SE_LO_LO4_GAIN WCD9335_REG(0x06, 0x0fa) + +/* Page-10 Registers */ +#define WCD9335_CDC_TX0_TX_PATH_CTL WCD9335_REG(0x0a, 0x031) +#define WCD9335_CDC_TX_PATH_CTL_PCM_RATE_MASK GENMASK(3, 0) +#define WCD9335_CDC_TX_PATH_CTL(dec) WCD9335_REG(0xa, (0x31 + dec * 0x10)) +#define WCD9335_CDC_TX0_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x032) +#define WCD9335_CDC_TX_ADC_AMIC_DMIC_SEL_MASK BIT(7) +#define WCD9335_CDC_TX_ADC_DMIC_SEL BIT(7) +#define WCD9335_CDC_TX_ADC_AMIC_SEL 0 +#define WCD9335_CDC_TX0_TX_VOL_CTL WCD9335_REG(0x0a, 0x034) +#define WCD9335_CDC_TX0_TX_PATH_SEC2 WCD9335_REG(0x0a, 0x039) +#define WCD9335_CDC_TX0_TX_PATH_SEC7 WCD9335_REG(0x0a, 0x03e) +#define WCD9335_CDC_TX1_TX_PATH_CTL WCD9335_REG(0x0a, 0x041) +#define WCD9335_CDC_TX1_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x042) +#define WCD9335_CDC_TX2_TX_PATH_CTL WCD9335_REG(0x0a, 0x051) +#define WCD9335_CDC_TX2_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x052) +#define WCD9335_CDC_TX2_TX_VOL_CTL WCD9335_REG(0x0a, 0x054) +#define WCD9335_CDC_TX3_TX_PATH_CTL WCD9335_REG(0x0a, 0x061) +#define WCD9335_CDC_TX3_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x062) +#define WCD9335_CDC_TX3_TX_VOL_CTL WCD9335_REG(0x0a, 0x064) +#define WCD9335_CDC_TX4_TX_PATH_CTL WCD9335_REG(0x0a, 0x071) +#define WCD9335_CDC_TX4_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x072) +#define WCD9335_CDC_TX4_TX_VOL_CTL WCD9335_REG(0x0a, 0x074) +#define WCD9335_CDC_TX5_TX_PATH_CTL WCD9335_REG(0x0a, 0x081) +#define WCD9335_CDC_TX5_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x082) +#define WCD9335_CDC_TX5_TX_VOL_CTL WCD9335_REG(0x0a, 0x084) +#define WCD9335_CDC_TX6_TX_PATH_CTL WCD9335_REG(0x0a, 0x091) +#define WCD9335_CDC_TX6_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x092) +#define WCD9335_CDC_TX6_TX_VOL_CTL WCD9335_REG(0x0a, 0x094) +#define WCD9335_CDC_TX7_TX_PATH_CTL WCD9335_REG(0x0a, 0x0a1) +#define WCD9335_CDC_TX7_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x0a2) +#define WCD9335_CDC_TX7_TX_VOL_CTL WCD9335_REG(0x0a, 0x0a4) +#define WCD9335_CDC_TX8_TX_PATH_CTL WCD9335_REG(0x0a, 0x0b1) +#define WCD9335_CDC_TX8_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x0b2) +#define WCD9335_CDC_TX8_TX_VOL_CTL WCD9335_REG(0x0a, 0x0b4) +#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0c3) +#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0c7) +#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0cb) +#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0cf) + +/* Page-11 Registers */ +#define WCD9335_PAGE11_PAGE_REGISTER WCD9335_REG(0x0b, 0x000) +#define WCD9335_CDC_COMPANDER1_CTL0 WCD9335_REG(0x0b, 0x001) +#define WCD9335_CDC_COMPANDER1_CTL(c) WCD9335_REG(0x0b, (0x001 + c * 0x8)) +#define WCD9335_CDC_COMPANDER_CLK_EN_MASK BIT(0) +#define WCD9335_CDC_COMPANDER_CLK_ENABLE BIT(0) +#define WCD9335_CDC_COMPANDER_CLK_DISABLE 0 +#define WCD9335_CDC_COMPANDER_SOFT_RST_MASK BIT(1) +#define WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE BIT(1) +#define WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE 0 +#define WCD9335_CDC_COMPANDER_HALT_MASK BIT(2) +#define WCD9335_CDC_COMPANDER_HALT BIT(2) +#define WCD9335_CDC_COMPANDER_NOHALT 0 +#define WCD9335_CDC_COMPANDER7_CTL3 WCD9335_REG(0x0b, 0x034) +#define WCD9335_CDC_COMPANDER7_CTL7 WCD9335_REG(0x0b, 0x038) +#define WCD9335_CDC_COMPANDER8_CTL3 WCD9335_REG(0x0b, 0x03c) +#define WCD9335_CDC_COMPANDER8_CTL7 WCD9335_REG(0x0b, 0x040) +#define WCD9335_CDC_RX0_RX_PATH_CTL WCD9335_REG(0x0b, 0x041) +#define WCD9335_CDC_RX_PGA_MUTE_EN_MASK BIT(4) +#define WCD9335_CDC_RX_PGA_MUTE_ENABLE BIT(4) +#define WCD9335_CDC_RX_PGA_MUTE_DISABLE 0 +#define WCD9335_CDC_RX_CLK_EN_MASK BIT(5) +#define WCD9335_CDC_RX_CLK_ENABLE BIT(5) +#define WCD9335_CDC_RX_CLK_DISABLE 0 +#define WCD9335_CDC_RX_RESET_MASK BIT(6) +#define WCD9335_CDC_RX_RESET_ENABLE BIT(6) +#define WCD9335_CDC_RX_RESET_DISABLE 0 +#define WCD9335_CDC_RX_PATH_CTL(rx) WCD9335_REG(0x0b, (0x041 + rx * 0x14)) +#define WCD9335_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x042) +#define WCD9335_CDC_RX0_RX_PATH_CFG1 WCD9335_REG(0x0b, 0x043) +#define WCD9335_CDC_RX0_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x044) +#define WCD9335_CDC_RX0_RX_VOL_CTL WCD9335_REG(0x0b, 0x045) +#define WCD9335_CDC_RX0_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x046) +#define WCD9335_CDC_MIX_PCM_RATE_MASK GENMASK(3, 0) +#define WCD9335_CDC_RX_PATH_MIX_CTL(rx) WCD9335_REG(0x0b, (0x46 + rx * 0x14)) +#define WCD9335_CDC_RX0_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x047) +#define WCD9335_CDC_RX0_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x048) +#define WCD9335_CDC_RX0_RX_PATH_SEC0 WCD9335_REG(0x0b, 0x049) +#define WCD9335_CDC_RX0_RX_PATH_SEC7 WCD9335_REG(0x0b, 0x050) +#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC0 WCD9335_REG(0x0b, 0x051) +#define WCD9335_CDC_RX1_RX_PATH_CTL WCD9335_REG(0x0b, 0x055) +#define WCD9335_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x056) +#define WCD9335_CDC_RX1_RX_PATH_CFG(c) WCD9335_REG(0x0b, (0x056 + c * 0x14)) +#define WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK BIT(1) +#define WCD9335_CDC_RX_PATH_CFG_CMP_ENABLE BIT(1) +#define WCD9335_CDC_RX_PATH_CFG_CMP_DISABLE 0 +#define WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK BIT(2) +#define WCD9335_CDC_RX_PATH_CFG_HD2_ENABLE BIT(2) +#define WCD9335_CDC_RX_PATH_CFG_HD2_DISABLE 0 +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN_MASK BIT(3) +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN BIT(3) +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_DISABLE 0 +#define WCD9335_CDC_RX1_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x058) +#define WCD9335_CDC_RX1_RX_VOL_CTL WCD9335_REG(0x0b, 0x059) +#define WCD9335_CDC_RX1_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x05a) +#define WCD9335_CDC_RX1_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x05b) +#define WCD9335_CDC_RX1_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x05c) +#define WCD9335_CDC_RX1_RX_PATH_SEC0 WCD9335_REG(0x0b, 0x05d) +#define WCD9335_CDC_RX1_RX_PATH_SEC3 WCD9335_REG(0x0b, 0x060) +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK GENMASK(1, 0) +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_2 0x1 +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_1 0 +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK GENMASK(5, 2) +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P2500 0x10 +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000 0 +#define WCD9335_CDC_RX2_RX_PATH_CTL WCD9335_REG(0x0b, 0x069) +#define WCD9335_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x06a) +#define WCD9335_CDC_RX2_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x06c) +#define WCD9335_CDC_RX2_RX_VOL_CTL WCD9335_REG(0x0b, 0x06d) +#define WCD9335_CDC_RX2_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x06e) +#define WCD9335_CDC_RX2_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x06f) +#define WCD9335_CDC_RX2_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x070) +#define WCD9335_CDC_RX2_RX_PATH_SEC0 WCD9335_REG(0x0b, 0x071) +#define WCD9335_CDC_RX_PATH_DEM_INP_SEL_MASK GENMASK(1, 0) +#define WCD9335_CDC_RX2_RX_PATH_SEC3 WCD9335_REG(0x0b, 0x074) +#define WCD9335_CDC_RX3_RX_PATH_CTL WCD9335_REG(0x0b, 0x07d) +#define WCD9335_CDC_RX3_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x07e) +#define WCD9335_CDC_RX3_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x080) +#define WCD9335_CDC_RX3_RX_VOL_CTL WCD9335_REG(0x0b, 0x081) +#define WCD9335_CDC_RX3_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x082) +#define WCD9335_CDC_RX3_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x083) +#define WCD9335_CDC_RX3_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x084) +#define WCD9335_CDC_RX4_RX_PATH_CTL WCD9335_REG(0x0b, 0x091) +#define WCD9335_CDC_RX4_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x092) +#define WCD9335_CDC_RX4_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x094) +#define WCD9335_CDC_RX4_RX_VOL_CTL WCD9335_REG(0x0b, 0x095) +#define WCD9335_CDC_RX4_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x096) +#define WCD9335_CDC_RX4_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x097) +#define WCD9335_CDC_RX4_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x098) +#define WCD9335_CDC_RX5_RX_PATH_CTL WCD9335_REG(0x0b, 0x0a5) +#define WCD9335_CDC_RX5_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0a6) +#define WCD9335_CDC_RX5_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0a8) +#define WCD9335_CDC_RX5_RX_VOL_CTL WCD9335_REG(0x0b, 0x0a9) +#define WCD9335_CDC_RX5_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0aa) +#define WCD9335_CDC_RX5_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0ab) +#define WCD9335_CDC_RX5_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0ac) +#define WCD9335_CDC_RX6_RX_PATH_CTL WCD9335_REG(0x0b, 0x0b9) +#define WCD9335_CDC_RX6_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0ba) +#define WCD9335_CDC_RX6_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0bc) +#define WCD9335_CDC_RX6_RX_VOL_CTL WCD9335_REG(0x0b, 0x0bd) +#define WCD9335_CDC_RX6_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0be) +#define WCD9335_CDC_RX6_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0bf) +#define WCD9335_CDC_RX6_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0c0) +#define WCD9335_CDC_RX7_RX_PATH_CTL WCD9335_REG(0x0b, 0x0cd) +#define WCD9335_CDC_RX7_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0ce) +#define WCD9335_CDC_RX7_RX_PATH_CFG1 WCD9335_REG(0x0b, 0x0cf) +#define WCD9335_CDC_RX7_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0d0) +#define WCD9335_CDC_RX7_RX_VOL_CTL WCD9335_REG(0x0b, 0x0d1) +#define WCD9335_CDC_RX7_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0d2) +#define WCD9335_CDC_RX7_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0d3) +#define WCD9335_CDC_RX7_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0d4) +#define WCD9335_CDC_RX8_RX_PATH_CTL WCD9335_REG(0x0b, 0x0e1) +#define WCD9335_CDC_RX8_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0e2) +#define WCD9335_CDC_RX8_RX_PATH_CFG1 WCD9335_REG(0x0b, 0x0e3) +#define WCD9335_CDC_RX8_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0e4) +#define WCD9335_CDC_RX8_RX_VOL_CTL WCD9335_REG(0x0b, 0x0e5) +#define WCD9335_CDC_RX8_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0e6) +#define WCD9335_CDC_RX8_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0e7) +#define WCD9335_CDC_RX8_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0e8) + +/* Page-12 Registers */ +#define WCD9335_PAGE12_PAGE_REGISTER WCD9335_REG(0x0c, 0x000) +#define WCD9335_CDC_CLSH_K2_MSB WCD9335_REG(0x0c, 0x00a) +#define WCD9335_CDC_CLSH_K2_LSB WCD9335_REG(0x0c, 0x00b) +#define WCD9335_CDC_BOOST0_BOOST_CTL WCD9335_REG(0x0c, 0x01a) +#define WCD9335_CDC_BOOST0_BOOST_CFG1 WCD9335_REG(0x0c, 0x01b) +#define WCD9335_CDC_BOOST0_BOOST_CFG2 WCD9335_REG(0x0c, 0x01c) +#define WCD9335_CDC_BOOST1_BOOST_CTL WCD9335_REG(0x0c, 0x022) +#define WCD9335_CDC_BOOST1_BOOST_CFG1 WCD9335_REG(0x0c, 0x023) +#define WCD9335_CDC_BOOST1_BOOST_CFG2 WCD9335_REG(0x0c, 0x024) + +/* Page-13 Registers */ +#define WCD9335_PAGE13_PAGE_REGISTER WCD9335_REG(0x0d, 0x000) +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0 WCD9335_REG(0x0d, 0x001) +#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG0(i) WCD9335_REG(0xd, (0x1 + i * 0x2)) +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1 WCD9335_REG(0xd, 0x002) +#define WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK GENMASK(3, 0) +#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(i) WCD9335_REG(0xd, (0x2 + i * 0x2)) + +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0 WCD9335_REG(0x0d, 0x003) +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1 WCD9335_REG(0x0d, 0x004) +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0 WCD9335_REG(0x0d, 0x005) +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1 WCD9335_REG(0x0d, 0x006) +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0 WCD9335_REG(0x0d, 0x007) +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1 WCD9335_REG(0x0d, 0x008) +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0 WCD9335_REG(0x0d, 0x009) +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1 WCD9335_REG(0x0d, 0x00a) +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0 WCD9335_REG(0x0d, 0x00b) +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1 WCD9335_REG(0x0d, 0x00c) +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0 WCD9335_REG(0x0d, 0x00d) +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1 WCD9335_REG(0x0d, 0x00e) +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0 WCD9335_REG(0x0d, 0x00f) +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1 WCD9335_REG(0x0d, 0x010) +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0 WCD9335_REG(0x0d, 0x011) +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1 WCD9335_REG(0x0d, 0x012) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 WCD9335_REG(0x0d, 0x01d) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 WCD9335_REG(0x0d, 0x01e) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0 WCD9335_REG(0x0d, 0x01f) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1 WCD9335_REG(0x0d, 0x020) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0 WCD9335_REG(0x0d, 0x021) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1 WCD9335_REG(0x0d, 0x022) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0 WCD9335_REG(0x0d, 0x023) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1 WCD9335_REG(0x0d, 0x024) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 WCD9335_REG(0x0d, 0x025) +#define WCD9335_CDC_TX_INP_MUX_SEL_AMIC 0x1 +#define WCD9335_CDC_TX_INP_MUX_SEL_DMIC 0 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0 WCD9335_REG(0x0d, 0x026) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0 WCD9335_REG(0x0d, 0x027) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0 WCD9335_REG(0x0d, 0x028) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0 WCD9335_REG(0x0d, 0x029) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0 WCD9335_REG(0x0d, 0x02b) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0 WCD9335_REG(0x0d, 0x02c) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0 WCD9335_REG(0x0d, 0x02d) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0 WCD9335_REG(0x0d, 0x02e) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0 WCD9335_REG(0x0d, 0x03a) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1 WCD9335_REG(0x0d, 0x03b) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2 WCD9335_REG(0x0d, 0x03c) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3 WCD9335_REG(0x0d, 0x03d) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0x0d, 0x041) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_ENABLE BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_DISABLE 0 +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL WCD9335_REG(0x0d, 0x042) +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_EN_MASK BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_ENABLE BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_DISABLE 0 +#define WCD9335_CDC_TOP_TOP_CFG1 WCD9335_REG(0x0d, 0x082) +#define WCD9335_MAX_REGISTER WCD9335_REG(0x80, 0x0FF) + +/* SLIMBUS Slave Registers */ +#define WCD9335_SLIM_PGD_PORT_INT_EN0 WCD9335_REG(0, 0x30) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0 WCD9335_REG(0, 0x34) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_1 WCD9335_REG(0, 0x35) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_0 WCD9335_REG(0, 0x36) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1 WCD9335_REG(0, 0x37) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0 WCD9335_REG(0, 0x38) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_1 WCD9335_REG(0, 0x39) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_0 WCD9335_REG(0, 0x3A) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_1 WCD9335_REG(0, 0x3B) +#define WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 WCD9335_REG(0, 0x60) +#define WCD9335_SLIM_PGD_PORT_INT_TX_SOURCE0 WCD9335_REG(0, 0x70) +#define WCD9335_SLIM_PGD_RX_PORT_CFG(p) WCD9335_REG(0, (0x30 + p)) +#define WCD9335_SLIM_PGD_PORT_CFG(p) WCD9335_REG(0, (0x40 + p)) +#define WCD9335_SLIM_PGD_TX_PORT_CFG(p) WCD9335_REG(0, (0x50 + p)) +#define WCD9335_SLIM_PGD_PORT_INT_SRC(p) WCD9335_REG(0, (0x60 + p)) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS(p) WCD9335_REG(0, (0x80 + p)) +#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x100 + 4 * p)) +/* ports range from 10-16 */ +#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_1(p) WCD9335_REG(0, (0x101 + 4 * p)) +#define WCD9335_SLIM_PGD_RX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x140 + 4 * p)) + +#endif diff --git a/include/linux/mfd/wcd9335/wcd9335.h b/include/linux/mfd/wcd9335/wcd9335.h new file mode 100644 index 000000000000..6b7fa6a66d8f --- /dev/null +++ b/include/linux/mfd/wcd9335/wcd9335.h @@ -0,0 +1,40 @@ +#ifndef __WCD9335_H__ +#define __WCD9335_H__ + +#include +#include + +#define WCD9335_VERSION_1_0 0 +#define WCD9335_VERSION_1_1 1 +#define WCD9335_VERSION_2_0 2 +#define WCD9335_IS_1_0(ver) \ + ((ver == WCD9335_VERSION_1_0) ? 1 : 0) +#define WCD9335_IS_1_1(ver) \ + ((ver == WCD9335_VERSION_1_1) ? 1 : 0) +#define WCD9335_IS_2_0(ver) \ + ((ver == WCD9335_VERSION_2_0) ? 1 : 0) + +enum wcd_interface_type { + WCD9335_INTERFACE_TYPE_SLIMBUS = 1, + WCD9335_INTERFACE_TYPE_I2C, +}; + +#define WCD9335_MAX_SUPPLY 5 + +struct wcd9335 { + int version; + int intr1; + int reset_gpio; + enum wcd_interface_type intf_type; + struct device *dev; + struct clk *mclk; + struct clk *native_clk; + struct slim_device *slim; + struct slim_device *slim_ifd; + struct regmap *regmap; + struct regmap *ifd_regmap; + struct regmap_irq_chip_data *irq_data; + struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; +}; + +#endif /* __WCD9335_H__ */ From patchwork Mon Jul 23 15:54:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540539 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 01DBF157A for ; Mon, 23 Jul 2018 15:58:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E353028CDC for ; Mon, 23 Jul 2018 15:58:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D633F28CF3; Mon, 23 Jul 2018 15:58:42 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8A3A428CDC for ; Mon, 23 Jul 2018 15:58:41 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 6AB6F26720C; Mon, 23 Jul 2018 17:58:26 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 9AA71267715; Mon, 23 Jul 2018 17:58:22 +0200 (CEST) Received: from mail-wm0-f66.google.com (mail-wm0-f66.google.com [74.125.82.66]) by alsa0.perex.cz (Postfix) with ESMTP id 4350026763A for ; Mon, 23 Jul 2018 17:58:19 +0200 (CEST) Received: by mail-wm0-f66.google.com with SMTP id o18-v6so1766425wmc.0 for ; Mon, 23 Jul 2018 08:58:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tvUxwhCKq75M5Kj5g6KwaXItwimpitViFd9VBJeELCI=; b=VkSKfskWzoJ63aoca2AoE4+hjgoJzJT/YY2fo0/KnbRZdWCaj2InuuYTC4m8I4Z0I5 sPqbe1slveN2aw64H2/ahXEndcaMLZpK32hjatKeTQkgSScZjrktTzqm6o+Jsa3daRL6 HMZGR0CJyqBO8/h1yYlPb0pjyP0jD9QI9ocQI= 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=tvUxwhCKq75M5Kj5g6KwaXItwimpitViFd9VBJeELCI=; b=oDLueenFbbFTh3LZ35cEJr50XBmJEg54MmhsmrWZrPtzNgKVMzAzyCBwhXuL7Du/LB vXBf/D/7huJbJ7C5MVhdxpyu2cDxpVH6T5gMdr85S1PyQ2UJnLjJxW9sXyqIM92eAsZB CZCf94pKsLvfXt0rgHwJJ0onqAtgQ+vO5yH9/z9f8AFYsBYxv2BLa/amogDBKmzmMxTG 4i5XE9P/BS13P2p1uT4XhdXglgjtDV/UBmmgp9ivat8CG+7FIXHZ2lq0AjBhjQw1WvBx I2iZ8MhvpbzCW0MZ0cKNPUENnzGEd2yoHoMjapTSmCPIblbvOpgdISvjSVY60uSCS+oA rYWg== X-Gm-Message-State: AOUpUlET3Cvb3lfENa6It2Hc8I7jHfl4NtOJxhVth3HvMhGfEZ0wpZB0 YcQ5k8nWxiye3V8oVr+OF+UzBA== X-Google-Smtp-Source: AAOMgpfPt8Sk0P+zmH3F/RVLa+uupLCPiyx+t0GAGsDI7v/GWtJkFnp4BLfWMqRP8XOZhNPZnV9o2A== X-Received: by 2002:a1c:19c2:: with SMTP id 185-v6mr7740747wmz.79.1532361499379; Mon, 23 Jul 2018 08:58:19 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:18 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:01 +0100 Message-Id: <20180723155410.9494-4-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 03/12] mfd: wcd9335: add wcd irq support X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP WCD9335 supports two lines of irqs INTR1 and INTR2. Mutiple interrupts are muxed via these lines. INTR1 consists of all possible interrupt sources like: Ear OCP, HPH OCP, MBHC, MAD, VBAT, and SVA INTR2 is a subset of first interrupt sources like MAD, VBAT, and SVA Signed-off-by: Srinivas Kandagatla --- drivers/mfd/Makefile | 2 +- drivers/mfd/wcd9335-core.c | 9 ++ drivers/mfd/wcd9335-irq.c | 172 ++++++++++++++++++++++++++++++++++++ include/dt-bindings/mfd/wcd9335.h | 43 +++++++++ include/linux/mfd/wcd9335/wcd9335.h | 3 + 5 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 drivers/mfd/wcd9335-irq.c create mode 100644 include/dt-bindings/mfd/wcd9335.h diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index a4697370640b..210875afe78a 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_MFD_ARIZONA) += cs47l24-tables.o endif obj-$(CONFIG_MFD_WCD9335) += wcd9335.o -wcd9335-objs := wcd9335-core.o +wcd9335-objs := wcd9335-core.o wcd9335-irq.o obj-$(CONFIG_MFD_WM8400) += wm8400-core.o wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o diff --git a/drivers/mfd/wcd9335-core.c b/drivers/mfd/wcd9335-core.c index ccdd27c3a351..7d478d87e16f 100644 --- a/drivers/mfd/wcd9335-core.c +++ b/drivers/mfd/wcd9335-core.c @@ -244,12 +244,20 @@ static int wcd9335_slim_status(struct slim_device *sdev, return ret; } + wcd9335_irq_init(wcd); wcd->slim_ifd = wcd->slim_ifd; return mfd_add_devices(wcd->dev, 0, wcd9335_devices, ARRAY_SIZE(wcd9335_devices), NULL, 0, NULL); } +static void wcd9335_slim_remove(struct slim_device *sdev) +{ + struct wcd9335 *wcd = dev_get_drvdata(&sdev->dev); + + wcd9335_irq_exit(wcd); +} + static const struct slim_device_id wcd9335_slim_id[] = { {0x217, 0x1a0, 0x1, 0x0}, {} @@ -260,6 +268,7 @@ static struct slim_driver wcd9335_slim_driver = { .name = "wcd9335-slim", }, .probe = wcd9335_slim_probe, + .remove = wcd9335_slim_remove, .device_status = wcd9335_slim_status, .id_table = wcd9335_slim_id, }; diff --git a/drivers/mfd/wcd9335-irq.c b/drivers/mfd/wcd9335-irq.c new file mode 100644 index 000000000000..84098c89419b --- /dev/null +++ b/drivers/mfd/wcd9335-irq.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, Linaro Limited +// +#include +#include +#include +#include +#include +#include +#include + +static const struct regmap_irq wcd9335_irqs[] = { + /* INTR_REG 0 */ + [WCD9335_IRQ_SLIMBUS] = { + .reg_offset = 0, + .mask = BIT(0), + }, + [WCD9335_IRQ_FLL_LOCK_LOSS] = { + .reg_offset = 0, + .mask = BIT(1), + }, + [WCD9335_IRQ_HPH_PA_OCPL_FAULT] = { + .reg_offset = 0, + .mask = BIT(2), + }, + [WCD9335_IRQ_HPH_PA_OCPR_FAULT] = { + .reg_offset = 0, + .mask = BIT(3), + }, + [WCD9335_IRQ_EAR_PA_OCP_FAULT] = { + .reg_offset = 0, + .mask = BIT(4), + }, + [WCD9335_IRQ_HPH_PA_CNPL_COMPLETE] = { + .reg_offset = 0, + .mask = BIT(5), + }, + [WCD9335_IRQ_HPH_PA_CNPR_COMPLETE] = { + .reg_offset = 0, + .mask = BIT(6), + }, + [WCD9335_IRQ_EAR_PA_CNP_COMPLETE] = { + .reg_offset = 0, + .mask = BIT(7), + }, + /* INTR_REG 1 */ + [WCD9335_IRQ_MBHC_SW_DET] = { + .reg_offset = 1, + .mask = BIT(0), + }, + [WCD9335_IRQ_MBHC_ELECT_INS_REM_DET] = { + .reg_offset = 1, + .mask = BIT(1), + }, + [WCD9335_IRQ_MBHC_BUTTON_PRESS_DET] = { + .reg_offset = 1, + .mask = BIT(2), + }, + [WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET] = { + .reg_offset = 1, + .mask = BIT(3), + }, + [WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET] = { + .reg_offset = 1, + .mask = BIT(4), + }, + /* INTR_REG 2 */ + [WCD9335_IRQ_LINE_PA1_CNP_COMPLETE] = { + .reg_offset = 2, + .mask = BIT(0), + }, + [WCD9335_IRQ_LINE_PA2_CNP_COMPLETE] = { + .reg_offset = 2, + .mask = BIT(1), + }, + [WCD9335_IRQ_LINE_PA3_CNP_COMPLETE] = { + .reg_offset = 2, + .mask = BIT(2), + }, + [WCD9335_IRQ_LINE_PA4_CNP_COMPLETE] = { + .reg_offset = 2, + .mask = BIT(3), + }, + [WCD9335_IRQ_SOUNDWIRE] = { + .reg_offset = 2, + .mask = BIT(4), + }, + [WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE] = { + .reg_offset = 2, + .mask = BIT(5), + }, + [WCD9335_IRQ_RCO_ERROR] = { + .reg_offset = 2, + .mask = BIT(6), + }, + [WCD9335_IRQ_SVA_ERROR] = { + .reg_offset = 2, + .mask = BIT(7), + }, + /* INTR_REG 3 */ + [WCD9335_IRQ_MAD_AUDIO] = { + .reg_offset = 3, + .mask = BIT(0), + }, + [WCD9335_IRQ_MAD_BEACON] = { + .reg_offset = 3, + .mask = BIT(1), + }, + [WCD9335_IRQ_MAD_ULTRASOUND] = { + .reg_offset = 3, + .mask = BIT(2), + }, + [WCD9335_IRQ_VBAT_ATTACK] = { + .reg_offset = 3, + .mask = BIT(3), + }, + [WCD9335_IRQ_VBAT_RESTORE] = { + .reg_offset = 3, + .mask = BIT(4), + }, + [WCD9335_IRQ_SVA_OUTBOX1] = { + .reg_offset = 3, + .mask = BIT(5), + }, + [WCD9335_IRQ_SVA_OUTBOX2] = { + .reg_offset = 3, + .mask = BIT(6), + }, +}; + +static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = { + .name = "wcd9335_pin1_irq", + .status_base = WCD9335_INTR_PIN1_STATUS0, + .mask_base = WCD9335_INTR_PIN1_MASK0, + .ack_base = WCD9335_INTR_PIN1_CLEAR0, + .type_base = WCD9335_INTR_LEVEL0, + .num_regs = 4, + .irqs = wcd9335_irqs, + .num_irqs = ARRAY_SIZE(wcd9335_irqs), +}; + +int wcd9335_irq_init(struct wcd9335 *wcd) +{ + int ret; + /* + * INTR1 consists of all possible interrupt sources Ear OCP, + * HPH OCP, MBHC, MAD, VBAT, and SVA + * INTR2 is a subset of first interrupt sources MAD, VBAT, and SVA + */ + wcd->intr1 = of_irq_get_byname(wcd->dev->of_node, "intr1"); + if (wcd->intr1 < 0 || wcd->intr1 == -EPROBE_DEFER) { + dev_err(wcd->dev, "Unable to configure irq\n"); + return wcd->intr1; + } + + ret = regmap_add_irq_chip(wcd->regmap, wcd->intr1, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + 0, &wcd9335_regmap_irq1_chip, + &wcd->irq_data); + if (ret != 0) { + dev_err(wcd->dev, "Failed to register IRQ chip: %d\n", ret); + return ret; + } + + return 0; +} + +int wcd9335_irq_exit(struct wcd9335 *wcd) +{ + regmap_del_irq_chip(wcd->intr1, wcd->irq_data); + return 0; +} diff --git a/include/dt-bindings/mfd/wcd9335.h b/include/dt-bindings/mfd/wcd9335.h new file mode 100644 index 000000000000..17f985be8f52 --- /dev/null +++ b/include/dt-bindings/mfd/wcd9335.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides macros for WCD9335 device bindings. + * + * Copyright (c) 2018, Linaro Limited + */ + +#ifndef _DT_BINDINGS_MFD_WCD9335_H +#define _DT_BINDINGS_MFD_WCD9335_H + +#define WCD9335_IRQ_SLIMBUS 1 +#define WCD9335_IRQ_FLL_LOCK_LOSS 2 +#define WCD9335_IRQ_HPH_PA_OCPL_FAULT 3 +#define WCD9335_IRQ_HPH_PA_OCPR_FAULT 4 +#define WCD9335_IRQ_EAR_PA_OCP_FAULT 5 +#define WCD9335_IRQ_HPH_PA_CNPL_COMPLETE 6 +#define WCD9335_IRQ_HPH_PA_CNPR_COMPLETE 7 +#define WCD9335_IRQ_EAR_PA_CNP_COMPLETE 8 +#define WCD9335_IRQ_MBHC_SW_DET 9 +#define WCD9335_IRQ_MBHC_ELECT_INS_REM_DET 10 +#define WCD9335_IRQ_MBHC_BUTTON_PRESS_DET 11 +#define WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET 12 +#define WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET 13 +#define WCD9335_IRQ_RESERVED_0 14 +#define WCD9335_IRQ_RESERVED_1 15 +#define WCD9335_IRQ_RESERVED_2 16 +#define WCD9335_IRQ_LINE_PA1_CNP_COMPLETE 17 +#define WCD9335_IRQ_LINE_PA2_CNP_COMPLETE 18 +#define WCD9335_IRQ_LINE_PA3_CNP_COMPLETE 19 +#define WCD9335_IRQ_LINE_PA4_CNP_COMPLETE 20 +#define WCD9335_IRQ_SOUNDWIRE 21 +#define WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE 22 +#define WCD9335_IRQ_RCO_ERROR 23 +#define WCD9335_IRQ_SVA_ERROR 24 +#define WCD9335_IRQ_MAD_AUDIO 25 +#define WCD9335_IRQ_MAD_BEACON 26 +#define WCD9335_IRQ_MAD_ULTRASOUND 27 +#define WCD9335_IRQ_VBAT_ATTACK 28 +#define WCD9335_IRQ_VBAT_RESTORE 29 +#define WCD9335_IRQ_SVA_OUTBOX1 30 +#define WCD9335_IRQ_SVA_OUTBOX2 31 + +#endif /* _DT_BINDINGS_MFD_WCD9335_H */ diff --git a/include/linux/mfd/wcd9335/wcd9335.h b/include/linux/mfd/wcd9335/wcd9335.h index 6b7fa6a66d8f..ac0853625c72 100644 --- a/include/linux/mfd/wcd9335/wcd9335.h +++ b/include/linux/mfd/wcd9335/wcd9335.h @@ -37,4 +37,7 @@ struct wcd9335 { struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; }; +extern int wcd9335_irq_init(struct wcd9335 *wcd); +extern int wcd9335_irq_exit(struct wcd9335 *wcd); + #endif /* __WCD9335_H__ */ From patchwork Mon Jul 23 15:54:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540543 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 31EF413BB for ; Mon, 23 Jul 2018 15:59:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 209F328CDC for ; Mon, 23 Jul 2018 15:59:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 14C9A28CF8; Mon, 23 Jul 2018 15:59:02 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6C97128CDC for ; Mon, 23 Jul 2018 15:59:01 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 9B3C426776E; Mon, 23 Jul 2018 17:58:31 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 660D6267715; Mon, 23 Jul 2018 17:58:23 +0200 (CEST) Received: from mail-wm0-f67.google.com (mail-wm0-f67.google.com [74.125.82.67]) by alsa0.perex.cz (Postfix) with ESMTP id 695742676D4 for ; Mon, 23 Jul 2018 17:58:20 +0200 (CEST) Received: by mail-wm0-f67.google.com with SMTP id n11-v6so1727271wmc.2 for ; Mon, 23 Jul 2018 08:58:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=PuBAy/+QqrCI6FlnCJX4HOLVTirOiWLuNBsfvVcjRB0=; b=dKMlPkvbOJYv+A5nYLv+IO62ZVyHDbfAB/DBMyYRaTFbeXFYzA0aWP8CjvpKT8K+PB pe/UHvo6In/wbUuFBa68IpUS3yD7PsCijKbHh3gXPvaRlLf227k11QnoCW1mSINYQI0t A5iRHoCMWgFGSQG8fvui+jESIA4mglHwNjHiM= 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=PuBAy/+QqrCI6FlnCJX4HOLVTirOiWLuNBsfvVcjRB0=; b=cdDdtz37c64sPAPljs6K61el4GT9Iy6ZEBrbhjp70mGbopv2/i/cpJL+9wlTBc+XNt 0vdy+qe7WCH0+QUNSWAB3YHqV2MpUoKbWiqFbehJrXwCNtHwzKFWBgilDWF3L0kC6oAU Nv0JRs+O24DDPoEWlYw3DIHc5CrO325vMVEkCU0IFkAqgZVMJ8HadDn8bcrRk/XDGErI WxtzvTssU1Twq4iSD78E48L7TxX5St+8V2iGYJW53Fd+eujXIbU/CcYqJG9V4laiw7Gx kkwYSD3njIC/56lTnkRxy/jXujzcIDUGm/LarfaHptHLuHjLwSlkTP/nlG7KLUpCyfzC QDyQ== X-Gm-Message-State: AOUpUlFFKusYMgTN0QbSqhEPxbesZoNHGo4XZrROPHcax+laFlx04Y6L C6JeEG3GAAVKL0EcYewN55mA3g== X-Google-Smtp-Source: AAOMgpe/yhsYs2V1Zy0jAGNbUtf2iwF2I4pgtLhRjuXtbeD9jJC0kOd3He5/E6tg53Gd5ut7vftGKg== X-Received: by 2002:a1c:c3c4:: with SMTP id t187-v6mr8344054wmf.123.1532361500407; Mon, 23 Jul 2018 08:58:20 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:19 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:02 +0100 Message-Id: <20180723155410.9494-5-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 04/12] ASoC: dt-bindings: add dt bindings for wcd9335 audio codec X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds bindings for wcd9335 audio codec which can support both SLIMbus and I2S/I2C interface. Signed-off-by: Srinivas Kandagatla --- .../devicetree/bindings/sound/qcom,wcd9335.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd9335.txt diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt new file mode 100644 index 000000000000..55fcf7504fe1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt @@ -0,0 +1,21 @@ +QCOM WCD9335 Audio Codec + +Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC, +It supports both I2S/I2C and SLIMbus audio interfaces. + +- compatible: + Usage: required + Value type: + Definition: "qcom,wcd9335-codec" + +- #sound-dai-cells + Usage: required + Value type: + Definition: Must be 1 + += EXAMPLE + +codec { + compatible = "qcom,wcd9335-codec"; + #sound-dai-cells = <1>; +}; From patchwork Mon Jul 23 15:54:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540545 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A653613BB for ; Mon, 23 Jul 2018 15:59:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 93F4B28CDC for ; Mon, 23 Jul 2018 15:59:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 87D1728CF3; Mon, 23 Jul 2018 15:59:10 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D648528CDC for ; Mon, 23 Jul 2018 15:59:09 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 412FE267763; Mon, 23 Jul 2018 17:58:33 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id D7D28267749; Mon, 23 Jul 2018 17:58:23 +0200 (CEST) Received: from mail-wm0-f66.google.com (mail-wm0-f66.google.com [74.125.82.66]) by alsa0.perex.cz (Postfix) with ESMTP id 32CCA26720C for ; Mon, 23 Jul 2018 17:58:21 +0200 (CEST) Received: by mail-wm0-f66.google.com with SMTP id s9-v6so1632909wmh.3 for ; Mon, 23 Jul 2018 08:58:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=CzBFjPKScoyq8BRqzbqfUtYN9SRCEjh94Gk9yR48PY4=; b=Exd/jRYCdnfSbligYmk3crjO2fB9cN2/GDgfJ4B1iopHDyR02iJBZn4XjbvO+G1ARe 6Y/x4boHJ7ODa2Ilws/+HexkfYAMmNj61kr1vlEE4I2Ih9Nc0qRqiWcaw5kKHPHp3rj5 WLCKWFhVYOrADM+CkOID6mX6r/I9zpbsKoN2M= 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=CzBFjPKScoyq8BRqzbqfUtYN9SRCEjh94Gk9yR48PY4=; b=mybOT8zP/3nZYL5HK2nGg2eTXGF+2QTt1lAR73DpL9PIzspW0pPd6ucAC8g2u4CvEX qm518LDmj3HM7yXAVysbrT1GnsbwU6lVTLKo17O2mT/YsWuDDQI8Ecvs0Ni2kU/Nfg4V d8u1q1Vbc4B5dAeRzhS7+VRHMqfzE0aXl5nVUEyivUG5mv0tlU+iA8jWZs5I8A4si4wJ qiQCn0pkooS/oRXAYRERaLbBJK+f6OBzs9vatgfOqcLVkUyjMMeGf7plvIS8UciVJztT 2lokjNleIxP5lZVzvgK8dxqmAsgwKwJxqJ59kfHdAjuRlFQmGFaQ0cs8Dy+PTvamFWln lvBA== X-Gm-Message-State: AOUpUlF9xtcgIN+/F9vS7c3cIli9RhVCQwKgZDgziueQLIcbvqt6DoH0 OnmuRwMb7LvKOJPvEPqPrYYuf4Te/Js= X-Google-Smtp-Source: AAOMgpdAoFdtunQpKzD4ENl3qlOWLmmLeTFznKqG8/wb/3yfFst00xxEsULR6wuGRmT+cYPBPK/WIA== X-Received: by 2002:a1c:93d3:: with SMTP id v202-v6mr8084643wmd.57.1532361501376; Mon, 23 Jul 2018 08:58:21 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:20 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:03 +0100 Message-Id: <20180723155410.9494-6-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 05/12] ASoC: core: add support to snd_soc_dai_get_channel_map() X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP On Qualcomm platforms, specifically with SLIMbus interfaced codecs, the codec slim channel numbers are passed to DSP while configuring the slim audio path. Having get_channel_map() would allow dais to share such information across multiple dais. Signed-off-by: Srinivas Kandagatla --- include/sound/soc-dai.h | 8 ++++++++ sound/soc/soc-core.c | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index a14bc0608ae9..f5d70041108f 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -138,6 +138,11 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, int direction); + +int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot); + int snd_soc_dai_is_dummy(struct snd_soc_dai *dai); struct snd_soc_dai_ops { @@ -165,6 +170,9 @@ struct snd_soc_dai_ops { int (*set_channel_map)(struct snd_soc_dai *dai, unsigned int tx_num, unsigned int *tx_slot, unsigned int rx_num, unsigned int *rx_slot); + int (*get_channel_map)(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot); int (*set_tristate)(struct snd_soc_dai *dai, int tristate); int (*set_sdw_stream)(struct snd_soc_dai *dai, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ad5b0ef16d82..81b27923303d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2679,6 +2679,28 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); +/** + * snd_soc_dai_get_channel_map - Get DAI audio channel map + * @dai: DAI + * @tx_num: how many TX channels + * @tx_slot: pointer to an array which imply the TX slot number channel + * 0~num-1 uses + * @rx_num: how many RX channels + * @rx_slot: pointer to an array which imply the RX slot number channel + * 0~num-1 uses + */ +int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + if (dai->driver->ops->get_channel_map) + return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot, + rx_num, rx_slot); + else + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map); + /** * snd_soc_dai_set_tristate - configure DAI system or master clock. * @dai: DAI From patchwork Mon Jul 23 15:54:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540547 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 75AD6157A for ; Mon, 23 Jul 2018 15:59:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5EC6128CDC for ; Mon, 23 Jul 2018 15:59:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5053B28CF3; Mon, 23 Jul 2018 15:59:21 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2B34628CDC for ; Mon, 23 Jul 2018 15:59:19 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 110772677A3; Mon, 23 Jul 2018 17:58:37 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 67412267759; Mon, 23 Jul 2018 17:58:26 +0200 (CEST) Received: from mail-wm0-f66.google.com (mail-wm0-f66.google.com [74.125.82.66]) by alsa0.perex.cz (Postfix) with ESMTP id 8B33226720C for ; Mon, 23 Jul 2018 17:58:23 +0200 (CEST) Received: by mail-wm0-f66.google.com with SMTP id l2-v6so10097092wme.1 for ; Mon, 23 Jul 2018 08:58:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=v5h/EoiNgL6W02eN9S3DcYhytYAJJgEYLwY9r3XrslQ=; b=fRNC0Zgt4Qrq8ZYpekSuVmPTtN7nmVIsIAJi0j7A3/Emg7T2uCv3jFfX6PPPF/xxSC eXHRfcegDP10d2xOt+a7JHAn43TazzvzYMPxL7mVeR2DMH9O8hrMTw56+olh8aaxoBgy +emt2kpcxbI9MHkrMiRivOvHwcClWJ/c3Xc9M= 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=v5h/EoiNgL6W02eN9S3DcYhytYAJJgEYLwY9r3XrslQ=; b=jPShrHIrxmjKC1UWo1Ou2p/mSREUf5hBuYZVdXps6Ep6A1xSSXLhmdx6fK3QPgv/mk Jh2VV3BSCoFPwuunIJQWQQWzUVqPVSjscS19gIAUBzm7sb58y386tvk4Joa7g/rBYW/c inPCtYmTjjv8Yz6rZN7xk9s7LgwgObI2fr4FNEvqUM13VDKXjXDK5AKbVa3X8+RoFnH2 9g2ZALw37LQ05h7qsBw3OfF8TWop1QnToXtecwdAUMeKdOuPkc3mg8YxW/BByQ8pqRt7 kuMQ/afOMnJbLUFs15btgXB1htB90Qx7a9ea1VNEjys18H77Z2xFDOMtcIWWWY9Bdk5J AEfg== X-Gm-Message-State: AOUpUlE/0ttTIEBIi/Ow7pErxza+OuArVM3fO2mOmRSrzuqvf3Fr/9lh tJLNv1AhjsQWmvgtnx6YMzcuoQ== X-Google-Smtp-Source: AAOMgpf5CuXFrIVzAfbUxImO297FEXtaySg14OKc2Eiicp9xzlQFoXV3Wn2qaU8ikYd4gEN0cZQMxA== X-Received: by 2002:a1c:ad50:: with SMTP id w77-v6mr8257785wme.54.1532361502618; Mon, 23 Jul 2018 08:58:22 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:22 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:04 +0100 Message-Id: <20180723155410.9494-7-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 06/12] ASoC: wcd9335: add support to wcd9335 codec X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC, It supports both I2S/I2C and SLIMbus audio interfaces. On slimbus interface it supports two data lanes; 16 Tx ports and 8 Rx ports. It has Seven DACs and nine dedicated interpolators, Seven (six audio ADCs, and one VBAT ADC), Multibutton headset control (MBHC), Active noise cancellation and Sidetone paths and processing. This patchset adds very basic support for playback and capture via the 9 interpolators and ADC respectively. Signed-off-by: Srinivas Kandagatla --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wcd9335.c | 1160 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1167 insertions(+) create mode 100644 sound/soc/codecs/wcd9335.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efb095dbcd71..cb09abf18dde 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1066,6 +1066,11 @@ config SND_SOC_UDA1380 tristate depends on I2C +config SND_SOC_WCD9335 + tristate "WCD9335 Codec" + depends on MFD_WCD9335 + tristate + config SND_SOC_WL1273 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7ae7c85e8219..01410b63daac 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -192,6 +192,7 @@ snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o +snd-soc-wcd9335-objs := wcd9335.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o @@ -451,6 +452,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o +obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c new file mode 100644 index 000000000000..307672b8d188 --- /dev/null +++ b/sound/soc/codecs/wcd9335.c @@ -0,0 +1,1160 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +// Copyright (c) 2017-2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +/* Fractional Rates */ +#define WCD9335_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100) +#define WCD9335_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +/* slave port water mark level + * (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes) + */ +#define SLAVE_PORT_WATER_MARK_6BYTES 0 +#define SLAVE_PORT_WATER_MARK_9BYTES 1 +#define SLAVE_PORT_WATER_MARK_12BYTES 2 +#define SLAVE_PORT_WATER_MARK_15BYTES 3 +#define SLAVE_PORT_WATER_MARK_SHIFT 1 +#define SLAVE_PORT_ENABLE 1 +#define SLAVE_PORT_DISABLE 0 +#define WCD9335_SLIM_WATER_MARK_VAL \ + ((SLAVE_PORT_WATER_MARK_12BYTES << SLAVE_PORT_WATER_MARK_SHIFT) | \ + (SLAVE_PORT_ENABLE)) + +#define WCD9335_SLIM_NUM_PORT_REG 3 +#define WCD9335_SLIM_PGD_PORT_INT_TX_EN0 (WCD9335_SLIM_PGD_PORT_INT_EN0 + 2) + +#define WCD9335_MCLK_CLK_12P288MHZ 12288000 +#define WCD9335_MCLK_CLK_9P6MHZ 9600000 + +#define WCD9335_SLIM_CLOSE_TIMEOUT 1000 +#define WCD9335_SLIM_IRQ_OVERFLOW (1 << 0) +#define WCD9335_SLIM_IRQ_UNDERFLOW (1 << 1) +#define WCD9335_SLIM_IRQ_PORT_CLOSED (1 << 2) + +#define WCD9335_NUM_INTERPOLATORS 9 +#define WCD9335_RX_START 16 +#define WCD9335_SLIM_CH_START 128 + +#define WCD9335_SLIM_RX_CH(p) \ + {.port = p + WCD9335_RX_START, .shift = p,} + +/* vout step value */ +#define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) + +enum { + WCD9335_RX0 = 0, + WCD9335_RX1, + WCD9335_RX2, + WCD9335_RX3, + WCD9335_RX4, + WCD9335_RX5, + WCD9335_RX6, + WCD9335_RX7, + WCD9335_RX8, + WCD9335_RX9, + WCD9335_RX10, + WCD9335_RX11, + WCD9335_RX12, + WCD9335_RX_MAX, +}; + +enum { + SIDO_SOURCE_INTERNAL = 0, + SIDO_SOURCE_RCO_BG, +}; + +enum wcd9335_sido_voltage { + SIDO_VOLTAGE_SVS_MV = 950, + SIDO_VOLTAGE_NOMINAL_MV = 1100, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + AIF2_PB, + AIF2_CAP, + AIF3_PB, + AIF3_CAP, + AIF4_PB, + NUM_CODEC_DAIS, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, + INTn_2_INP_SEL_RX6, + INTn_2_INP_SEL_RX7, + INTn_2_INP_SEL_PROXIMITY, +}; + +enum { + INTn_1_MIX_INP_SEL_ZERO = 0, + INTn_1_MIX_INP_SEL_DEC0, + INTn_1_MIX_INP_SEL_DEC1, + INTn_1_MIX_INP_SEL_IIR0, + INTn_1_MIX_INP_SEL_IIR1, + INTn_1_MIX_INP_SEL_RX0, + INTn_1_MIX_INP_SEL_RX1, + INTn_1_MIX_INP_SEL_RX2, + INTn_1_MIX_INP_SEL_RX3, + INTn_1_MIX_INP_SEL_RX4, + INTn_1_MIX_INP_SEL_RX5, + INTn_1_MIX_INP_SEL_RX6, + INTn_1_MIX_INP_SEL_RX7, + +}; + +enum wcd_clock_type { + WCD_CLK_OFF, + WCD_CLK_RCO, + WCD_CLK_MCLK, +}; + +struct wcd9335_slim_ch { + u32 ch_num; + u16 port; + u16 shift; + struct list_head list; +}; + +struct wcd_slim_codec_dai_data { + struct list_head slim_ch_list; + struct slim_stream_config sconfig; + struct slim_stream_runtime *sruntime; +}; + +struct wcd9335_codec { + struct device *dev; + struct clk *mclk; + struct clk *native_clk; + u32 mclk_rate; + u8 intf_type; + u8 version; + + struct slim_device *slim; + struct slim_device *slim_ifd; + struct regmap *regmap; + struct regmap *if_regmap; + struct regmap_irq_chip_data *irq_data; + + struct wcd9335_slim_ch rx_chs[WCD9335_RX_MAX]; + u32 num_rx_port; + + int sido_input_src; + enum wcd9335_sido_voltage sido_voltage; + + struct wcd_slim_codec_dai_data dai[NUM_CODEC_DAIS]; + struct snd_soc_component *component; + + int master_bias_users; + int clk_mclk_users; + int clk_rco_users; + int sido_ccl_cnt; + enum wcd_clock_type clk_type; + + u32 hph_mode; +}; + +static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = { + WCD9335_SLIM_RX_CH(0), /* 16 */ + WCD9335_SLIM_RX_CH(1), /* 17 */ + WCD9335_SLIM_RX_CH(2), + WCD9335_SLIM_RX_CH(3), + WCD9335_SLIM_RX_CH(4), + WCD9335_SLIM_RX_CH(5), + WCD9335_SLIM_RX_CH(6), + WCD9335_SLIM_RX_CH(7), + WCD9335_SLIM_RX_CH(8), + WCD9335_SLIM_RX_CH(9), + WCD9335_SLIM_RX_CH(10), + WCD9335_SLIM_RX_CH(11), + WCD9335_SLIM_RX_CH(12), +}; + +struct interp_sample_rate { + int rate; + int rate_val; +}; + +static struct interp_sample_rate int_mix_rate_val[] = { + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ +}; + +static struct interp_sample_rate int_prim_rate_val[] = { + {8000, 0x0}, /* 8K */ + {16000, 0x1}, /* 16K */ + {24000, -EINVAL},/* 24K */ + {32000, 0x3}, /* 32K */ + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ + {384000, 0x7}, /* 384K */ + {44100, 0x8}, /* 44.1K */ +}; + +struct wcd9335_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init_val_2_0[] = { + {WCD9335_RCO_CTRL_2, 0x0F, 0x08}, + {WCD9335_RX_BIAS_FLYB_MID_RST, 0xF0, 0x10}, + {WCD9335_FLYBACK_CTRL_1, 0x20, 0x20}, + {WCD9335_HPH_OCP_CTL, 0xFF, 0x5A}, + {WCD9335_HPH_L_TEST, 0x01, 0x01}, + {WCD9335_HPH_R_TEST, 0x01, 0x01}, + {WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12}, + {WCD9335_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x1E, 0x18}, + {WCD9335_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12}, + {WCD9335_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x1E, 0x18}, + {WCD9335_CDC_TX0_TX_PATH_SEC7, 0xFF, 0x45}, + {WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02}, +}; + +static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init_common_val[] = { + /* Rbuckfly/R_EAR(32) */ + {WCD9335_CDC_CLSH_K2_MSB, 0x0F, 0x00}, + {WCD9335_CDC_CLSH_K2_LSB, 0xFF, 0x60}, + {WCD9335_CPE_SS_DMIC_CFG, 0x80, 0x00}, + {WCD9335_CDC_BOOST0_BOOST_CTL, 0x70, 0x50}, + {WCD9335_CDC_BOOST1_BOOST_CTL, 0x70, 0x50}, + {WCD9335_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08}, + {WCD9335_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08}, + {WCD9335_ANA_LO_1_2, 0x3C, 0X3C}, + {WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x70, 0x00}, + {WCD9335_DIFF_LO_COM_PA_FREQ, 0x70, 0x40}, + {WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03}, + {WCD9335_CDC_TOP_TOP_CFG1, 0x02, 0x02}, + {WCD9335_CDC_TOP_TOP_CFG1, 0x01, 0x01}, + {WCD9335_EAR_CMBUFF, 0x08, 0x00}, + {WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01}, + {WCD9335_CDC_RX0_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX1_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX2_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX3_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX4_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX5_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX6_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX7_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX8_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_VBADC_IBIAS_FE, 0x0C, 0x08}, +}; + +static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, + int rate_val, + u32 rate) +{ + struct snd_soc_component *component = dai->component; + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + struct wcd9335_slim_ch *ch; + int val, j; + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) { + for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) { + val = snd_soc_component_read32(component, + WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(j)) & + WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + + if (val == (ch->shift + INTn_2_INP_SEL_RX0)) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX_PATH_MIX_CTL(j), + WCD9335_CDC_MIX_PCM_RATE_MASK, + rate_val); + } + } + + return 0; +} + +static int wcd9335_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_val, + u32 rate) +{ + struct snd_soc_component *comp = dai->component; + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + struct wcd9335_slim_ch *ch; + u8 cfg0, cfg1, inp0_sel, inp1_sel, inp2_sel; + int inp, j; + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) { + inp = ch->shift + INTn_1_MIX_INP_SEL_RX0; + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the slim rx port + * is connected + */ + for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) { + cfg0 = snd_soc_component_read32(comp, + WCD9335_CDC_RX_INP_MUX_RX_INT_CFG0(j)); + cfg1 = snd_soc_component_read32(comp, + WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(j)); + + inp0_sel = cfg0 & WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + inp1_sel = (cfg0 >> 4) & WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + inp2_sel = (cfg1 >> 4) & WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + + if ((inp0_sel == inp) || (inp1_sel == inp) || + (inp2_sel == inp)) { + /* rate is in Hz */ + if ((j == 0) && (rate == 44100)) + dev_info(wcd->dev, + "Cannot set 44.1KHz on INT0\n"); + else + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX_PATH_CTL(j), + WCD9335_CDC_MIX_PCM_RATE_MASK, + rate_val); + } + } + } + + return 0; +} + +static int wcd9335_set_interpolator_rate(struct snd_soc_dai *dai, u32 rate) +{ + int i; + + /* set mixing path rate */ + for (i = 0; i < ARRAY_SIZE(int_mix_rate_val); i++) { + if (rate == int_mix_rate_val[i].rate) { + wcd9335_set_mix_interpolator_rate(dai, + int_mix_rate_val[i].rate_val, rate); + break; + } + } + + /* set primary path sample rate */ + for (i = 0; i < ARRAY_SIZE(int_prim_rate_val); i++) { + if (rate == int_prim_rate_val[i].rate) { + wcd9335_set_prim_interpolator_rate(dai, + int_prim_rate_val[i].rate_val, rate); + break; + } + } + + return 0; +} + +static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd, + struct wcd_slim_codec_dai_data *dai_data, + int direction) +{ + struct list_head *slim_ch_list = &dai_data->slim_ch_list; + struct slim_stream_config *cfg = &dai_data->sconfig; + struct wcd9335_slim_ch *ch; + u16 payload = 0; + int ret, i; + + cfg->ch_count = 0; + cfg->direction = direction; + cfg->port_mask = 0; + + /* Configure slave interface device */ + list_for_each_entry(ch, slim_ch_list, list) { + cfg->ch_count++; + payload |= 1 << ch->shift; + cfg->port_mask |= BIT(ch->port); + } + + cfg->chs = kcalloc(cfg->ch_count, sizeof(unsigned int), GFP_KERNEL); + if (!cfg->chs) + return -ENOMEM; + + i = 0; + list_for_each_entry(ch, slim_ch_list, list) { + cfg->chs[i++] = ch->ch_num; + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + /* write to interface device */ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_RX_PORT_MULTI_CHNL_0(ch->port), + payload); + + if (ret < 0) + goto err; + + /* configure the slave port for water mark and enable*/ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_RX_PORT_CFG(ch->port), + WCD9335_SLIM_WATER_MARK_VAL); + if (ret < 0) + goto err; + } + } + + dai_data->sruntime = slim_stream_allocate(wcd->slim, "WCD9335-SLIM"); + slim_stream_prepare(dai_data->sruntime, cfg); + + return 0; + +err: + dev_err(wcd->dev, "Error Setting slim hw params\n"); + kfree(cfg->chs); + cfg->chs = NULL; + + return ret; +} + +static int wcd9335_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wcd9335_codec *wcd; + int ret; + + wcd = snd_soc_component_get_drvdata(dai->component); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = wcd9335_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err(wcd->dev, "cannot set sample rate: %u\n", + params_rate(params)); + return ret; + } + switch (params_width(params)) { + case 16 ... 24: + wcd->dai[dai->id].sconfig.bps = params_width(params); + break; + default: + dev_err(wcd->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + } + break; + default: + dev_err(wcd->dev, "Invalid stream type %d\n", + substream->stream); + return -EINVAL; + }; + + wcd->dai[dai->id].sconfig.rate = params_rate(params); + wcd9335_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream); + + return 0; +} + +static int wcd9335_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct wcd_slim_codec_dai_data *dai_data; + struct wcd9335_codec *wcd; + + wcd = snd_soc_component_get_drvdata(dai->component); + dai_data = &wcd->dai[dai->id]; + slim_stream_enable(dai_data->sruntime); + + return 0; +} + +static int wcd9335_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct wcd9335_codec *wcd; + int i; + + wcd = snd_soc_component_get_drvdata(dai->component); + + if (!tx_slot || !rx_slot) { + dev_err(wcd->dev, "Invalid tx_slot=%p, rx_slot=%p\n", + tx_slot, rx_slot); + return -EINVAL; + } + + if (wcd->rx_chs) { + wcd->num_rx_port = rx_num; + for (i = 0; i < rx_num; i++) { + wcd->rx_chs[i].ch_num = rx_slot[i]; + INIT_LIST_HEAD(&wcd->rx_chs[i].list); + } + } + + return 0; +} + +static int wcd9335_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct wcd9335_slim_ch *ch; + struct wcd9335_codec *wcd; + int i = 0; + + wcd = snd_soc_component_get_drvdata(dai->component); + + switch (dai->id) { + case AIF1_PB: + case AIF2_PB: + case AIF3_PB: + case AIF4_PB: + if (!rx_slot || !rx_num) { + dev_err(wcd->dev, "Invalid rx_slot %p or rx_num %p\n", + rx_slot, rx_num); + return -EINVAL; + } + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) + rx_slot[i++] = ch->ch_num; + + *rx_num = i; + break; + default: + dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id); + break; + } + + return 0; +} + +static struct snd_soc_dai_ops wcd9335_dai_ops = { + .hw_params = wcd9335_hw_params, + .prepare = wcd9335_prepare, + .set_channel_map = wcd9335_set_channel_map, + .get_channel_map = wcd9335_get_channel_map, +}; + +static struct snd_soc_dai_driver wcd9335_slim_dai[] = { + [0] = { + .name = "wcd9335_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, + [1] = { + .name = "wcd9335_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = WCD9335_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd9335_dai_ops, + }, + [2] = { + .name = "wcd9335_rx2", + .id = AIF2_PB, + .playback = { + .stream_name = "AIF2 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, + [3] = { + .name = "wcd9335_tx2", + .id = AIF2_CAP, + .capture = { + .stream_name = "AIF2 Capture", + .rates = WCD9335_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd9335_dai_ops, + }, + [4] = { + .name = "wcd9335_rx3", + .id = AIF3_PB, + .playback = { + .stream_name = "AIF3 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, + [5] = { + .name = "wcd9335_tx3", + .id = AIF3_CAP, + .capture = { + .stream_name = "AIF3 Capture", + .rates = WCD9335_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd9335_dai_ops, + }, + [6] = { + .name = "wcd9335_rx4", + .id = AIF4_PB, + .playback = { + .stream_name = "AIF4 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, +}; + +static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) +{ + struct wcd9335_codec *wcd = data; + unsigned long status = 0; + int i, j, port_id; + unsigned int val, int_val = 0; + bool tx; + unsigned short reg = 0; + + for (i = WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0; + i <= WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) { + regmap_read(wcd->if_regmap, i, &val); + status |= ((u32)val << (8 * j)); + } + + for_each_set_bit(j, &status, 32) { + tx = (j >= 16 ? true : false); + port_id = (tx ? j - 16 : j); + regmap_read(wcd->if_regmap, + WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val); + if (val) { + if (!tx) + reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + + (port_id / 8); + else + reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + regmap_read( + wcd->if_regmap, reg, &int_val); + /* + * Ignore interrupts for ports for which the + * interrupts are not specifically enabled. + */ + if (!(int_val & (1 << (port_id % 8)))) + continue; + } + if (val & WCD9335_SLIM_IRQ_OVERFLOW) + dev_err_ratelimited(wcd->dev, + "%s: overflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + if (val & WCD9335_SLIM_IRQ_UNDERFLOW) + dev_err_ratelimited(wcd->dev, + "%s: underflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + if ((val & WCD9335_SLIM_IRQ_OVERFLOW) || + (val & WCD9335_SLIM_IRQ_UNDERFLOW)) { + if (!tx) + reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + + (port_id / 8); + else + reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + regmap_read( + wcd->if_regmap, reg, &int_val); + if (int_val & (1 << (port_id % 8))) { + int_val = int_val ^ (1 << (port_id % 8)); + regmap_write(wcd->if_regmap, + reg, int_val); + } + } + + regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0 + (j / 8), + BIT(j % 8)); + } + + return IRQ_HANDLED; +} + +static int wcd9335_setup_irqs(struct wcd9335_codec *wcd) +{ + int slim_irq = regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS); + int i, ret = 0; + + ret = request_threaded_irq(slim_irq, NULL, wcd9335_slimbus_irq, + IRQF_TRIGGER_RISING, "SLIMBus Slave", wcd); + if (ret) { + dev_err(wcd->dev, "Failed to request SLIMBUS irq\n"); + return ret; + } + + /* enable interrupts on all slave ports */ + for (i = 0; i < WCD9335_SLIM_NUM_PORT_REG; i++) + regmap_write(wcd->if_regmap, WCD9335_SLIM_PGD_PORT_INT_EN0 + i, + 0xFF); + + return ret; +} + +static void wcd9335_cdc_sido_ccl_enable(struct wcd9335_codec *wcd, + bool ccl_flag) +{ + struct snd_soc_component *comp = wcd->component; + + if (ccl_flag) { + if (++wcd->sido_ccl_cnt == 1) + snd_soc_component_write(comp, WCD9335_SIDO_SIDO_CCL_10, + WCD9335_SIDO_SIDO_CCL_DEF_VALUE); + } else { + if (wcd->sido_ccl_cnt == 0) { + dev_err(wcd->dev, "sido_ccl already disabled\n"); + return; + } + if (--wcd->sido_ccl_cnt == 0) + snd_soc_component_write(comp, WCD9335_SIDO_SIDO_CCL_10, + WCD9335_SIDO_SIDO_CCL_10_ICHARG_PWR_SEL_C320FF); + } +} + +static int wcd9335_enable_master_bias(struct wcd9335_codec *wcd) +{ + wcd->master_bias_users++; + if (wcd->master_bias_users == 1) { + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_EN_MASK, + WCD9335_ANA_BIAS_ENABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_EN_MASK, + WCD9335_ANA_BIAS_PRECHRG_ENABLE); + /* + * 1ms delay is required after pre-charge is enabled + * as per HW requirement + */ + usleep_range(1000, 1100); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_EN_MASK, + WCD9335_ANA_BIAS_PRECHRG_DISABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL); + } + + return 0; +} + +static int wcd9335_enable_mclk(struct wcd9335_codec *wcd) +{ + /* Enable mclk requires master bias to be enabled first */ + if (wcd->master_bias_users <= 0) + return -EINVAL; + + if (((wcd->clk_mclk_users == 0) && (wcd->clk_type == WCD_CLK_MCLK)) || + ((wcd->clk_mclk_users > 0) && (wcd->clk_type != WCD_CLK_MCLK))) { + dev_err(wcd->dev, "Error enabling MCLK, clk_type: %d\n", + wcd->clk_type); + return -EINVAL; + } + + if (++wcd->clk_mclk_users == 1) { + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK, + WCD9335_ANA_CLK_EXT_CLKBUF_ENABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_SRC_MASK, + WCD9335_ANA_CLK_MCLK_SRC_EXTERNAL); + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_EN_MASK, + WCD9335_ANA_CLK_MCLK_ENABLE); + regmap_update_bits(wcd->regmap, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_EN_MASK, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_ENABLE); + regmap_update_bits(wcd->regmap, + WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL, + WCD9335_CDC_CLK_RST_CTRL_MCLK_EN_MASK, + WCD9335_CDC_CLK_RST_CTRL_MCLK_ENABLE); + /* + * 10us sleep is required after clock is enabled + * as per HW requirement + */ + usleep_range(10, 15); + } + + wcd->clk_type = WCD_CLK_MCLK; + + return 0; +} + +static int wcd9335_disable_mclk(struct wcd9335_codec *wcd) +{ + if (wcd->clk_mclk_users <= 0) + return -EINVAL; + + if (--wcd->clk_mclk_users == 0) { + if (wcd->clk_rco_users > 0) { + /* MCLK to RCO switch */ + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_SRC_MASK, + WCD9335_ANA_CLK_MCLK_SRC_RCO); + wcd->clk_type = WCD_CLK_RCO; + } else { + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_EN_MASK, + WCD9335_ANA_CLK_MCLK_DISABLE); + wcd->clk_type = WCD_CLK_OFF; + } + + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK, + WCD9335_ANA_CLK_EXT_CLKBUF_DISABLE); + } + + return 0; +} + +static int wcd9335_disable_master_bias(struct wcd9335_codec *wcd) +{ + if (wcd->master_bias_users <= 0) + return -EINVAL; + + wcd->master_bias_users--; + if (wcd->master_bias_users == 0) { + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_EN_MASK, + WCD9335_ANA_BIAS_DISABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL); + } + return 0; +} + +static int wcd9335_cdc_req_mclk_enable(struct wcd9335_codec *wcd, + bool enable) +{ + int ret = 0; + + if (enable) { + wcd9335_cdc_sido_ccl_enable(wcd, true); + ret = clk_prepare_enable(wcd->mclk); + if (ret) { + dev_err(wcd->dev, "%s: ext clk enable failed\n", + __func__); + goto err; + } + /* get BG */ + wcd9335_enable_master_bias(wcd); + /* get MCLK */ + wcd9335_enable_mclk(wcd); + + } else { + /* put MCLK */ + wcd9335_disable_mclk(wcd); + /* put BG */ + wcd9335_disable_master_bias(wcd); + clk_disable_unprepare(wcd->mclk); + wcd9335_cdc_sido_ccl_enable(wcd, false); + } +err: + return ret; +} + +static void wcd9335_codec_apply_sido_voltage(struct wcd9335_codec *wcd, + enum wcd9335_sido_voltage req_mv) +{ + struct snd_soc_component *comp = wcd->component; + int vout_d_val; + + if (req_mv == wcd->sido_voltage) + return; + + /* compute the vout_d step value */ + vout_d_val = WCD9335_CALCULATE_VOUT_D(req_mv) & + WCD9335_ANA_BUCK_VOUT_MASK; + snd_soc_component_write(comp, WCD9335_ANA_BUCK_VOUT_D, vout_d_val); + snd_soc_component_update_bits(comp, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_RAMP_START_MASK, + WCD9335_ANA_BUCK_CTL_RAMP_START_ENABLE); + + /* 1 msec sleep required after SIDO Vout_D voltage change */ + usleep_range(1000, 1100); + wcd->sido_voltage = req_mv; + snd_soc_component_update_bits(comp, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_RAMP_START_MASK, + WCD9335_ANA_BUCK_CTL_RAMP_START_DISABLE); +} + +static int wcd9335_codec_update_sido_voltage(struct wcd9335_codec *wcd, + enum wcd9335_sido_voltage req_mv) +{ + int ret = 0; + + /* enable mclk before setting SIDO voltage */ + ret = wcd9335_cdc_req_mclk_enable(wcd, true); + if (ret) { + dev_err(wcd->dev, "Ext clk enable failed\n"); + goto err; + } + + wcd9335_codec_apply_sido_voltage(wcd, req_mv); + wcd9335_cdc_req_mclk_enable(wcd, false); + +err: + return ret; +} + +static int _wcd9335_codec_enable_mclk(struct snd_soc_component *component, + int enable) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int ret; + + if (enable) { + ret = wcd9335_cdc_req_mclk_enable(wcd, true); + if (ret) + return ret; + + wcd9335_codec_apply_sido_voltage(wcd, + SIDO_VOLTAGE_NOMINAL_MV); + } else { + wcd9335_codec_update_sido_voltage(wcd, + wcd->sido_voltage); + wcd9335_cdc_req_mclk_enable(wcd, false); + } + + return 0; +} + +static void wcd9335_enable_sido_buck(struct snd_soc_component *component) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + snd_soc_component_update_bits(component, WCD9335_ANA_RCO, + WCD9335_ANA_RCO_BG_EN_MASK, + WCD9335_ANA_RCO_BG_ENABLE); + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_MASK, + WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_EXT); + /* 100us sleep needed after IREF settings */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_MASK, + WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT); + /* 100us sleep needed after VREF settings */ + usleep_range(100, 110); + wcd->sido_input_src = SIDO_SOURCE_RCO_BG; +} + +static int wcd9335_enable_efuse_sensing(struct snd_soc_component *comp) +{ + _wcd9335_codec_enable_mclk(comp, true); + snd_soc_component_update_bits(comp, + WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, + WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK, + WCD9335_CHIP_TIER_CTRL_EFUSE_ENABLE); + /* + * 5ms sleep required after enabling efuse control + * before checking the status. + */ + usleep_range(5000, 5500); + + if (!(snd_soc_component_read32(comp, + WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS) & + WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK)) + WARN(1, "%s: Efuse sense is not complete\n", __func__); + + wcd9335_enable_sido_buck(comp); + _wcd9335_codec_enable_mclk(comp, false); + + return 0; +} + +static void wcd9335_codec_init(struct snd_soc_component *component) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int i; + + /* ungate MCLK and set clk rate */ + regmap_update_bits(wcd->regmap, WCD9335_CODEC_RPM_CLK_GATE, + WCD9335_CODEC_RPM_CLK_GATE_MCLK_GATE_MASK, 0); + + regmap_update_bits(wcd->regmap, WCD9335_CODEC_RPM_CLK_MCLK_CFG, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ); + + for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init_common_val); i++) + snd_soc_component_update_bits(component, + wcd9335_codec_reg_init_common_val[i].reg, + wcd9335_codec_reg_init_common_val[i].mask, + wcd9335_codec_reg_init_common_val[i].val); + + if (WCD9335_IS_2_0(wcd->version)) { + for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init_val_2_0); i++) + snd_soc_component_update_bits(component, + wcd9335_codec_reg_init_val_2_0[i].reg, + wcd9335_codec_reg_init_val_2_0[i].mask, + wcd9335_codec_reg_init_val_2_0[i].val); + } + + wcd9335_enable_efuse_sensing(component); +} + +static int wcd9335_codec_probe(struct snd_soc_component *component) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int i; + + snd_soc_component_init_regmap(component, wcd->regmap); + wcd->component = component; + + wcd9335_codec_init(component); + + for (i = 0; i < NUM_CODEC_DAIS; i++) + INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list); + + return wcd9335_setup_irqs(wcd); +} + +static void wcd9335_codec_remove(struct snd_soc_component *comp) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + free_irq(regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS), wcd); +} + +static int wcd9335_codec_set_sysclk(struct snd_soc_component *comp, + int clk_id, int source, + unsigned int freq, int dir) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + wcd->mclk_rate = freq; + + if (wcd->mclk_rate == WCD9335_MCLK_CLK_12P288MHZ) + snd_soc_component_update_bits(comp, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ); + else if (wcd->mclk_rate == WCD9335_MCLK_CLK_9P6MHZ) + snd_soc_component_update_bits(comp, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ); + + return clk_set_rate(wcd->mclk, freq); +} + +static const struct snd_soc_component_driver wcd9335_component_drv = { + .probe = wcd9335_codec_probe, + .remove = wcd9335_codec_remove, + .set_sysclk = wcd9335_codec_set_sysclk, +}; + +static int wcd9335_probe(struct platform_device *pdev) +{ + struct wcd9335 *pdata = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct wcd9335_codec *wcd; + + wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); + if (!wcd) + return -ENOMEM; + + dev_set_drvdata(dev, wcd); + + memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs)); + + wcd->regmap = pdata->regmap; + wcd->if_regmap = pdata->ifd_regmap; + wcd->slim = pdata->slim; + wcd->slim_ifd = pdata->slim_ifd; + wcd->irq_data = pdata->irq_data; + wcd->version = pdata->version; + wcd->intf_type = pdata->intf_type; + wcd->dev = dev; + wcd->mclk = pdata->mclk; + wcd->native_clk = pdata->native_clk; + wcd->sido_input_src = SIDO_SOURCE_INTERNAL; + wcd->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV; + + return devm_snd_soc_register_component(dev, &wcd9335_component_drv, + wcd9335_slim_dai, + ARRAY_SIZE(wcd9335_slim_dai)); +} + +static const struct of_device_id wcd9335_of_match[] = { + { .compatible = "qcom,wcd9335-codec", }, + {} +}; + +static struct platform_driver wcd9335_codec_driver = { + .probe = wcd9335_probe, + .driver = { + .name = "wcd9335_codec", + .of_match_table = wcd9335_of_match, + }, +}; +module_platform_driver(wcd9335_codec_driver); +MODULE_DESCRIPTION("WCD9335 Codec driver"); +MODULE_LICENSE("GPL v2"); From patchwork Mon Jul 23 15:54:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540551 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BE6EB13BB for ; Mon, 23 Jul 2018 15:59:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A937028CDC for ; Mon, 23 Jul 2018 15:59:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9D14E28CF3; Mon, 23 Jul 2018 15:59:37 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 694B928CDC for ; Mon, 23 Jul 2018 15:59:35 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 1F61A2677A9; Mon, 23 Jul 2018 17:58:42 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 9A4A62676D4; Mon, 23 Jul 2018 17:58:29 +0200 (CEST) Received: from mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65]) by alsa0.perex.cz (Postfix) with ESMTP id 52E0A267750 for ; Mon, 23 Jul 2018 17:58:25 +0200 (CEST) Received: by mail-wm0-f65.google.com with SMTP id z13-v6so1734322wma.5 for ; Mon, 23 Jul 2018 08:58:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=lKu5rXVt2uTVTGxTTxo6GZ7BB4N4A1w7llYTILPr8Bs=; b=JAWOrLe3MCqSUx/50xhDWJNNiMIiSo182tH+iRDKuR1dvbqybSeAXGg9oyMxFPsmwW 7Ach3sktClD9vCs1GAEPdBd2Ps0ICAtgJkvZKXI7WZJuho1ljpU+ND3c3op0+GD33WoT NKs8mp6iOJhS/LybqdbQu+s318TGMDUcLygvc= 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=lKu5rXVt2uTVTGxTTxo6GZ7BB4N4A1w7llYTILPr8Bs=; b=iw43DLRWn8ncVXW/f1FolzuqX1OzOmAg3HqlpMd/sBBv725CwxNy5dhXTFZbFTcIu3 L9BSXs3FvpTOnfuOQStv39Wn9W9ct3v3SCsv78HVJpVO8qPFXVafnN0r5DQgdHWg4ECo p7MnjLVNKJcvG25ANJ79IvTcN1p4Np9KtORgmYLkn7uIEwX1p8VE2uYHOwx8SLtcVqxU 4GETborLoQgE7keBhfasdn/NCu9BIqoxOyVkC+yWGMKQOVoJqJfnaRCh9ZPfzkQzJKbO W0dRneO3rhSshorVvUzSUDXIyGPJJnY3B5j5ccKR4YgmETfarpU7gXYuJzHgnwSU+LMx e2NA== X-Gm-Message-State: AOUpUlGiDedvBrnC/nYum46aGuceNtSm1tnnejypgR2liraz1MKf+1A1 CblsDZipAt/JtBuhzbzvDSL5iw== X-Google-Smtp-Source: AAOMgpeObbEKteMZn+/anKYSQ1WFyuA0a+7xDjA2k9J6AeGBwmTTxLqgrjQaXRHKwa7DOfpRo8Rb8g== X-Received: by 2002:a1c:ec9d:: with SMTP id h29-v6mr8182917wmi.94.1532361504580; Mon, 23 Jul 2018 08:58:24 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:23 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:05 +0100 Message-Id: <20180723155410.9494-8-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 07/12] ASoC: wcd9335: add CLASS-H Controller support X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP CLASS-H controller/Amplifier is common accorss Qualcomm WCD codec series. This patchset adds basic CLASS-H controller apis for WCD codecs after wcd9335 to use. Signed-off-by: Srinivas Kandagatla --- sound/soc/codecs/Makefile | 2 +- sound/soc/codecs/wcd-clsh.c | 1010 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd-clsh.h | 69 +++ sound/soc/codecs/wcd9335.c | 10 + 4 files changed, 1090 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/wcd-clsh.c create mode 100644 sound/soc/codecs/wcd-clsh.h diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 01410b63daac..e3a3d4694e15 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -192,7 +192,7 @@ snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o -snd-soc-wcd9335-objs := wcd9335.o +snd-soc-wcd9335-objs := wcd-clsh.o wcd9335.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o diff --git a/sound/soc/codecs/wcd-clsh.c b/sound/soc/codecs/wcd-clsh.c new file mode 100644 index 000000000000..95c167239f42 --- /dev/null +++ b/sound/soc/codecs/wcd-clsh.c @@ -0,0 +1,1010 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +// Copyright (c) 2017-2018, Linaro Limited +// +#include +#include +#include +#include +#include +#include +#include "wcd-clsh.h" + +struct wcd_clsh_ctrl { + int state; + int mode; + int flyback_users; + int buck_users; + int clsh_users; + int codec_version; + int interpolator_modes[WCD_CLSH_STATE_MAX]; + struct snd_soc_component *comp; +}; + +/* Class-H registers for codecs from and above WCD9335 */ +#define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0xB, 0x42) +#define WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK BIT(6) +#define WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE BIT(6) +#define WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE 0 +#define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0xB, 0x56) +#define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0xB, 0x6A) +#define WCD9XXX_A_CDC_CLSH_K1_MSB WCD9335_REG(0xC, 0x08) +#define WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK GENMASK(3, 0) +#define WCD9XXX_A_CDC_CLSH_K1_LSB WCD9335_REG(0xC, 0x09) +#define WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK GENMASK(7, 0) +#define WCD9XXX_A_ANA_RX_SUPPLIES WCD9335_REG(0x6, 0x08) +#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK BIT(1) +#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H 0 +#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB BIT(1) +#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK BIT(2) +#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA BIT(2) +#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT 0 +#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK BIT(3) +#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA BIT(3) +#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT 0 +#define WCD9XXX_A_ANA_RX_VNEG_EN_MASK BIT(6) +#define WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT 6 +#define WCD9XXX_A_ANA_RX_VNEG_ENABLE BIT(6) +#define WCD9XXX_A_ANA_RX_VNEG_DISABLE 0 +#define WCD9XXX_A_ANA_RX_VPOS_EN_MASK BIT(7) +#define WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT 7 +#define WCD9XXX_A_ANA_RX_VPOS_ENABLE BIT(7) +#define WCD9XXX_A_ANA_RX_VPOS_DISABLE 0 +#define WCD9XXX_A_ANA_HPH WCD9335_REG(0x6, 0x09) +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK GENMASK(3, 2) +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA 0x08 +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP 0x04 +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL 0x0 +#define WCD9XXX_A_CDC_CLSH_CRC WCD9335_REG(0xC, 0x01) +#define WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK BIT(0) +#define WCD9XXX_A_CDC_CLSH_CRC_CLK_ENABLE BIT(0) +#define WCD9XXX_A_CDC_CLSH_CRC_CLK_DISABLE 0 +#define WCD9XXX_FLYBACK_EN WCD9335_REG(0x6, 0xA4) +#define WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK GENMASK(6, 5) +#define WCD9XXX_FLYBACK_EN_DELAY_26P25_US 0x40 +#define WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK BIT(4) +#define WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY BIT(4) +#define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0 + +#define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7) +#define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) +#define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(0, 3) +#define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3) +#define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3) +#define WCD9XXX_HPH_CONST_SEL_BYPASS 0 +#define WCD9XXX_HPH_CONST_SEL_LP_PATH 0x40 +#define WCD9XXX_HPH_CONST_SEL_HQ_PATH 0x80 +#define WCD9XXX_HPH_R_EN WCD9335_REG(0x6, 0xD6) +#define WCD9XXX_HPH_REFBUFF_UHQA_CTL WCD9335_REG(0x6, 0xDD) +#define WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK GENMASK(2, 0) +#define WCD9XXX_CLASSH_CTRL_VCL_2 WCD9335_REG(0x6, 0x9B) +#define WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK GENMASK(5, 4) +#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM 0x20 +#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM 0x0 +#define WCD9XXX_CDC_CLSH_HPH_V_PA WCD9335_REG(0xC, 0x04) +#define WCD9XXX_CDC_RX0_RX_PATH_SEC0 WCD9335_REG(0xB, 0x49) +#define WCD9XXX_CDC_RX0_RX_PATH_SEC0_DEM_INP_SEL GENMASK(1, 0) +#define WCD9XXX_CDC_RX0_RX_PATH_SEC0_DEM_INP_CLSH 0x1 +#define WCD9XXX_CDC_RX1_RX_PATH_CTL WCD9335_REG(0xB, 0x55) +#define WCD9XXX_CDC_RX2_RX_PATH_CTL WCD9335_REG(0xB, 0x69) +#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0xD, 0x41) +#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0) +#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK BIT(1) +#define WCD9XXX_CLASSH_CTRL_CCL_1 WCD9335_REG(0x6, 0x9C) +#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK GENMASK(7, 4) +#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50 +#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30 + +#define CLSH_REQ_ENABLE true +#define CLSH_REQ_DISABLE false +#define WCD_USLEEP_RANGE 50 + +enum { + DAC_GAIN_0DB = 0, + DAC_GAIN_0P2DB, + DAC_GAIN_0P4DB, + DAC_GAIN_0P6DB, + DAC_GAIN_0P8DB, + DAC_GAIN_M0P2DB, + DAC_GAIN_M0P4DB, + DAC_GAIN_M0P6DB, +}; + +static bool is_native_44_1_active(struct snd_soc_component *comp) +{ + bool native_active = false; + int native_clk, rx1_rate, rx2_rate; + + native_clk = snd_soc_component_read32(comp, + WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL); + rx1_rate = snd_soc_component_read32(comp, WCD9XXX_CDC_RX1_RX_PATH_CTL); + rx2_rate = snd_soc_component_read32(comp, WCD9XXX_CDC_RX2_RX_PATH_CTL); + + if ((native_clk & WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK) && + ((rx1_rate & 0x0F) == 0x9 || (rx2_rate & 0x0F) == 0x9)) + native_active = true; + + return native_active; +} + +static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl, + bool enable) +{ + struct snd_soc_component *comp = ctrl->comp; + + if ((enable && ++ctrl->clsh_users == 1) || + (!enable && --ctrl->clsh_users == 0)) + snd_soc_component_update_bits(comp, WCD9XXX_A_CDC_CLSH_CRC, + WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK, + enable); + if (ctrl->clsh_users < 0) + ctrl->clsh_users = 0; +} + +static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp) +{ + return snd_soc_component_read32(comp, WCD9XXX_A_CDC_CLSH_CRC) & + WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK; +} + +static inline int wcd_clsh_get_int_mode(struct wcd_clsh_ctrl *ctrl, + int clsh_state) +{ + int mode; + + if ((clsh_state != WCD_CLSH_STATE_EAR) && + (clsh_state != WCD_CLSH_STATE_HPHL) && + (clsh_state != WCD_CLSH_STATE_HPHR) && + (clsh_state != WCD_CLSH_STATE_LO)) + mode = CLS_NONE; + else + mode = ctrl->interpolator_modes[ffs(clsh_state)]; + + return mode; +} + +static inline void wcd_clsh_set_int_mode(struct wcd_clsh_ctrl *ctrl, + int clsh_state, int mode) +{ + if ((clsh_state != WCD_CLSH_STATE_EAR) && + (clsh_state != WCD_CLSH_STATE_HPHL) && + (clsh_state != WCD_CLSH_STATE_HPHR) && + (clsh_state != WCD_CLSH_STATE_LO)) + return; + + ctrl->interpolator_modes[ffs(clsh_state)] = mode; +} + +static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, + int mode) +{ + /* set to HIFI */ + if (mode == CLS_H_HIFI) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA); + else + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT); +} + +static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp, + int mode) +{ + /* set to HIFI */ + if (mode == CLS_H_HIFI) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA); + else + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT); +} + +static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + struct snd_soc_component *comp = ctrl->comp; + + /* enable/disable buck */ + if ((enable && (++ctrl->buck_users == 1)) || + (!enable && (--ctrl->buck_users == 0))) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VPOS_EN_MASK, + enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT); + /* + * 500us sleep is required after buck enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); +} + +static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + struct snd_soc_component *comp = ctrl->comp; + + int vneg[] = {0x00, 0x40}; + + /* enable/disable flyback */ + if ((enable && (++ctrl->flyback_users == 1)) || + (!enable && (--ctrl->flyback_users == 0))) { + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VNEG_EN_MASK, + enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT); + /* 100usec delay is needed as per HW requirement */ + usleep_range(100, 110); + + if (enable && (WCD9335_IS_1_1(ctrl->codec_version))) { + wcd_clsh_set_flyback_mode(comp, CLS_H_HIFI); + snd_soc_component_update_bits(comp, WCD9XXX_FLYBACK_EN, + WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK, + WCD9XXX_FLYBACK_EN_DELAY_26P25_US); + snd_soc_component_update_bits(comp, WCD9XXX_FLYBACK_EN, + WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK, + WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY); + vneg[0] = snd_soc_component_read32(comp, + WCD9XXX_A_ANA_RX_SUPPLIES); + vneg[0] &= ~(0x40); + vneg[1] = vneg[0] | 0x40; + + snd_soc_component_write(comp, + WCD9XXX_A_ANA_RX_SUPPLIES, vneg[0]); + snd_soc_component_write(comp, + WCD9XXX_A_ANA_RX_SUPPLIES, vneg[1]); + /* 500usec delay is needed as per HW requirement */ + usleep_range(500, 510); + snd_soc_component_update_bits(comp, WCD9XXX_FLYBACK_EN, + WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK, + WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY); + wcd_clsh_set_flyback_mode(comp, mode); + } + + } + /* + * 500us sleep is required after flyback enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); +} + +static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + int val = 0; + + switch (mode) { + case CLS_H_NORMAL: + case CLS_AB: + val = WCD9XXX_HPH_CONST_SEL_BYPASS; + break; + case CLS_H_HIFI: + val = WCD9XXX_HPH_CONST_SEL_HQ_PATH; + break; + case CLS_H_LP: + val = WCD9XXX_HPH_CONST_SEL_LP_PATH; + break; + }; + + snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN, + WCD9XXX_HPH_CONST_SEL_L_MASK, + val); + + snd_soc_component_update_bits(comp, WCD9XXX_HPH_R_EN, + WCD9XXX_HPH_CONST_SEL_L_MASK, + val); +} + +static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, + int mode) +{ + int val = 0, gain = 0, res_val; + int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + + res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM; + switch (mode) { + case CLS_H_NORMAL: + res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM; + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; + gain = DAC_GAIN_0DB; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + break; + case CLS_AB: + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; + gain = DAC_GAIN_0DB; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + break; + case CLS_H_HIFI: + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA; + gain = DAC_GAIN_M0P2DB; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + break; + case CLS_H_LP: + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA; + break; + }; + + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH, + WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val); + snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2, + WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK, + res_val); + if (mode != CLS_H_LP) + snd_soc_component_update_bits(comp, + WCD9XXX_HPH_REFBUFF_UHQA_CTL, + WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK, + gain); + snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1, + WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK, + ipeak); +} + +static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp, + int mode) +{ + + snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, + WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A); + snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, + WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A); + /* Sleep needed to avoid click and pop as per HW requirement */ + usleep_range(100, 110); +} + +static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp, + int mode) +{ + if (mode == CLS_AB) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB); + else + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H); +} + +static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode != CLS_AB) { + dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n", + __func__, mode); + return; + } + + if (is_enable) { + wcd_clsh_set_buck_regulator_mode(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + } else { + wcd_clsh_buck_ctrl(ctrl, mode, false); + wcd_clsh_flyback_ctrl(ctrl, mode, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_hph_ear(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + int hph_mode = 0; + + if (is_enable) { + if (req_state == WCD_CLSH_STATE_EAR) { + /* If HPH is running in CLS-AB when + * EAR comes, let it continue to run + * in Class-AB, no need to enable Class-H + * for EAR. + */ + if (ctrl->state & WCD_CLSH_STATE_HPHL) + hph_mode = wcd_clsh_get_int_mode(ctrl, + WCD_CLSH_STATE_HPHL); + else if (ctrl->state & WCD_CLSH_STATE_HPHR) + hph_mode = wcd_clsh_get_int_mode(ctrl, + WCD_CLSH_STATE_HPHR); + if (hph_mode != CLS_AB && !is_native_44_1_active(comp)) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } + + if (is_native_44_1_active(comp)) { + snd_soc_component_write(comp, + WCD9XXX_CDC_CLSH_HPH_V_PA, 0x39); + snd_soc_component_update_bits(comp, + WCD9XXX_CDC_RX0_RX_PATH_SEC0, + WCD9XXX_CDC_RX0_RX_PATH_SEC0_DEM_INP_SEL, + 0x00); + if ((req_state == WCD_CLSH_STATE_HPHL) || + (req_state == WCD_CLSH_STATE_HPHR)) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + } + + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + if ((req_state == WCD_CLSH_STATE_HPHL) || + (req_state == WCD_CLSH_STATE_HPHR)) { + wcd_clsh_set_gain_path(ctrl, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + } + } else { + if (req_state == WCD_CLSH_STATE_EAR) { + /* + * If EAR goes away, disable EAR Channel Enable + * if HPH running in Class-H otherwise + * and if HPH requested mode is CLS_AB then + * no need to disable EAR channel enable bit. + */ + if (wcd_clsh_enable_status(comp)) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + } + + if (is_native_44_1_active(comp)) { + snd_soc_component_write(comp, + WCD9XXX_CDC_CLSH_HPH_V_PA, 0x1C); + snd_soc_component_update_bits(comp, + WCD9XXX_CDC_RX0_RX_PATH_SEC0, + WCD9XXX_CDC_RX0_RX_PATH_SEC0_DEM_INP_SEL, + WCD9XXX_CDC_RX0_RX_PATH_SEC0_DEM_INP_CLSH); + if (((ctrl->state & WCD_CLSH_STATE_HPH_ST) + != WCD_CLSH_STATE_HPH_ST) && + ((req_state == WCD_CLSH_STATE_HPHL) || + (req_state == WCD_CLSH_STATE_HPHR))) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } + + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + if ((req_state & WCD_CLSH_STATE_HPH_ST) && + !wcd_clsh_enable_status(comp)) { + /* If Class-H is not enabled when HPH is turned + * off, enable it as EAR is in progress + */ + wcd_enable_clsh_block(ctrl, true); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + } + } +} + +static void wcd_clsh_state_ear_lo(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (is_enable && (req_state == WCD_CLSH_STATE_LO)) { + wcd_clsh_set_buck_regulator_mode(comp, CLS_AB); + } else { + if (req_state == WCD_CLSH_STATE_EAR) + goto end; + + /* LO powerdown. + * If EAR Class-H is already enabled, just + * turn on regulator other enable Class-H + * configuration + */ + if (wcd_clsh_enable_status(comp)) { + wcd_clsh_set_buck_regulator_mode(comp, + CLS_H_NORMAL); + goto end; + } + wcd_enable_clsh_block(ctrl, true); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + wcd_clsh_set_buck_regulator_mode(comp, + CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_buck_ctrl(ctrl, mode, true); + } +end: + return; +} + +static void wcd_clsh_state_hph_lo(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + int hph_mode = 0; + + if (is_enable) { + /* + * If requested state is LO, put regulator + * in class-AB or if requested state is HPH, + * which means LO is already enabled, keep + * the regulator config the same at class-AB + * and just set the power modes for flyback + * and buck. + */ + if (req_state == WCD_CLSH_STATE_LO) + wcd_clsh_set_buck_regulator_mode(comp, CLS_AB); + else { + if (!wcd_clsh_enable_status(comp)) { + wcd_enable_clsh_block(ctrl, true); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_MSB, + WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, + 0x00); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_LSB, + WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, + 0xC0); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_set_gain_path(ctrl, mode); + } else { + dev_dbg(comp->dev, "%s:clsh is already enabled\n", + __func__); + } + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } + } else { + if ((req_state == WCD_CLSH_STATE_HPHL) || + (req_state == WCD_CLSH_STATE_HPHR)) { + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + /* + * If HPH is powering down first, then disable clsh, + * set the buck/flyback mode to default and keep the + * regulator at Class-AB + */ + if ((ctrl->state & WCD_CLSH_STATE_HPH_ST) + != WCD_CLSH_STATE_HPH_ST) { + wcd_enable_clsh_block(ctrl, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + } + } else { + /* LO powerdown. + * If HPH mode also is CLS-AB, no need + * to turn-on class-H, otherwise enable + * Class-H configuration. + */ + if (ctrl->state & WCD_CLSH_STATE_HPHL) + hph_mode = wcd_clsh_get_int_mode(ctrl, + WCD_CLSH_STATE_HPHL); + else if (ctrl->state & WCD_CLSH_STATE_HPHR) + hph_mode = wcd_clsh_get_int_mode(ctrl, + WCD_CLSH_STATE_HPHR); + + if ((hph_mode == CLS_AB) || + (hph_mode == CLS_NONE)) + goto end; + + /* + * If Class-H is already enabled (HPH ON and then + * LO ON), no need to turn on again, just set the + * regulator mode. + */ + if (wcd_clsh_enable_status(comp)) { + wcd_clsh_set_buck_regulator_mode(comp, + hph_mode); + goto end; + } else { + dev_dbg(comp->dev, "%s: clsh is not enabled\n", + __func__); + } + + wcd_enable_clsh_block(ctrl, true); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_MSB, + WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, + 0x00); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_LSB, + WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, + 0xC0); + wcd_clsh_set_buck_regulator_mode(comp, + hph_mode); + if (ctrl->state & WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + if (ctrl->state & WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + wcd_clsh_set_hph_mode(comp, hph_mode); + } + } +end: + return; +} + +static void wcd_clsh_state_hph_st(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode == CLS_AB) + return; + + if (is_enable) { + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } else { + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + } +} + +static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB) { + wcd_enable_clsh_block(ctrl, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_MSB, + WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, + 0x00); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_LSB, + WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, + 0xC0); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } + wcd_clsh_set_buck_regulator_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_set_gain_path(ctrl, mode); + } else { + wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + + if (mode != CLS_AB) { + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + wcd_enable_clsh_block(ctrl, false); + } + /* buck and flyback set to default mode and disable */ + wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB) { + wcd_enable_clsh_block(ctrl, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_MSB, + WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, + 0x00); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_LSB, + WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, + 0xC0); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } + wcd_clsh_set_buck_regulator_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_set_gain_path(ctrl, mode); + } else { + wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + + if (mode != CLS_AB) { + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + wcd_enable_clsh_block(ctrl, false); + } + /* set buck and flyback to Default Mode */ + wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode != CLS_H_NORMAL) { + dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n", + __func__, mode); + return; + } + + if (is_enable) { + wcd_enable_clsh_block(ctrl, true); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + } else { + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + wcd_enable_clsh_block(ctrl, false); + wcd_clsh_buck_ctrl(ctrl, mode, false); + wcd_clsh_flyback_ctrl(ctrl, mode, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + } +} + +static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int new_state, + int req_state, bool is_enable, int mode) +{ + switch (new_state) { + case WCD_CLSH_STATE_EAR: + wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPHL: + wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPHR: + wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPH_ST: + wcd_clsh_state_hph_st(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_LO: + wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_EAR_LO: + wcd_clsh_state_ear_lo(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPHL_EAR: + case WCD_CLSH_STATE_HPHR_EAR: + case WCD_CLSH_STATE_HPH_ST_EAR: + wcd_clsh_state_hph_ear(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPHL_LO: + case WCD_CLSH_STATE_HPHR_LO: + wcd_clsh_state_hph_lo(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPH_ST_LO: + wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); + break; + default: + break; + } + + return 0; +} + +/* + * Function: wcd_clsh_is_state_valid + * Params: state + * Description: + * Provides information on valid states of Class H configuration + */ +static bool wcd_clsh_is_state_valid(int state) +{ + switch (state) { + case WCD_CLSH_STATE_IDLE: + case WCD_CLSH_STATE_EAR: + case WCD_CLSH_STATE_HPHL: + case WCD_CLSH_STATE_HPHR: + case WCD_CLSH_STATE_HPH_ST: + case WCD_CLSH_STATE_LO: + case WCD_CLSH_STATE_HPHL_EAR: + case WCD_CLSH_STATE_HPHR_EAR: + case WCD_CLSH_STATE_HPH_ST_EAR: + case WCD_CLSH_STATE_HPHL_LO: + case WCD_CLSH_STATE_HPHR_LO: + case WCD_CLSH_STATE_HPH_ST_LO: + return true; + default: + return false; + }; +} + +/* + * Function: wcd_clsh_fsm + * Params: ctrl, req_state, req_type, clsh_event + * Description: + * This function handles PRE DAC and POST DAC conditions of different devices + * and updates class H configuration of different combination of devices + * based on validity of their states. ctrl will contain current + * class h state information + */ +int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + enum wcd_clsh_event clsh_event, + int req_state, + enum wcd_clsh_mode int_mode) +{ + struct snd_soc_component *comp = ctrl->comp; + int old_state, new_state; + + switch (clsh_event) { + case WCD_CLSH_EVENT_PRE_DAC: + old_state = ctrl->state; + new_state = old_state | req_state; + + if (!wcd_clsh_is_state_valid(new_state)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; + } + if (new_state == old_state) { + dev_err(comp->dev, "Class-H already in requested state\n"); + return -EINVAL; + } + ctrl->state = new_state; + wcd_clsh_set_int_mode(ctrl, req_state, int_mode); + _wcd_clsh_ctrl_set_state(ctrl, new_state, req_state, + CLSH_REQ_ENABLE, int_mode); + break; + case WCD_CLSH_EVENT_POST_PA: + old_state = ctrl->state; + new_state = old_state & (~req_state); + if (new_state < NUM_CLSH_STATES_V2) { + if (new_state == old_state) + return 0; + + _wcd_clsh_ctrl_set_state(ctrl, old_state, req_state, + CLSH_REQ_DISABLE, int_mode); + ctrl->state = new_state; + wcd_clsh_set_int_mode(ctrl, req_state, CLS_NONE); + } + break; + }; + + return 0; +} + +int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl) +{ + return ctrl->state; +} + +struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, + int version) +{ + struct wcd_clsh_ctrl *ctrl; + + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return ERR_PTR(-ENOMEM); + + ctrl->state = WCD_CLSH_STATE_IDLE; + ctrl->comp = comp; + + return ctrl; +} + +void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl) +{ + kfree(ctrl); +} diff --git a/sound/soc/codecs/wcd-clsh.h b/sound/soc/codecs/wcd-clsh.h new file mode 100644 index 000000000000..5e66781bc9de --- /dev/null +++ b/sound/soc/codecs/wcd-clsh.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +// Copyright (c) 2017-2018, Linaro Limited + +#ifndef _WCD_CLSH_V2_H_ +#define _WCD_CLSH_V2_H_ +#include + +enum wcd_clsh_event { + WCD_CLSH_EVENT_PRE_DAC = 1, + WCD_CLSH_EVENT_POST_PA, +}; + +/* + * Basic states for Class H state machine. + * represented as a bit mask within a u8 data type + * bit 0: EAR mode + * bit 1: HPH Left mode + * bit 2: HPH Right mode + * bit 3: Lineout mode + */ +#define WCD_CLSH_STATE_IDLE 0 +#define WCD_CLSH_STATE_EAR BIT(0) +#define WCD_CLSH_STATE_HPHL BIT(1) +#define WCD_CLSH_STATE_HPHR BIT(2) +#define WCD_CLSH_STATE_LO BIT(3) +#define WCD_CLSH_STATE_MAX 4 +#define NUM_CLSH_STATES_V2 BIT(WCD_CLSH_STATE_MAX) + +/* Derived States */ +#define WCD_CLSH_STATE_HPH_ST (WCD_CLSH_STATE_HPHL | \ + WCD_CLSH_STATE_HPHR) +#define WCD_CLSH_STATE_HPHL_LO (WCD_CLSH_STATE_HPHL | \ + WCD_CLSH_STATE_LO) +#define WCD_CLSH_STATE_HPHR_LO (WCD_CLSH_STATE_HPHR | \ + WCD_CLSH_STATE_LO) +#define WCD_CLSH_STATE_HPH_ST_LO (WCD_CLSH_STATE_HPH_ST | \ + WCD_CLSH_STATE_LO) +#define WCD_CLSH_STATE_EAR_LO (WCD_CLSH_STATE_EAR | \ + WCD_CLSH_STATE_LO) +#define WCD_CLSH_STATE_HPHL_EAR (WCD_CLSH_STATE_HPHL | \ + WCD_CLSH_STATE_EAR) +#define WCD_CLSH_STATE_HPHR_EAR (WCD_CLSH_STATE_HPHR | \ + WCD_CLSH_STATE_EAR) +#define WCD_CLSH_STATE_HPH_ST_EAR (WCD_CLSH_STATE_HPH_ST | \ + WCD_CLSH_STATE_EAR) + +enum wcd_clsh_mode { + CLS_H_NORMAL = 0, /* Class-H Default */ + CLS_H_HIFI, /* Class-H HiFi */ + CLS_H_LP, /* Class-H Low Power */ + CLS_AB, /* Class-AB */ + CLS_H_LOHIFI, /* LoHIFI */ + CLS_NONE, /* None of the above modes */ +}; + +struct wcd_clsh_ctrl; + +extern struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc( + struct snd_soc_component *component, + int version); +extern void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl); +extern int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl); +extern int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + enum wcd_clsh_event event, + int state, + enum wcd_clsh_mode mode); + +#endif /* _WCD_CLSH_V2_H_ */ diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 307672b8d188..7fe746271e48 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -21,6 +21,7 @@ #include #include #include +#include "wcd-clsh.h" #define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ @@ -181,6 +182,7 @@ struct wcd9335_codec { int sido_ccl_cnt; enum wcd_clock_type clk_type; + struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; }; @@ -1066,6 +1068,13 @@ static int wcd9335_codec_probe(struct snd_soc_component *component) int i; snd_soc_component_init_regmap(component, wcd->regmap); + /* Class-H Init*/ + wcd->clsh_ctrl = wcd_clsh_ctrl_alloc(component, wcd->version); + if (IS_ERR(wcd->clsh_ctrl)) + return PTR_ERR(wcd->clsh_ctrl); + + /* Default HPH Mode to Class-H HiFi */ + wcd->hph_mode = CLS_H_HIFI; wcd->component = component; wcd9335_codec_init(component); @@ -1080,6 +1089,7 @@ static void wcd9335_codec_remove(struct snd_soc_component *comp) { struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + wcd_clsh_ctrl_free(wcd->clsh_ctrl); free_irq(regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS), wcd); } From patchwork Mon Jul 23 15:54:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540549 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3BDE1157A for ; Mon, 23 Jul 2018 15:59:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 284B028CDC for ; Mon, 23 Jul 2018 15:59:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1C63328CF3; Mon, 23 Jul 2018 15:59:30 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B915D28CDC for ; Mon, 23 Jul 2018 15:59:28 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id BEA942677AE; Mon, 23 Jul 2018 17:58:40 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 8029226775C; Mon, 23 Jul 2018 17:58:29 +0200 (CEST) Received: from mail-wm0-f66.google.com (mail-wm0-f66.google.com [74.125.82.66]) by alsa0.perex.cz (Postfix) with ESMTP id 5F745267715 for ; Mon, 23 Jul 2018 17:58:26 +0200 (CEST) Received: by mail-wm0-f66.google.com with SMTP id s9-v6so1633117wmh.3 for ; Mon, 23 Jul 2018 08:58:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ml374zHoqo4F131K+6aSsL6ek+yThEExPOJuQcMy9FI=; b=LOwf7NfFy4Ujyg5EDGn/EtD2rUIsUb3ZEoxesoAL8I4o8vCWjf60aHLmHnoPwbGeOt rzZADK6Rk6s6TpEvLnp87U7B0MEQExpLKBv8jO1xakFuZgE+wFQf0GQIRVYIdignM8iA r+L4oizYJpVnDlvYZJcSa2Hb9uAkiv8nBKMOk= 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=ml374zHoqo4F131K+6aSsL6ek+yThEExPOJuQcMy9FI=; b=g5n6Mh2riM3mAveaaVFcEzn5xmYQIE7Ay/r27o840D/7jWKA7ME1M9lWMfqKFytymi zP6Afe7g5mz4Cp66W+gNe35HN6RwgmGuh9pTe8Vk5sezs1vdYobUVdauiBtBZ5J6pAAV Yojj0+ehuPw1oRA0x1B/BF/IiTXpQKuO0Rr/1imrpUzRfzkQffof8N946LCMS4fJ+/WY yYrIqtaRe6ZfE96ZER07vS8CqwPzxeqWaG36H6sbgqs0gJV6VH4RIrgDViovkAT81o7N vrwfXBABCRcWYVBa3qeoWW80UBcKEj6iXASaFewsnVUYnhnGBs3t//6wt6qUjervBFAT Yxjw== X-Gm-Message-State: AOUpUlEfWN/AxDlV37RWKaHtY5pZq9uWXP8SnLC7LS0kIh3wFRicxI2c js0yuaR14wy6BFVEhRJdBJkRbg== X-Google-Smtp-Source: AAOMgpfHM+q2Mr2MDjEkQsu+HLAx9p7KIEPURIuzELbNweSxWzD06u9Ml7Ss4jAmbN42IKWSWpQTEw== X-Received: by 2002:a1c:69d2:: with SMTP id z79-v6mr8175111wmh.92.1532361505799; Mon, 23 Jul 2018 08:58:25 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:25 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:06 +0100 Message-Id: <20180723155410.9494-9-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 08/12] ASoC: wcd9335: add basic controls X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds basic controls found in wcd9335 codec. Signed-off-by: Srinivas Kandagatla --- sound/soc/codecs/wcd9335.c | 371 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 7fe746271e48..e1f63d8cc7d4 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -104,6 +104,18 @@ enum { NUM_CODEC_DAIS, }; +enum { + COMPANDER_1, /* HPH_L */ + COMPANDER_2, /* HPH_R */ + COMPANDER_3, /* LO1_DIFF */ + COMPANDER_4, /* LO2_DIFF */ + COMPANDER_5, /* LO3_SE */ + COMPANDER_6, /* LO4_SE */ + COMPANDER_7, /* SWR SPK CH1 */ + COMPANDER_8, /* SWR SPK CH2 */ + COMPANDER_MAX, +}; + enum { INTn_2_INP_SEL_ZERO = 0, INTn_2_INP_SEL_RX0, @@ -184,6 +196,7 @@ struct wcd9335_codec { struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; + int comp_enabled[COMPANDER_MAX]; }; static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = { @@ -295,6 +308,118 @@ static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init_common_val[] = { {WCD9335_VBADC_IBIAS_FE, 0x0C, 0x08}, }; +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static const char * const rx_cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ", + "CF_NEG_3DB_0P48HZ" +}; + +static const char * const wcd9335_ear_pa_gain_text[] = { + "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", + "G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB" +}; + +static const char * const rx_hph_mode_mux_text[] = { + "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI" +}; + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + +static const struct soc_enum wcd9335_ear_pa_gain_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wcd9335_ear_pa_gain_text), + wcd9335_ear_pa_gain_text); + +static const struct soc_enum cf_dec0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX0_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX1_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX2_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX3_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX4_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX5_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX6_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX7_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX8_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_int0_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int1_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int2_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int3_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int4_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int5_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int5_2_enum, WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int6_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int6_2_enum, WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int7_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int8_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, int rate_val, u32 rate) @@ -670,6 +795,250 @@ static struct snd_soc_dai_driver wcd9335_slim_dai[] = { }, }; +static int wcd9335_get_compander(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + int comp = ((struct soc_mixer_control *)kc->private_value)->shift; + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + ucontrol->value.integer.value[0] = wcd->comp_enabled[comp]; + return 0; +} + +static int wcd9335_set_compander(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int comp = ((struct soc_mixer_control *) kc->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + int sel; + + wcd->comp_enabled[comp] = value; + sel = value ? WCD9335_HPH_GAIN_SRC_SEL_COMPANDER : + WCD9335_HPH_GAIN_SRC_SEL_REGISTER; + + /* Any specific register configuration for compander */ + switch (comp) { + case COMPANDER_1: + /* Set Gain Source Select based on compander enable/disable */ + snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_2: + snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_3: + break; + case COMPANDER_4: + break; + case COMPANDER_5: + snd_soc_component_update_bits(component, WCD9335_SE_LO_LO3_GAIN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_6: + snd_soc_component_update_bits(component, WCD9335_SE_LO_LO4_GAIN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_7: + break; + case COMPANDER_8: + break; + default: + /* + * if compander is not enabled for any interpolator, + * it does not cause any audio failure, so do not + * return error in this case, but just print a log + */ + dev_warn(component->dev, "%s: unknown compander: %d\n", + __func__, comp); + }; + return 0; +} + +static int wcd9335_rx_hph_mode_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + ucontrol->value.integer.value[0] = wcd->hph_mode; + + return 0; +} + +static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + u32 mode_val; + + mode_val = ucontrol->value.enumerated.item[0]; + + if (mode_val == 0) { + dev_err(wcd->dev, "Invalid HPH Mode, default to ClSH HiFi\n"); + mode_val = CLS_H_HIFI; + } + wcd->hph_mode = mode_val; + + return 0; +} + +static int wcd9335_ear_pa_gain_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + int ear_pa_gain; + + ear_pa_gain = snd_soc_component_read32(component, WCD9335_ANA_EAR); + ear_pa_gain = (ear_pa_gain & 0x70) >> 4; + ucontrol->value.integer.value[0] = ear_pa_gain; + + return 0; +} + +static int wcd9335_ear_pa_gain_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + u8 ear_pa_gain; + + ear_pa_gain = ucontrol->value.integer.value[0] << 4; + snd_soc_component_update_bits(component, WCD9335_ANA_EAR, + 0x70, ear_pa_gain); + + return 0; +} + +static const struct snd_kcontrol_new wcd9335_snd_controls[] = { + /* -84dB min - 40dB max */ + SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume", + WCD9335_CDC_RX0_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume", + WCD9335_CDC_RX1_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume", + WCD9335_CDC_RX2_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume", + WCD9335_CDC_RX3_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume", + WCD9335_CDC_RX4_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume", + WCD9335_CDC_RX5_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume", + WCD9335_CDC_RX6_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume", + WCD9335_CDC_RX7_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume", + WCD9335_CDC_RX8_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum), + SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum), + SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum), + SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum), + SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum), + SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum), + SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum), + SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum), + SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum), + SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum), + SOC_ENUM("RX INT5_1 HPF cut off", cf_int5_1_enum), + SOC_ENUM("RX INT5_2 HPF cut off", cf_int5_2_enum), + SOC_ENUM("RX INT6_1 HPF cut off", cf_int6_1_enum), + SOC_ENUM("RX INT6_2 HPF cut off", cf_int6_2_enum), + SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum), + SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum), + SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum), + SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum), + SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP5 Switch", SND_SOC_NOPM, COMPANDER_5, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP6 Switch", SND_SOC_NOPM, COMPANDER_6, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd9335_rx_hph_mode_get, wcd9335_rx_hph_mode_put), + + /* Gain Controls */ + SOC_ENUM_EXT("EAR PA Gain", wcd9335_ear_pa_gain_enum, + wcd9335_ear_pa_gain_get, wcd9335_ear_pa_gain_put), + + SOC_SINGLE_TLV("HPHL Volume", WCD9335_HPH_L_EN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD9335_HPH_R_EN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("LINEOUT1 Volume", WCD9335_DIFF_LO_LO1_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT2 Volume", WCD9335_DIFF_LO_LO2_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT3 Volume", WCD9335_SE_LO_LO3_GAIN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("LINEOUT4 Volume", WCD9335_SE_LO_LO4_GAIN, 0, 20, 1, + line_gain), + + SOC_SINGLE_TLV("ADC1 Volume", WCD9335_ANA_AMIC1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD9335_ANA_AMIC2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD9335_ANA_AMIC3, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD9335_ANA_AMIC4, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC5 Volume", WCD9335_ANA_AMIC5, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC6 Volume", WCD9335_ANA_AMIC6, 0, 20, 0, + analog_gain), + + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + SOC_ENUM("TX5 HPF cut off", cf_dec5_enum), + SOC_ENUM("TX6 HPF cut off", cf_dec6_enum), + SOC_ENUM("TX7 HPF cut off", cf_dec7_enum), + SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), +}; + static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) { struct wcd9335_codec *wcd = data; @@ -1119,6 +1488,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .probe = wcd9335_codec_probe, .remove = wcd9335_codec_remove, .set_sysclk = wcd9335_codec_set_sysclk, + .controls = wcd9335_snd_controls, + .num_controls = ARRAY_SIZE(wcd9335_snd_controls), }; static int wcd9335_probe(struct platform_device *pdev) From patchwork Mon Jul 23 15:54:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540555 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C769D1823 for ; Mon, 23 Jul 2018 15:59:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ADEB928CDC for ; Mon, 23 Jul 2018 15:59:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A0C5828CE8; Mon, 23 Jul 2018 15:59:53 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3EBAF28CE8 for ; Mon, 23 Jul 2018 15:59:50 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 45ED026779D; Mon, 23 Jul 2018 17:58:47 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 08C052677A2; Mon, 23 Jul 2018 17:58:35 +0200 (CEST) Received: from mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65]) by alsa0.perex.cz (Postfix) with ESMTP id 85E0E267762 for ; Mon, 23 Jul 2018 17:58:28 +0200 (CEST) Received: by mail-wm0-f65.google.com with SMTP id z13-v6so1734578wma.5 for ; Mon, 23 Jul 2018 08:58:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BxV9MpB3e1th9tBjCBPtrxc5048SWXxlkHiKPEu58aU=; b=hyCJDxdgrCMghfN55Jb9wOm9+qx5XLT6m/4hNdb6uax247juS5MKtkYBt666xs0BwK Y4d0nZpSwGe/DNHKh1uQtPQR6BaCnOkfTOYf+ZJrjvETdhkSHsao4a5FcoeXT/STFOwk 0lIEUjy/rLnb5BDnsPq1ZRu0T4tbDEGUY2PoM= 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=BxV9MpB3e1th9tBjCBPtrxc5048SWXxlkHiKPEu58aU=; b=lIWAdTYb3OZD9cCSCRXwffde2sHke53yJssexYMw9+RTPj5nK5B2EO9vGNFYqOAYXI ylnvogRC3gL7YxCjU2OtxmlNIqMXwaPK+8bDXgJSlVidWQI+7277mQ23A9Fpw/rG35LG q+GE92XP/LOQeAx4gVzIpqJ3YDLWRQYFr9aSufZcmqj7+v+65KPuTeUK1K5GNQ9rpI3R x95Z7Uc3Z7Pbw2EWY5S3btZMpA4hKp1AeAeiVG1lOT87Dx/vGhQOb7fQATDPK5x7aF6s RzzpCe5LrZDVeTt/UaR+t0Xe6mZtf/WvD8CuQQXno7KlN/SulgFm2+pfmVK0a9en2nuc syGw== X-Gm-Message-State: AOUpUlEobrj/2YyihXG49kwxxPcVMCfgLKvwfNFzXf5QLet0h29kdN7n gs9LBFBQRpi4ijeYESqbYL1Lcg== X-Google-Smtp-Source: AAOMgpdbxS1TWaFrfMf9I8WE21R5frf8Fc1mkzLVgCGBMwSL0shOKADqVqpx6fLRRzuFPa2owUgy9A== X-Received: by 2002:a1c:5582:: with SMTP id j124-v6mr8177067wmb.153.1532361507422; Mon, 23 Jul 2018 08:58:27 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:26 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:07 +0100 Message-Id: <20180723155410.9494-10-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 09/12] ASoC: wcd9335: add playback dapm widgets X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Srinivas Kandagatla --- sound/soc/codecs/wcd9335.c | 1802 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1802 insertions(+) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index e1f63d8cc7d4..3bdfa7f4e26e 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -146,6 +146,18 @@ enum { }; +enum { + INTERP_EAR = 0, + INTERP_HPHL, + INTERP_HPHR, + INTERP_LO1, + INTERP_LO2, + INTERP_LO3, + INTERP_LO4, + INTERP_SPKR1, + INTERP_SPKR2, +}; + enum wcd_clock_type { WCD_CLK_OFF, WCD_CLK_RCO, @@ -196,7 +208,14 @@ struct wcd9335_codec { struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; + int prim_int_users[WCD9335_NUM_INTERPOLATORS]; + int comp_enabled[COMPANDER_MAX]; + + unsigned int rx_port_value; + int hph_l_gain; + int hph_r_gain; + u32 rx_bias_count; }; static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = { @@ -323,10 +342,69 @@ static const char * const wcd9335_ear_pa_gain_text[] = { "G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB" }; +static const char * const rx_int0_7_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7", "PROXIMITY" +}; + +static const char * const rx_int_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7" +}; + +static const char * const rx_prim_mix_text[] = { + "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2", + "RX3", "RX4", "RX5", "RX6", "RX7" +}; + +static const char * const rx_int_dem_inp_mux_text[] = { + "NORMAL_DSM_OUT", "CLSH_DSM_OUT", +}; + +static const char * const rx_int0_interp_mux_text[] = { + "ZERO", "RX INT0 MIX2", +}; + +static const char * const rx_int1_interp_mux_text[] = { + "ZERO", "RX INT1 MIX2", +}; + +static const char * const rx_int2_interp_mux_text[] = { + "ZERO", "RX INT2 MIX2", +}; + +static const char * const rx_int3_interp_mux_text[] = { + "ZERO", "RX INT3 MIX2", +}; + +static const char * const rx_int4_interp_mux_text[] = { + "ZERO", "RX INT4 MIX2", +}; + +static const char * const rx_int5_interp_mux_text[] = { + "ZERO", "RX INT5 MIX2", +}; + +static const char * const rx_int6_interp_mux_text[] = { + "ZERO", "RX INT6 MIX2", +}; + +static const char * const rx_int7_interp_mux_text[] = { + "ZERO", "RX INT7 MIX2", +}; + +static const char * const rx_int8_interp_mux_text[] = { + "ZERO", "RX INT8 SEC MIX" +}; + static const char * const rx_hph_mode_mux_text[] = { "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI" }; +static const char *const slim_rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB", +}; + static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -420,6 +498,455 @@ static const struct soc_enum rx_hph_mode_mux_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text); +static const struct soc_enum slim_rx_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text); + +static const struct soc_enum rx_int0_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, 10, + rx_int0_7_mix_mux_text); + +static const struct soc_enum rx_int1_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int2_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int3_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int4_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int5_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int6_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int7_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, 10, + rx_int0_7_mix_mux_text); + +static const struct soc_enum rx_int8_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int0_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int1_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int2_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int0_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CTL, 5, 2, + rx_int0_interp_mux_text); + +static const struct soc_enum rx_int1_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CTL, 5, 2, + rx_int1_interp_mux_text); + +static const struct soc_enum rx_int2_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CTL, 5, 2, + rx_int2_interp_mux_text); + +static const struct soc_enum rx_int3_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CTL, 5, 2, + rx_int3_interp_mux_text); + +static const struct soc_enum rx_int4_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CTL, 5, 2, + rx_int4_interp_mux_text); + +static const struct soc_enum rx_int5_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CTL, 5, 2, + rx_int5_interp_mux_text); + +static const struct soc_enum rx_int6_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CTL, 5, 2, + rx_int6_interp_mux_text); + +static const struct soc_enum rx_int7_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CTL, 5, 2, + rx_int7_interp_mux_text); + +static const struct soc_enum rx_int8_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2, + rx_int8_interp_mux_text); + +static const struct snd_kcontrol_new rx_int0_2_mux = + SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int1_2_mux = + SOC_DAPM_ENUM("RX INT1_2 MUX Mux", rx_int1_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int2_2_mux = + SOC_DAPM_ENUM("RX INT2_2 MUX Mux", rx_int2_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int3_2_mux = + SOC_DAPM_ENUM("RX INT3_2 MUX Mux", rx_int3_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int4_2_mux = + SOC_DAPM_ENUM("RX INT4_2 MUX Mux", rx_int4_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int5_2_mux = + SOC_DAPM_ENUM("RX INT5_2 MUX Mux", rx_int5_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int6_2_mux = + SOC_DAPM_ENUM("RX INT6_2 MUX Mux", rx_int6_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int7_2_mux = + SOC_DAPM_ENUM("RX INT7_2 MUX Mux", rx_int7_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int8_2_mux = + SOC_DAPM_ENUM("RX INT8_2 MUX Mux", rx_int8_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP0 Mux", rx_int0_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP1 Mux", rx_int0_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP2 Mux", rx_int0_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP0 Mux", rx_int1_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP1 Mux", rx_int1_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP2 Mux", rx_int1_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP0 Mux", rx_int2_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP1 Mux", rx_int2_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP2 Mux", rx_int2_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP0 Mux", rx_int3_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP1 Mux", rx_int3_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP2 Mux", rx_int3_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP0 Mux", rx_int4_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP1 Mux", rx_int4_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP2 Mux", rx_int4_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP0 Mux", rx_int5_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP1 Mux", rx_int5_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP2 Mux", rx_int5_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP0 Mux", rx_int6_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP1 Mux", rx_int6_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP2 Mux", rx_int6_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP0 Mux", rx_int7_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP1 Mux", rx_int7_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP2 Mux", rx_int7_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP0 Mux", rx_int8_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP1 Mux", rx_int8_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP2 Mux", rx_int8_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int0_interp_mux = + SOC_DAPM_ENUM("RX INT0 INTERP Mux", rx_int0_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int1_interp_mux = + SOC_DAPM_ENUM("RX INT1 INTERP Mux", rx_int1_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int2_interp_mux = + SOC_DAPM_ENUM("RX INT2 INTERP Mux", rx_int2_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int3_interp_mux = + SOC_DAPM_ENUM("RX INT3 INTERP Mux", rx_int3_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int4_interp_mux = + SOC_DAPM_ENUM("RX INT4 INTERP Mux", rx_int4_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int5_interp_mux = + SOC_DAPM_ENUM("RX INT5 INTERP Mux", rx_int5_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int6_interp_mux = + SOC_DAPM_ENUM("RX INT6 INTERP Mux", rx_int6_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int7_interp_mux = + SOC_DAPM_ENUM("RX INT7 INTERP Mux", rx_int7_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int8_interp_mux = + SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum); + +static int slim_rx_mux_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev); + + ucontrol->value.enumerated.item[0] = wcd->rx_port_value; + + return 0; +} + +static int slim_rx_mux_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(w->dapm->dev); + struct soc_enum *e = (struct soc_enum *)kc->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 port_id = w->shift; + + wcd->rx_port_value = ucontrol->value.enumerated.item[0]; + + switch (wcd->rx_port_value) { + case 0: + list_del_init(&wcd->rx_chs[port_id].list); + break; + case 1: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF1_PB].slim_ch_list); + break; + case 2: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF2_PB].slim_ch_list); + break; + case 3: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF3_PB].slim_ch_list); + break; + case 4: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF4_PB].slim_ch_list); + break; + default: + dev_err(wcd->dev, "Unknown AIF %d\n", wcd->rx_port_value); + goto err; + } + + snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value, + e, update); + + return 0; +err: + return -EINVAL; +} + +static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = { + SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), +}; + +static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kc->private_value; + struct snd_soc_component *component; + int reg, val; + + component = snd_soc_dapm_kcontrol_component(kc); + val = ucontrol->value.enumerated.item[0]; + + if (e->reg == WCD9335_CDC_RX0_RX_PATH_SEC0) + reg = WCD9335_CDC_RX0_RX_PATH_CFG0; + else if (e->reg == WCD9335_CDC_RX1_RX_PATH_SEC0) + reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + else if (e->reg == WCD9335_CDC_RX2_RX_PATH_SEC0) + reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + else + return -EINVAL; + + /* Set Look Ahead Delay */ + snd_soc_component_update_bits(component, reg, + WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN_MASK, + val ? WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN : 0); + /* Set DEM INP Select */ + return snd_soc_dapm_put_enum_double(kc, ucontrol); +} + +static const struct snd_kcontrol_new rx_int0_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT0 DEM MUX Mux", rx_int0_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + wcd9335_int_dem_inp_mux_put); + +static const struct snd_kcontrol_new rx_int1_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT1 DEM MUX Mux", rx_int1_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + wcd9335_int_dem_inp_mux_put); + +static const struct snd_kcontrol_new rx_int2_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT2 DEM MUX Mux", rx_int2_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + wcd9335_int_dem_inp_mux_put); + static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, int rate_val, u32 rate) @@ -1039,6 +1566,994 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = { SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), }; +static void wcd9335_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai, + struct snd_soc_component *component) +{ + int port_num = 0; + unsigned short reg = 0; + unsigned int val = 0; + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + struct wcd9335_slim_ch *ch; + + list_for_each_entry(ch, &dai->slim_ch_list, list) { + if (ch->port >= WCD9335_RX_START) { + port_num = ch->port - WCD9335_RX_START; + reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + (port_num / 8); + } else { + port_num = ch->port; + reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8); + } + + regmap_read(wcd->if_regmap, reg, &val); + if (!(val & BIT(port_num % 8))) + regmap_write(wcd->if_regmap, reg, + val | BIT(port_num % 8)); + } +} + +static int wcd9335_codec_enable_slim(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp); + struct wcd_slim_codec_dai_data *dai = &wcd->dai[w->shift]; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + wcd9335_codec_enable_int_port(dai, comp); + break; + case SND_SOC_DAPM_POST_PMD: + slim_stream_unprepare(dai->sruntime); + slim_stream_disable(dai->sruntime); + kfree(dai->sconfig.chs); + + break; + } + + return ret; +} + +static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + int offset_val = 0; + int val = 0; + + switch (w->reg) { + case WCD9335_CDC_RX0_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX0_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX1_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX1_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX2_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX2_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX3_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX3_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX4_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX4_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX5_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX5_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX6_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX6_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX7_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX7_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX8_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX8_RX_VOL_MIX_CTL; + break; + default: + dev_err(comp->dev, "%s: No gain register avail for %s\n", + __func__, w->name); + return 0; + }; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = snd_soc_component_read32(comp, gain_reg); + val += offset_val; + snd_soc_component_write(comp, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + break; + }; + + return 0; +} + +static u16 wcd9335_interp_get_primary_reg(u16 reg, u16 *ind) +{ + u16 prim_int_reg; + + switch (reg) { + case WCD9335_CDC_RX0_RX_PATH_CTL: + case WCD9335_CDC_RX0_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL; + *ind = 0; + break; + case WCD9335_CDC_RX1_RX_PATH_CTL: + case WCD9335_CDC_RX1_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX1_RX_PATH_CTL; + *ind = 1; + break; + case WCD9335_CDC_RX2_RX_PATH_CTL: + case WCD9335_CDC_RX2_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX2_RX_PATH_CTL; + *ind = 2; + break; + case WCD9335_CDC_RX3_RX_PATH_CTL: + case WCD9335_CDC_RX3_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX3_RX_PATH_CTL; + *ind = 3; + break; + case WCD9335_CDC_RX4_RX_PATH_CTL: + case WCD9335_CDC_RX4_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX4_RX_PATH_CTL; + *ind = 4; + break; + case WCD9335_CDC_RX5_RX_PATH_CTL: + case WCD9335_CDC_RX5_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX5_RX_PATH_CTL; + *ind = 5; + break; + case WCD9335_CDC_RX6_RX_PATH_CTL: + case WCD9335_CDC_RX6_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX6_RX_PATH_CTL; + *ind = 6; + break; + case WCD9335_CDC_RX7_RX_PATH_CTL: + case WCD9335_CDC_RX7_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX7_RX_PATH_CTL; + *ind = 7; + break; + case WCD9335_CDC_RX8_RX_PATH_CTL: + case WCD9335_CDC_RX8_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX8_RX_PATH_CTL; + *ind = 8; + break; + }; + + return prim_int_reg; +} + +static void wcd9335_codec_hd2_control(struct snd_soc_component *component, + u16 prim_int_reg, int event) +{ + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + + if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX1_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + } + if (prim_int_reg == WCD9335_CDC_RX2_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX2_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P2500); + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_2); + snd_soc_component_update_bits(component, hd2_enable_reg, + WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_HD2_ENABLE); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_HD2_DISABLE); + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_1); + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000); + } +} + +static int wcd9335_codec_enable_prim_interpolator( + struct snd_soc_component *comp, + u16 reg, int event) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + u16 ind = 0; + int prim_int_reg = wcd9335_interp_get_primary_reg(reg, &ind); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd->prim_int_users[ind]++; + if (wcd->prim_int_users[ind] == 1) { + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_ENABLE); + wcd9335_codec_hd2_control(comp, prim_int_reg, event); + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_CLK_EN_MASK, + WCD9335_CDC_RX_CLK_ENABLE); + } + + if ((reg != prim_int_reg) && + ((snd_soc_component_read32(comp, prim_int_reg)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK)) + snd_soc_component_update_bits(comp, reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_ENABLE); + break; + case SND_SOC_DAPM_POST_PMD: + wcd->prim_int_users[ind]--; + if (wcd->prim_int_users[ind] == 0) { + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_CLK_EN_MASK, + WCD9335_CDC_RX_CLK_DISABLE); + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_RESET_MASK, + WCD9335_CDC_RX_RESET_ENABLE); + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_RESET_MASK, + WCD9335_CDC_RX_RESET_DISABLE); + wcd9335_codec_hd2_control(comp, prim_int_reg, event); + } + break; + }; + + return 0; +} + +static int wcd9335_config_compander(struct snd_soc_component *component, + int interp_n, int event) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int comp; + u16 comp_ctl0_reg, rx_path_cfg0_reg; + + /* EAR does not have compander */ + if (!interp_n) + return 0; + + comp = interp_n - 1; + if (!wcd->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = WCD9335_CDC_COMPANDER1_CTL(comp); + rx_path_cfg0_reg = WCD9335_CDC_RX1_RX_PATH_CFG(comp); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_CLK_EN_MASK, + WCD9335_CDC_COMPANDER_CLK_ENABLE); + /* Reset comander */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE); + /* Enables DRE in this path */ + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_CMP_ENABLE); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_HALT_MASK, + WCD9335_CDC_COMPANDER_HALT); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_CMP_DISABLE); + + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_CLK_EN_MASK, + WCD9335_CDC_COMPANDER_CLK_DISABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_HALT_MASK, + WCD9335_CDC_COMPANDER_NOHALT); + } + + return 0; +} + +static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + u16 reg; + int val; + int offset_val = 0; + + if (!(strcmp(w->name, "RX INT0 INTERP"))) { + reg = WCD9335_CDC_RX0_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX0_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT1 INTERP"))) { + reg = WCD9335_CDC_RX1_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX1_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT2 INTERP"))) { + reg = WCD9335_CDC_RX2_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX2_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT3 INTERP"))) { + reg = WCD9335_CDC_RX3_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX3_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT4 INTERP"))) { + reg = WCD9335_CDC_RX4_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX4_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT5 INTERP"))) { + reg = WCD9335_CDC_RX5_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX5_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT6 INTERP"))) { + reg = WCD9335_CDC_RX6_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX6_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT7 INTERP"))) { + reg = WCD9335_CDC_RX7_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX7_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT8 INTERP"))) { + reg = WCD9335_CDC_RX8_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX8_RX_VOL_CTL; + } else { + dev_err(comp->dev, "%s: Interpolator reg not found\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reset if needed */ + wcd9335_codec_enable_prim_interpolator(comp, reg, event); + break; + case SND_SOC_DAPM_POST_PMU: + wcd9335_config_compander(comp, w->shift, event); + val = snd_soc_component_read32(comp, gain_reg); + val += offset_val; + snd_soc_component_write(comp, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + wcd9335_config_compander(comp, w->shift, event); + wcd9335_codec_enable_prim_interpolator(comp, reg, event); + break; + }; + + return 0; +} + +static void wcd9335_codec_hph_mode_gain_opt(struct snd_soc_component *component, + u8 gain) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + u8 hph_l_en, hph_r_en; + u8 l_val, r_val; + u8 hph_pa_status; + bool is_hphl_pa, is_hphr_pa; + + hph_pa_status = snd_soc_component_read32(component, WCD9335_ANA_HPH); + is_hphl_pa = hph_pa_status >> 7; + is_hphr_pa = (hph_pa_status & 0x40) >> 6; + + hph_l_en = snd_soc_component_read32(component, WCD9335_HPH_L_EN); + hph_r_en = snd_soc_component_read32(component, WCD9335_HPH_R_EN); + + l_val = (hph_l_en & 0xC0) | 0x20 | gain; + r_val = (hph_r_en & 0xC0) | 0x20 | gain; + + /* + * Set HPH_L & HPH_R gain source selection to REGISTER + * for better click and pop only if corresponding PAs are + * not enabled. Also cache the values of the HPHL/R + * PA gains to be applied after PAs are enabled + */ + if ((l_val != hph_l_en) && !is_hphl_pa) { + snd_soc_component_write(component, WCD9335_HPH_L_EN, l_val); + wcd->hph_l_gain = hph_l_en & 0x1F; + } + + if ((r_val != hph_r_en) && !is_hphr_pa) { + snd_soc_component_write(component, WCD9335_HPH_R_EN, r_val); + wcd->hph_r_gain = hph_r_en & 0x1F; + } +} + +static void wcd9335_codec_hph_lohifi_config(struct snd_soc_component *comp, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(comp, WCD9335_RX_BIAS_HPH_PA, + WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK, + 0x06); + snd_soc_component_update_bits(comp, + WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, + 0xF0, 0x40); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + 0x0C); + wcd9335_codec_hph_mode_gain_opt(comp, 0x11); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500); + snd_soc_component_write(comp, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, + 0x8A); + snd_soc_component_update_bits(comp, WCD9335_RX_BIAS_HPH_PA, + WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK, + 0x0A); + } +} + +static void wcd9335_codec_hph_lp_config(struct snd_soc_component *comp, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + 0x0C); + wcd9335_codec_hph_mode_gain_opt(comp, 0x10); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK, + WCD9335_HPH_PA_CTL2_HPH_PSRR_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_RDAC_LDO_CTL, + WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_MASK, + WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_V_N1P60); + snd_soc_component_update_bits(comp, WCD9335_HPH_RDAC_LDO_CTL, + WCD9335_HPH_RDAC_1P65_LD_OUTCTL_MASK, + WCD9335_HPH_RDAC_1P65_LD_OUTCTL_V_N1P60); + snd_soc_component_update_bits(comp, + WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x0F, 0x01); + snd_soc_component_update_bits(comp, + WCD9335_RX_BIAS_HPH_RDAC_LDO, 0xF0, 0x10); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_write(comp, WCD9335_RX_BIAS_HPH_RDAC_LDO, + 0x88); + snd_soc_component_write(comp, WCD9335_HPH_RDAC_LDO_CTL, + 0x33); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK, + WCD9335_HPH_PA_CTL2_HPH_PSRR_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500); + snd_soc_component_update_bits(comp, WCD9335_HPH_R_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_HQ_PATH); + snd_soc_component_update_bits(comp, WCD9335_HPH_L_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_HQ_PATH); + } +} + +static void wcd9335_codec_hph_hifi_config(struct snd_soc_component *comp, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + 0x0C); + wcd9335_codec_hph_mode_gain_opt(comp, 0x11); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500); + } +} + +static void wcd9335_codec_hph_mode_config(struct snd_soc_component *component, + int event, int mode) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + if (!WCD9335_IS_2_0(wcd->version)) + return; + + switch (mode) { + case CLS_H_LP: + wcd9335_codec_hph_lp_config(component, event); + break; + case CLS_H_LOHIFI: + wcd9335_codec_hph_lohifi_config(component, event); + break; + case CLS_H_HIFI: + wcd9335_codec_hph_hifi_config(component, event); + break; + } +} + +static int wcd9335_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + u8 dem_inp; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32(comp, + WCD9335_CDC_RX1_RX_PATH_SEC0) & 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(comp->dev, "Incorrect DEM Input\n"); + return -EINVAL; + } + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_PRE_PMD: + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + + if (!(wcd_clsh_ctrl_get_state(wcd->clsh_ctrl) & + WCD_CLSH_STATE_HPHR)) + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + }; + + return ret; +} + +static int wcd9335_codec_lineout_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_LO, CLS_AB); + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_LO, CLS_AB); + break; + } + + return 0; +} + +static int wcd9335_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, CLS_H_NORMAL); + + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, CLS_H_NORMAL); + break; + }; + + return ret; +} + +static void wcd9335_codec_hph_post_pa_config(struct wcd9335_codec *wcd, + int mode, int event) +{ + u8 scale_val = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (mode) { + case CLS_H_HIFI: + scale_val = 0x3; + break; + case CLS_H_LOHIFI: + scale_val = 0x1; + break; + } + break; + case SND_SOC_DAPM_PRE_PMD: + scale_val = 0x6; + break; + } + + if (scale_val) + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + scale_val << 1); + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (wcd->comp_enabled[COMPANDER_1] || + wcd->comp_enabled[COMPANDER_2]) { + /* GAIN Source Selection */ + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_L_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, + WCD9335_HPH_GAIN_SRC_SEL_COMPANDER); + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_R_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, + WCD9335_HPH_GAIN_SRC_SEL_COMPANDER); + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_AUTO_CHOP, + WCD9335_HPH_AUTO_CHOP_MASK, + WCD9335_HPH_AUTO_CHOP_FORCE_ENABLE); + } + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_L_EN, + WCD9335_HPH_PA_GAIN_MASK, + wcd->hph_l_gain); + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_R_EN, + WCD9335_HPH_PA_GAIN_MASK, + wcd->hph_r_gain); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_AUTO_CHOP, + WCD9335_HPH_AUTO_CHOP_MASK, + WCD9335_HPH_AUTO_CHOP_ENABLE_BY_CMPDR_GAIN); +} + +static int wcd9335_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + u8 dem_inp; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32(comp, + WCD9335_CDC_RX2_RX_PATH_SEC0) & + WCD9335_CDC_RX_PATH_DEM_INP_SEL_MASK; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(comp->dev, "DEM Input not set correctly, hph_mode: %d\n", + hph_mode); + return -EINVAL; + } + + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + + if (!(wcd_clsh_ctrl_get_state(wcd->clsh_ctrl) & + WCD_CLSH_STATE_HPHL)) + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + }; + + return ret; +} + +static int wcd9335_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(7000, 7100); + + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX1_RX_PATH_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + break; + case SND_SOC_DAPM_PRE_PMD: + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + break; + }; + + return ret; +} + +static int wcd9335_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + int vol_reg = 0, mix_vol_reg = 0; + int ret = 0; + + if (w->reg == WCD9335_ANA_LO_1_2) { + if (w->shift == 7) { + vol_reg = WCD9335_CDC_RX3_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX3_RX_PATH_MIX_CTL; + } else if (w->shift == 6) { + vol_reg = WCD9335_CDC_RX4_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX4_RX_PATH_MIX_CTL; + } + } else if (w->reg == WCD9335_ANA_LO_3_4) { + if (w->shift == 7) { + vol_reg = WCD9335_CDC_RX5_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX5_RX_PATH_MIX_CTL; + } else if (w->shift == 6) { + vol_reg = WCD9335_CDC_RX6_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX6_RX_PATH_MIX_CTL; + } + } else { + dev_err(comp->dev, "Error enabling lineout PA\n"); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(comp, vol_reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, mix_vol_reg)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, mix_vol_reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + break; + }; + + return ret; +} + +static void wcd9335_codec_init_flyback(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_BYPASS); + snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_BYPASS); + snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, + WCD9335_RX_BIAS_FLYB_VPOS_5_UA_MASK, + WCD9335_RX_BIAS_FLYB_I_0P0_UA); + snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, + WCD9335_RX_BIAS_FLYB_VNEG_5_UA_MASK, + WCD9335_RX_BIAS_FLYB_I_0P0_UA); +} + +static int wcd9335_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd->rx_bias_count++; + if (wcd->rx_bias_count == 1) { + if (WCD9335_IS_2_0(wcd->version)) + wcd9335_codec_init_flyback(comp); + snd_soc_component_update_bits(comp, + WCD9335_ANA_RX_SUPPLIES, + WCD9335_ANA_RX_BIAS_ENABLE_MASK, + WCD9335_ANA_RX_BIAS_ENABLE); + } + break; + case SND_SOC_DAPM_POST_PMD: + wcd->rx_bias_count--; + if (!wcd->rx_bias_count) + snd_soc_component_update_bits(comp, + WCD9335_ANA_RX_SUPPLIES, + WCD9335_ANA_RX_BIAS_ENABLE_MASK, + WCD9335_ANA_RX_BIAS_DISABLE); + break; + }; + + return 0; +} + +static int wcd9335_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(7000, 7100); + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX2_RX_PATH_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + break; + + case SND_SOC_DAPM_PRE_PMD: + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + break; + }; + + return ret; +} + +static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX0_RX_PATH_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, + WCD9335_CDC_RX0_RX_PATH_MIX_CTL)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX0_RX_PATH_MIX_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + + break; + }; + + return ret; +} + static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) { struct wcd9335_codec *wcd = data; @@ -1357,6 +2872,291 @@ static int _wcd9335_codec_enable_mclk(struct snd_soc_component *component, return 0; } +static int wcd9335_codec_enable_mclk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return _wcd9335_codec_enable_mclk(comp, true); + case SND_SOC_DAPM_POST_PMD: + return _wcd9335_codec_enable_mclk(comp, false); + } + + return 0; +} + +static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = { + /* TODO SPK1 & SPK2 OUT*/ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + SND_SOC_DAPM_OUTPUT("LINEOUT1"), + SND_SOC_DAPM_OUTPUT("LINEOUT2"), + SND_SOC_DAPM_OUTPUT("LINEOUT3"), + SND_SOC_DAPM_OUTPUT("LINEOUT4"), + SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM, + AIF1_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM, + AIF2_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM, + AIF3_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM, + AIF4_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("SLIM RX0 MUX", SND_SOC_NOPM, WCD9335_RX0, 0, + &slim_rx_mux[WCD9335_RX0]), + SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, WCD9335_RX1, 0, + &slim_rx_mux[WCD9335_RX1]), + SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, WCD9335_RX2, 0, + &slim_rx_mux[WCD9335_RX2]), + SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, WCD9335_RX3, 0, + &slim_rx_mux[WCD9335_RX3]), + SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, WCD9335_RX4, 0, + &slim_rx_mux[WCD9335_RX4]), + SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, WCD9335_RX5, 0, + &slim_rx_mux[WCD9335_RX5]), + SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, WCD9335_RX6, 0, + &slim_rx_mux[WCD9335_RX6]), + SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, WCD9335_RX7, 0, + &slim_rx_mux[WCD9335_RX7]), + SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", WCD9335_CDC_RX0_RX_PATH_MIX_CTL, + 5, 0, &rx_int0_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + 5, 0, &rx_int1_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + 5, 0, &rx_int2_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", WCD9335_CDC_RX3_RX_PATH_MIX_CTL, + 5, 0, &rx_int3_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", WCD9335_CDC_RX4_RX_PATH_MIX_CTL, + 5, 0, &rx_int4_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT5_2 MUX", WCD9335_CDC_RX5_RX_PATH_MIX_CTL, + 5, 0, &rx_int5_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT6_2 MUX", WCD9335_CDC_RX6_RX_PATH_MIX_CTL, + 5, 0, &rx_int6_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", WCD9335_CDC_RX7_RX_PATH_MIX_CTL, + 5, 0, &rx_int7_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", WCD9335_CDC_RX8_RX_PATH_MIX_CTL, + 5, 0, &rx_int8_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp2_mux), + + SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int0_dem_inp_mux), + SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int1_dem_inp_mux), + SND_SOC_DAPM_MUX("RX INT2 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int2_dem_inp_mux), + + SND_SOC_DAPM_MUX_E("RX INT0 INTERP", SND_SOC_NOPM, + INTERP_EAR, 0, &rx_int0_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1 INTERP", SND_SOC_NOPM, + INTERP_HPHL, 0, &rx_int1_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2 INTERP", SND_SOC_NOPM, + INTERP_HPHR, 0, &rx_int2_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT3 INTERP", SND_SOC_NOPM, + INTERP_LO1, 0, &rx_int3_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT4 INTERP", SND_SOC_NOPM, + INTERP_LO2, 0, &rx_int4_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT5 INTERP", SND_SOC_NOPM, + INTERP_LO3, 0, &rx_int5_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT6 INTERP", SND_SOC_NOPM, + INTERP_LO4, 0, &rx_int6_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7 INTERP", SND_SOC_NOPM, + INTERP_SPKR1, 0, &rx_int7_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8 INTERP", SND_SOC_NOPM, + INTERP_SPKR2, 0, &rx_int8_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, WCD9335_ANA_HPH, + 5, 0, wcd9335_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, WCD9335_ANA_HPH, + 4, 0, wcd9335_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT5 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT6 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0, + wcd9335_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PA", WCD9335_ANA_HPH, 6, 0, NULL, 0, + wcd9335_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("EAR PA", WCD9335_ANA_EAR, 7, 0, NULL, 0, + wcd9335_codec_enable_ear_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD9335_ANA_LO_1_2, 7, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD9335_ANA_LO_1_2, 6, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT3 PA", WCD9335_ANA_LO_3_4, 7, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT4 PA", WCD9335_ANA_LO_3_4, 6, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_mclk, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + +}; + static void wcd9335_enable_sido_buck(struct snd_soc_component *component) { struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); @@ -1490,6 +3290,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .set_sysclk = wcd9335_codec_set_sysclk, .controls = wcd9335_snd_controls, .num_controls = ARRAY_SIZE(wcd9335_snd_controls), + .dapm_widgets = wcd9335_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets), }; static int wcd9335_probe(struct platform_device *pdev) From patchwork Mon Jul 23 15:54:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540561 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CCDE314BC for ; Mon, 23 Jul 2018 16:00:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B80AF28D2F for ; Mon, 23 Jul 2018 16:00:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ABE5028D01; Mon, 23 Jul 2018 16:00:08 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BB6B828D50 for ; Mon, 23 Jul 2018 16:00:05 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 5B1DB2677C6; Mon, 23 Jul 2018 17:58:52 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id E09422677B8; Mon, 23 Jul 2018 17:58:40 +0200 (CEST) Received: from mail-wr1-f66.google.com (mail-wr1-f66.google.com [209.85.221.66]) by alsa0.perex.cz (Postfix) with ESMTP id 6024B267793 for ; Mon, 23 Jul 2018 17:58:29 +0200 (CEST) Received: by mail-wr1-f66.google.com with SMTP id c13-v6so1249189wrt.1 for ; Mon, 23 Jul 2018 08:58:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=RC8AlHD4uKW2eAOwUyzra5CRnBKG9B8f5W3Ay4tuox4=; b=Kuts83lTJQf4vWL5vTWx9ERYXb+QxSXi27j6PZ87i6SSqvf8zKYVCZh+cQoeIcKnKp 9qizbDU9jdIZ4maO0yuq3+VfJ6An85NeA0yAqg8CO9GWomiO9RVe+tn5ofs2DWTi0UBm e0SSznN37z8y9oviECKpjdG7XFImucp/O3MPE= 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=RC8AlHD4uKW2eAOwUyzra5CRnBKG9B8f5W3Ay4tuox4=; b=kmH8RQMjxxtdzFijBQROJjkgqXW0yOUr4nLT0kIs/GTLc05mn1v9jBvEB3STZuY/QW 9dqh6WLDr2bE+47YOaR6wUY4KCBYH5GxIb+5M4yYRf2btpXu4KeiYAbd+jZLQTWgHZ87 Qzo2Gk0DiA/OZ+PQAOE0p3x4ZFnYCXb40Cx1Cz8r1T29fUK6Q0b2MciUJlxDdjPtaXza j9HE4QjaGl9JL1KFzmQxhXYwXHZhR/exDacSTswldRuArNcdAqSvLETsbvHBt9MVjeeA 8MMA9Qc1Wb5dAIAzEk9CGPYYyVXP/uNWWUkWidG+CSRxAtHXtvImuDfkhi3ecqc0Tt5C pUlg== X-Gm-Message-State: AOUpUlEQm0nYY5zdtsUP9e79lZlG66nwoiQFiUZk41OLBXpKHDT+Lmdh jDARY0Drr3fhSRRB9CfWp7rGAQ== X-Google-Smtp-Source: AAOMgpcD7sFbns4fitGVERp3Zy2kYxvMI5TnNS3fAZvxd+QatW1NxRAm8ZzXGXIkN8Ubi1Cp/TueJA== X-Received: by 2002:adf:84e5:: with SMTP id 92-v6mr9186219wrg.56.1532361508881; Mon, 23 Jul 2018 08:58:28 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:28 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:08 +0100 Message-Id: <20180723155410.9494-11-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 10/12] ASoC: wcd9335: add capture dapm widgets X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Srinivas Kandagatla --- sound/soc/codecs/wcd9335.c | 1451 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1450 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 3bdfa7f4e26e..a08703681674 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -59,10 +59,46 @@ #define WCD9335_NUM_INTERPOLATORS 9 #define WCD9335_RX_START 16 #define WCD9335_SLIM_CH_START 128 +#define WCD9335_MAX_MICBIAS 4 +#define WCD9335_MAX_VALID_ADC_MUX 13 +#define WCD9335_INVALID_ADC_MUX 9 + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 +#define WCD9335_DMIC_CLK_DIV_2 0x0 +#define WCD9335_DMIC_CLK_DIV_3 0x1 +#define WCD9335_DMIC_CLK_DIV_4 0x2 +#define WCD9335_DMIC_CLK_DIV_6 0x3 +#define WCD9335_DMIC_CLK_DIV_8 0x4 +#define WCD9335_DMIC_CLK_DIV_16 0x5 +#define WCD9335_DMIC_CLK_DRIVE_DEFAULT 0x02 +#define WCD9335_AMIC_PWR_LEVEL_LP 0 +#define WCD9335_AMIC_PWR_LEVEL_DEFAULT 1 +#define WCD9335_AMIC_PWR_LEVEL_HP 2 +#define WCD9335_AMIC_PWR_LVL_MASK 0x60 +#define WCD9335_AMIC_PWR_LVL_SHIFT 0x5 + +#define WCD9335_DEC_PWR_LVL_MASK 0x06 +#define WCD9335_DEC_PWR_LVL_LP 0x02 +#define WCD9335_DEC_PWR_LVL_HP 0x04 +#define WCD9335_DEC_PWR_LVL_DF 0x00 + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +#define WCD9335_ANC_DMIC_X2_FULL_RATE 1 +#define WCD9335_ANC_DMIC_X2_HALF_RATE 0 #define WCD9335_SLIM_RX_CH(p) \ {.port = p + WCD9335_RX_START, .shift = p,} +#define WCD9335_SLIM_TX_CH(p) \ + {.port = p, .shift = p,} + /* vout step value */ #define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) @@ -83,6 +119,26 @@ enum { WCD9335_RX_MAX, }; +enum { + WCD9335_TX0 = 0, + WCD9335_TX1, + WCD9335_TX2, + WCD9335_TX3, + WCD9335_TX4, + WCD9335_TX5, + WCD9335_TX6, + WCD9335_TX7, + WCD9335_TX8, + WCD9335_TX9, + WCD9335_TX10, + WCD9335_TX11, + WCD9335_TX12, + WCD9335_TX13, + WCD9335_TX14, + WCD9335_TX15, + WCD9335_TX_MAX, +}; + enum { SIDO_SOURCE_INTERNAL = 0, SIDO_SOURCE_RCO_BG, @@ -164,6 +220,20 @@ enum wcd_clock_type { WCD_CLK_MCLK, }; +enum { + MIC_BIAS_1 = 1, + MIC_BIAS_2, + MIC_BIAS_3, + MIC_BIAS_4 +}; + +enum { + MICB_PULLUP_ENABLE, + MICB_PULLUP_DISABLE, + MICB_ENABLE, + MICB_DISABLE, +}; + struct wcd9335_slim_ch { u32 ch_num; u16 port; @@ -192,7 +262,9 @@ struct wcd9335_codec { struct regmap_irq_chip_data *irq_data; struct wcd9335_slim_ch rx_chs[WCD9335_RX_MAX]; + struct wcd9335_slim_ch tx_chs[WCD9335_TX_MAX]; u32 num_rx_port; + u32 num_tx_port; int sido_input_src; enum wcd9335_sido_voltage sido_voltage; @@ -213,9 +285,41 @@ struct wcd9335_codec { int comp_enabled[COMPANDER_MAX]; unsigned int rx_port_value; + unsigned int tx_port_value; int hph_l_gain; int hph_r_gain; u32 rx_bias_count; + + /*TX*/ + int micb_ref[WCD9335_MAX_MICBIAS]; + int pullup_ref[WCD9335_MAX_MICBIAS]; + + int dmic_0_1_clk_cnt; + int dmic_2_3_clk_cnt; + int dmic_4_5_clk_cnt; + int dmic_sample_rate; + int mad_dmic_sample_rate; + + int native_clk_users; +}; + +static const struct wcd9335_slim_ch wcd9335_tx_chs[WCD9335_TX_MAX] = { + WCD9335_SLIM_TX_CH(0), + WCD9335_SLIM_TX_CH(1), + WCD9335_SLIM_TX_CH(2), + WCD9335_SLIM_TX_CH(3), + WCD9335_SLIM_TX_CH(4), + WCD9335_SLIM_TX_CH(5), + WCD9335_SLIM_TX_CH(6), + WCD9335_SLIM_TX_CH(7), + WCD9335_SLIM_TX_CH(8), + WCD9335_SLIM_TX_CH(9), + WCD9335_SLIM_TX_CH(10), + WCD9335_SLIM_TX_CH(11), + WCD9335_SLIM_TX_CH(12), + WCD9335_SLIM_TX_CH(13), + WCD9335_SLIM_TX_CH(14), + WCD9335_SLIM_TX_CH(15), }; static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = { @@ -405,6 +509,59 @@ static const char *const slim_rx_mux_text[] = { "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB", }; +static const char * const adc_mux_text[] = { + "DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2" +}; + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", + "SMIC0", "SMIC1", "SMIC2", "SMIC3" +}; + +static const char * const dmic_mux_alt_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", +}; + +static const char * const amic_mux_text[] = { + "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6" +}; + +static const char * const sb_tx0_mux_text[] = { + "ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192" +}; + +static const char * const sb_tx1_mux_text[] = { + "ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192" +}; + +static const char * const sb_tx2_mux_text[] = { + "ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192" +}; + +static const char * const sb_tx3_mux_text[] = { + "ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192" +}; + +static const char * const sb_tx4_mux_text[] = { + "ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192" +}; + +static const char * const sb_tx5_mux_text[] = { + "ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192" +}; + +static const char * const sb_tx6_mux_text[] = { + "ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192" +}; + +static const char * const sb_tx7_mux_text[] = { + "ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192" +}; + +static const char * const sb_tx8_mux_text[] = { + "ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192" +}; + static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -696,6 +853,150 @@ static const struct soc_enum rx_int8_interp_mux_enum = SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2, rx_int8_interp_mux_text); +static const struct soc_enum tx_adc_mux0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux3_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux4_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux5_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux6_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux7_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux8_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_dmic_mux0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_amic_mux0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum sb_tx0_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0, 4, + sb_tx0_mux_text); + +static const struct soc_enum sb_tx1_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 2, 4, + sb_tx1_mux_text); + +static const struct soc_enum sb_tx2_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 4, 4, + sb_tx2_mux_text); + +static const struct soc_enum sb_tx3_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 6, 4, + sb_tx3_mux_text); + +static const struct soc_enum sb_tx4_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 0, 4, + sb_tx4_mux_text); + +static const struct soc_enum sb_tx5_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 2, 4, + sb_tx5_mux_text); + +static const struct soc_enum sb_tx6_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 4, 4, + sb_tx6_mux_text); + +static const struct soc_enum sb_tx7_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 6, 4, + sb_tx7_mux_text); + +static const struct soc_enum sb_tx8_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 0, 4, + sb_tx8_mux_text); + static const struct snd_kcontrol_new rx_int0_2_mux = SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum); @@ -831,6 +1132,87 @@ static const struct snd_kcontrol_new rx_int7_interp_mux = static const struct snd_kcontrol_new rx_int8_interp_mux = SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum); +static const struct snd_kcontrol_new tx_dmic_mux0 = + SOC_DAPM_ENUM("DMIC MUX0 Mux", tx_dmic_mux0_enum); + +static const struct snd_kcontrol_new tx_dmic_mux1 = + SOC_DAPM_ENUM("DMIC MUX1 Mux", tx_dmic_mux1_enum); + +static const struct snd_kcontrol_new tx_dmic_mux2 = + SOC_DAPM_ENUM("DMIC MUX2 Mux", tx_dmic_mux2_enum); + +static const struct snd_kcontrol_new tx_dmic_mux3 = + SOC_DAPM_ENUM("DMIC MUX3 Mux", tx_dmic_mux3_enum); + +static const struct snd_kcontrol_new tx_dmic_mux4 = + SOC_DAPM_ENUM("DMIC MUX4 Mux", tx_dmic_mux4_enum); + +static const struct snd_kcontrol_new tx_dmic_mux5 = + SOC_DAPM_ENUM("DMIC MUX5 Mux", tx_dmic_mux5_enum); + +static const struct snd_kcontrol_new tx_dmic_mux6 = + SOC_DAPM_ENUM("DMIC MUX6 Mux", tx_dmic_mux6_enum); + +static const struct snd_kcontrol_new tx_dmic_mux7 = + SOC_DAPM_ENUM("DMIC MUX7 Mux", tx_dmic_mux7_enum); + +static const struct snd_kcontrol_new tx_dmic_mux8 = + SOC_DAPM_ENUM("DMIC MUX8 Mux", tx_dmic_mux8_enum); + +static const struct snd_kcontrol_new tx_amic_mux0 = + SOC_DAPM_ENUM("AMIC MUX0 Mux", tx_amic_mux0_enum); + +static const struct snd_kcontrol_new tx_amic_mux1 = + SOC_DAPM_ENUM("AMIC MUX1 Mux", tx_amic_mux1_enum); + +static const struct snd_kcontrol_new tx_amic_mux2 = + SOC_DAPM_ENUM("AMIC MUX2 Mux", tx_amic_mux2_enum); + +static const struct snd_kcontrol_new tx_amic_mux3 = + SOC_DAPM_ENUM("AMIC MUX3 Mux", tx_amic_mux3_enum); + +static const struct snd_kcontrol_new tx_amic_mux4 = + SOC_DAPM_ENUM("AMIC MUX4 Mux", tx_amic_mux4_enum); + +static const struct snd_kcontrol_new tx_amic_mux5 = + SOC_DAPM_ENUM("AMIC MUX5 Mux", tx_amic_mux5_enum); + +static const struct snd_kcontrol_new tx_amic_mux6 = + SOC_DAPM_ENUM("AMIC MUX6 Mux", tx_amic_mux6_enum); + +static const struct snd_kcontrol_new tx_amic_mux7 = + SOC_DAPM_ENUM("AMIC MUX7 Mux", tx_amic_mux7_enum); + +static const struct snd_kcontrol_new tx_amic_mux8 = + SOC_DAPM_ENUM("AMIC MUX8 Mux", tx_amic_mux8_enum); + +static const struct snd_kcontrol_new sb_tx0_mux = + SOC_DAPM_ENUM("SLIM TX0 MUX Mux", sb_tx0_mux_enum); + +static const struct snd_kcontrol_new sb_tx1_mux = + SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum); + +static const struct snd_kcontrol_new sb_tx2_mux = + SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum); + +static const struct snd_kcontrol_new sb_tx3_mux = + SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum); + +static const struct snd_kcontrol_new sb_tx4_mux = + SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum); + +static const struct snd_kcontrol_new sb_tx5_mux = + SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum); + +static const struct snd_kcontrol_new sb_tx6_mux = + SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum); + +static const struct snd_kcontrol_new sb_tx7_mux = + SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum); + +static const struct snd_kcontrol_new sb_tx8_mux = + SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum); + static int slim_rx_mux_get(struct snd_kcontrol *kc, struct snd_ctl_elem_value *ucontrol) { @@ -886,6 +1268,55 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc, return -EINVAL; } +static int slim_tx_mixer_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev); + + ucontrol->value.integer.value[0] = wcd->tx_port_value; + + return 0; +} + +static int slim_tx_mixer_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(widget->dapm->dev); + struct snd_soc_dapm_update *update = NULL; + struct soc_mixer_control *mixer = + (struct soc_mixer_control *)kc->private_value; + int enable = ucontrol->value.integer.value[0]; + int dai_id = widget->shift; + int port_id = mixer->shift; + + switch (dai_id) { + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + /* only add to the list if value not set */ + if (enable && !(wcd->tx_port_value & BIT(port_id))) { + wcd->tx_port_value |= BIT(port_id); + list_add_tail(&wcd->tx_chs[port_id].list, + &wcd->dai[dai_id].slim_ch_list); + } else if (!enable && (wcd->tx_port_value & BIT(port_id))) { + wcd->tx_port_value &= ~BIT(port_id); + list_del_init(&wcd->tx_chs[port_id].list); + } + break; + default: + dev_err(wcd->dev, "Unknown AIF %d\n", dai_id); + return -EINVAL; + } + + snd_soc_dapm_mixer_update_power(widget->dapm, kc, enable, update); + + return 0; +} + static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = { SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum, slim_rx_mux_get, slim_rx_mux_put), @@ -905,6 +1336,136 @@ static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = { slim_rx_mux_get, slim_rx_mux_put), }; +static const struct snd_kcontrol_new aif1_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD9335_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD9335_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD9335_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD9335_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif2_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD9335_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD9335_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD9335_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD9335_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif3_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static int wcd9335_put_dec_enum(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct soc_enum *e = (struct soc_enum *)kc->private_value; + unsigned int val, reg, sel; + + val = ucontrol->value.enumerated.item[0]; + + switch (e->reg) { + case WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1: + reg = WCD9335_CDC_TX0_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1: + reg = WCD9335_CDC_TX1_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1: + reg = WCD9335_CDC_TX2_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1: + reg = WCD9335_CDC_TX3_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0: + reg = WCD9335_CDC_TX4_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0: + reg = WCD9335_CDC_TX5_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0: + reg = WCD9335_CDC_TX6_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0: + reg = WCD9335_CDC_TX7_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0: + reg = WCD9335_CDC_TX8_TX_PATH_CFG0; + break; + default: + return -EINVAL; + } + + /* AMIC: 0, DMIC: 1 */ + sel = val ? WCD9335_CDC_TX_ADC_AMIC_SEL : WCD9335_CDC_TX_ADC_DMIC_SEL; + snd_soc_component_update_bits(component, reg, + WCD9335_CDC_TX_ADC_AMIC_DMIC_SEL_MASK, + sel); + + return snd_soc_dapm_put_enum_double(kc, ucontrol); +} + static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kc, struct snd_ctl_elem_value *ucontrol) { @@ -947,6 +1508,51 @@ static const struct snd_kcontrol_new rx_int2_dem_inp_mux = snd_soc_dapm_get_enum_double, wcd9335_int_dem_inp_mux_put); +static const struct snd_kcontrol_new tx_adc_mux0 = + SOC_DAPM_ENUM_EXT("ADC MUX0 Mux", tx_adc_mux0_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux1 = + SOC_DAPM_ENUM_EXT("ADC MUX1 Mux", tx_adc_mux1_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux2 = + SOC_DAPM_ENUM_EXT("ADC MUX2 Mux", tx_adc_mux2_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux3 = + SOC_DAPM_ENUM_EXT("ADC MUX3 Mux", tx_adc_mux3_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux4 = + SOC_DAPM_ENUM_EXT("ADC MUX4 Mux", tx_adc_mux4_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux5 = + SOC_DAPM_ENUM_EXT("ADC MUX5 Mux", tx_adc_mux5_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux6 = + SOC_DAPM_ENUM_EXT("ADC MUX6 Mux", tx_adc_mux6_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux7 = + SOC_DAPM_ENUM_EXT("ADC MUX7 Mux", tx_adc_mux7_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux8 = + SOC_DAPM_ENUM_EXT("ADC MUX8 Mux", tx_adc_mux8_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, int rate_val, u32 rate) @@ -1086,6 +1692,27 @@ static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd, WCD9335_SLIM_WATER_MARK_VAL); if (ret < 0) goto err; + } else { + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_0(ch->port), + payload & 0x00FF); + if (ret < 0) + goto err; + + /* ports 8,9 */ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_1(ch->port), + (payload & 0xFF00)>>8); + if (ret < 0) + goto err; + + /* configure the slave port for water mark and enable*/ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_TX_PORT_CFG(ch->port), + WCD9335_SLIM_WATER_MARK_VAL); + + if (ret < 0) + goto err; } } @@ -1102,12 +1729,90 @@ static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd, return ret; } +static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai, + u8 rate_val, u32 rate) +{ + struct snd_soc_component *comp = dai->component; + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp); + u8 shift = 0, shift_val = 0, tx_mux_sel; + struct wcd9335_slim_ch *ch; + int tx_port, tx_port_reg; + int decimator = -1; + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) { + tx_port = ch->port; + if ((tx_port == 12) || (tx_port >= 14)) { + dev_err(wcd->dev, "Invalid SLIM TX%u port DAI ID:%d\n", + tx_port, dai->id); + return -EINVAL; + } + /* Find the SB TX MUX input - which decimator is connected */ + if (tx_port < 4) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0; + shift = (tx_port << 1); + shift_val = 0x03; + } else if ((tx_port >= 4) && (tx_port < 8)) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1; + shift = ((tx_port - 4) << 1); + shift_val = 0x03; + } else if ((tx_port >= 8) && (tx_port < 11)) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2; + shift = ((tx_port - 8) << 1); + shift_val = 0x03; + } else if (tx_port == 11) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 0; + shift_val = 0x0F; + } else if (tx_port == 13) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 4; + shift_val = 0x03; + } else + return -EINVAL; + + tx_mux_sel = snd_soc_component_read32(comp, tx_port_reg) & + (shift_val << shift); + + tx_mux_sel = tx_mux_sel >> shift; + if (tx_port <= 8) { + if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3)) + decimator = tx_port; + } else if (tx_port <= 10) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = ((tx_port == 9) ? 7 : 6); + } else if (tx_port == 11) { + if ((tx_mux_sel >= 1) && (tx_mux_sel < 7)) + decimator = tx_mux_sel - 1; + } else if (tx_port == 13) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = 5; + } + + if (decimator >= 0) { + snd_soc_component_update_bits(comp, + WCD9335_CDC_TX_PATH_CTL(decimator), + WCD9335_CDC_TX_PATH_CTL_PCM_RATE_MASK, + rate_val); + } else if ((tx_port <= 8) && (tx_mux_sel == 0x01)) { + /* Check if the TX Mux input is RX MIX TXn */ + dev_err(wcd->dev, "RX_MIX_TX%u going to SLIM TX%u\n", + tx_port, tx_port); + } else { + dev_err(wcd->dev, "ERROR: Invalid decimator: %d\n", + decimator); + return -EINVAL; + } + } + + return 0; +} + static int wcd9335_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct wcd9335_codec *wcd; - int ret; + int ret, tx_fs_rate = 0; wcd = snd_soc_component_get_drvdata(dai->component); @@ -1129,6 +1834,53 @@ static int wcd9335_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } break; + + case SNDRV_PCM_STREAM_CAPTURE: + switch (params_rate(params)) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + case 384000: + tx_fs_rate = 7; + break; + default: + dev_err(wcd->dev, "%s: Invalid TX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + + }; + + ret = wcd9335_set_decimator_rate(dai, tx_fs_rate, + params_rate(params)); + if (ret < 0) { + dev_err(wcd->dev, "Cannot set TX Decimator rate\n"); + return ret; + } + switch (params_width(params)) { + case 16 ... 32: + wcd->dai[dai->id].sconfig.bps = params_width(params); + break; + default: + dev_err(wcd->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + }; + break; default: dev_err(wcd->dev, "Invalid stream type %d\n", substream->stream); @@ -1177,6 +1929,14 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai, } } + if (wcd->tx_chs) { + wcd->num_tx_port = tx_num; + for (i = 0; i < tx_num; i++) { + wcd->tx_chs[i].ch_num = tx_slot[i]; + INIT_LIST_HEAD(&wcd->tx_chs[i].list); + } + } + return 0; } @@ -1206,6 +1966,19 @@ static int wcd9335_get_channel_map(struct snd_soc_dai *dai, *rx_num = i; break; + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + if (!tx_slot || !tx_num) { + dev_err(wcd->dev, "Invalid tx_slot %p or tx_num %p\n", + tx_slot, tx_num); + return -EINVAL; + } + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) + tx_slot[i++] = ch->ch_num; + + *tx_num = i; + break; default: dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id); break; @@ -1566,6 +2339,496 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = { SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), }; +static int wcd9335_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(component); + int micb_index = micb_num - 1; + u16 micb_reg; + + if ((micb_index < 0) || (micb_index > WCD9335_MAX_MICBIAS - 1)) { + dev_err(wcd->dev, "Invalid micbias index, micb_ind:%d\n", + micb_index); + return -EINVAL; + } + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD9335_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD9335_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD9335_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD9335_ANA_MICB4; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + + switch (req) { + case MICB_PULLUP_ENABLE: + wcd->pullup_ref[micb_index]++; + if ((wcd->pullup_ref[micb_index] == 1) && + (wcd->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + wcd->pullup_ref[micb_index]--; + if ((wcd->pullup_ref[micb_index] == 0) && + (wcd->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + break; + case MICB_ENABLE: + wcd->micb_ref[micb_index]++; + if (wcd->micb_ref[micb_index] == 1) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x40); + break; + case MICB_DISABLE: + wcd->micb_ref[micb_index]--; + if ((wcd->micb_ref[micb_index] == 0) && + (wcd->pullup_ref[micb_index] > 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + else if ((wcd->micb_ref[micb_index] == 0) && + (wcd->pullup_ref[micb_index] == 0)) { + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + } + break; + }; + + return 0; +} + +static int __wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + int micb_num; + + if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) + micb_num = MIC_BIAS_4; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* + * MIC BIAS can also be requested by MBHC, + * so use ref count to handle micbias pullup + * and enable requests + */ + wcd9335_micbias_control(comp, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* wait for cnp time */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd9335_micbias_control(comp, micb_num, MICB_DISABLE, true); + break; + }; + + return 0; +} + +static int wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + return __wcd9335_codec_enable_micbias(w, event); +} + +static void wcd9335_codec_set_tx_hold(struct snd_soc_component *comp, + u16 amic_reg, bool set) +{ + u8 mask = 0x20; + u8 val; + + if (amic_reg == WCD9335_ANA_AMIC1 || amic_reg == WCD9335_ANA_AMIC3 || + amic_reg == WCD9335_ANA_AMIC5) + mask = 0x40; + + val = set ? mask : 0x00; + + switch (amic_reg) { + case WCD9335_ANA_AMIC1: + case WCD9335_ANA_AMIC2: + snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC2, mask, + val); + break; + case WCD9335_ANA_AMIC3: + case WCD9335_ANA_AMIC4: + snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC4, mask, + val); + break; + case WCD9335_ANA_AMIC5: + case WCD9335_ANA_AMIC6: + snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC6, mask, + val); + break; + default: + dev_err(comp->dev, "%s: invalid amic: %d\n", + __func__, amic_reg); + break; + } +} + +static int wcd9335_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd9335_codec_set_tx_hold(comp, w->reg, true); + break; + default: + break; + } + + return 0; +} + +static int wcd9335_codec_find_amic_input(struct snd_soc_component *comp, + int adc_mux_n) +{ + int mux_sel, reg, mreg; + + if (adc_mux_n < 0 || adc_mux_n > WCD9335_MAX_VALID_ADC_MUX || + adc_mux_n == WCD9335_INVALID_ADC_MUX) + return 0; + + /* Check whether adc mux input is AMIC or DMIC */ + if (adc_mux_n < 4) { + reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + 2 * adc_mux_n; + mreg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + 2 * adc_mux_n; + mux_sel = snd_soc_component_read32(comp, reg) & 0x3; + } else { + reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + adc_mux_n - 4; + mreg = reg; + mux_sel = snd_soc_component_read32(comp, reg) >> 6; + } + + if (mux_sel != WCD9335_CDC_TX_INP_MUX_SEL_AMIC) + return 0; + + return snd_soc_component_read32(comp, mreg) & 0x07; +} + +static u16 wcd9335_codec_get_amic_pwlvl_reg(struct snd_soc_component *comp, + int amic) +{ + u16 pwr_level_reg = 0; + + switch (amic) { + case 1: + case 2: + pwr_level_reg = WCD9335_ANA_AMIC1; + break; + + case 3: + case 4: + pwr_level_reg = WCD9335_ANA_AMIC3; + break; + + case 5: + case 6: + pwr_level_reg = WCD9335_ANA_AMIC5; + break; + default: + dev_err(comp->dev, "invalid amic: %d\n", amic); + break; + } + + return pwr_level_reg; +} + +static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + unsigned int decimator; + char *dec_adc_mux_name = NULL; + char *widget_name = NULL; + char *wname; + int ret = 0, amic_n; + u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg; + u16 tx_gain_ctl_reg; + char *dec; + u8 hpf_coff_freq; + + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) + return -ENOMEM; + + wname = widget_name; + dec_adc_mux_name = strsep(&widget_name, " "); + if (!dec_adc_mux_name) { + dev_err(comp->dev, "%s: Invalid decimator = %s\n", + __func__, w->name); + ret = -EINVAL; + goto out; + } + dec_adc_mux_name = widget_name; + + dec = strpbrk(dec_adc_mux_name, "012345678"); + if (!dec) { + dev_err(comp->dev, "%s: decimator index not found\n", + __func__); + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(dec, 10, &decimator); + if (ret < 0) { + dev_err(comp->dev, "%s: Invalid decimator = %s\n", + __func__, wname); + ret = -EINVAL; + goto out; + } + + tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator; + hpf_gate_reg = WCD9335_CDC_TX0_TX_PATH_SEC2 + 16 * decimator; + dec_cfg_reg = WCD9335_CDC_TX0_TX_PATH_CFG0 + 16 * decimator; + tx_gain_ctl_reg = WCD9335_CDC_TX0_TX_VOL_CTL + 16 * decimator; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + amic_n = wcd9335_codec_find_amic_input(comp, decimator); + if (amic_n) + pwr_level_reg = wcd9335_codec_get_amic_pwlvl_reg(comp, + amic_n); + + if (pwr_level_reg) { + switch ((snd_soc_component_read32(comp, pwr_level_reg) & + WCD9335_AMIC_PWR_LVL_MASK) >> + WCD9335_AMIC_PWR_LVL_SHIFT) { + case WCD9335_AMIC_PWR_LEVEL_LP: + snd_soc_component_update_bits(comp, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_LP); + break; + + case WCD9335_AMIC_PWR_LEVEL_HP: + snd_soc_component_update_bits(comp, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_HP); + break; + case WCD9335_AMIC_PWR_LEVEL_DEFAULT: + default: + snd_soc_component_update_bits(comp, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_DF); + break; + } + } + hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + + if (hpf_coff_freq != CF_MIN_3DB_150HZ) + snd_soc_component_update_bits(comp, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, + 0x10, 0x10); + /* Enable APC */ + snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x08); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(comp, hpf_gate_reg, 0x01, 0x00); + + if (decimator == 0) { + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x83); + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0xA3); + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x83); + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x03); + } + + snd_soc_component_update_bits(comp, hpf_gate_reg, + 0x01, 0x01); + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, + 0x10, 0x00); + snd_soc_component_write(comp, tx_gain_ctl_reg, + snd_soc_component_read32(comp, tx_gain_ctl_reg)); + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x10); + snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x00); + if (hpf_coff_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(comp, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_coff_freq << 5); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00); + break; + }; +out: + kfree(wname); + return ret; +} + +static u8 wcd9335_get_dmic_clk_val(struct snd_soc_component *component, + u32 mclk_rate, u32 dmic_clk_rate) +{ + u32 div_factor; + u8 dmic_ctl_val; + + dev_err(component->dev, + "%s: mclk_rate = %d, dmic_sample_rate = %d\n", + __func__, mclk_rate, dmic_clk_rate); + + /* Default value to return in case of error */ + if (mclk_rate == WCD9335_MCLK_CLK_9P6MHZ) + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; + else + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; + + if (dmic_clk_rate == 0) { + dev_err(component->dev, + "%s: dmic_sample_rate cannot be 0\n", + __func__); + goto done; + } + + div_factor = mclk_rate / dmic_clk_rate; + switch (div_factor) { + case 2: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; + break; + case 3: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; + break; + case 4: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4; + break; + case 6: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6; + break; + case 8: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8; + break; + case 16: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16; + break; + default: + dev_err(component->dev, + "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n", + __func__, div_factor, mclk_rate, dmic_clk_rate); + break; + } + +done: + return dmic_ctl_val; +} + +static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg; + s32 *dmic_clk_cnt; + u8 dmic_rate_val, dmic_rate_shift = 1; + unsigned int dmic; + int ret; + char *wname; + + wname = strpbrk(w->name, "012345"); + if (!wname) { + dev_err(comp->dev, "%s: widget not found\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(wname, 10, &dmic); + if (ret < 0) { + dev_err(comp->dev, "%s: Invalid DMIC line on the codec\n", + __func__); + return -EINVAL; + } + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(wcd->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC0_CTL; + break; + case 2: + case 3: + dmic_clk_cnt = &(wcd->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC1_CTL; + break; + case 4: + case 5: + dmic_clk_cnt = &(wcd->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC2_CTL; + break; + default: + dev_err(comp->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + }; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + dmic_rate_val = + wcd9335_get_dmic_clk_val(comp, + wcd->mclk_rate, + wcd->dmic_sample_rate); + + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(comp, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + snd_soc_component_update_bits(comp, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } + + break; + case SND_SOC_DAPM_POST_PMD: + dmic_rate_val = + wcd9335_get_dmic_clk_val(comp, + wcd->mclk_rate, + wcd->mad_dmic_sample_rate); + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(comp, dmic_clk_reg, + dmic_clk_en, 0); + snd_soc_component_update_bits(comp, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + } + break; + }; + + return 0; +} + static void wcd9335_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai, struct snd_soc_component *component) { @@ -3155,6 +4418,191 @@ static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = { wcd9335_codec_enable_mclk, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* TX */ + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + SND_SOC_DAPM_INPUT("AMIC6"), + + SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM, + AIF1_CAP, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM, + AIF2_CAP, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM, + AIF3_CAP, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD9335_ANA_AMIC1, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD9335_ANA_AMIC2, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD9335_ANA_AMIC3, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD9335_ANA_AMIC4, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC5", NULL, WCD9335_ANA_AMIC5, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC6", NULL, WCD9335_ANA_AMIC6, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + + /* Digital Mic Inputs */ + SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("DMIC MUX0", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux0), + SND_SOC_DAPM_MUX("DMIC MUX1", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux1), + SND_SOC_DAPM_MUX("DMIC MUX2", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux2), + SND_SOC_DAPM_MUX("DMIC MUX3", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux3), + SND_SOC_DAPM_MUX("DMIC MUX4", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux4), + SND_SOC_DAPM_MUX("DMIC MUX5", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux5), + SND_SOC_DAPM_MUX("DMIC MUX6", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux6), + SND_SOC_DAPM_MUX("DMIC MUX7", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux7), + SND_SOC_DAPM_MUX("DMIC MUX8", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux8), + + SND_SOC_DAPM_MUX("AMIC MUX0", SND_SOC_NOPM, 0, 0, + &tx_amic_mux0), + SND_SOC_DAPM_MUX("AMIC MUX1", SND_SOC_NOPM, 0, 0, + &tx_amic_mux1), + SND_SOC_DAPM_MUX("AMIC MUX2", SND_SOC_NOPM, 0, 0, + &tx_amic_mux2), + SND_SOC_DAPM_MUX("AMIC MUX3", SND_SOC_NOPM, 0, 0, + &tx_amic_mux3), + SND_SOC_DAPM_MUX("AMIC MUX4", SND_SOC_NOPM, 0, 0, + &tx_amic_mux4), + SND_SOC_DAPM_MUX("AMIC MUX5", SND_SOC_NOPM, 0, 0, + &tx_amic_mux5), + SND_SOC_DAPM_MUX("AMIC MUX6", SND_SOC_NOPM, 0, 0, + &tx_amic_mux6), + SND_SOC_DAPM_MUX("AMIC MUX7", SND_SOC_NOPM, 0, 0, + &tx_amic_mux7), + SND_SOC_DAPM_MUX("AMIC MUX8", SND_SOC_NOPM, 0, 0, + &tx_amic_mux8), + + SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0, + aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0, + aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0, + aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)), + + SND_SOC_DAPM_MUX("SLIM TX0 MUX", SND_SOC_NOPM, WCD9335_TX0, 0, + &sb_tx0_mux), + SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, WCD9335_TX1, 0, + &sb_tx1_mux), + SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, WCD9335_TX2, 0, + &sb_tx2_mux), + SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, WCD9335_TX3, 0, + &sb_tx3_mux), + SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, WCD9335_TX4, 0, + &sb_tx4_mux), + SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, WCD9335_TX5, 0, + &sb_tx5_mux), + SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, WCD9335_TX6, 0, + &sb_tx6_mux), + SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, WCD9335_TX7, 0, + &sb_tx7_mux), + SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, WCD9335_TX8, 0, + &sb_tx8_mux), + + SND_SOC_DAPM_MUX_E("ADC MUX0", WCD9335_CDC_TX0_TX_PATH_CTL, 5, 0, + &tx_adc_mux0, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX1", WCD9335_CDC_TX1_TX_PATH_CTL, 5, 0, + &tx_adc_mux1, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX2", WCD9335_CDC_TX2_TX_PATH_CTL, 5, 0, + &tx_adc_mux2, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX3", WCD9335_CDC_TX3_TX_PATH_CTL, 5, 0, + &tx_adc_mux3, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX4", WCD9335_CDC_TX4_TX_PATH_CTL, 5, 0, + &tx_adc_mux4, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX5", WCD9335_CDC_TX5_TX_PATH_CTL, 5, 0, + &tx_adc_mux5, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX6", WCD9335_CDC_TX6_TX_PATH_CTL, 5, 0, + &tx_adc_mux6, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX7", WCD9335_CDC_TX7_TX_PATH_CTL, 5, 0, + &tx_adc_mux7, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX8", WCD9335_CDC_TX8_TX_PATH_CTL, 5, 0, + &tx_adc_mux8, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), }; static void wcd9335_enable_sido_buck(struct snd_soc_component *component) @@ -3307,6 +4755,7 @@ static int wcd9335_probe(struct platform_device *pdev) dev_set_drvdata(dev, wcd); memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs)); + memcpy(wcd->tx_chs, wcd9335_tx_chs, sizeof(wcd9335_tx_chs)); wcd->regmap = pdata->regmap; wcd->if_regmap = pdata->ifd_regmap; From patchwork Mon Jul 23 15:54:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540553 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CDEB513BB for ; Mon, 23 Jul 2018 15:59:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BB46128CDC for ; Mon, 23 Jul 2018 15:59:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AF03528CF3; Mon, 23 Jul 2018 15:59:44 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID,UPPERCASE_50_75 autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BB24428CDC for ; Mon, 23 Jul 2018 15:59:43 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id C2FA32677C8; Mon, 23 Jul 2018 17:58:45 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id DEDDD267763; Mon, 23 Jul 2018 17:58:32 +0200 (CEST) Received: from mail-wr1-f65.google.com (mail-wr1-f65.google.com [209.85.221.65]) by alsa0.perex.cz (Postfix) with ESMTP id 7E21F267763 for ; Mon, 23 Jul 2018 17:58:30 +0200 (CEST) Received: by mail-wr1-f65.google.com with SMTP id h14-v6so1208772wrw.13 for ; Mon, 23 Jul 2018 08:58:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=3x8vuKyRQzgywnvIbeJU55F96yDHdOBpteyrvUj4ng8=; b=L0YQjcKmHGUrlj+vwy9TvAyfv8KP05PoS/ougg7NGbSeEx79mYj2VL3g16f7UdjpAS Gb4em5iSYPVu9r43Wn7zCAXVfbBw38bQ5SgCPUP1JrX1CerFiFyPFtlb02MCnnJL8yHV 527LW0O8SDRcXUG/2ZNcFzf3i1Ou7J0m3N2bo= 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=3x8vuKyRQzgywnvIbeJU55F96yDHdOBpteyrvUj4ng8=; b=dyPaEdedGmLdjUhSmIuE7bGWAU3HNoHPA5Oor9NydX58QmFvO4S+ePUqWud/nvmZP4 LZothwAC5Tim1RiBB/KHERgw5XzHDIXeOYAqEts1miBHRUAi7tfBIJhEhRrvcD57EkQ+ kzQvt3x+Qbtf25rcZbgKON6Nv0ozp7TNQBVAwmKXybqtT9FFz2KbRcTk4g6IYqLW8UK0 sbQnha+pkYj7de4Vku4MJzmouF6Tfa/qjuFJAaQnGH0iWEMvSuC7pQLQRo1CPvbOBx7L f9+qrMKUBBmN7/TKkEowTW6z88BKy42jTJBfP9n1EGo6mi8AH3KuNXtNFBBShqkPdBu4 Wkow== X-Gm-Message-State: AOUpUlFU9qxUZfbpYQQFW5OtyXFIWD0R2jH+UEncR6jlylVeu2j1JoPN 5Lu8Bt1YrIHUhAtKMG4tQflosg== X-Google-Smtp-Source: AAOMgpeDe1LyozREF8XNuyQf+rZEG8ijgFAMtu6mKZdFuY66SsYTruByk6x2IRops7oZrK9FA6iiNA== X-Received: by 2002:adf:e491:: with SMTP id i17-v6mr9394885wrm.145.1532361509842; Mon, 23 Jul 2018 08:58:29 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:29 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:09 +0100 Message-Id: <20180723155410.9494-12-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 11/12] ASoC: wcd9335: add audio routings X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Srinivas Kandagatla --- sound/soc/codecs/wcd9335.c | 189 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index a08703681674..b185ed29d0dd 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -102,6 +102,67 @@ /* vout step value */ #define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) +#define WCD9335_INTERPOLATOR_PATH(id) \ + {"RX INT" #id "_1 MIX1 INP0", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_2 MUX", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_2 MUX", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_2 MUX", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_2 MUX", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_2 MUX", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_2 MUX", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_2 MUX", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_2 MUX", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP0"}, \ + {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP1"}, \ + {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP2"}, \ + {"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_2 MUX"}, \ + {"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_1 MIX1"}, \ + {"RX INT" #id " MIX2", NULL, "RX INT" #id " SEC MIX"}, \ + {"RX INT" #id " INTERP", NULL, "RX INT" #id " MIX2"} + +#define WCD9335_ADC_MUX_PATH(id) \ + {"AIF1_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \ + {"AIF2_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \ + {"AIF3_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \ + {"SLIM TX" #id " MUX", "DEC" #id, "ADC MUX" #id}, \ + {"ADC MUX" #id, "DMIC", "DMIC MUX" #id}, \ + {"ADC MUX" #id, "AMIC", "AMIC MUX" #id}, \ + {"DMIC MUX" #id, "DMIC0", "DMIC0"}, \ + {"DMIC MUX" #id, "DMIC1", "DMIC1"}, \ + {"DMIC MUX" #id, "DMIC2", "DMIC2"}, \ + {"DMIC MUX" #id, "DMIC3", "DMIC3"}, \ + {"DMIC MUX" #id, "DMIC4", "DMIC4"}, \ + {"DMIC MUX" #id, "DMIC5", "DMIC5"}, \ + {"AMIC MUX" #id, "ADC1", "ADC1"}, \ + {"AMIC MUX" #id, "ADC2", "ADC2"}, \ + {"AMIC MUX" #id, "ADC3", "ADC3"}, \ + {"AMIC MUX" #id, "ADC4", "ADC4"}, \ + {"AMIC MUX" #id, "ADC5", "ADC5"}, \ + {"AMIC MUX" #id, "ADC6", "ADC6"} + enum { WCD9335_RX0 = 0, WCD9335_RX1, @@ -2339,6 +2400,132 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = { SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), }; +static const struct snd_soc_dapm_route wcd9335_audio_map[] = { + {"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"}, + + {"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"}, + + {"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"}, + + {"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"}, + + {"SLIM RX0", NULL, "SLIM RX0 MUX"}, + {"SLIM RX1", NULL, "SLIM RX1 MUX"}, + {"SLIM RX2", NULL, "SLIM RX2 MUX"}, + {"SLIM RX3", NULL, "SLIM RX3 MUX"}, + {"SLIM RX4", NULL, "SLIM RX4 MUX"}, + {"SLIM RX5", NULL, "SLIM RX5 MUX"}, + {"SLIM RX6", NULL, "SLIM RX6 MUX"}, + {"SLIM RX7", NULL, "SLIM RX7 MUX"}, + + WCD9335_INTERPOLATOR_PATH(0), + WCD9335_INTERPOLATOR_PATH(1), + WCD9335_INTERPOLATOR_PATH(2), + WCD9335_INTERPOLATOR_PATH(3), + WCD9335_INTERPOLATOR_PATH(4), + WCD9335_INTERPOLATOR_PATH(5), + WCD9335_INTERPOLATOR_PATH(6), + WCD9335_INTERPOLATOR_PATH(7), + WCD9335_INTERPOLATOR_PATH(8), + + /* EAR PA */ + {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 INTERP"}, + {"RX INT0 DAC", NULL, "RX INT0 DEM MUX"}, + {"RX INT0 DAC", NULL, "RX_BIAS"}, + {"EAR PA", NULL, "RX INT0 DAC"}, + {"EAR", NULL, "EAR PA"}, + + /* HPHL */ + {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 INTERP"}, + {"RX INT1 DAC", NULL, "RX INT1 DEM MUX"}, + {"RX INT1 DAC", NULL, "RX_BIAS"}, + {"HPHL PA", NULL, "RX INT1 DAC"}, + {"HPHL", NULL, "HPHL PA"}, + + /* HPHR */ + {"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 INTERP"}, + {"RX INT2 DAC", NULL, "RX INT2 DEM MUX"}, + {"RX INT2 DAC", NULL, "RX_BIAS"}, + {"HPHR PA", NULL, "RX INT2 DAC"}, + {"HPHR", NULL, "HPHR PA"}, + + /* LINEOUT1 */ + {"RX INT3 DAC", NULL, "RX INT3 INTERP"}, + {"RX INT3 DAC", NULL, "RX_BIAS"}, + {"LINEOUT1 PA", NULL, "RX INT3 DAC"}, + {"LINEOUT1", NULL, "LINEOUT1 PA"}, + + /* LINEOUT2 */ + {"RX INT4 DAC", NULL, "RX INT4 INTERP"}, + {"RX INT4 DAC", NULL, "RX_BIAS"}, + {"LINEOUT2 PA", NULL, "RX INT4 DAC"}, + {"LINEOUT2", NULL, "LINEOUT2 PA"}, + + /* LINEOUT3 */ + {"RX INT5 DAC", NULL, "RX INT5 INTERP"}, + {"RX INT5 DAC", NULL, "RX_BIAS"}, + {"LINEOUT3 PA", NULL, "RX INT5 DAC"}, + {"LINEOUT3", NULL, "LINEOUT3 PA"}, + + /* LINEOUT4 */ + {"RX INT6 DAC", NULL, "RX INT6 INTERP"}, + {"RX INT6 DAC", NULL, "RX_BIAS"}, + {"LINEOUT4 PA", NULL, "RX INT6 DAC"}, + {"LINEOUT4", NULL, "LINEOUT4 PA"}, + + /* SLIMBUS Connections */ + {"AIF1 CAP", NULL, "AIF1_CAP Mixer"}, + {"AIF2 CAP", NULL, "AIF2_CAP Mixer"}, + {"AIF3 CAP", NULL, "AIF3_CAP Mixer"}, + + /* ADC Mux */ + WCD9335_ADC_MUX_PATH(0), + WCD9335_ADC_MUX_PATH(1), + WCD9335_ADC_MUX_PATH(2), + WCD9335_ADC_MUX_PATH(3), + WCD9335_ADC_MUX_PATH(4), + WCD9335_ADC_MUX_PATH(5), + WCD9335_ADC_MUX_PATH(6), + WCD9335_ADC_MUX_PATH(7), + WCD9335_ADC_MUX_PATH(8), + + /* ADC Connections */ + {"ADC1", NULL, "AMIC1"}, + {"ADC2", NULL, "AMIC2"}, + {"ADC3", NULL, "AMIC3"}, + {"ADC4", NULL, "AMIC4"}, + {"ADC5", NULL, "AMIC5"}, + {"ADC6", NULL, "AMIC6"}, +}; + static int wcd9335_micbias_control(struct snd_soc_component *component, int micb_num, int req, bool is_dapm) { @@ -4740,6 +4927,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .num_controls = ARRAY_SIZE(wcd9335_snd_controls), .dapm_widgets = wcd9335_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets), + .dapm_routes = wcd9335_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd9335_audio_map), }; static int wcd9335_probe(struct platform_device *pdev) From patchwork Mon Jul 23 15:54:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 10540559 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4E5CB13BB for ; Mon, 23 Jul 2018 15:59:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3BFDC28CDC for ; Mon, 23 Jul 2018 15:59:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2FC9528CF3; Mon, 23 Jul 2018 15:59:58 +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=-2.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6696E28CDC for ; Mon, 23 Jul 2018 15:59:57 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 96CB72677D3; Mon, 23 Jul 2018 17:58:48 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 5E2092677A1; Mon, 23 Jul 2018 17:58:35 +0200 (CEST) Received: from mail-wr1-f68.google.com (mail-wr1-f68.google.com [209.85.221.68]) by alsa0.perex.cz (Postfix) with ESMTP id 2FA8D267791 for ; Mon, 23 Jul 2018 17:58:31 +0200 (CEST) Received: by mail-wr1-f68.google.com with SMTP id h14-v6so1208850wrw.13 for ; Mon, 23 Jul 2018 08:58:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=aoEJ2XVT3uF75MOnrQF1a4afNWLnbIC2KbwDpWmLedk=; b=hLPUgSvP3vpyK/thpvQIH+n1IRAbh0j0kAk/aYYEUDZf++P9N2qPe/oHjXTdt8Qdq5 P5Hv9RmETHLsLWEUlXH58KiikP1/rn+sGFZKB/f2hTrv1haI1VBq2tq+/dxGZsxDAngP BWeF7J+ltJq79O4znseXo9EJxm7nxtd1Gcays= 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=aoEJ2XVT3uF75MOnrQF1a4afNWLnbIC2KbwDpWmLedk=; b=MJKdNOAkIOyWgrCMPAaOlydOv4vKkaTSdm1FrJ+Xzn0R082SCmwC77Rm0Xun3rsZ5Z /P7YSzNOX/bfgyKNQyEOwDAidBgZ0UKmXe8wfmqJi+7zudLRGyHWuDDH1fFLbKs/PTDq hlAng0DC3NZgYvCMYwvRNyXt6T9ZlRwj20aoAkVXT86eZ9q+uyTyojpJhr/bQXBQVYW5 opitbMsLi7WJmrr6yvT5ooMyHBaoXTk0a21MQof2nu2AHEy+fLRv5+xwW0N05KwOdz61 T9qCKynuPQZ0UM6Jfzy9Ld9UsXCtoozyNSD0auN4NbzYlH0fMohFGHieNyjZy3eo/CoK BeKw== X-Gm-Message-State: AOUpUlH8+p0jVRfSKtGAqTeOrykUzXo4oP3adeaKc8j8caVqE8EGiTW9 PmDEncBrNjo+yXzZXhsSzHPi6I9lEbs= X-Google-Smtp-Source: AAOMgpfiKrsFXaCMe9yarlyLgcSoW8TvX92zk1LfL9RaLYVMip3CdsSBQBAGQZ7AedOirM4i+CulRQ== X-Received: by 2002:adf:ae01:: with SMTP id x1-v6mr9481597wrc.45.1532361510917; Mon, 23 Jul 2018 08:58:30 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id 14-v6sm206385wmt.1.2018.07.23.08.58.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Jul 2018 08:58:30 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Mon, 23 Jul 2018 16:54:10 +0100 Message-Id: <20180723155410.9494-13-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> References: <20180723155410.9494-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, tiwai@suse.com, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH 12/12] ASoC: apq8096: Add support to Analog audio via WCD9335 slim X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support Analog audio via WCD9335 Codec connected via SLIMBus. Tested it on DB820c. Signed-off-by: Srinivas Kandagatla --- sound/soc/qcom/apq8096.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index a56156281c8d..3c0f5cb544d5 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -10,6 +10,72 @@ #include #include +#define SLIM_MAX_TX_PORTS 16 +#define SLIM_MAX_RX_PORTS 16 +#define WCD9335_DEFAULT_MCLK_RATE 9600000 + +static int msm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + int ret = 0; + + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret != 0 && ret != -ENOTSUPP) { + pr_err("failed to get codec chan map, err:%d\n", ret); + goto end; + } else if (ret == -ENOTSUPP) { + return 0; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, + rx_ch_cnt, rx_ch); + else + ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt, tx_ch, + 0, NULL); + if (ret != 0 && ret != -ENOTSUPP) + pr_err("Failed to set cpu chan map, err:%d\n", ret); + +end: + return ret; +} + +static struct snd_soc_ops apq8096_ops = { + .hw_params = msm_snd_hw_params, +}; + +static int apq8096_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm = &rtd->card->dapm; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + /* + * Codec SLIMBUS configuration + * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13 + * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13 + * TX14, TX15, TX16 + */ + unsigned int rx_ch[SLIM_MAX_RX_PORTS] = {144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156}; + unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143}; + + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + + snd_soc_dai_set_sysclk(codec_dai, 0, 9600000, + SNDRV_PCM_STREAM_PLAYBACK); + + return 0; +} + static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -100,6 +166,8 @@ static int apq8096_sbc_parse_of(struct snd_soc_card *card) link->no_pcm = 1; link->ignore_pmdown_time = 1; link->be_hw_params_fixup = apq8096_be_hw_params_fixup; + link->init = apq8096_init; + link->ops = &apq8096_ops; } else { link->platform_of_node = link->cpu_of_node; link->codec_dai_name = "snd-soc-dummy-dai";