From patchwork Fri Jun 19 11:53:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gene Chen X-Patchwork-Id: 11613995 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7A2FF90 for ; Fri, 19 Jun 2020 11:55:02 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0DEBB21548 for ; Fri, 19 Jun 2020 11:55:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Wjqg2okW"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="cEbG/vDa" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0DEBB21548 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=sfPhamFsJkv6rF+C214JV2vU8edFkQle1Rkadq/MA5w=; b=Wjqg2okW2+ggMbYhIKDqT+Lq6J knJG4laMhyskwqWO85HNtIVNkd46AxB2c88aAu/MfHyy23huajHpHeYln5Jp+tHM2NrvXGcToXuzV i7Jf2nwhT1UU59VhnFdH+EUmHS661D5Gk3CFpncycfe8AYAEne2CFcQ2k2PjCfSLrDEVIIvMzeCmg tnWLKqL9q4oUq6gUl81UqGwFC3KJ3zroUXyX7lSk5CksanAfUyyrLYC37SLC6XMfkWW6PBIXSOG4/ GZDArYjRhKvKX6FYQXmKwfxqjrW+fgnrHCIyu7cJatBCQA1KFUfy0DPKTQym0hcF/hNPuoKWMRPXX yv7WtSpg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jmFbo-0007nr-7B; Fri, 19 Jun 2020 11:55:00 +0000 Received: from mail-pl1-x641.google.com ([2607:f8b0:4864:20::641]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jmFbM-0007NO-4X; Fri, 19 Jun 2020 11:54:33 +0000 Received: by mail-pl1-x641.google.com with SMTP id n9so3852275plk.1; Fri, 19 Jun 2020 04:54:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=649vrouwnwNw8hZJmDui7hqgFQ4vaLHMeburQrpsbms=; b=cEbG/vDax/+j3lSPHK8/nHyvCjYB2tiiBwqR60bvfnEHJoxK4blTHPBKwKhBAp3cIp bsErxLaZ49/662w8ilOcd5ylWAwD0KnZip+va+BWpfAEaTVqCMOFys5qfpr5zz+5RCwf UsROPptozBcXt43gbOg+mLqShquDKaQIcnZK/gyT6r9fSOhzJ8HR+5QE6h+cOo+W2TQz NebvFnXFTQUsFEtTGRAvNMyzvTLJXsmAWG4MrT5BeYFI8sDxmEv23yVSWjTr8xtc6xav U/ZZB9WSMhh2+Vw20ZeVI0yUS+mJ0JW95JiNp2Q90n/JktQZ+m4IualUzUEyrhDAloI6 MZpw== 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=649vrouwnwNw8hZJmDui7hqgFQ4vaLHMeburQrpsbms=; b=mi0WbLhhb5J3/AxYHfj8ixoWTmIH/ONOx+xz//5S0fI7T3FSVjZuIApVBXdecIuuVz SGsDwvvuAkPhqcvglEj2yR6yN5FyKy3XPN/t/9Ghy1DnBdr05w9mjqy9SRHJfmgE+5vK 4eHLDi0fP/KIte3g8zsbebF9KpW8FV14C7rSKl2JW1H62COrVMpAsQk5Pdzy87DrNl7V WPgB/4DauiGeFZNsOO3LkU+vn45KIzMSnJnj0nw/mkZUFtl0uLjHlb7L0e1bJY+SAnRN phOqpEwezrYaSEu+nA4zAcSW1KTrDLv4uvyVgFFU9hs3wXduR90+sUAOG9o1UcBdIlNa oTTQ== X-Gm-Message-State: AOAM531RYoeiVvo8lqMzFZa9dh4oVGPyL34NrGWZ1ar+IkxqIv15HAbX tgizyIE3AhPzu5BkoDHGBQIwgQUR X-Google-Smtp-Source: ABdhPJzebrHgH8OaOUPSrWFqgAVqn30OWaq7q/7pjgpLWyM8CBheEmOSw1CN+ye0n7VavPf/P0ypMQ== X-Received: by 2002:a17:902:6ac2:: with SMTP id i2mr7667948plt.243.1592567671500; Fri, 19 Jun 2020 04:54:31 -0700 (PDT) Received: from localhost.localdomain ([2402:7500:46c:79b7:a5d3:5b37:1d99:175a]) by smtp.gmail.com with ESMTPSA id n64sm5026712pga.38.2020.06.19.04.54.26 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 19 Jun 2020 04:54:31 -0700 (PDT) From: Gene Chen To: lee.jones@linaro.org, jic23@kernel.org, jacek.anaszewski@gmail.com, pavel@ucw.cz, matthias.bgg@gmail.com Subject: [PATCH v2 1/4] dt-bindings: mfd: Add bindings for the Mediatek MT6360 PMIC Date: Fri, 19 Jun 2020 19:53:48 +0800 Message-Id: <1592567631-20363-2-git-send-email-gene.chen.richtek@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1592567631-20363-1-git-send-email-gene.chen.richtek@gmail.com> References: <1592567631-20363-1-git-send-email-gene.chen.richtek@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200619_045432_216266_8A4C0E53 X-CRM114-Status: GOOD ( 13.30 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:641 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [gene.chen.richtek[at]gmail.com] -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: gene_chen@richtek.com, lars@metafoo.de, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, cy_huang@richtek.com, benjamin.chao@mediatek.com, broonie@kernel.org, linux-mediatek@lists.infradead.org, dmurphy@ti.com, pmeerw@pmeerw.net, knaack.h@gmx.de, linux-arm-kernel@lists.infradead.org, shufan_lee@richtek.com MIME-Version: 1.0 Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org From: Gene Chen Add devicetree binding document support Mediatek MT6360 PMIC Signed-off-by: Gene Chen --- Documentation/devicetree/bindings/mfd/mt6360.txt | 122 +++++++++++++++++++++++ include/dt-bindings/mfd/mt6360.h | 15 +++ 2 files changed, 137 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/mt6360.txt create mode 100644 include/dt-bindings/mfd/mt6360.h diff --git a/Documentation/devicetree/bindings/mfd/mt6360.txt b/Documentation/devicetree/bindings/mfd/mt6360.txt new file mode 100644 index 0000000..7d7d349 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mt6360.txt @@ -0,0 +1,122 @@ +MediaTek MT6360 PMIC Driver + +MT6360 is a multifunction device with the following sub modules: +It is interfaced to host controller using I2C interface. +This document describes the binding for PMIC device and its sub module. + +- ADC +- Battery Charger/OTG boost +- Flash LED/RGB LED/moonlight LED +- 2-channel Buck and 6-channel LDO +- USB_PD + +Required properties: +- compatible: Must be "mediatek,mt6360-pmu" +- reg: Specifies the I2C slave address of PMIC block, Must be <0x34> +- interrupts: I2C device IRQ line connected to the main SoC. + +Optional subnodes: +- ADC + Required properties: + - compatible: "mediatek,mt6360-adc" +- battery charger/OTG boost + Required properties: + - compatible: "mediatek,mt6360-chg" +- Flash LED/RGB LED/moonlight LED + Required properties: + - compatible: "mediatek,mt6360-led" +- 2-channel Buck and 6-channel LDO + Required properties: + - compatible: "mediatek,mt6360-regulator" +- USB_PD + Required properties: + - compatible: "mediatek,mt6360-tcpc" + +Example: + + #include + #include + + mt6360@34 { + compatible = "mediatek,mt6360"; + reg = <0x34>; + wakeup-source; + interrupts-extended = <&gpio26 0 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "IRQB"; + interrupt-controller; + #interrupt-cells = <1>; + adc { + compatible = "mediatek,mt6360-adc"; + #io-channel-cells = <1>; + }; + regulator { + compatible = "mediatek,mt6360-regulator"; + LDO_VIN3-supply = <&BUCK2>; + buck1 { + regulator-compatible = "BUCK1"; + regulator-name = "mt6360,buck1"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1300000>; + regulator-allowed-modes = ; + }; + BUCK2: buck2 { + regulator-compatible = "BUCK2"; + regulator-name = "mt6360,buck2"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1300000>; + regulator-allowed-modes = ; + }; + ldo6 { + regulator-compatible = "LDO6"; + regulator-name = "mt6360,ldo6"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2100000>; + regulator-allowed-modes = ; + }; + ldo7 { + regulator-compatible = "LDO7"; + regulator-name = "mt6360,ldo7"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2100000>; + regulator-allowed-modes = ; + }; + ldo1 { + regulator-compatible = "LDO1"; + regulator-name = "mt6360,ldo1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3600000>; + regulator-allowed-modes = ; + }; + ldo2 { + regulator-compatible = "LDO2"; + regulator-name = "mt6360,ldo2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3600000>; + regulator-allowed-modes = ; + }; + ldo3 { + regulator-compatible = "LDO3"; + regulator-name = "mt6360,ldo3"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3600000>; + regulator-allowed-modes = ; + }; + ldo5 { + regulator-compatible = "LDO5"; + regulator-name = "mt6360,ldo5"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3600000>; + regulator-allowed-modes = ; + }; + }; + }; diff --git a/include/dt-bindings/mfd/mt6360.h b/include/dt-bindings/mfd/mt6360.h new file mode 100644 index 0000000..6368388 --- /dev/null +++ b/include/dt-bindings/mfd/mt6360.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides macros for MT6360 device bindings. + * + * Copyright (c) 2020 Mediatek Inc. + */ + +#ifndef __DT_BINDINGS_MT6360_H__ +#define __DT_BINDINGS_MT6360_H__ + +#define MT6360_OPMODE_LP (2) +#define MT6360_OPMODE_ULP (3) +#define MT6360_OPMODE_NORMAL (0) + +#endif /* __DT_BINDINGS_MT6360_H__ */ From patchwork Fri Jun 19 11:53:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gene Chen X-Patchwork-Id: 11613999 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6DC4990 for ; Fri, 19 Jun 2020 11:55:34 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 40BE52083B for ; Fri, 19 Jun 2020 11:55:34 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="en2qaWn9"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="RLc/eMd1" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 40BE52083B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=OoPvxT8eZo9fTTCpLv7nVWVm+beq7h5skGX/Oqqp7ew=; b=en2qaWn9G2o6cZ26LBt6M+ZGnf upLfrm5mVpRfY59ZIM2dBumFJXq3yntR0XaaPaaBFVFD3RDdinZdmZErBWC94cqJS+y2FplzYKqZ8 7acXVp9M+HSPCvKzk3rsSkyw2ctufp1/i9xkVvrM2wkkiuzcC5o4Hckr3A1rlnU8+DW1NSTPHFOgE sNDDfv5dV/Fky7bzYEvOqqzxbLkqSIdyjPKdrEjYGLUPTaVIwMjn/eGWllTchpk62IU8mmLe8MWTl I2+8dkoJDgz0Q+7DVeLnn1FuBbd7FLSPpbVv0FSYnemeCl79iJLRhWHQ0gaWf3lbpKjC1HoE7sOPP aA5MVWrQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jmFcK-0002GH-Rh; Fri, 19 Jun 2020 11:55:32 +0000 Received: from mail-pf1-x444.google.com ([2607:f8b0:4864:20::444]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jmFbZ-0007aA-3s; Fri, 19 Jun 2020 11:54:50 +0000 Received: by mail-pf1-x444.google.com with SMTP id j1so4343636pfe.4; Fri, 19 Jun 2020 04:54:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=R7iOJ3VbMICFwDJGcoWnaL3IWI5iJC6yLRKljUH5RlI=; b=RLc/eMd1oSGu5MQHtVB9eKjFEnC0qE8/AyYf/WH993tEehH3kHC6larsiydl0cs1a/ wfnJPsXCJIhv3cHx/RGLqoAZTng2Hh2wXiDtCillp/M31febicf89ff4lIyiT2ZJ78gg v75sAVBIDSRcvjUyf8ZgSw3rsWlxde2FeQiPyRaTlaabyQ95TZPJhbjwiKdjmeO20kEw 8Qs06a7l9l/WsUafhiNRK9ZHmlqMJCyx4Ru6FDvtmqpxl59FdieRJYBagm4H7b9cTyy9 RH6mUvlU61yIMwR/8mUu6Sw0ImtgAoOBeCi6Lp6BMMSf1xmtJUt+i7zyQPkCY6xUnmIt 5PPQ== 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=R7iOJ3VbMICFwDJGcoWnaL3IWI5iJC6yLRKljUH5RlI=; b=NDl32GudyeqsZQFxL9Cs6IjswcIGvZABP+6BQDUGqi6Qgq1gSxoWZzFWIO4/hgXN8b CfI/wIWMNHwwkSFDoNcBztyDPM79qFRcTVvkpaSqE/r7PPflYKg7NBUyX8MP2wJ7vynb UrSiyEG9OBdO9ZFrTgnFLFLB9EtjFWizoQQozXPP/ofFERDMeYZt0cHDhX7dt0fceWmW nGvbSZYtnoUDcraUQtheNA2X12F33hvw5NO0vVXWzhsZrstjZ0wvVD466Q4KucLog5as Eq5/jtVF/z5dk/jC3u7ZkGVgC2r8F9901pl1594Zk6TZhBPAydLc9N8z7vR68Zh17rTL Tf9Q== X-Gm-Message-State: AOAM531NFv+ErVfaTlISs/KVeT12nHrN16Mvw3YMJ4aKfh9mmi7P6fhP OAQWrOG6f8jAELsUcuiBuvs= X-Google-Smtp-Source: ABdhPJwLKgFyR2PXwTyztWAp1fMfiQ49ZTXtXes86whG3F8Ys9MwFt9PHQdSU62vbcmJb+cG0SWxZw== X-Received: by 2002:a63:f050:: with SMTP id s16mr2688986pgj.261.1592567683124; Fri, 19 Jun 2020 04:54:43 -0700 (PDT) Received: from localhost.localdomain ([2402:7500:46c:79b7:a5d3:5b37:1d99:175a]) by smtp.gmail.com with ESMTPSA id n64sm5026712pga.38.2020.06.19.04.54.37 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 19 Jun 2020 04:54:42 -0700 (PDT) From: Gene Chen To: lee.jones@linaro.org, jic23@kernel.org, jacek.anaszewski@gmail.com, pavel@ucw.cz, matthias.bgg@gmail.com Subject: [PATCH v2 2/4] mfd: mt6360: implement i2c R/W with CRC Date: Fri, 19 Jun 2020 19:53:49 +0800 Message-Id: <1592567631-20363-3-git-send-email-gene.chen.richtek@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1592567631-20363-1-git-send-email-gene.chen.richtek@gmail.com> References: <1592567631-20363-1-git-send-email-gene.chen.richtek@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200619_045445_492981_A300DE59 X-CRM114-Status: GOOD ( 13.89 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:444 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [gene.chen.richtek[at]gmail.com] -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: gene_chen@richtek.com, lars@metafoo.de, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, cy_huang@richtek.com, benjamin.chao@mediatek.com, broonie@kernel.org, linux-mediatek@lists.infradead.org, dmurphy@ti.com, pmeerw@pmeerw.net, knaack.h@gmx.de, linux-arm-kernel@lists.infradead.org, shufan_lee@richtek.com MIME-Version: 1.0 Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org From: Gene Chen imlement i2c R/W with CRC when access sub-device PMIC and LDO part Signed-off-by: Gene Chen --- drivers/mfd/Kconfig | 1 + drivers/mfd/mt6360-core.c | 541 +++++++++++++++++++++++++++++---------------- include/linux/mfd/mt6360.h | 240 -------------------- 3 files changed, 357 insertions(+), 425 deletions(-) delete mode 100644 include/linux/mfd/mt6360.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a37d7d1..0684ddc 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -913,6 +913,7 @@ config MFD_MT6360 select MFD_CORE select REGMAP_I2C select REGMAP_IRQ + select CRC8 depends on I2C help Say Y here to enable MT6360 PMU/PMIC/LDO functional support. diff --git a/drivers/mfd/mt6360-core.c b/drivers/mfd/mt6360-core.c index e9cacc2..00e3cb5 100644 --- a/drivers/mfd/mt6360-core.c +++ b/drivers/mfd/mt6360-core.c @@ -5,122 +5,160 @@ * Author: Gene Chen */ +#include +#include #include -#include +#include +#include +#include #include -#include #include -#include -#include -#include -#include -#include +enum { + MT6360_SLAVE_TCPC = 0, + MT6360_SLAVE_PMIC, + MT6360_SLAVE_LDO, + MT6360_SLAVE_PMU, + MT6360_SLAVE_MAX, +}; + +struct mt6360_data { + struct i2c_client *i2c[MT6360_SLAVE_MAX]; + struct device *dev; + struct regmap *regmap; + struct regmap_irq_chip_data *irq_data; + unsigned int chip_rev; + u8 crc8_tbl[CRC8_TABLE_SIZE]; +}; + +#define MT6360_PMU_SLAVEID 0x34 +#define MT6360_PMIC_SLAVEID 0x1A +#define MT6360_LDO_SLAVEID 0x64 +#define MT6360_TCPC_SLAVEID 0x4E + +#define MT6360_REG_TCPCSTART 0x00 +#define MT6360_REG_TCPCEND 0xFF +#define MT6360_REG_PMICSTART 0x100 +#define MT6360_REG_PMICEND 0x13B +#define MT6360_REG_LDOSTART 0x200 +#define MT6360_REG_LDOEND 0x21C +#define MT6360_REG_PMUSTART 0x300 +#define MT6360_REG_PMU_DEVINFO 0x300 +#define MT6360_REG_PMU_CHGIRQ1 0x3D0 +#define MT6360_REG_PMU_CHGMASK1 0x3F0 +#define MT6360_REG_PMUEND 0x3FF + +/* from 0x3D0 to 0x3DF */ +#define MT6360_IRQ_REGNUM 16 + +#define MT6360_CHIPVEN_MASK 0xF0 +#define MT6360_CHIPVEN_VAL 0x50 +#define MT6360_CHIPREV_MASK 0x0F /* reg 0 -> 0 ~ 7 */ -#define MT6360_CHG_TREG_EVT (4) -#define MT6360_CHG_AICR_EVT (5) -#define MT6360_CHG_MIVR_EVT (6) -#define MT6360_PWR_RDY_EVT (7) +#define MT6360_CHG_TREG_EVT 4 +#define MT6360_CHG_AICR_EVT 5 +#define MT6360_CHG_MIVR_EVT 6 +#define MT6360_PWR_RDY_EVT 7 /* REG 1 -> 8 ~ 15 */ -#define MT6360_CHG_BATSYSUV_EVT (9) -#define MT6360_FLED_CHG_VINOVP_EVT (11) -#define MT6360_CHG_VSYSUV_EVT (12) -#define MT6360_CHG_VSYSOV_EVT (13) -#define MT6360_CHG_VBATOV_EVT (14) -#define MT6360_CHG_VBUSOV_EVT (15) +#define MT6360_CHG_BATSYSUV_EVT 9 +#define MT6360_FLED_CHG_VINOVP_EVT 11 +#define MT6360_CHG_VSYSUV_EVT 12 +#define MT6360_CHG_VSYSOV_EVT 13 +#define MT6360_CHG_VBATOV_EVT 14 +#define MT6360_CHG_VBUSOV_EVT 15 /* REG 2 -> 16 ~ 23 */ /* REG 3 -> 24 ~ 31 */ -#define MT6360_WD_PMU_DET (25) -#define MT6360_WD_PMU_DONE (26) -#define MT6360_CHG_TMRI (27) -#define MT6360_CHG_ADPBADI (29) -#define MT6360_CHG_RVPI (30) -#define MT6360_OTPI (31) +#define MT6360_WD_PMU_DET 25 +#define MT6360_WD_PMU_DONE 26 +#define MT6360_CHG_TMRI 27 +#define MT6360_CHG_ADPBADI 29 +#define MT6360_CHG_RVPI 30 +#define MT6360_OTPI 31 /* REG 4 -> 32 ~ 39 */ -#define MT6360_CHG_AICCMEASL (32) -#define MT6360_CHGDET_DONEI (34) -#define MT6360_WDTMRI (35) -#define MT6360_SSFINISHI (36) -#define MT6360_CHG_RECHGI (37) -#define MT6360_CHG_TERMI (38) -#define MT6360_CHG_IEOCI (39) +#define MT6360_CHG_AICCMEASL 32 +#define MT6360_CHGDET_DONEI 34 +#define MT6360_WDTMRI 35 +#define MT6360_SSFINISHI 36 +#define MT6360_CHG_RECHGI 37 +#define MT6360_CHG_TERMI 38 +#define MT6360_CHG_IEOCI 39 /* REG 5 -> 40 ~ 47 */ -#define MT6360_PUMPX_DONEI (40) -#define MT6360_BAT_OVP_ADC_EVT (41) -#define MT6360_TYPEC_OTP_EVT (42) -#define MT6360_ADC_WAKEUP_EVT (43) -#define MT6360_ADC_DONEI (44) -#define MT6360_BST_BATUVI (45) -#define MT6360_BST_VBUSOVI (46) -#define MT6360_BST_OLPI (47) +#define MT6360_PUMPX_DONEI 40 +#define MT6360_BAT_OVP_ADC_EVT 41 +#define MT6360_TYPEC_OTP_EVT 42 +#define MT6360_ADC_WAKEUP_EVT 43 +#define MT6360_ADC_DONEI 44 +#define MT6360_BST_BATUVI 45 +#define MT6360_BST_VBUSOVI 46 +#define MT6360_BST_OLPI 47 /* REG 6 -> 48 ~ 55 */ -#define MT6360_ATTACH_I (48) -#define MT6360_DETACH_I (49) -#define MT6360_QC30_STPDONE (51) -#define MT6360_QC_VBUSDET_DONE (52) -#define MT6360_HVDCP_DET (53) -#define MT6360_CHGDETI (54) -#define MT6360_DCDTI (55) +#define MT6360_ATTACH_I 48 +#define MT6360_DETACH_I 49 +#define MT6360_QC30_STPDONE 51 +#define MT6360_QC_VBUSDET_DONE 52 +#define MT6360_HVDCP_DET 53 +#define MT6360_CHGDETI 54 +#define MT6360_DCDTI 55 /* REG 7 -> 56 ~ 63 */ -#define MT6360_FOD_DONE_EVT (56) -#define MT6360_FOD_OV_EVT (57) -#define MT6360_CHRDET_UVP_EVT (58) -#define MT6360_CHRDET_OVP_EVT (59) -#define MT6360_CHRDET_EXT_EVT (60) -#define MT6360_FOD_LR_EVT (61) -#define MT6360_FOD_HR_EVT (62) -#define MT6360_FOD_DISCHG_FAIL_EVT (63) +#define MT6360_FOD_DONE_EVT 56 +#define MT6360_FOD_OV_EVT 57 +#define MT6360_CHRDET_UVP_EVT 58 +#define MT6360_CHRDET_OVP_EVT 59 +#define MT6360_CHRDET_EXT_EVT 60 +#define MT6360_FOD_LR_EVT 61 +#define MT6360_FOD_HR_EVT 62 +#define MT6360_FOD_DISCHG_FAIL_EVT 63 /* REG 8 -> 64 ~ 71 */ -#define MT6360_USBID_EVT (64) -#define MT6360_APWDTRST_EVT (65) -#define MT6360_EN_EVT (66) -#define MT6360_QONB_RST_EVT (67) -#define MT6360_MRSTB_EVT (68) -#define MT6360_OTP_EVT (69) -#define MT6360_VDDAOV_EVT (70) -#define MT6360_SYSUV_EVT (71) +#define MT6360_USBID_EVT 64 +#define MT6360_APWDTRST_EVT 65 +#define MT6360_EN_EVT 66 +#define MT6360_QONB_RST_EVT 67 +#define MT6360_MRSTB_EVT 68 +#define MT6360_OTP_EVT 69 +#define MT6360_VDDAOV_EVT 70 +#define MT6360_SYSUV_EVT 71 /* REG 9 -> 72 ~ 79 */ -#define MT6360_FLED_STRBPIN_EVT (72) -#define MT6360_FLED_TORPIN_EVT (73) -#define MT6360_FLED_TX_EVT (74) -#define MT6360_FLED_LVF_EVT (75) -#define MT6360_FLED2_SHORT_EVT (78) -#define MT6360_FLED1_SHORT_EVT (79) +#define MT6360_FLED_STRBPIN_EVT 72 +#define MT6360_FLED_TORPIN_EVT 73 +#define MT6360_FLED_TX_EVT 74 +#define MT6360_FLED_LVF_EVT 75 +#define MT6360_FLED2_SHORT_EVT 78 +#define MT6360_FLED1_SHORT_EVT 79 /* REG 10 -> 80 ~ 87 */ -#define MT6360_FLED2_STRB_EVT (80) -#define MT6360_FLED1_STRB_EVT (81) -#define MT6360_FLED2_STRB_TO_EVT (82) -#define MT6360_FLED1_STRB_TO_EVT (83) -#define MT6360_FLED2_TOR_EVT (84) -#define MT6360_FLED1_TOR_EVT (85) +#define MT6360_FLED2_STRB_EVT 80 +#define MT6360_FLED1_STRB_EVT 81 +#define MT6360_FLED2_STRB_TO_EVT 82 +#define MT6360_FLED1_STRB_TO_EVT 83 +#define MT6360_FLED2_TOR_EVT 84 +#define MT6360_FLED1_TOR_EVT 85 /* REG 11 -> 88 ~ 95 */ /* REG 12 -> 96 ~ 103 */ -#define MT6360_BUCK1_PGB_EVT (96) -#define MT6360_BUCK1_OC_EVT (100) -#define MT6360_BUCK1_OV_EVT (101) -#define MT6360_BUCK1_UV_EVT (102) +#define MT6360_BUCK1_PGB_EVT 96 +#define MT6360_BUCK1_OC_EVT 100 +#define MT6360_BUCK1_OV_EVT 101 +#define MT6360_BUCK1_UV_EVT 102 /* REG 13 -> 104 ~ 111 */ -#define MT6360_BUCK2_PGB_EVT (104) -#define MT6360_BUCK2_OC_EVT (108) -#define MT6360_BUCK2_OV_EVT (109) -#define MT6360_BUCK2_UV_EVT (110) +#define MT6360_BUCK2_PGB_EVT 104 +#define MT6360_BUCK2_OC_EVT 108 +#define MT6360_BUCK2_OV_EVT 109 +#define MT6360_BUCK2_UV_EVT 110 /* REG 14 -> 112 ~ 119 */ -#define MT6360_LDO1_OC_EVT (113) -#define MT6360_LDO2_OC_EVT (114) -#define MT6360_LDO3_OC_EVT (115) -#define MT6360_LDO5_OC_EVT (117) -#define MT6360_LDO6_OC_EVT (118) -#define MT6360_LDO7_OC_EVT (119) +#define MT6360_LDO1_OC_EVT 113 +#define MT6360_LDO2_OC_EVT 114 +#define MT6360_LDO3_OC_EVT 115 +#define MT6360_LDO5_OC_EVT 117 +#define MT6360_LDO6_OC_EVT 118 +#define MT6360_LDO7_OC_EVT 119 /* REG 15 -> 120 ~ 127 */ -#define MT6360_LDO1_PGB_EVT (121) -#define MT6360_LDO2_PGB_EVT (122) -#define MT6360_LDO3_PGB_EVT (123) -#define MT6360_LDO5_PGB_EVT (125) -#define MT6360_LDO6_PGB_EVT (126) -#define MT6360_LDO7_PGB_EVT (127) - -static const struct regmap_irq mt6360_pmu_irqs[] = { +#define MT6360_LDO1_PGB_EVT 121 +#define MT6360_LDO2_PGB_EVT 122 +#define MT6360_LDO3_PGB_EVT 123 +#define MT6360_LDO5_PGB_EVT 125 +#define MT6360_LDO6_PGB_EVT 126 +#define MT6360_LDO7_PGB_EVT 127 + +static const struct regmap_irq mt6360_irqs[] = { REGMAP_IRQ_REG_LINE(MT6360_CHG_TREG_EVT, 8), REGMAP_IRQ_REG_LINE(MT6360_CHG_AICR_EVT, 8), REGMAP_IRQ_REG_LINE(MT6360_CHG_MIVR_EVT, 8), @@ -209,30 +247,16 @@ static const struct regmap_irq mt6360_pmu_irqs[] = { REGMAP_IRQ_REG_LINE(MT6360_LDO7_PGB_EVT, 8), }; -static int mt6360_pmu_handle_post_irq(void *irq_drv_data) -{ - struct mt6360_pmu_data *mpd = irq_drv_data; - - return regmap_update_bits(mpd->regmap, - MT6360_PMU_IRQ_SET, MT6360_IRQ_RETRIG, MT6360_IRQ_RETRIG); -} - -static struct regmap_irq_chip mt6360_pmu_irq_chip = { - .irqs = mt6360_pmu_irqs, - .num_irqs = ARRAY_SIZE(mt6360_pmu_irqs), - .num_regs = MT6360_PMU_IRQ_REGNUM, - .mask_base = MT6360_PMU_CHG_MASK1, - .status_base = MT6360_PMU_CHG_IRQ1, - .ack_base = MT6360_PMU_CHG_IRQ1, +static const struct regmap_irq_chip mt6360_irq_chip = { + .name = "mt6360_irqs", + .irqs = mt6360_irqs, + .num_irqs = ARRAY_SIZE(mt6360_irqs), + .num_regs = MT6360_IRQ_REGNUM, + .mask_base = MT6360_REG_PMU_CHGMASK1, + .status_base = MT6360_REG_PMU_CHGIRQ1, + .ack_base = MT6360_REG_PMU_CHGIRQ1, .init_ack_masked = true, .use_ack = true, - .handle_post_irq = mt6360_pmu_handle_post_irq, -}; - -static const struct regmap_config mt6360_pmu_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = MT6360_PMU_MAXREG, }; static const struct resource mt6360_adc_resources[] = { @@ -266,7 +290,7 @@ static const struct resource mt6360_led_resources[] = { DEFINE_RES_IRQ_NAMED(MT6360_FLED1_STRB_TO_EVT, "fled1_strb_to_evt"), }; -static const struct resource mt6360_pmic_resources[] = { +static const struct resource mt6360_regulator_resources[] = { DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_PGB_EVT, "buck1_pgb_evt"), DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_OC_EVT, "buck1_oc_evt"), DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_OV_EVT, "buck1_ov_evt"), @@ -279,9 +303,6 @@ static const struct resource mt6360_pmic_resources[] = { DEFINE_RES_IRQ_NAMED(MT6360_LDO7_OC_EVT, "ldo7_oc_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO6_PGB_EVT, "ldo6_pgb_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO7_PGB_EVT, "ldo7_pgb_evt"), -}; - -static const struct resource mt6360_ldo_resources[] = { DEFINE_RES_IRQ_NAMED(MT6360_LDO1_OC_EVT, "ldo1_oc_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO2_OC_EVT, "ldo2_oc_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO3_OC_EVT, "ldo3_oc_evt"), @@ -293,94 +314,245 @@ static const struct resource mt6360_ldo_resources[] = { }; static const struct mfd_cell mt6360_devs[] = { - OF_MFD_CELL("mt6360_adc", mt6360_adc_resources, - NULL, 0, 0, "mediatek,mt6360_adc"), - OF_MFD_CELL("mt6360_chg", mt6360_chg_resources, - NULL, 0, 0, "mediatek,mt6360_chg"), - OF_MFD_CELL("mt6360_led", mt6360_led_resources, - NULL, 0, 0, "mediatek,mt6360_led"), - OF_MFD_CELL("mt6360_pmic", mt6360_pmic_resources, - NULL, 0, 0, "mediatek,mt6360_pmic"), - OF_MFD_CELL("mt6360_ldo", mt6360_ldo_resources, - NULL, 0, 0, "mediatek,mt6360_ldo"), - OF_MFD_CELL("mt6360_tcpc", NULL, - NULL, 0, 0, "mediatek,mt6360_tcpc"), + OF_MFD_CELL("mt6360-adc", mt6360_adc_resources, + NULL, 0, 0, "mediatek,mt6360-adc"), + OF_MFD_CELL("mt6360-chg", mt6360_chg_resources, + NULL, 0, 0, "mediatek,mt6360-chg"), + OF_MFD_CELL("mt6360-led", mt6360_led_resources, + NULL, 0, 0, "mediatek,mt6360-led"), + OF_MFD_CELL("mt6360-regulator", mt6360_regulator_resources, + NULL, 0, 0, "mediatek,mt6360-regulator"), + OF_MFD_CELL("mt6360-tcpc", NULL, + NULL, 0, 0, "mediatek,mt6360-tcpc"), }; -static const unsigned short mt6360_slave_addr[MT6360_SLAVE_MAX] = { - MT6360_PMU_SLAVEID, +static int mt6360_check_vendor_info(struct mt6360_data *data) +{ + u32 info; + int ret; + + ret = regmap_read(data->regmap, MT6360_REG_PMU_DEVINFO, &info); + if (ret < 0) + return ret; + + if ((info & MT6360_CHIPVEN_MASK) != MT6360_CHIPVEN_VAL) + return -ENODEV; + + data->chip_rev = info & MT6360_CHIPREV_MASK; + + return 0; +} + +static const u16 mt6360_slave_addrs[MT6360_SLAVE_MAX] = { + MT6360_TCPC_SLAVEID, MT6360_PMIC_SLAVEID, MT6360_LDO_SLAVEID, - MT6360_TCPC_SLAVEID, + MT6360_PMU_SLAVEID, }; -static int mt6360_pmu_probe(struct i2c_client *client) +static int mt6360_xlate_pmicldo_addr(u8 *addr, int rw_size) { - struct mt6360_pmu_data *mpd; - unsigned int reg_data; - int i, ret; + u8 flags[4] = { 0x00, 0x40, 0x80, 0xc0 }; + + if (rw_size < 1 || rw_size > 4) + return -EINVAL; - mpd = devm_kzalloc(&client->dev, sizeof(*mpd), GFP_KERNEL); - if (!mpd) + *addr &= 0x3f; + *addr |= flags[rw_size - 1]; + + return 0; +} + +static int mt6360_regmap_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct mt6360_data *data = context; + u8 bank = *(u8 *)reg, reg_addr = *(u8 *)(reg + 1); + struct i2c_client *i2c = data->i2c[bank]; + bool crc_needed = false; + u8 *buf; + /* first two is i2c_addr + reg_addr , last is crc8 */ + int alloc_size = 2 + val_size + 1, read_size = val_size; + u8 crc; + int ret; + + if (bank == MT6360_SLAVE_PMIC || bank == MT6360_SLAVE_LDO) { + crc_needed = true; + ret = mt6360_xlate_pmicldo_addr(®_addr, val_size); + if (ret < 0) + return ret; + read_size += 1; + } + + buf = kzalloc(alloc_size, GFP_KERNEL); + if (!buf) return -ENOMEM; - mpd->dev = &client->dev; - i2c_set_clientdata(client, mpd); + /* 7 bit slave addr + read bit */ + buf[0] = ((i2c->addr & 0x7f) << 1) + 1; + buf[1] = reg_addr; - mpd->regmap = devm_regmap_init_i2c(client, &mt6360_pmu_regmap_config); - if (IS_ERR(mpd->regmap)) { - dev_err(&client->dev, "Failed to register regmap\n"); - return PTR_ERR(mpd->regmap); + ret = i2c_smbus_read_i2c_block_data(i2c, reg_addr, read_size, buf + 2); + + if (ret == read_size) { + memcpy(val, buf + 2, val_size); + if (crc_needed) { + crc = crc8(data->crc8_tbl, buf, val_size + 2, 0); + if (crc != buf[val_size + 2]) + ret = -EIO; + } } - ret = regmap_read(mpd->regmap, MT6360_PMU_DEV_INFO, ®_data); - if (ret) { - dev_err(&client->dev, "Device not found\n"); + kfree(buf); + + if (ret < 0) return ret; + else if (ret != read_size) + return -EIO; + + return 0; +} + +static int mt6360_regmap_write(void *context, const void *val, size_t val_size) +{ + struct mt6360_data *data = context; + u8 bank = *(u8 *)val, reg_addr = *(u8 *)(val + 1); + struct i2c_client *i2c = data->i2c[bank]; + bool crc_needed = false; + u8 *buf; + /* first two is i2c_addr + reg_addr , last crc8 + dummy */ + int alloc_size = 2 + val_size + 2, write_size = val_size - 2; + int ret; + + if (bank == MT6360_SLAVE_PMIC || bank == MT6360_SLAVE_LDO) { + crc_needed = true; + ret = mt6360_xlate_pmicldo_addr(®_addr, val_size - 2); + if (ret < 0) + return ret; } - mpd->chip_rev = reg_data & CHIP_REV_MASK; - if (mpd->chip_rev != CHIP_VEN_MT6360) { - dev_err(&client->dev, "Device not supported\n"); - return -ENODEV; + buf = kzalloc(alloc_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* 7 bit slave addr + write bit */ + buf[0] = ((i2c->addr & 0x7f) << 1); + buf[1] = reg_addr; + /* val need to minus regaddr 16bit */ + memcpy(buf + 2, val + 2, write_size); + + if (crc_needed) { + buf[val_size] = crc8(data->crc8_tbl, buf, val_size, 0); + write_size += 2; } - mt6360_pmu_irq_chip.irq_drv_data = mpd; - ret = devm_regmap_add_irq_chip(&client->dev, mpd->regmap, client->irq, - IRQF_TRIGGER_FALLING, 0, - &mt6360_pmu_irq_chip, &mpd->irq_data); - if (ret) { - dev_err(&client->dev, "Failed to add Regmap IRQ Chip\n"); + ret = i2c_smbus_write_i2c_block_data(i2c, + reg_addr, write_size, buf + 2); + + kfree(buf); + + if (ret < 0) return ret; + + return 0; +} + +static const struct regmap_bus mt6360_regmap_bus = { + .read = mt6360_regmap_read, + .write = mt6360_regmap_write, + + /* due to pmic and ldo crc access size limit */ + .max_raw_read = 4, + .max_raw_write = 4, +}; + +static bool mt6360_is_readwrite_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MT6360_REG_TCPCSTART ... MT6360_REG_TCPCEND: + case MT6360_REG_PMICSTART ... MT6360_REG_PMICEND: + case MT6360_REG_LDOSTART ... MT6360_REG_LDOEND: + fallthrough; + case MT6360_REG_PMUSTART ... MT6360_REG_PMUEND: + return true; } - mpd->i2c[0] = client; - for (i = 1; i < MT6360_SLAVE_MAX; i++) { - mpd->i2c[i] = devm_i2c_new_dummy_device(&client->dev, - client->adapter, - mt6360_slave_addr[i]); - if (IS_ERR(mpd->i2c[i])) { + return false; +} + +static const struct regmap_config mt6360_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + + .reg_format_endian = REGMAP_ENDIAN_BIG, + + /* bank1:tcpc, bank2:pmic, bank3:ldo, bank4:pmu */ + .max_register = MT6360_REG_PMUEND, + .writeable_reg = mt6360_is_readwrite_reg, + .readable_reg = mt6360_is_readwrite_reg, +}; + +static int mt6360_probe(struct i2c_client *client) +{ + struct mt6360_data *data; + int i, ret; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &client->dev; + crc8_populate_msb(data->crc8_tbl, 0x7); + + for (i = 0; i < MT6360_SLAVE_PMU; i++) { + data->i2c[i] = devm_i2c_new_dummy_device(&client->dev, + client->adapter, + mt6360_slave_addrs[i]); + if (IS_ERR(data->i2c[i])) { dev_err(&client->dev, "Failed to get new dummy I2C device for address 0x%x", - mt6360_slave_addr[i]); - return PTR_ERR(mpd->i2c[i]); + mt6360_slave_addrs[i]); + return PTR_ERR(data->i2c[i]); } - i2c_set_clientdata(mpd->i2c[i], mpd); + } + data->i2c[MT6360_SLAVE_PMU] = client; + + data->regmap = devm_regmap_init(&client->dev, &mt6360_regmap_bus, + data, &mt6360_regmap_config); + if (IS_ERR(data->regmap)) { + dev_err(&client->dev, "Failed to register regmap\n"); + return PTR_ERR(data->regmap); + } + + ret = mt6360_check_vendor_info(data); + if (ret) { + dev_err(&client->dev, "Device not supported\n"); + return ret; + } + + ret = devm_regmap_add_irq_chip(&client->dev, data->regmap, client->irq, + IRQF_ONESHOT, 0, &mt6360_irq_chip, + &data->irq_data); + if (ret) { + dev_err(&client->dev, "Failed to add Regmap IRQ Chip\n"); + return ret; } ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, mt6360_devs, ARRAY_SIZE(mt6360_devs), NULL, - 0, regmap_irq_get_domain(mpd->irq_data)); + 0, regmap_irq_get_domain(data->irq_data)); if (ret) { dev_err(&client->dev, "Failed to register subordinate devices\n"); return ret; } + i2c_set_clientdata(client, data); + return 0; } -static int __maybe_unused mt6360_pmu_suspend(struct device *dev) +static int __maybe_unused mt6360_suspend(struct device *dev) { struct i2c_client *i2c = to_i2c_client(dev); @@ -390,7 +562,7 @@ static int __maybe_unused mt6360_pmu_suspend(struct device *dev) return 0; } -static int __maybe_unused mt6360_pmu_resume(struct device *dev) +static int __maybe_unused mt6360_resume(struct device *dev) { struct i2c_client *i2c = to_i2c_client(dev); @@ -401,25 +573,24 @@ static int __maybe_unused mt6360_pmu_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(mt6360_pmu_pm_ops, - mt6360_pmu_suspend, mt6360_pmu_resume); +static SIMPLE_DEV_PM_OPS(mt6360_pm_ops, mt6360_suspend, mt6360_resume); -static const struct of_device_id __maybe_unused mt6360_pmu_of_id[] = { - { .compatible = "mediatek,mt6360_pmu", }, +static const struct of_device_id __maybe_unused mt6360_of_id[] = { + { .compatible = "mediatek,mt6360", }, {}, }; -MODULE_DEVICE_TABLE(of, mt6360_pmu_of_id); +MODULE_DEVICE_TABLE(of, mt6360_of_id); -static struct i2c_driver mt6360_pmu_driver = { +static struct i2c_driver mt6360_driver = { .driver = { - .name = "mt6360_pmu", - .pm = &mt6360_pmu_pm_ops, - .of_match_table = of_match_ptr(mt6360_pmu_of_id), + .name = "mt6360", + .pm = &mt6360_pm_ops, + .of_match_table = of_match_ptr(mt6360_of_id), }, - .probe_new = mt6360_pmu_probe, + .probe_new = mt6360_probe, }; -module_i2c_driver(mt6360_pmu_driver); +module_i2c_driver(mt6360_driver); MODULE_AUTHOR("Gene Chen "); -MODULE_DESCRIPTION("MT6360 PMU I2C Driver"); +MODULE_DESCRIPTION("MT6360 I2C Driver"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/mt6360.h b/include/linux/mfd/mt6360.h deleted file mode 100644 index ea13040..0000000 --- a/include/linux/mfd/mt6360.h +++ /dev/null @@ -1,240 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2020 MediaTek Inc. - */ - -#ifndef __MT6360_H__ -#define __MT6360_H__ - -#include - -enum { - MT6360_SLAVE_PMU = 0, - MT6360_SLAVE_PMIC, - MT6360_SLAVE_LDO, - MT6360_SLAVE_TCPC, - MT6360_SLAVE_MAX, -}; - -#define MT6360_PMU_SLAVEID (0x34) -#define MT6360_PMIC_SLAVEID (0x1A) -#define MT6360_LDO_SLAVEID (0x64) -#define MT6360_TCPC_SLAVEID (0x4E) - -struct mt6360_pmu_data { - struct i2c_client *i2c[MT6360_SLAVE_MAX]; - struct device *dev; - struct regmap *regmap; - struct regmap_irq_chip_data *irq_data; - unsigned int chip_rev; -}; - -/* PMU register defininition */ -#define MT6360_PMU_DEV_INFO (0x00) -#define MT6360_PMU_CORE_CTRL1 (0x01) -#define MT6360_PMU_RST1 (0x02) -#define MT6360_PMU_CRCEN (0x03) -#define MT6360_PMU_RST_PAS_CODE1 (0x04) -#define MT6360_PMU_RST_PAS_CODE2 (0x05) -#define MT6360_PMU_CORE_CTRL2 (0x06) -#define MT6360_PMU_TM_PAS_CODE1 (0x07) -#define MT6360_PMU_TM_PAS_CODE2 (0x08) -#define MT6360_PMU_TM_PAS_CODE3 (0x09) -#define MT6360_PMU_TM_PAS_CODE4 (0x0A) -#define MT6360_PMU_IRQ_IND (0x0B) -#define MT6360_PMU_IRQ_MASK (0x0C) -#define MT6360_PMU_IRQ_SET (0x0D) -#define MT6360_PMU_SHDN_CTRL (0x0E) -#define MT6360_PMU_TM_INF (0x0F) -#define MT6360_PMU_I2C_CTRL (0x10) -#define MT6360_PMU_CHG_CTRL1 (0x11) -#define MT6360_PMU_CHG_CTRL2 (0x12) -#define MT6360_PMU_CHG_CTRL3 (0x13) -#define MT6360_PMU_CHG_CTRL4 (0x14) -#define MT6360_PMU_CHG_CTRL5 (0x15) -#define MT6360_PMU_CHG_CTRL6 (0x16) -#define MT6360_PMU_CHG_CTRL7 (0x17) -#define MT6360_PMU_CHG_CTRL8 (0x18) -#define MT6360_PMU_CHG_CTRL9 (0x19) -#define MT6360_PMU_CHG_CTRL10 (0x1A) -#define MT6360_PMU_CHG_CTRL11 (0x1B) -#define MT6360_PMU_CHG_CTRL12 (0x1C) -#define MT6360_PMU_CHG_CTRL13 (0x1D) -#define MT6360_PMU_CHG_CTRL14 (0x1E) -#define MT6360_PMU_CHG_CTRL15 (0x1F) -#define MT6360_PMU_CHG_CTRL16 (0x20) -#define MT6360_PMU_CHG_AICC_RESULT (0x21) -#define MT6360_PMU_DEVICE_TYPE (0x22) -#define MT6360_PMU_QC_CONTROL1 (0x23) -#define MT6360_PMU_QC_CONTROL2 (0x24) -#define MT6360_PMU_QC30_CONTROL1 (0x25) -#define MT6360_PMU_QC30_CONTROL2 (0x26) -#define MT6360_PMU_USB_STATUS1 (0x27) -#define MT6360_PMU_QC_STATUS1 (0x28) -#define MT6360_PMU_QC_STATUS2 (0x29) -#define MT6360_PMU_CHG_PUMP (0x2A) -#define MT6360_PMU_CHG_CTRL17 (0x2B) -#define MT6360_PMU_CHG_CTRL18 (0x2C) -#define MT6360_PMU_CHRDET_CTRL1 (0x2D) -#define MT6360_PMU_CHRDET_CTRL2 (0x2E) -#define MT6360_PMU_DPDN_CTRL (0x2F) -#define MT6360_PMU_CHG_HIDDEN_CTRL1 (0x30) -#define MT6360_PMU_CHG_HIDDEN_CTRL2 (0x31) -#define MT6360_PMU_CHG_HIDDEN_CTRL3 (0x32) -#define MT6360_PMU_CHG_HIDDEN_CTRL4 (0x33) -#define MT6360_PMU_CHG_HIDDEN_CTRL5 (0x34) -#define MT6360_PMU_CHG_HIDDEN_CTRL6 (0x35) -#define MT6360_PMU_CHG_HIDDEN_CTRL7 (0x36) -#define MT6360_PMU_CHG_HIDDEN_CTRL8 (0x37) -#define MT6360_PMU_CHG_HIDDEN_CTRL9 (0x38) -#define MT6360_PMU_CHG_HIDDEN_CTRL10 (0x39) -#define MT6360_PMU_CHG_HIDDEN_CTRL11 (0x3A) -#define MT6360_PMU_CHG_HIDDEN_CTRL12 (0x3B) -#define MT6360_PMU_CHG_HIDDEN_CTRL13 (0x3C) -#define MT6360_PMU_CHG_HIDDEN_CTRL14 (0x3D) -#define MT6360_PMU_CHG_HIDDEN_CTRL15 (0x3E) -#define MT6360_PMU_CHG_HIDDEN_CTRL16 (0x3F) -#define MT6360_PMU_CHG_HIDDEN_CTRL17 (0x40) -#define MT6360_PMU_CHG_HIDDEN_CTRL18 (0x41) -#define MT6360_PMU_CHG_HIDDEN_CTRL19 (0x42) -#define MT6360_PMU_CHG_HIDDEN_CTRL20 (0x43) -#define MT6360_PMU_CHG_HIDDEN_CTRL21 (0x44) -#define MT6360_PMU_CHG_HIDDEN_CTRL22 (0x45) -#define MT6360_PMU_CHG_HIDDEN_CTRL23 (0x46) -#define MT6360_PMU_CHG_HIDDEN_CTRL24 (0x47) -#define MT6360_PMU_CHG_HIDDEN_CTRL25 (0x48) -#define MT6360_PMU_BC12_CTRL (0x49) -#define MT6360_PMU_CHG_STAT (0x4A) -#define MT6360_PMU_RESV1 (0x4B) -#define MT6360_PMU_TYPEC_OTP_TH_SEL_CODEH (0x4E) -#define MT6360_PMU_TYPEC_OTP_TH_SEL_CODEL (0x4F) -#define MT6360_PMU_TYPEC_OTP_HYST_TH (0x50) -#define MT6360_PMU_TYPEC_OTP_CTRL (0x51) -#define MT6360_PMU_ADC_BAT_DATA_H (0x52) -#define MT6360_PMU_ADC_BAT_DATA_L (0x53) -#define MT6360_PMU_IMID_BACKBST_ON (0x54) -#define MT6360_PMU_IMID_BACKBST_OFF (0x55) -#define MT6360_PMU_ADC_CONFIG (0x56) -#define MT6360_PMU_ADC_EN2 (0x57) -#define MT6360_PMU_ADC_IDLE_T (0x58) -#define MT6360_PMU_ADC_RPT_1 (0x5A) -#define MT6360_PMU_ADC_RPT_2 (0x5B) -#define MT6360_PMU_ADC_RPT_3 (0x5C) -#define MT6360_PMU_ADC_RPT_ORG1 (0x5D) -#define MT6360_PMU_ADC_RPT_ORG2 (0x5E) -#define MT6360_PMU_BAT_OVP_TH_SEL_CODEH (0x5F) -#define MT6360_PMU_BAT_OVP_TH_SEL_CODEL (0x60) -#define MT6360_PMU_CHG_CTRL19 (0x61) -#define MT6360_PMU_VDDASUPPLY (0x62) -#define MT6360_PMU_BC12_MANUAL (0x63) -#define MT6360_PMU_CHGDET_FUNC (0x64) -#define MT6360_PMU_FOD_CTRL (0x65) -#define MT6360_PMU_CHG_CTRL20 (0x66) -#define MT6360_PMU_CHG_HIDDEN_CTRL26 (0x67) -#define MT6360_PMU_CHG_HIDDEN_CTRL27 (0x68) -#define MT6360_PMU_RESV2 (0x69) -#define MT6360_PMU_USBID_CTRL1 (0x6D) -#define MT6360_PMU_USBID_CTRL2 (0x6E) -#define MT6360_PMU_USBID_CTRL3 (0x6F) -#define MT6360_PMU_FLED_CFG (0x70) -#define MT6360_PMU_RESV3 (0x71) -#define MT6360_PMU_FLED1_CTRL (0x72) -#define MT6360_PMU_FLED_STRB_CTRL (0x73) -#define MT6360_PMU_FLED1_STRB_CTRL2 (0x74) -#define MT6360_PMU_FLED1_TOR_CTRL (0x75) -#define MT6360_PMU_FLED2_CTRL (0x76) -#define MT6360_PMU_RESV4 (0x77) -#define MT6360_PMU_FLED2_STRB_CTRL2 (0x78) -#define MT6360_PMU_FLED2_TOR_CTRL (0x79) -#define MT6360_PMU_FLED_VMIDTRK_CTRL1 (0x7A) -#define MT6360_PMU_FLED_VMID_RTM (0x7B) -#define MT6360_PMU_FLED_VMIDTRK_CTRL2 (0x7C) -#define MT6360_PMU_FLED_PWSEL (0x7D) -#define MT6360_PMU_FLED_EN (0x7E) -#define MT6360_PMU_FLED_Hidden1 (0x7F) -#define MT6360_PMU_RGB_EN (0x80) -#define MT6360_PMU_RGB1_ISNK (0x81) -#define MT6360_PMU_RGB2_ISNK (0x82) -#define MT6360_PMU_RGB3_ISNK (0x83) -#define MT6360_PMU_RGB_ML_ISNK (0x84) -#define MT6360_PMU_RGB1_DIM (0x85) -#define MT6360_PMU_RGB2_DIM (0x86) -#define MT6360_PMU_RGB3_DIM (0x87) -#define MT6360_PMU_RESV5 (0x88) -#define MT6360_PMU_RGB12_Freq (0x89) -#define MT6360_PMU_RGB34_Freq (0x8A) -#define MT6360_PMU_RGB1_Tr (0x8B) -#define MT6360_PMU_RGB1_Tf (0x8C) -#define MT6360_PMU_RGB1_TON_TOFF (0x8D) -#define MT6360_PMU_RGB2_Tr (0x8E) -#define MT6360_PMU_RGB2_Tf (0x8F) -#define MT6360_PMU_RGB2_TON_TOFF (0x90) -#define MT6360_PMU_RGB3_Tr (0x91) -#define MT6360_PMU_RGB3_Tf (0x92) -#define MT6360_PMU_RGB3_TON_TOFF (0x93) -#define MT6360_PMU_RGB_Hidden_CTRL1 (0x94) -#define MT6360_PMU_RGB_Hidden_CTRL2 (0x95) -#define MT6360_PMU_RESV6 (0x97) -#define MT6360_PMU_SPARE1 (0x9A) -#define MT6360_PMU_SPARE2 (0xA0) -#define MT6360_PMU_SPARE3 (0xB0) -#define MT6360_PMU_SPARE4 (0xC0) -#define MT6360_PMU_CHG_IRQ1 (0xD0) -#define MT6360_PMU_CHG_IRQ2 (0xD1) -#define MT6360_PMU_CHG_IRQ3 (0xD2) -#define MT6360_PMU_CHG_IRQ4 (0xD3) -#define MT6360_PMU_CHG_IRQ5 (0xD4) -#define MT6360_PMU_CHG_IRQ6 (0xD5) -#define MT6360_PMU_QC_IRQ (0xD6) -#define MT6360_PMU_FOD_IRQ (0xD7) -#define MT6360_PMU_BASE_IRQ (0xD8) -#define MT6360_PMU_FLED_IRQ1 (0xD9) -#define MT6360_PMU_FLED_IRQ2 (0xDA) -#define MT6360_PMU_RGB_IRQ (0xDB) -#define MT6360_PMU_BUCK1_IRQ (0xDC) -#define MT6360_PMU_BUCK2_IRQ (0xDD) -#define MT6360_PMU_LDO_IRQ1 (0xDE) -#define MT6360_PMU_LDO_IRQ2 (0xDF) -#define MT6360_PMU_CHG_STAT1 (0xE0) -#define MT6360_PMU_CHG_STAT2 (0xE1) -#define MT6360_PMU_CHG_STAT3 (0xE2) -#define MT6360_PMU_CHG_STAT4 (0xE3) -#define MT6360_PMU_CHG_STAT5 (0xE4) -#define MT6360_PMU_CHG_STAT6 (0xE5) -#define MT6360_PMU_QC_STAT (0xE6) -#define MT6360_PMU_FOD_STAT (0xE7) -#define MT6360_PMU_BASE_STAT (0xE8) -#define MT6360_PMU_FLED_STAT1 (0xE9) -#define MT6360_PMU_FLED_STAT2 (0xEA) -#define MT6360_PMU_RGB_STAT (0xEB) -#define MT6360_PMU_BUCK1_STAT (0xEC) -#define MT6360_PMU_BUCK2_STAT (0xED) -#define MT6360_PMU_LDO_STAT1 (0xEE) -#define MT6360_PMU_LDO_STAT2 (0xEF) -#define MT6360_PMU_CHG_MASK1 (0xF0) -#define MT6360_PMU_CHG_MASK2 (0xF1) -#define MT6360_PMU_CHG_MASK3 (0xF2) -#define MT6360_PMU_CHG_MASK4 (0xF3) -#define MT6360_PMU_CHG_MASK5 (0xF4) -#define MT6360_PMU_CHG_MASK6 (0xF5) -#define MT6360_PMU_QC_MASK (0xF6) -#define MT6360_PMU_FOD_MASK (0xF7) -#define MT6360_PMU_BASE_MASK (0xF8) -#define MT6360_PMU_FLED_MASK1 (0xF9) -#define MT6360_PMU_FLED_MASK2 (0xFA) -#define MT6360_PMU_FAULTB_MASK (0xFB) -#define MT6360_PMU_BUCK1_MASK (0xFC) -#define MT6360_PMU_BUCK2_MASK (0xFD) -#define MT6360_PMU_LDO_MASK1 (0xFE) -#define MT6360_PMU_LDO_MASK2 (0xFF) -#define MT6360_PMU_MAXREG (MT6360_PMU_LDO_MASK2) - -/* MT6360_PMU_IRQ_SET */ -#define MT6360_PMU_IRQ_REGNUM (MT6360_PMU_LDO_IRQ2 - MT6360_PMU_CHG_IRQ1 + 1) -#define MT6360_IRQ_RETRIG BIT(2) - -#define CHIP_VEN_MASK (0xF0) -#define CHIP_VEN_MT6360 (0x50) -#define CHIP_REV_MASK (0x0F) - -#endif /* __MT6360_H__ */ From patchwork Fri Jun 19 11:53:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gene Chen X-Patchwork-Id: 11614003 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E7BF513B1 for ; Fri, 19 Jun 2020 11:56:05 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B634F2083B for ; Fri, 19 Jun 2020 11:56:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="cDtHoWBk"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QSOfULew" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B634F2083B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=pPdPRNjc3p3LG6FmGSpYxWSRye9ddd4HAE3MQeroB0U=; b=cDtHoWBk1mVGOUrZHDMBFDXBzS hnw0mTNiMkMvPXcF2l4+NKKlGWVe/zgRm3E0AdCjrjV3fTwZe6R00zF1PaLkRP2hyCYAeeYT4GbDc 5SNGPO9da0fW2SD9u4WgnLCBNGN8HWogYtbBMYZ1xnd/3YDNidE/GUoWH2yYw5KnAtX0qrL1iFx6P FgF3t3GJJhEh0emwl88LaBKKq7kvNfQ4M8jKaGtWYamMvb3gfFzHgEMr+2pmyYCmCh6cOxqPyBZG3 X+FTnJmmR0DTNC4Xg7HW3Y0T+eWgN0kdsC/nQcT+E7ZTemoLgW4ZKYOhJqw6+enzo6bz/D3DPl4W/ l2M0F23A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jmFcp-0002yR-Vx; Fri, 19 Jun 2020 11:56:04 +0000 Received: from mail-pj1-x1041.google.com ([2607:f8b0:4864:20::1041]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jmFbg-0007h8-4S; Fri, 19 Jun 2020 11:54:54 +0000 Received: by mail-pj1-x1041.google.com with SMTP id k2so3984111pjs.2; Fri, 19 Jun 2020 04:54:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=OL6qEmwiDI00DREj99RAu4RhZr0L6rP8DGjoGZeNxMU=; b=QSOfULewQhPqGkXO1surS+5mrsy5CFU9klKHs/HAtKZDikUdmzglAbtVfIJMy40dKL ujnuPmltmegEY3PgY2I30Mt7tubFC/2V2o5x4MEfhWsmeQohRQO1/sLhfpZThOspqqFG mil8x5KCsh6vwUYBj+WW+t0tHSDKnhLPGFjPmhqvMwghkjyLIqXuzSi/FOPyk5OPO2V7 +b8KAkLIMYuRknfklgTT01RfaTl58SI/mGfS9jBdm7z/QXmtRIa0EyGPv3AwlaPyv90I EOjxmXh/eWnJthyhQI5b428fV0Tup+k/wHCcO525Gofp9aS4jeY9EoRG4Q/0nxpTYPP0 8XxA== 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=OL6qEmwiDI00DREj99RAu4RhZr0L6rP8DGjoGZeNxMU=; b=YcmsFSC4RLJn9oZAI5XfsKbB0YrWRyAN+b9KNNUsWf2YsFFCqtALM9AFXnehHmOKyO vh//pzwRWxaTvqQF42a9qefWm59LXo5nWYC8TQFgvysRQJF0gJyv4titRFpEksEmrqUs 3kQXJ2bcv59i+sjoaH4dEWy51pJj7c+TPU+UPchl+iw+Wszthw68ryAJbl7PpQlpTrkx FvIGWEkwJvPwtOQsAglt35hHsEHTWwDuur5JdScGN9gY8TwChxMjnTA4kyGyd/fceX4D MLD2C6ry4ndiuXM8obK2RjgVvfckiz9cHh+K94IKHo+wfEe+3Z77fg3ehre/DA9IZxFW LI0A== X-Gm-Message-State: AOAM530YdyvoLxVFsH/wW+++HLOKBEVcIszM9A10E8Z+5FJg9pKJsYM9 Kf4rkWWEX7NkpP9crGg0NDg= X-Google-Smtp-Source: ABdhPJytpgnbWnTDlb5gcE4DuLeIzbpACpN5MZdp+bjFW5krAlBHwmfmPVdDKmrr3+dGHfUe/mIIlQ== X-Received: by 2002:a17:90a:1985:: with SMTP id 5mr3205948pji.123.1592567691059; Fri, 19 Jun 2020 04:54:51 -0700 (PDT) Received: from localhost.localdomain ([2402:7500:46c:79b7:a5d3:5b37:1d99:175a]) by smtp.gmail.com with ESMTPSA id n64sm5026712pga.38.2020.06.19.04.54.45 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 19 Jun 2020 04:54:50 -0700 (PDT) From: Gene Chen To: lee.jones@linaro.org, jic23@kernel.org, jacek.anaszewski@gmail.com, pavel@ucw.cz, matthias.bgg@gmail.com Subject: [PATCH v2 3/4] iio: adc: mt6360: Add ADC driver for MT6360 Date: Fri, 19 Jun 2020 19:53:50 +0800 Message-Id: <1592567631-20363-4-git-send-email-gene.chen.richtek@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1592567631-20363-1-git-send-email-gene.chen.richtek@gmail.com> References: <1592567631-20363-1-git-send-email-gene.chen.richtek@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200619_045452_830203_DAE26ED5 X-CRM114-Status: GOOD ( 20.54 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:1041 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [gene.chen.richtek[at]gmail.com] -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: gene_chen@richtek.com, lars@metafoo.de, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, cy_huang@richtek.com, benjamin.chao@mediatek.com, broonie@kernel.org, linux-mediatek@lists.infradead.org, dmurphy@ti.com, pmeerw@pmeerw.net, knaack.h@gmx.de, linux-arm-kernel@lists.infradead.org, shufan_lee@richtek.com MIME-Version: 1.0 Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org From: Gene Chen Add MT6360 ADC driver include Charger Current, Voltage, and Temperature. Signed-off-by: Gene Chen --- drivers/iio/adc/Kconfig | 11 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mt6360-adc.c | 388 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 400 insertions(+) create mode 100644 drivers/iio/adc/mt6360-adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index ff35696..7c77424 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -702,6 +702,17 @@ config MCP3911 This driver can also be built as a module. If so, the module will be called mcp3911. +config MEDIATEK_MT6360_ADC + tristate "Mediatek MT6360 ADC Part" + depends on MFD_MT6360 + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here to enable MT6360 ADC Part. + Integrated for System Monitoring include + Charger and Battery Current, Voltage and + Temperature + config MEDIATEK_MT6577_AUXADC tristate "MediaTek AUXADC driver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 90f94ad..5fca90a 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_MAX9611) += max9611.o obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MCP3911) += mcp3911.o +obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_MESON_SARADC) += meson_saradc.o diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c new file mode 100644 index 0000000..a8ca80d --- /dev/null +++ b/drivers/iio/adc/mt6360-adc.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 MediaTek Inc. + * + * Author: Gene Chen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6360_REG_PMUCHGCTRL3 0x313 +#define MT6360_REG_PMUADCCFG 0x356 +#define MT6360_REG_PMUADCRPT1 0x35A + +/* PMUCHGCTRL3 0x313 */ +#define MT6360_AICR_MASK 0xFC +#define MT6360_AICR_SHFT 2 +#define MT6360_AICR_400MA 0x6 +/* PMUADCCFG 0x356 */ +#define MT6360_ADCEN_MASK 0x8000 +/* PMUADCRPT1 0x35A */ +#define MT6360_PREFERCH_MASK 0xF0 +#define MT6360_PREFERCH_SHFT 4 +#define MT6360_RPTCH_MASK 0x0F + +enum { + MT6360_CHAN_USBID = 0, + MT6360_CHAN_VBUSDIV5, + MT6360_CHAN_VBUSDIV2, + MT6360_CHAN_VSYS, + MT6360_CHAN_VBAT, + MT6360_CHAN_IBUS, + MT6360_CHAN_IBAT, + MT6360_CHAN_CHG_VDDP, + MT6360_CHAN_TEMP_JC, + MT6360_CHAN_VREF_TS, + MT6360_CHAN_TS, + MT6360_CHAN_MAX, +}; + +struct mt6360_adc_data { + struct device *dev; + struct regmap *regmap; + struct completion adc_complete; + struct mutex adc_lock; + ktime_t last_off_timestamps[MT6360_CHAN_MAX]; + int irq; +}; + +static inline int mt6360_adc_val_converter(int val, int multiplier, + int offset, int divisor) +{ + return ((val * multiplier) + offset) / divisor; +} + +static int mt6360_adc_convert_processed_val(struct mt6360_adc_data *info, + int chan_idx, int *val) +{ + unsigned int regval = 0; + const struct converter { + int multiplier; + int offset; + int divisor; + } adc_converter[MT6360_CHAN_MAX] = { + { 1250, 0, 1}, /* USBID */ + { 6250, 0, 1}, /* VBUSDIV5 */ + { 2500, 0, 1}, /* VBUSDIV2 */ + { 1250, 0, 1}, /* VSYS */ + { 1250, 0, 1}, /* VBAT */ + { 2500, 0, 1}, /* IBUS */ + { 2500, 0, 1}, /* IBAT */ + { 1250, 0, 1}, /* CHG_VDDP */ + { 105, -8000, 100}, /* TEMP_JC */ + { 1250, 0, 1}, /* VREF_TS */ + { 1250, 0, 1}, /* TS */ + }, sp_ibus_adc_converter = { 1900, 0, 1 }, *sel_converter; + int ret; + + sel_converter = adc_converter + chan_idx; + if (chan_idx == MT6360_CHAN_IBUS) { + /* ibus chan will be affected by aicr config */ + /* if aicr < 400, apply the special ibus converter */ + ret = regmap_read(info->regmap, + MT6360_REG_PMUCHGCTRL3, ®val); + if (ret) + return ret; + + regval = (regval & MT6360_AICR_MASK) >> MT6360_AICR_SHFT; + if (regval < MT6360_AICR_400MA) + sel_converter = &sp_ibus_adc_converter; + } + + *val = mt6360_adc_val_converter(*val, sel_converter->multiplier, + sel_converter->offset, + sel_converter->divisor); + + return 0; +} + +static int mt6360_adc_read_processed(struct mt6360_adc_data *mad, + int channel, int *val) +{ + u16 adc_enable; + u8 rpt[3]; + ktime_t start_t, predict_end_t; + long timeout; + int value, ret; + + mutex_lock(&mad->adc_lock); + + /* select preferred channel that we want */ + ret = regmap_update_bits(mad->regmap, + MT6360_REG_PMUADCRPT1, MT6360_PREFERCH_MASK, + channel << MT6360_PREFERCH_SHFT); + if (ret) + goto out_adc; + + /* enable adc channel we want and adc_en */ + adc_enable = MT6360_ADCEN_MASK | BIT(channel); + adc_enable = cpu_to_be16(adc_enable); + ret = regmap_raw_write(mad->regmap, MT6360_REG_PMUADCCFG, + (void *)&adc_enable, sizeof(u16)); + if (ret) + goto out_adc; + + start_t = ktime_get(); + predict_end_t = ktime_add_ms(mad->last_off_timestamps[channel], 50); + + if (ktime_after(start_t, predict_end_t)) + predict_end_t = ktime_add_ms(start_t, 25); + else + predict_end_t = ktime_add_ms(start_t, 75); + + enable_irq(mad->irq); +adc_retry: + reinit_completion(&mad->adc_complete); + + /* wait for conversion to complete */ + timeout = wait_for_completion_timeout(&mad->adc_complete, + msecs_to_jiffies(200)); + if (timeout == 0) { + ret = -ETIMEDOUT; + goto out_adc_conv; + } else if (timeout < 0) { + ret = -EINTR; + goto out_adc_conv; + } + + ret = regmap_raw_read(mad->regmap, + MT6360_REG_PMUADCRPT1, rpt, sizeof(rpt)); + if (ret) + goto out_adc_conv; + + /* check the current reported channel */ + if ((rpt[0] & MT6360_RPTCH_MASK) != channel) { + dev_dbg(mad->dev, + "not wanted channel report [%02x]\n", rpt[0]); + goto adc_retry; + } + + if (!ktime_after(ktime_get(), predict_end_t)) { + dev_dbg(mad->dev, "time is not after one adc_conv_t\n"); + goto adc_retry; + } + + value = (rpt[1] << 8) | rpt[2]; + + ret = mt6360_adc_convert_processed_val(mad, channel, &value); + if (ret) + goto out_adc_conv; + + *val = value; + ret = IIO_VAL_INT; + +out_adc_conv: + disable_irq(mad->irq); + adc_enable = MT6360_ADCEN_MASK; + adc_enable = cpu_to_be16(adc_enable); + regmap_raw_write(mad->regmap, MT6360_REG_PMUADCCFG, + (void *)&adc_enable, sizeof(u16)); + mad->last_off_timestamps[channel] = ktime_get(); + /* set prefer channel to 0xf */ + regmap_update_bits(mad->regmap, MT6360_REG_PMUADCRPT1, + MT6360_PREFERCH_MASK, 0xF << MT6360_PREFERCH_SHFT); +out_adc: + mutex_unlock(&mad->adc_lock); + + return ret; +} + +static int mt6360_adc_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mt6360_adc_data *mad = iio_priv(iio_dev); + + if (mask == IIO_CHAN_INFO_PROCESSED) + return mt6360_adc_read_processed(mad, chan->channel, val); + + return -EINVAL; +} + +static const struct iio_info mt6360_adc_iio_info = { + .read_raw = mt6360_adc_read_raw, +}; + +#define MT6360_ADC_CHAN(_idx, _type) { \ + .type = _type, \ + .channel = MT6360_CHAN_##_idx, \ + .scan_index = MT6360_CHAN_##_idx, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 32, \ + .storagebits = 32, \ + .shift = 0, \ + .endianness = IIO_CPU, \ + }, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ + .extend_name = #_idx, \ + .datasheet_name = #_idx, \ + .indexed = 1, \ +} + +static const struct iio_chan_spec mt6360_adc_channels[] = { + MT6360_ADC_CHAN(USBID, IIO_VOLTAGE), + MT6360_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE), + MT6360_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE), + MT6360_ADC_CHAN(VSYS, IIO_VOLTAGE), + MT6360_ADC_CHAN(VBAT, IIO_VOLTAGE), + MT6360_ADC_CHAN(IBUS, IIO_CURRENT), + MT6360_ADC_CHAN(IBAT, IIO_CURRENT), + MT6360_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE), + MT6360_ADC_CHAN(TEMP_JC, IIO_TEMP), + MT6360_ADC_CHAN(VREF_TS, IIO_VOLTAGE), + MT6360_ADC_CHAN(TS, IIO_VOLTAGE), + IIO_CHAN_SOFT_TIMESTAMP(MT6360_CHAN_MAX), +}; + +static irqreturn_t mt6360_pmu_adc_donei_handler(int irq, void *data) +{ + struct mt6360_adc_data *mad = iio_priv(data); + + complete(&mad->adc_complete); + return IRQ_HANDLED; +} + +static irqreturn_t mt6360_adc_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + /* 11 ch s32 numbers + 1 s64 timestamp */ + s32 data[MT6360_CHAN_MAX + 2] = { }; + int i = 0, bit, val, ret; + + for_each_set_bit(bit, + indio_dev->active_scan_mask, indio_dev->masklength) { + const struct iio_chan_spec *chan = indio_dev->channels + bit; + + ret = mt6360_adc_read_raw(indio_dev, chan, &val, + NULL, IIO_CHAN_INFO_PROCESSED); + if (ret != IIO_VAL_INT) { + dev_warn(&indio_dev->dev, + "Failed to get %d conversion val\n", bit); + goto out; + } + + data[i++] = val; + } + iio_push_to_buffers_with_timestamp(indio_dev, + data, iio_get_time_ns(indio_dev)); +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static inline int mt6360_adc_reset(struct mt6360_adc_data *info) +{ + u8 configs[3] = {0x80, 0, 0}; + ktime_t all_off_time; + int i; + + all_off_time = ktime_get(); + for (i = 0; i < MT6360_CHAN_MAX; i++) + info->last_off_timestamps[i] = all_off_time; + + /* enable adc_en, clear adc_chn_en/zcv_en/adc_wait_t/adc_idle_t */ + return regmap_raw_write(info->regmap, + MT6360_REG_PMUADCCFG, configs, sizeof(configs)); +} + +static int mt6360_adc_probe(struct platform_device *pdev) +{ + struct mt6360_adc_data *mad; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*mad)); + if (!indio_dev) + return -ENOMEM; + + mad = iio_priv(indio_dev); + mad->dev = &pdev->dev; + init_completion(&mad->adc_complete); + mutex_init(&mad->adc_lock); + + mad->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!mad->regmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + ret = mt6360_adc_reset(mad); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to reset adc\n"); + return ret; + } + + mad->irq = platform_get_irq_byname(pdev, "adc_donei"); + if (mad->irq < 0) { + dev_err(&pdev->dev, "Failed to get adc_done irq\n"); + return mad->irq; + } + + irq_set_status_flags(mad->irq, IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(&pdev->dev, mad->irq, NULL, + mt6360_pmu_adc_donei_handler, + IRQF_TRIGGER_NONE, "adc_donei", + indio_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register adc_done irq\n"); + return ret; + } + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &mt6360_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mt6360_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(mt6360_adc_channels); + + ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev, NULL, + mt6360_adc_trigger_handler, NULL); + if (ret) { + dev_err(&pdev->dev, "Failed to allocate iio trigger buffer\n"); + return ret; + } + + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register iio device\n"); + return ret; + } + + platform_set_drvdata(pdev, indio_dev); + + return 0; +} + +static const struct of_device_id __maybe_unused mt6360_adc_of_id[] = { + { .compatible = "mediatek,mt6360-adc", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt6360_adc_of_id); + +static struct platform_driver mt6360_adc_driver = { + .driver = { + .name = "mt6360-adc", + .of_match_table = mt6360_adc_of_id, + }, + .probe = mt6360_adc_probe, +}; +module_platform_driver(mt6360_adc_driver); + +MODULE_AUTHOR("Gene Chen "); +MODULE_DESCRIPTION("MT6360 ADC Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Fri Jun 19 11:53:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gene Chen X-Patchwork-Id: 11614007 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1C40390 for ; Fri, 19 Jun 2020 11:56:32 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CFD41208B8 for ; Fri, 19 Jun 2020 11:56:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="JK7AwpxK"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FTp4Ik5o" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CFD41208B8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=UcHRHOx6JkB77edJvosfYeirK+jg0C8JVmhB/3kVyKA=; b=JK7AwpxKe2HpmWT+YYyd8y+OlU pBQl9lNUc5buqq/qSfgxPBF8jgQg/9vBp51Y7GnIny8XxjOxrYzNd35in6RtqRg0Wl2uJB0azRC8r OrVdlg65pN3TBCwRv83aB1SyMiHUtW3mBQ8hJ60h6C/SwumifLrBtoSgJQnMVaIr6aT94t7n++1zr 61ruxTSKWoPdUDXNalq1BzLQ5bZaDhTbUAiw3lIIOoLI0AXkqGwvYf5Lpo/NxizXYsIqgjD3hNwGW vzs5HAzzL8g1iHrzgWjH9t9uVT173fAQjuCTfyfey0tYut+qrh5BDcdlwcpoA4XKfjp5zezOuvrRr /AOm+4qg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jmFdE-0003S2-9t; Fri, 19 Jun 2020 11:56:28 +0000 Received: from mail-pg1-x541.google.com ([2607:f8b0:4864:20::541]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jmFbo-0007oa-Vt; Fri, 19 Jun 2020 11:55:08 +0000 Received: by mail-pg1-x541.google.com with SMTP id v11so4398149pgb.6; Fri, 19 Jun 2020 04:55:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=dcN3meLAI17H/mxoVJQTTxgzB2Vv0fY9Kr8wPSUTW+E=; b=FTp4Ik5oWvgmg6rVSFIxHcJ/QLbu1kBf50kBC+XBVcG97UMArK1uMyBog2z0E/H6wb knjyN9qFaDm6oH6xP0RYTzuWJP3KV6oAFa8UjNZKGLc63aAU7TsMIupxGQsvnP/rcs9v nRJ6FGF+pBMbzlWpDcGj5fzNSpqMN/xsbAZA3kR3gnmX5C1cVIjVz9vc720NCjkjFaY0 DJdEgwBQdrbAr5s/R92F1LwxprJ8dDytQMK4WIHVLbNvXPeGl3nAQ9ezGInp38LX5PlJ 13yvsFNNN8bgPgwdBWRmoxAiuR5Evgj4tLfqP7pO2Fq86TvN669LzIe4KoqBeyP0fhMV 12Xw== 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=dcN3meLAI17H/mxoVJQTTxgzB2Vv0fY9Kr8wPSUTW+E=; b=LLNJks1GrsvIMy+vOlj82XJBCocsEqXKbcaMxrIKY9l61Cr/X4KYx8gUffdR+SzoOD pr5g4BV5j9ccu5mVLMcgsFzuZ1W1kriOO3zVGg0K9Bh6kLn1c3/RanMFrAXPJbiLPRa9 Vkb5y8uI2aGtXwrcdMj62COndTZJygV9l1EZtO1qJ4Gnv1qUuMO5aIxC6kegvwit9/JI KMgMwHh9HnuSuuSuuzYQJBbK4W/UJucNAeC3d8V2XZ1mzhgxKKFRsLaKGXoxK05l4bHN 9XRApnRZnxf0s5FF9u8p3p51R63yV2Dezap0uPmCo+TX/Z3tjDQ2+2x+IXE5RWqwVJbN 5UhA== X-Gm-Message-State: AOAM532ii10r5qJYgmJU8yVzgA5jrG+AlBMjgOB4RWfgZq9vInYShXUm 6M3fu1TJInuHpjJTjC9qmUU= X-Google-Smtp-Source: ABdhPJwRULU+2sQ6xiSpEtBJmt71hLIyZtH2JJH+60C9gdSU6VGOhh1cV4rLtkrM6BmS2Si3hCOMNA== X-Received: by 2002:a62:8106:: with SMTP id t6mr7994109pfd.103.1592567700002; Fri, 19 Jun 2020 04:55:00 -0700 (PDT) Received: from localhost.localdomain ([2402:7500:46c:79b7:a5d3:5b37:1d99:175a]) by smtp.gmail.com with ESMTPSA id n64sm5026712pga.38.2020.06.19.04.54.55 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 19 Jun 2020 04:54:59 -0700 (PDT) From: Gene Chen To: lee.jones@linaro.org, jic23@kernel.org, jacek.anaszewski@gmail.com, pavel@ucw.cz, matthias.bgg@gmail.com Subject: [PATCH v2 4/4] regulator: mt6360: Add support for MT6360 regulator Date: Fri, 19 Jun 2020 19:53:51 +0800 Message-Id: <1592567631-20363-5-git-send-email-gene.chen.richtek@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1592567631-20363-1-git-send-email-gene.chen.richtek@gmail.com> References: <1592567631-20363-1-git-send-email-gene.chen.richtek@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200619_045501_065717_7D7F8AFC X-CRM114-Status: GOOD ( 16.59 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:541 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [gene.chen.richtek[at]gmail.com] -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: gene_chen@richtek.com, lars@metafoo.de, lgirdwood@gmail.com, linux-kernel@vger.kernel.org, cy_huang@richtek.com, benjamin.chao@mediatek.com, broonie@kernel.org, linux-mediatek@lists.infradead.org, dmurphy@ti.com, pmeerw@pmeerw.net, knaack.h@gmx.de, linux-arm-kernel@lists.infradead.org, shufan_lee@richtek.com MIME-Version: 1.0 Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org From: Gene Chen Add MT6360 regulator driver include 2-channel buck and 6-channel ldo Signed-off-by: Gene Chen --- drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/mt6360-regulator.c | 485 +++++++++++++++++++++++++++++++++++ 3 files changed, 495 insertions(+) create mode 100644 drivers/regulator/mt6360-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 8f677f5..9ae5711 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -691,6 +691,15 @@ config REGULATOR_MT6358 This driver supports the control of different power rails of device through regulator interface. +config REGULATOR_MT6360 + tristate "MT6360 SubPMIC Regulator" + depends on MFD_MT6360 + help + Say Y here to enable MT6360 regulator support. + This is support MT6360 PMIC/LDO part include + 2-channel buck with Thermal Shutdown and Overload Protection + 6-channel High PSRR and Low Dropout LDO. + config REGULATOR_MT6380 tristate "MediaTek MT6380 PMIC" depends on MTK_PMIC_WRAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index e8f1633..7256457 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_REGULATOR_MPQ7920) += mpq7920.o obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o +obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o diff --git a/drivers/regulator/mt6360-regulator.c b/drivers/regulator/mt6360-regulator.c new file mode 100644 index 0000000..f3c8911 --- /dev/null +++ b/drivers/regulator/mt6360-regulator.c @@ -0,0 +1,485 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (c) 2020 MediaTek Inc. + +// Author: Gene Chen + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +enum { + MT6360_REGULATOR_BUCK1 = 0, + MT6360_REGULATOR_BUCK2, + MT6360_REGULATOR_LDO6, + MT6360_REGULATOR_LDO7, + MT6360_REGULATOR_LDO1, + MT6360_REGULATOR_LDO2, + MT6360_REGULATOR_LDO3, + MT6360_REGULATOR_LDO5, + MT6360_REGULATOR_MAX, +}; + +struct mt6360_irq_mapping { + const char *name; + irq_handler_t handler; +}; + +struct mt6360_regulator_desc { + const struct regulator_desc desc; + unsigned int mode_reg; + unsigned int mode_mask; + unsigned int state_reg; + unsigned int state_mask; + const struct mt6360_irq_mapping *irq_tables; + int irq_table_size; +}; + +struct mt6360_regulator_data { + struct device *dev; + struct regmap *regmap; +}; + +static irqreturn_t mt6360_pgb_event_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_FAIL, NULL); + return IRQ_HANDLED; +} + +static irqreturn_t mt6360_oc_event_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL); + return IRQ_HANDLED; +} + +static irqreturn_t mt6360_ov_event_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, + REGULATOR_EVENT_REGULATION_OUT, NULL); + return IRQ_HANDLED; +} + +static irqreturn_t mt6360_uv_event_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, + REGULATOR_EVENT_UNDER_VOLTAGE, NULL); + return IRQ_HANDLED; +} + +static const struct mt6360_irq_mapping buck1_irq_tbls[] = { + { "buck1_pgb_evt", mt6360_pgb_event_handler }, + { "buck1_oc_evt", mt6360_oc_event_handler }, + { "buck1_ov_evt", mt6360_ov_event_handler }, + { "buck1_uv_evt", mt6360_uv_event_handler }, +}; + +static const struct mt6360_irq_mapping buck2_irq_tbls[] = { + { "buck2_pgb_evt", mt6360_pgb_event_handler }, + { "buck2_oc_evt", mt6360_oc_event_handler }, + { "buck2_ov_evt", mt6360_ov_event_handler }, + { "buck2_uv_evt", mt6360_uv_event_handler }, +}; + +static const struct mt6360_irq_mapping ldo6_irq_tbls[] = { + { "ldo6_pgb_evt", mt6360_pgb_event_handler }, + { "ldo6_oc_evt", mt6360_oc_event_handler }, +}; + +static const struct mt6360_irq_mapping ldo7_irq_tbls[] = { + { "ldo7_pgb_evt", mt6360_pgb_event_handler }, + { "ldo7_oc_evt", mt6360_oc_event_handler }, +}; + +static const struct mt6360_irq_mapping ldo1_irq_tbls[] = { + { "ldo1_pgb_evt", mt6360_pgb_event_handler }, + { "ldo1_oc_evt", mt6360_oc_event_handler }, +}; + +static const struct mt6360_irq_mapping ldo2_irq_tbls[] = { + { "ldo2_pgb_evt", mt6360_pgb_event_handler }, + { "ldo2_oc_evt", mt6360_oc_event_handler }, +}; + +static const struct mt6360_irq_mapping ldo3_irq_tbls[] = { + { "ldo3_pgb_evt", mt6360_pgb_event_handler }, + { "ldo3_oc_evt", mt6360_oc_event_handler }, +}; + +static const struct mt6360_irq_mapping ldo5_irq_tbls[] = { + { "ldo5_pgb_evt", mt6360_pgb_event_handler }, + { "ldo5_oc_evt", mt6360_oc_event_handler }, +}; + +static const struct linear_range buck_vout_ranges[] = { + REGULATOR_LINEAR_RANGE(300000, 0x00, 0xc7, 5000), + REGULATOR_LINEAR_RANGE(1300000, 0xc8, 0xff, 0), +}; + +static const struct linear_range ldo_vout_ranges1[] = { + REGULATOR_LINEAR_RANGE(500000, 0x00, 0x09, 10000), + REGULATOR_LINEAR_RANGE(600000, 0x0a, 0x10, 0), + REGULATOR_LINEAR_RANGE(610000, 0x11, 0x19, 10000), + REGULATOR_LINEAR_RANGE(700000, 0x1a, 0x20, 0), + REGULATOR_LINEAR_RANGE(710000, 0x21, 0x29, 10000), + REGULATOR_LINEAR_RANGE(800000, 0x2a, 0x30, 0), + REGULATOR_LINEAR_RANGE(810000, 0x31, 0x39, 10000), + REGULATOR_LINEAR_RANGE(900000, 0x3a, 0x40, 0), + REGULATOR_LINEAR_RANGE(910000, 0x41, 0x49, 10000), + REGULATOR_LINEAR_RANGE(1000000, 0x4a, 0x50, 0), + REGULATOR_LINEAR_RANGE(1010000, 0x51, 0x59, 10000), + REGULATOR_LINEAR_RANGE(1100000, 0x5a, 0x60, 0), + REGULATOR_LINEAR_RANGE(1110000, 0x61, 0x69, 10000), + REGULATOR_LINEAR_RANGE(1200000, 0x6a, 0x70, 0), + REGULATOR_LINEAR_RANGE(1210000, 0x71, 0x79, 10000), + REGULATOR_LINEAR_RANGE(1300000, 0x7a, 0x80, 0), + REGULATOR_LINEAR_RANGE(1310000, 0x81, 0x89, 10000), + REGULATOR_LINEAR_RANGE(1400000, 0x8a, 0x90, 0), + REGULATOR_LINEAR_RANGE(1410000, 0x91, 0x99, 10000), + REGULATOR_LINEAR_RANGE(1500000, 0x9a, 0xa0, 0), + REGULATOR_LINEAR_RANGE(1510000, 0xa1, 0xa9, 10000), + REGULATOR_LINEAR_RANGE(1600000, 0xaa, 0xb0, 0), + REGULATOR_LINEAR_RANGE(1610000, 0xb1, 0xb9, 10000), + REGULATOR_LINEAR_RANGE(1700000, 0xba, 0xc0, 0), + REGULATOR_LINEAR_RANGE(1710000, 0xc1, 0xc9, 10000), + REGULATOR_LINEAR_RANGE(1800000, 0xca, 0xd0, 0), + REGULATOR_LINEAR_RANGE(1810000, 0xd1, 0xd9, 10000), + REGULATOR_LINEAR_RANGE(1900000, 0xda, 0xe0, 0), + REGULATOR_LINEAR_RANGE(1910000, 0xe1, 0xe9, 10000), + REGULATOR_LINEAR_RANGE(2000000, 0xea, 0xf0, 0), + REGULATOR_LINEAR_RANGE(2010000, 0xf1, 0xf9, 10000), + REGULATOR_LINEAR_RANGE(2100000, 0xfa, 0xff, 0), +}; + +static const struct linear_range ldo_vout_ranges2[] = { + REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x09, 10000), + REGULATOR_LINEAR_RANGE(1300000, 0x0a, 0x10, 0), + REGULATOR_LINEAR_RANGE(1310000, 0x11, 0x19, 10000), + REGULATOR_LINEAR_RANGE(1400000, 0x1a, 0x1f, 0), + REGULATOR_LINEAR_RANGE(1500000, 0x20, 0x29, 10000), + REGULATOR_LINEAR_RANGE(1600000, 0x2a, 0x2f, 0), + REGULATOR_LINEAR_RANGE(1700000, 0x30, 0x39, 10000), + REGULATOR_LINEAR_RANGE(1800000, 0x3a, 0x40, 0), + REGULATOR_LINEAR_RANGE(1810000, 0x41, 0x49, 10000), + REGULATOR_LINEAR_RANGE(1900000, 0x4a, 0x4f, 0), + REGULATOR_LINEAR_RANGE(2000000, 0x50, 0x59, 10000), + REGULATOR_LINEAR_RANGE(2100000, 0x5a, 0x60, 0), + REGULATOR_LINEAR_RANGE(2110000, 0x61, 0x69, 10000), + REGULATOR_LINEAR_RANGE(2200000, 0x6a, 0x6f, 0), + REGULATOR_LINEAR_RANGE(2500000, 0x70, 0x79, 10000), + REGULATOR_LINEAR_RANGE(2600000, 0x7a, 0x7f, 0), + REGULATOR_LINEAR_RANGE(2700000, 0x80, 0x89, 10000), + REGULATOR_LINEAR_RANGE(2800000, 0x8a, 0x90, 0), + REGULATOR_LINEAR_RANGE(2810000, 0x91, 0x99, 10000), + REGULATOR_LINEAR_RANGE(2900000, 0x9a, 0xa0, 0), + REGULATOR_LINEAR_RANGE(2910000, 0xa1, 0xa9, 10000), + REGULATOR_LINEAR_RANGE(3000000, 0xaa, 0xb0, 0), + REGULATOR_LINEAR_RANGE(3010000, 0xb1, 0xb9, 10000), + REGULATOR_LINEAR_RANGE(3100000, 0xba, 0xc0, 0), + REGULATOR_LINEAR_RANGE(3110000, 0xc1, 0xc9, 10000), + REGULATOR_LINEAR_RANGE(3200000, 0xca, 0xcf, 0), + REGULATOR_LINEAR_RANGE(3300000, 0xd0, 0xd9, 10000), + REGULATOR_LINEAR_RANGE(3400000, 0xda, 0xe0, 0), + REGULATOR_LINEAR_RANGE(3410000, 0xe1, 0xe9, 10000), + REGULATOR_LINEAR_RANGE(3500000, 0xea, 0xf0, 0), + REGULATOR_LINEAR_RANGE(3510000, 0xf1, 0xf9, 10000), + REGULATOR_LINEAR_RANGE(3600000, 0xfa, 0xff, 0), +}; + +static const struct linear_range ldo_vout_ranges3[] = { + REGULATOR_LINEAR_RANGE(2700000, 0x00, 0x09, 10000), + REGULATOR_LINEAR_RANGE(2800000, 0x0a, 0x10, 0), + REGULATOR_LINEAR_RANGE(2810000, 0x11, 0x19, 10000), + REGULATOR_LINEAR_RANGE(2900000, 0x1a, 0x20, 0), + REGULATOR_LINEAR_RANGE(2910000, 0x21, 0x29, 10000), + REGULATOR_LINEAR_RANGE(3000000, 0x2a, 0x30, 0), + REGULATOR_LINEAR_RANGE(3010000, 0x31, 0x39, 10000), + REGULATOR_LINEAR_RANGE(3100000, 0x3a, 0x40, 0), + REGULATOR_LINEAR_RANGE(3110000, 0x41, 0x49, 10000), + REGULATOR_LINEAR_RANGE(3200000, 0x4a, 0x4f, 0), + REGULATOR_LINEAR_RANGE(3300000, 0x50, 0x59, 10000), + REGULATOR_LINEAR_RANGE(3400000, 0x5a, 0x60, 0), + REGULATOR_LINEAR_RANGE(3410000, 0x61, 0x69, 10000), + REGULATOR_LINEAR_RANGE(3500000, 0x6a, 0x70, 0), + REGULATOR_LINEAR_RANGE(3510000, 0x71, 0x79, 10000), + REGULATOR_LINEAR_RANGE(3600000, 0x7a, 0x7f, 0), +}; + +static int mt6360_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + const struct mt6360_regulator_desc *rdesc = + (const struct mt6360_regulator_desc *)rdev->desc; + struct regmap *regmap = rdev_get_regmap(rdev); + int shift = ffs(rdesc->mode_mask) - 1; + unsigned int val; + int ret; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = MT6360_OPMODE_NORMAL; + break; + case REGULATOR_MODE_STANDBY: + val = MT6360_OPMODE_ULP; + break; + case REGULATOR_MODE_IDLE: + val = MT6360_OPMODE_LP; + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(regmap, rdesc->mode_reg, + rdesc->mode_mask, val << shift); + if (ret) { + dev_err(&rdev->dev, "%s: fail (%d)\n", __func__, ret); + return ret; + } + + return 0; +} + +static unsigned int mt6360_regulator_get_mode(struct regulator_dev *rdev) +{ + const struct mt6360_regulator_desc *rdesc = + (const struct mt6360_regulator_desc *)rdev->desc; + struct regmap *regmap = rdev_get_regmap(rdev); + int shift = ffs(rdesc->mode_mask) - 1; + unsigned int val; + int ret; + + ret = regmap_read(regmap, rdesc->mode_reg, &val); + if (ret) + return ret; + + val &= rdesc->mode_mask; + val >>= shift; + + switch (val) { + case MT6360_OPMODE_LP: + return REGULATOR_MODE_IDLE; + case MT6360_OPMODE_ULP: + return REGULATOR_MODE_STANDBY; + case MT6360_OPMODE_NORMAL: + return REGULATOR_MODE_NORMAL; + default: + return -EINVAL; + } +} + +static int mt6360_regulator_get_status(struct regulator_dev *rdev) +{ + const struct mt6360_regulator_desc *rdesc = + (const struct mt6360_regulator_desc *)rdev->desc; + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int val; + int ret; + + ret = regmap_read(regmap, rdesc->state_reg, &val); + if (ret) + return ret; + + if (val & rdesc->state_mask) + return REGULATOR_STATUS_ON; + + return REGULATOR_STATUS_OFF; +} + +static const struct regulator_ops mt6360_regulator_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_mode = mt6360_regulator_set_mode, + .get_mode = mt6360_regulator_get_mode, + .get_status = mt6360_regulator_get_status, +}; + +static unsigned int mt6360_regulator_of_map_mode(unsigned int hw_mode) +{ + switch (hw_mode) { + case MT6360_OPMODE_NORMAL: + return REGULATOR_MODE_NORMAL; + case MT6360_OPMODE_LP: + return REGULATOR_MODE_IDLE; + case MT6360_OPMODE_ULP: + return REGULATOR_MODE_STANDBY; + default: + return REGULATOR_MODE_INVALID; + } +} + +#define MT6360_REGULATOR_DESC(_name, _sname, ereg, emask, vreg, vmask, \ + mreg, mmask, streg, stmask, vranges, \ + vcnts, offon_delay, irq_tbls) \ +{ \ + .desc = { \ + .name = #_name, \ + .supply_name = #_sname, \ + .id = MT6360_REGULATOR_##_name, \ + .of_match = of_match_ptr(#_name), \ + .of_map_mode = mt6360_regulator_of_map_mode, \ + .owner = THIS_MODULE, \ + .ops = &mt6360_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .vsel_reg = vreg, \ + .vsel_mask = vmask, \ + .enable_reg = ereg, \ + .enable_mask = emask, \ + .linear_ranges = vranges, \ + .n_linear_ranges = ARRAY_SIZE(vranges), \ + .n_voltages = vcnts, \ + .off_on_delay = offon_delay, \ + }, \ + .mode_reg = mreg, \ + .mode_mask = mmask, \ + .state_reg = streg, \ + .state_mask = stmask, \ + .irq_tables = irq_tbls, \ + .irq_table_size = ARRAY_SIZE(irq_tbls), \ +} + +static const struct mt6360_regulator_desc mt6360_regulator_descs[] = { + MT6360_REGULATOR_DESC(BUCK1, BUCK1_VIN, 0x117, 0x40, 0x110, 0xff, 0x117, + 0x30, 0x117, 0x04, buck_vout_ranges, 256, 0, + buck1_irq_tbls), + MT6360_REGULATOR_DESC(BUCK2, BUCK2_VIN, 0x127, 0x40, 0x120, 0xff, 0x127, + 0x30, 0x127, 0x04, buck_vout_ranges, 256, 0, + buck2_irq_tbls), + MT6360_REGULATOR_DESC(LDO6, LDO_VIN3, 0x137, 0x40, 0x13B, 0xff, 0x137, + 0x30, 0x137, 0x04, ldo_vout_ranges1, 256, 0, + ldo6_irq_tbls), + MT6360_REGULATOR_DESC(LDO7, LDO_VIN3, 0x131, 0x40, 0x135, 0xff, 0x131, + 0x30, 0x131, 0x04, ldo_vout_ranges1, 256, 0, + ldo7_irq_tbls), + MT6360_REGULATOR_DESC(LDO1, LDO_VIN1, 0x217, 0x40, 0x21B, 0xff, 0x217, + 0x30, 0x217, 0x04, ldo_vout_ranges2, 256, 0, + ldo1_irq_tbls), + MT6360_REGULATOR_DESC(LDO2, LDO_VIN1, 0x211, 0x40, 0x215, 0xff, 0x211, + 0x30, 0x211, 0x04, ldo_vout_ranges2, 256, 0, + ldo2_irq_tbls), + MT6360_REGULATOR_DESC(LDO3, LDO_VIN1, 0x205, 0x40, 0x209, 0xff, 0x205, + 0x30, 0x205, 0x04, ldo_vout_ranges2, 256, 100, + ldo3_irq_tbls), + MT6360_REGULATOR_DESC(LDO5, LDO_VIN2, 0x20B, 0x40, 0x20F, 0x7f, 0x20B, + 0x30, 0x20B, 0x04, ldo_vout_ranges3, 128, 100, + ldo5_irq_tbls), +}; + +static int mt6360_regulator_irq_register(struct platform_device *pdev, + struct regulator_dev *rdev, + const struct mt6360_irq_mapping *tbls, + int tbl_size) +{ + int i, irq, ret; + + for (i = 0; i < tbl_size; i++) { + const struct mt6360_irq_mapping *irq_desc = tbls + i; + + irq = platform_get_irq_byname(pdev, irq_desc->name); + if (irq < 0) { + dev_err(&pdev->dev, + "Fail to get %s irq\n", irq_desc->name); + return irq; + } + + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + irq_desc->handler, + IRQF_TRIGGER_NONE, + irq_desc->name, + rdev); + if (ret) { + dev_err(&pdev->dev, + "Fail to request %s irq\n", irq_desc->name); + return ret; + } + } + + return 0; +} + +static int mt6360_regulator_probe(struct platform_device *pdev) +{ + struct mt6360_regulator_data *mrd; + struct regulator_config config = {}; + int i, ret; + + mrd = devm_kzalloc(&pdev->dev, sizeof(*mrd), GFP_KERNEL); + if (!mrd) + return -ENOMEM; + + mrd->dev = &pdev->dev; + + mrd->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!mrd->regmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + config.dev = &pdev->dev; + config.driver_data = mrd; + config.regmap = mrd->regmap; + + for (i = 0; i < ARRAY_SIZE(mt6360_regulator_descs); i++) { + const struct mt6360_regulator_desc *rdesc = + mt6360_regulator_descs + i; + struct regulator_dev *rdev; + + rdev = devm_regulator_register(&pdev->dev, + &rdesc->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "Failed to register %d regulaotr\n", i); + return PTR_ERR(rdev); + } + + ret = mt6360_regulator_irq_register(pdev, rdev, + rdesc->irq_tables, + rdesc->irq_table_size); + if (ret) { + dev_err(&pdev->dev, + "Failed to register %d regulaotr irqs\n", i); + return ret; + } + } + + platform_set_drvdata(pdev, mrd); + + return 0; +} + +static const struct of_device_id __maybe_unused mt6360_regulator_of_id[] = { + { .compatible = "mediatek,mt6360-regulator", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt6360_regulator_of_id); + +static struct platform_driver mt6360_regulator_driver = { + .driver = { + .name = "mt6360-regulator", + .of_match_table = mt6360_regulator_of_id, + }, + .probe = mt6360_regulator_probe, +}; +module_platform_driver(mt6360_regulator_driver); + +MODULE_AUTHOR("Gene Chen "); +MODULE_DESCRIPTION("MT6360 Regulator Driver"); +MODULE_LICENSE("GPL v2");