From patchwork Tue Sep 4 10:24:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 145897 Delivered-To: patch@linaro.org Received: by 2002:a2e:1648:0:0:0:0:0 with SMTP id 8-v6csp3488750ljw; Tue, 4 Sep 2018 03:28:04 -0700 (PDT) X-Google-Smtp-Source: ANB0VdaMqDXtumM6T42EzOzJ0Og0La6Heg1I1AR14E1SFGpONb2NOzsenHosz9H9MOgRAT7BroCO X-Received: by 2002:a1c:7711:: with SMTP id t17-v6mr7472490wmi.35.1536056884346; Tue, 04 Sep 2018 03:28:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1536056884; cv=none; d=google.com; s=arc-20160816; b=LeGmJXeznOSBI8Q2wsOv9VIVF09sblosNr+lr6zoAP/FTfugP1h1Ng4qRQAYDk+f+9 XNYEoaP0FF967BBK9j09xLjWlxFE7PHG26/7LIfbYwhiLMDRkIbietp1octs5oIPhoDB iz1tocWNelKLLoRrEvxkE632X/HdF0+2xIzTks4PO7S44cgl1+P59cmUxiEakVEU8GYQ 0XyFOoL8vibNUNMtuourms7kujsL0f/vnBrzsr5e0kspAYnIS231UmC6y4X4BCkOfn1J 355PHXsq2JOVHuI5pAfHT8n59vZ6KdLfS2L3EQtAWng5tgBfqhPuj7pbjfZlSvluffl2 HepQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:delivered-to; bh=ywQDoAEiuAK2hqNDUFASKM70r2hg6LtvJyHktHWjk2k=; b=UP63vMWIBfADCZsbX3gE78Fv2sEMU1tZBllZqUx6mYYTJa2yydZf9a4YXSuqw0ip7g dgDcJCi6AwzzZy7W7j79unO0EY6PYOGsFSwjO9Z86r4QKvdI+mKOvp0t5D8Mu9euQRfd NM3bKfXt7MhqZQbNNZU6dc2JORROzAsIa205RRGBhL/pPkuxr6/m81cj+naNT8Plw8E8 OnvViMfTVgj7T+rvfnQafBv8X51xEHm6DqUWeEzA0KX//BGe8pqCictlRYxZNo2iOwQ5 STu2+i0Ex6HcPaEkMy7rfEFBhl9S7bc9wqeUK7fQ62ph45hUdIMqu8iR24aebJpPvcdO i64g== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=XheSZURX; spf=pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) smtp.mailfrom=alsa-devel-bounces@alsa-project.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from alsa0.perex.cz (alsa0.perex.cz. [77.48.224.243]) by mx.google.com with ESMTP id d7-v6si10995656wmf.149.2018.09.04.03.28.04; Tue, 04 Sep 2018 03:28:04 -0700 (PDT) Received-SPF: pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) client-ip=77.48.224.243; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=XheSZURX; spf=pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) smtp.mailfrom=alsa-devel-bounces@alsa-project.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 7380926790B; Tue, 4 Sep 2018 12:27: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 EA75A267905; Tue, 4 Sep 2018 12:27:36 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail1.perex.cz X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_PASS autolearn=disabled version=3.4.0 Received: from mail-wm0-f68.google.com (mail-wm0-f68.google.com [74.125.82.68]) by alsa0.perex.cz (Postfix) with ESMTP id 3A62D2678EC for ; Tue, 4 Sep 2018 12:27:34 +0200 (CEST) Received: by mail-wm0-f68.google.com with SMTP id f21-v6so3809489wmc.5 for ; Tue, 04 Sep 2018 03:27:34 -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=tLhsmS/tYLvaeyroShZfcALGFxP0X7g73uUGhVVsmUA=; b=XheSZURXybH6gynbO9xFmh1k+HgdvSQZGAHVXn38kSpf5K8HfP8gzSYyQqJVP2x5Sd bFuBHiRfn/TdySK5wDfnFvbC2Lw/kcYflQdlZQgsQ77K/PkixeSNsN7I+gRZZ9ULjBHB YL0GU9HbDdOgZr+R2mFc07fPQiqle0UUypgsQ= 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=tLhsmS/tYLvaeyroShZfcALGFxP0X7g73uUGhVVsmUA=; b=QIz3k8lvUnNJbKrXsNLKwB6LbYZrstMX4y8SfrDx9Ax12t1QHJpJfr/uBH1LIfGxko l0zCeuYLDh1CR+2ZXO3unuJ4zfEYaEFbJw7PaBShYed0orKpv5Q9o8y7soRzOXJrG3PH fzNw+9Q5fJDKfSvqUe5d5Ji+Ad/j7DHylHRfBYAa5YRPSyDP4aCtUNhpFRC7dRCHZKRU uqmXsFUJWwLC+UvCqmC5Egw9Hio3RB4uSiR6ZL5+48N/JwXhpYD+Anfgg2uT6tKV+nsV QPgg/t6cJA8ZpsX7Dmg1D+YkzH/gVhSnv1ZK12WtMlNJML5kHdk17Wa7Yr/L3F1TozFQ dKtw== X-Gm-Message-State: APzg51Bi7+1kepFWASFh0Wk8F5VJbgCNjMMt0dqOKA8LhNA4ZhPCd0m8 egChgNcpTxwS7G8M+hcWr/QWYA== X-Received: by 2002:a1c:9b91:: with SMTP id d139-v6mr2104359wme.50.1536056853653; Tue, 04 Sep 2018 03:27:33 -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 g129-v6sm16903325wmf.42.2018.09.04.03.27.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 04 Sep 2018 03:27:32 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Tue, 4 Sep 2018 11:24:50 +0100 Message-Id: <20180904102500.30318-4-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180904102500.30318-1-srinivas.kandagatla@linaro.org> References: <20180904102500.30318-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH v3 03/13] 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 WCD9335 supports two lines of irqs INTR1 and INTR2. Multiple 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 Reviewed-by: Vinod Koul --- drivers/mfd/wcd9335-core.c | 78 +++++++++++++++++++++++++++++ include/linux/mfd/wcd9335/wcd9335.h | 33 ++++++++++++ 2 files changed, 111 insertions(+) -- 2.18.0 _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel diff --git a/drivers/mfd/wcd9335-core.c b/drivers/mfd/wcd9335-core.c index dbfae50c28b2..e2fc438c1a34 100644 --- a/drivers/mfd/wcd9335-core.c +++ b/drivers/mfd/wcd9335-core.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +86,52 @@ static struct regmap_config wcd9335_ifc_regmap_config = { .num_ranges = ARRAY_SIZE(wcd9335_ifc_ranges), }; +static const struct regmap_irq wcd9335_irqs[] = { + /* INTR_REG 0 */ + REGMAP_IRQ_REG(WCD9335_IRQ_SLIMBUS, 0, BIT(0)), + REGMAP_IRQ_REG(WCD9335_IRQ_FLL_LOCK_LOSS, 0, BIT(1)), + REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_OCPL_FAULT, 0, BIT(2)), + REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_OCPR_FAULT, 0, BIT(3)), + REGMAP_IRQ_REG(WCD9335_IRQ_EAR_PA_OCP_FAULT, 0, BIT(4)), + REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, 0, BIT(5)), + REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, 0, BIT(6)), + REGMAP_IRQ_REG(WCD9335_IRQ_EAR_PA_CNP_COMPLETE, 0, BIT(7)), + /* INTR_REG 1 */ + REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_SW_DET, 1, BIT(0)), + REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, 1, BIT(1)), + REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, 1, BIT(2)), + REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, 1, BIT(3)), + REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 1, BIT(4)), + /* INTR_REG 2 */ + REGMAP_IRQ_REG(WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, 2, BIT(0)), + REGMAP_IRQ_REG(WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, 2, BIT(1)), + REGMAP_IRQ_REG(WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, 2, BIT(2)), + REGMAP_IRQ_REG(WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, 2, BIT(3)), + REGMAP_IRQ_REG(WCD9335_IRQ_SOUNDWIRE, 2, BIT(4)), + REGMAP_IRQ_REG(WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, 2, BIT(5)), + REGMAP_IRQ_REG(WCD9335_IRQ_RCO_ERROR, 2, BIT(6)), + REGMAP_IRQ_REG(WCD9335_IRQ_SVA_ERROR, 2, BIT(7)), + /* INTR_REG 3 */ + REGMAP_IRQ_REG(WCD9335_IRQ_MAD_AUDIO, 3, BIT(0)), + REGMAP_IRQ_REG(WCD9335_IRQ_MAD_BEACON, 3, BIT(1)), + REGMAP_IRQ_REG(WCD9335_IRQ_MAD_ULTRASOUND, 3, BIT(2)), + REGMAP_IRQ_REG(WCD9335_IRQ_VBAT_ATTACK, 3, BIT(3)), + REGMAP_IRQ_REG(WCD9335_IRQ_VBAT_RESTORE, 3, BIT(4)), + REGMAP_IRQ_REG(WCD9335_IRQ_SVA_OUTBOX1, 3, BIT(5)), + REGMAP_IRQ_REG(WCD9335_IRQ_SVA_OUTBOX2, 3, 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), +}; + static int wcd9335_parse_dt(struct wcd9335 *wcd) { struct device *dev = wcd->dev; @@ -183,6 +231,32 @@ static int wcd9335_bring_up(struct wcd9335 *wcd) return 0; } +static 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) { + if (wcd->intr1 != -EPROBE_DEFER) + dev_err(wcd->dev, "Unable to configure IRQ\n"); + + return wcd->intr1; + } + + ret = devm_regmap_add_irq_chip(wcd->dev, wcd->regmap, wcd->intr1, + IRQF_TRIGGER_HIGH, 0, + &wcd9335_regmap_irq1_chip, &wcd->irq_data); + if (ret) + dev_err(wcd->dev, "Failed to register IRQ chip: %d\n", ret); + + return ret; +} + static int wcd9335_slim_probe(struct slim_device *slim) { struct device *dev = &slim->dev; @@ -264,6 +338,10 @@ static int wcd9335_slim_status(struct slim_device *sdev, return ret; } + ret = wcd9335_irq_init(wcd); + if (ret) + return ret; + ret = devm_mfd_add_devices(wcd->dev, 0, wcd9335_devices, ARRAY_SIZE(wcd9335_devices), NULL, 0, NULL); if (ret < 0) diff --git a/include/linux/mfd/wcd9335/wcd9335.h b/include/linux/mfd/wcd9335/wcd9335.h index b16d730aa1a4..82a18d08433f 100644 --- a/include/linux/mfd/wcd9335/wcd9335.h +++ b/include/linux/mfd/wcd9335/wcd9335.h @@ -9,6 +9,38 @@ #define WCD9335_VERSION_2_0 2 #define WCD9335_MAX_SUPPLY 5 +#define WCD9335_IRQ_SLIMBUS 0 +#define WCD9335_IRQ_FLL_LOCK_LOSS 1 +#define WCD9335_IRQ_HPH_PA_OCPL_FAULT 2 +#define WCD9335_IRQ_HPH_PA_OCPR_FAULT 3 +#define WCD9335_IRQ_EAR_PA_OCP_FAULT 4 +#define WCD9335_IRQ_HPH_PA_CNPL_COMPLETE 5 +#define WCD9335_IRQ_HPH_PA_CNPR_COMPLETE 6 +#define WCD9335_IRQ_EAR_PA_CNP_COMPLETE 7 +#define WCD9335_IRQ_MBHC_SW_DET 8 +#define WCD9335_IRQ_MBHC_ELECT_INS_REM_DET 9 +#define WCD9335_IRQ_MBHC_BUTTON_PRESS_DET 10 +#define WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET 11 +#define WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET 12 +#define WCD9335_IRQ_RESERVED_0 13 +#define WCD9335_IRQ_RESERVED_1 14 +#define WCD9335_IRQ_RESERVED_2 15 +#define WCD9335_IRQ_LINE_PA1_CNP_COMPLETE 16 +#define WCD9335_IRQ_LINE_PA2_CNP_COMPLETE 17 +#define WCD9335_IRQ_LINE_PA3_CNP_COMPLETE 18 +#define WCD9335_IRQ_LINE_PA4_CNP_COMPLETE 19 +#define WCD9335_IRQ_SOUNDWIRE 20 +#define WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE 21 +#define WCD9335_IRQ_RCO_ERROR 22 +#define WCD9335_IRQ_SVA_ERROR 23 +#define WCD9335_IRQ_MAD_AUDIO 24 +#define WCD9335_IRQ_MAD_BEACON 25 +#define WCD9335_IRQ_MAD_ULTRASOUND 26 +#define WCD9335_IRQ_VBAT_ATTACK 27 +#define WCD9335_IRQ_VBAT_RESTORE 28 +#define WCD9335_IRQ_SVA_OUTBOX1 29 +#define WCD9335_IRQ_SVA_OUTBOX2 30 + enum wcd_interface_type { WCD9335_INTERFACE_TYPE_SLIMBUS = 1, WCD9335_INTERFACE_TYPE_I2C, @@ -26,6 +58,7 @@ struct wcd9335 { struct slim_device *slim_ifc_dev; struct regmap *regmap; struct regmap *ifc_dev_regmap; + struct regmap_irq_chip_data *irq_data; struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; }; From patchwork Tue Sep 4 10:24:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 145899 Delivered-To: patch@linaro.org Received: by 2002:a2e:1648:0:0:0:0:0 with SMTP id 8-v6csp3489067ljw; Tue, 4 Sep 2018 03:28:27 -0700 (PDT) X-Google-Smtp-Source: ANB0Vdb4hYYcEyVkF3wykkbialO/4hczIBfmylqxAYf6uN7fMF7EUBPIGsVNrnPuc3hlIFT2AduK X-Received: by 2002:adf:8b98:: with SMTP id o24-v6mr21612295wra.110.1536056907038; Tue, 04 Sep 2018 03:28:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1536056907; cv=none; d=google.com; s=arc-20160816; b=MA6WczjkVdtMvEk5f176MLQ3Tp+xgAye21VZKCz6FcJvNYfPZWyfhCKHzacT+bXu9a IuICPCA7TR68QnFtr189NEjNLlOp2AXLAU3x91qcts3z/jtT8CWh+cqeJBYKwTerFsEI WAAOtungV5AcUmfbI612Rr8o/pIpDnhCNWdpuocO29oo5yOQ+Qv1HHhsXMIegaCo2LSL 5wpEIfdk0pRbd5HX9ThyGloL3iq1RH8AasJvY9qS1evAQdcHErSAqy4QGCGwMTNhmNN+ jdbMfQX6uxSr46yTICQMY0gk/6JJcEjY64fqa1ZFcYR7SHcNN/l1gQjDhUH6OxRtVRIK +ugQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:delivered-to:arc-authentication-results; bh=kbXrkSzejOSvlQxtZWMvfTiHrFn+UGW4X9FDU1iRv0I=; b=jFKF0rRHYiAeEW67+syX7OB3AVizLByeGzeFP7mKCtIeUPPmYZ1OIAQLLAQfMG32rp coQDbLEo9G/sVQ2Qy9qtmOLnX/a8+xWcWIPuKGiYEhBm9lqW1DAP7LX85LgjhPjxzTvD frLHxkic335CnWCmz9l4qvqy4/jXmn0lm2ckCNN1INcaWpiqxBlUT7VAjPATJgWf7LkR c9grPqh9TfYf+a7JHnitJUO2i/ooCWnJZjgtabel2RJ1SopykdbBXhrcUUvN2peDdq6a tt+YHK/2L9lamFJdux+kJdwLAn2PHM8XD07sYkyc7oIdHi5IEOHjhp42IPSig9WAhwO5 fTPA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=jQZSE9Jv; spf=pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) smtp.mailfrom=alsa-devel-bounces@alsa-project.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from alsa0.perex.cz (alsa0.perex.cz. [77.48.224.243]) by mx.google.com with ESMTP id d2-v6si18589272wrj.111.2018.09.04.03.28.26; Tue, 04 Sep 2018 03:28:27 -0700 (PDT) Received-SPF: pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) client-ip=77.48.224.243; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=jQZSE9Jv; spf=pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) smtp.mailfrom=alsa-devel-bounces@alsa-project.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id D904F267928; Tue, 4 Sep 2018 12:27: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 B924A267917; Tue, 4 Sep 2018 12:27:42 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail1.perex.cz X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_PASS autolearn=disabled version=3.4.0 Received: from mail-wr1-f66.google.com (mail-wr1-f66.google.com [209.85.221.66]) by alsa0.perex.cz (Postfix) with ESMTP id 021DF2678CB for ; Tue, 4 Sep 2018 12:27:36 +0200 (CEST) Received: by mail-wr1-f66.google.com with SMTP id w11-v6so3388828wrc.5 for ; Tue, 04 Sep 2018 03:27:36 -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=snp87os3BoXyBSDrXywMzeJTbUHiDioia8y01odw9Do=; b=jQZSE9JvbEDTr5o64fXR/v7LzHqCkqpDbWC6FmkTHPse6UZ7Zv88VoPEGtj5R5rKTh icIasow3vbAljuw1aedE6yo0ZvSOqVHWD7WmxEA4CUDuQMVDQrT/Kr4zvXx3hmErJxf4 BcDAzXq28XpySbJ83pFJhTpx2tZ9fJNyb8vx8= 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=snp87os3BoXyBSDrXywMzeJTbUHiDioia8y01odw9Do=; b=HxZ65bKPcp1gw4KfSJkqiOzJ812kDIdbUcNcvbGw0ZiOwX+XercFPYUO9yk9PMkMLk 1iFG/0FzAQDaIA4XqOsKvR41z12hVnJ/htFDA6Xjm090pkqLfDrYUg2AmvsuJ2iidB9i OdWvVWdmUhOpXzISW3wVFN6bxoQBl3IVyFtBmrti1is1q3bFwbPwK/TUB5E+zaAbzlU+ i5DuyZ8Id4twZrnup7bKjlve2ZtYyVN3puItSI7SHUzwovEajaziS15Bmx9wIIdrYrSV 4EcyadiqJHv0pAz/2wS1ksIjQcGyQq1cUd3VVfnJTZSfL0RiP2ZYMUSP8kF8DkVEJGqJ WZNg== X-Gm-Message-State: APzg51BgIvPDQr3XcvcGh7mfbePH1wB/OL6/DQ6C9Bw+vctEyiE8ctJp 0EiVbzdF9XfLi5htATFLGrBn+w== X-Received: by 2002:a5d:574b:: with SMTP id q11-v6mr11668158wrw.272.1536056856252; Tue, 04 Sep 2018 03:27:36 -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 g129-v6sm16903325wmf.42.2018.09.04.03.27.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 04 Sep 2018 03:27:35 -0700 (PDT) From: Srinivas Kandagatla To: lee.jones@linaro.org, robh+dt@kernel.org, broonie@kernel.org Date: Tue, 4 Sep 2018 11:24:52 +0100 Message-Id: <20180904102500.30318-6-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180904102500.30318-1-srinivas.kandagatla@linaro.org> References: <20180904102500.30318-1-srinivas.kandagatla@linaro.org> Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, vkoul@kernel.org, Srinivas Kandagatla Subject: [alsa-devel] [PATCH v3 05/13] 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 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 Reviewed-by: Vinod Koul --- sound/soc/codecs/Makefile | 2 +- sound/soc/codecs/wcd-clsh-v2.c | 577 +++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd-clsh-v2.h | 49 +++ sound/soc/codecs/wcd9335.c | 10 + 4 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/wcd-clsh-v2.c create mode 100644 sound/soc/codecs/wcd-clsh-v2.h -- 2.18.0 _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 01410b63daac..847a2e533a2f 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-v2.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-v2.c b/sound/soc/codecs/wcd-clsh-v2.c new file mode 100644 index 000000000000..d5124bd5dd6a --- /dev/null +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -0,0 +1,577 @@ +// 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-v2.h" + +struct wcd_clsh_ctrl { + int state; + int mode; + int flyback_users; + int buck_users; + int clsh_users; + int codec_version; + 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_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 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 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; + + /* 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); + } + /* + * 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_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 req_state, + bool is_enable, int mode) +{ + switch (req_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; + break; + case WCD_CLSH_STATE_LO: + wcd_clsh_state_lo(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_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 nstate, + enum wcd_clsh_mode mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (nstate == ctrl->state) + return 0; + + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; + } + + switch (clsh_event) { + case WCD_CLSH_EVENT_PRE_DAC: + _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode); + break; + case WCD_CLSH_EVENT_POST_PA: + _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode); + break; + }; + + ctrl->state = nstate; + ctrl->mode = mode; + + 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-v2.h b/sound/soc/codecs/wcd-clsh-v2.h new file mode 100644 index 000000000000..a902f9893467 --- /dev/null +++ b/sound/soc/codecs/wcd-clsh-v2.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#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) + +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 0fa090f0b9d9..ab202b5dfdfa 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -20,6 +20,7 @@ #include #include #include +#include "wcd-clsh-v2.h" #define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ @@ -180,6 +181,7 @@ struct wcd9335_codec { int sido_ccl_cnt; enum wcd_clock_type clk_type; + struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; }; @@ -1082,6 +1084,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); @@ -1096,6 +1105,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); }