From patchwork Fri Jul 15 11:25:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919063 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8AA01CCA47C for ; Fri, 15 Jul 2022 11:26:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229452AbiGOL0e (ORCPT ); Fri, 15 Jul 2022 07:26:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45606 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231928AbiGOL0d (ORCPT ); Fri, 15 Jul 2022 07:26:33 -0400 Received: from mail-pf1-x42a.google.com (mail-pf1-x42a.google.com [IPv6:2607:f8b0:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BF27F87C2F; Fri, 15 Jul 2022 04:26:28 -0700 (PDT) Received: by mail-pf1-x42a.google.com with SMTP id y141so4421965pfb.7; Fri, 15 Jul 2022 04:26:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=EKmNQ8jzp5T9yDlHBcPnxdkBT3bPgsI1Zy7bvplXzhs=; b=dM2vJA4m5tndM2YqWNChQvV612aceWv+sz8S5PyiJ4Y5aoTV6LOkaJQWmzUP/xg6ta qCYtaPPtLJeMJ0nVjU0teMHZf0hNcD6E3WCpSyk83tUqWoOBINoWz8XUkEGdT66AS4L6 QXlWza3ewY9p7byKmLDYj/TBoSPbUbX/mIm/OSCEJTlTLDvOfXtvw/j4ABRsY4hVSaWC lk2n8k2vG492/R5d2w9R1jLn0KprrlC7YPhxdnDJKjeTqjnUQ6w/ERzXb82a+Kj7h9sx b+eDRz6hlDAmmJjkQeq5gytTxbfE0dDujNUpoc9zbwe3YYgZcUThwLqdBYIFaUUwunAe LwQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=EKmNQ8jzp5T9yDlHBcPnxdkBT3bPgsI1Zy7bvplXzhs=; b=HQVznNblOWxR62ezzhoMTJD2n3u+m6jpqxJAIrREfddPI507BDPayaoiqxngyOQivs UVAlYDjNgpn9i96p+YOTG69p9snZ7kvhViTpo4eTVHobSB4QkDC5j9Os5iboRltDIKNA /F/gM9FuFMuy95CdaLaQaZ7c3BQ/y2c7lCrccEPXOkXEvdO1K7f+P3YnJwPCmn2yFgBF ++c032l3VLKA8Cgv7wCw7zI6k/RTbR2zotWmArhRcnYFG0Au85gAQYR46o1WSs+zy+od OeIQfEfHIsPs3Liv8p/WQMg9ryUUSt0jDhtiR9n54pPooQvb/ccgN13Qv1dL+wTaUb1e Dg8Q== X-Gm-Message-State: AJIora+7GHC91R4BSTBjV6SiCUOX4rqHOixUUjZZg9eMPovsFU+41boZ ouh015nn+juZBmE1r0HbvTE= X-Google-Smtp-Source: AGRyM1tpynyvAvekOW3RZZP9tybhRUVpPyV/kx5yxMHMHgxsvvYgAcZ4Bsjsnpz63WdQnjk7NScSIg== X-Received: by 2002:a63:8649:0:b0:419:be28:bc36 with SMTP id x70-20020a638649000000b00419be28bc36mr5791024pgd.549.1657884388311; Fri, 15 Jul 2022 04:26:28 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.26.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:26:27 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com, Krzysztof Kozlowski Subject: [PATCH v5 01/13] dt-bindings: usb: Add MediaTek MT6370 TCPC Date: Fri, 15 Jul 2022 19:25:55 +0800 Message-Id: <20220715112607.591-2-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiYuan Huang Add MediaTek MT6370 TCPC binding documentation. Signed-off-by: ChiYuan Huang Reviewed-by: Krzysztof Kozlowski --- .../bindings/usb/mediatek,mt6370-tcpc.yaml | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml new file mode 100644 index 0000000..72f56cc --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller + +maintainers: + - ChiYuan Huang + +description: | + MediaTek MT6370 is a multi-functional device. + It integrates charger, ADC, flash, RGB indicators, + regulators (DSV/VIBLDO), and TypeC Port Switch with Power Delivery controller. + This document only describes MT6370 Type-C Port Switch and + Power Delivery controller. + +properties: + compatible: + enum: + - mediatek,mt6370-tcpc + + interrupts: + maxItems: 1 + + connector: + type: object + $ref: /schemas/connector/usb-connector.yaml# + unevaluatedProperties: false + +additionalProperties: false + +required: + - compatible + - interrupts From patchwork Fri Jul 15 11:25:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919064 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 23080C433EF for ; Fri, 15 Jul 2022 11:26:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232267AbiGOL0h (ORCPT ); Fri, 15 Jul 2022 07:26:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45696 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231749AbiGOL0g (ORCPT ); Fri, 15 Jul 2022 07:26:36 -0400 Received: from mail-pj1-x1030.google.com (mail-pj1-x1030.google.com [IPv6:2607:f8b0:4864:20::1030]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AF33B87C1F; Fri, 15 Jul 2022 04:26:34 -0700 (PDT) Received: by mail-pj1-x1030.google.com with SMTP id x18-20020a17090a8a9200b001ef83b332f5so11366199pjn.0; Fri, 15 Jul 2022 04:26:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RtO+yg7Wi4JSj3ZmHONhdPt1sUn6ZtFJMnIAL1+O4g0=; b=MxhXhpk7Ks0RWEvd9kFA9v3SZ8AzSin2yjmbK6C1k369LpIP0hKZupdIq0qEl0dte5 i9TBORRgmpb/z/CAyA8YHTgT91PSqkfn6wTbXD2mezNTndRRe79UQowzeMFniVFItM+d chN7ZH9k41k9o22X3/RxGomlrOdokzIkSq2INwkk4u4RFHm4XYZg4x3Ykj3f7h+njCMI hRfAdAvEZ1bAcCSf/NcKMoj6lE62CBTRW1sVW5vX3HUmztLYV8+cpI8QfkG1i/If0sSf h6gjbnkwrWsUGpaJvyfXFastJKJdEnkJG86eFBgFxOzpXYuxj7l5kp/MF4vwSlWGZGhk lP9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RtO+yg7Wi4JSj3ZmHONhdPt1sUn6ZtFJMnIAL1+O4g0=; b=nBtktmYv+6d/6HOSMbVcnLeDJ16vKhYnX/ahA5anhM5j8kmQdCanx5vmg8rEPzEC18 QQSojALjpi553Kdf0uLyxfoo7Fqe/oGyJT7rBTDXIeXtypVh7zOK+XO1jgRp5iZVOeEk Ikj4c8q5VICHJT8Tu2nHVef9olcFgOvf3CrCn+0oAWSpuQpVzpE0sGpMc+S3BdQvWb5J 6M2BkwhUD4OMphQ9z/sv4lMislz5kK0SI2wb5pZZvWoL31zBdR5WDU0mmBU7nfyJ2+Ni L1oaIbYIvDlZmxZh5pi5mKLufEv9bP93DVwwAIFLGFlcYWBHNkynCGqMORK1pIA4SRFV 06VA== X-Gm-Message-State: AJIora8CYC5TzHO6sk8lIOAh/52NK89I3jSoh1Rhf7OUT1cKuce+y4HP syPzwXN0Ec3ytha+UYB7gA4= X-Google-Smtp-Source: AGRyM1sFeRtrbGN2hqRqxJUOt5WA81Ct6iRVr9pZJ5dkJiTPbuxUedwsmxzgqDnxutg/Gx+lwHQrUQ== X-Received: by 2002:a17:903:1109:b0:16c:b5e7:652f with SMTP id n9-20020a170903110900b0016cb5e7652fmr6278114plh.142.1657884394006; Fri, 15 Jul 2022 04:26:34 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.26.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:26:33 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com, Krzysztof Kozlowski Subject: [PATCH v5 02/13] dt-bindings: power: supply: Add MediaTek MT6370 Charger Date: Fri, 15 Jul 2022 19:25:56 +0800 Message-Id: <20220715112607.591-3-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiaEn Wu Add MediaTek MT6370 Charger binding documentation. Signed-off-by: ChiaEn Wu Reviewed-by: Krzysztof Kozlowski --- .../power/supply/mediatek,mt6370-charger.yaml | 88 ++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml diff --git a/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml new file mode 100644 index 0000000..bd09a0a --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/mediatek,mt6370-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT6370 Battery Charger + +maintainers: + - ChiaEn Wu + +description: | + This module is part of the MT6370 MFD device. + Provides Battery Charger, Boost for OTG devices and BC1.2 detection. + +properties: + compatible: + const: mediatek,mt6370-charger + + interrupts: + description: | + Specify what irqs are needed to be handled by MT6370 Charger driver. IRQ + "MT6370_IRQ_CHG_MIVR", "MT6370_IRQ_ATTACH" and "MT6370_IRQ_OVPCTRL_UVP_D" + are required. + items: + - description: BC1.2 done irq + - description: usb plug in irq + - description: mivr irq + + interrupt-names: + items: + - const: attach_i + - const: uvp_d_evt + - const: mivr + + io-channels: + description: | + Use ADC channel to read VBUS, IBUS, IBAT, etc., info. + minItems: 1 + items: + - description: | + VBUS voltage with lower accuracy (+-75mV) but higher measure + range (1~22V) + - description: | + VBUS voltage with higher accuracy (+-30mV) but lower measure + range (1~9.76V) + - description: the main system input voltage + - description: battery voltage + - description: battery temperature-sense input voltage + - description: IBUS current (required) + - description: battery current + - description: | + regulated output voltage to supply for the PWM low-side gate driver + and the bootstrap capacitor + - description: IC junction temperature + + io-channel-names: + minItems: 1 + items: + - const: vbusdiv5 + - const: vbusdiv2 + - const: vsys + - const: vbat + - const: ts_bat + - const: ibus + - const: ibat + - const: chg_vddp + - const: temp_jc + + usb-otg-vbus-regulator: + type: object + description: OTG boost regulator. + unevaluatedProperties: false + $ref: /schemas/regulator/regulator.yaml# + + properties: + enable-gpios: + maxItems: 1 + +required: + - compatible + - interrupts + - interrupt-names + - io-channels + +additionalProperties: false + +... From patchwork Fri Jul 15 11:25:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919065 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D85E2CCA480 for ; Fri, 15 Jul 2022 11:26:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232832AbiGOL0x (ORCPT ); Fri, 15 Jul 2022 07:26:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46180 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232951AbiGOL0t (ORCPT ); Fri, 15 Jul 2022 07:26:49 -0400 Received: from mail-pl1-x62d.google.com (mail-pl1-x62d.google.com [IPv6:2607:f8b0:4864:20::62d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC79987F51; Fri, 15 Jul 2022 04:26:41 -0700 (PDT) Received: by mail-pl1-x62d.google.com with SMTP id z1so2981526plb.1; Fri, 15 Jul 2022 04:26:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=IxQGn4iIVyQgO4sCNH7+LFX9XzovM/Q2pkwFCARsvl8=; b=Mgv/uMAS6quJW6YOZJXpMrDjRfPkFpN+lUMCrij5TBWPh0sRprsv1vbBDjKB3yyw+2 2R5YnmXIe/LBE2jM97adfXCANPNts4ZSLncX3BhmojlH6iJB4B9fPJNdHe2pKNN9oytd u62zCqRFFeFhM9pcOxcs6unc0wEmMbyI6pKZY1FRUU18doVFIHRsJEVlNVin2BBRgaAh 8FWBSrqiYL4BsoR3E6tSKYQK9LpGXBALXysPOw1quULxO7mxCGPmyvnr5yUev6asjhrH wTud6mjKTQu6+640YM/rWz7AK/cKlRMyoADJCuFRKViULuePnuLVKaDKPbSfyhvRDtfa nd8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=IxQGn4iIVyQgO4sCNH7+LFX9XzovM/Q2pkwFCARsvl8=; b=zh+bTxzXkP3D4F73FBxEubsmqA1FVeoRD1LKz6iMVPaGVBpqrxdsOsu6Kie4q2ujpV PkwDi/R2Ay0h01HsI/EsbpZIlPv+rVINGdszsYVh2A/qtTjAs6QePCxbQO1wizCDJhV0 OAo0jxEqPtLPo+Y7Psp+fh5xUafXf9weDztm5M8ViiR9CbdfZFSKq/rgM2bHd1jXAi4L 2237sT++kMHZRlXIFG48WpkLyqT6oKDcXSuYB8AgNqhsOuuV404kMTTVJdw5hkkO5jBm TyKyJbcYt1X9j8G9Wu6RaJhBFxSzuLkWj/+Yl6UzTxVx+yOhTUQIBRCwjUYN3Mqsg1H4 nWDA== X-Gm-Message-State: AJIora8ZOUCopDQ1QKLWktlZe4vCJVwH6PA+n2+okfCEaL89zQdmWYLF Ad6EKiKF124kVdUhpsD8Lls= X-Google-Smtp-Source: AGRyM1s3nsMjuXz7+TjcArNnQ5dHqg+xYnlDeUbRjeQaq2MhYrhBmlzeb//JROOfLXHQe+5HiF+Isw== X-Received: by 2002:a17:90b:3811:b0:1ef:d704:24cf with SMTP id mq17-20020a17090b381100b001efd70424cfmr14962651pjb.14.1657884401220; Fri, 15 Jul 2022 04:26:41 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.26.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:26:40 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com, Krzysztof Kozlowski Subject: [PATCH v5 03/13] dt-bindings: leds: mt6370: Add MediaTek MT6370 current sink type LED indicator Date: Fri, 15 Jul 2022 19:25:57 +0800 Message-Id: <20220715112607.591-4-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiYuan Huang Add MediaTek MT6370 current sink type LED indicator binding documentation. Signed-off-by: ChiYuan Huang Reviewed-by: Krzysztof Kozlowski --- .../bindings/leds/mediatek,mt6370-indicator.yaml | 77 ++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml new file mode 100644 index 0000000..45030f3 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/mediatek,mt6370-indicator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LED driver for MT6370 PMIC from MediaTek Integrated. + +maintainers: + - Alice Chen + +description: | + This module is part of the MT6370 MFD device. + Add MT6370 LED driver include 4-channel RGB LED support Register/PWM/Breath Mode + +allOf: + - $ref: leds-class-multicolor.yaml# + +properties: + compatible: + const: mediatek,mt6370-indicator + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^multi-led@[0-3]$": + type: object + + properties: + reg: + enum: [0, 1, 2, 3] + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^led@[0-2]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + required: + - reg + - color + + required: + - reg + - color + - "#address-cells" + - "#size-cells" + + "^led@[0-3]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + enum: [0, 1, 2, 3] + + required: + - reg + - color + +required: + - compatible + - "#address-cells" + - "#size-cells" + +additionalProperties: false From patchwork Fri Jul 15 11:25:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919066 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 62842C43334 for ; Fri, 15 Jul 2022 11:27:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232976AbiGOL1E (ORCPT ); Fri, 15 Jul 2022 07:27:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46032 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232953AbiGOL0y (ORCPT ); Fri, 15 Jul 2022 07:26:54 -0400 Received: from mail-pj1-x102a.google.com (mail-pj1-x102a.google.com [IPv6:2607:f8b0:4864:20::102a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 22F9288768; Fri, 15 Jul 2022 04:26:47 -0700 (PDT) Received: by mail-pj1-x102a.google.com with SMTP id b8so5371546pjo.5; Fri, 15 Jul 2022 04:26:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=SxGKLw/sS7fdJZuE8bLGBTMKV4RyLr0/hVQFdtvG6hY=; b=WboNAeOE8zUIByDWEwnyde87CtzBmrbdti4AKCsZfCWV2qiSc8kOZu41SxPIZj8GET c13f4iEKQtbYsCgkl25EFNQeJqBoxRhrmcEORQKISJjJXA1C4SG8M7mgZJdk9JLAk1Nx gS4IDfySupoxdTro7OH0R34aAROWLE2Wg4Ll6D3MUVmEFM4H9miJcsDxTPL5+SEFmdFO GYz3l37CyNfTwziEu3yBr+JiwWx5NR06sGtTakqH682gRLtstaxj7jN/lk06dNqf6Da+ wMMp90zBsAGb7CgnJG6GcxBnh2dnmWDpzR2ycGXP2eh1lUZ3pbQ7oPmAFk9azTRatLzm Gtbg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=SxGKLw/sS7fdJZuE8bLGBTMKV4RyLr0/hVQFdtvG6hY=; b=OLCoWt16ut2sZlb+rWwBFEQ3ylwgbQDZ1QXH9rXThxgGudm2p5bVskKlET5R7NQlTU 5+p0hJY1vyrQYNDly79wWk2F6QhAjaAEiJSu8JWnD8yweYISHsrOjtsxpDs+Q64nkATA iCWyUQzm1oqp/GZQg+EEdK1CvWsZhNeiZIBHq3nk92MaNoyEazncGq224NkFqkJRojmI esIMCJVe3BmG2fuykAVWWl/NdqOVmuHph1/+ASZzx9CZcBiqMTrJl8dfgsaPquQFwmGG 5d3glO1Nd1m1v+2udgC85UDgQVMTJO+jA9NAr1Kb7G1KL/HQJNLff/oa1+X7UhTYUZwn vmGA== X-Gm-Message-State: AJIora+7TjjNoY7V668h0s6B4U+38Ukcea4HOvVkMnmrXlbZPZPgOWt5 4QAdaD9I9twRQ0nv5Y3h+Ks= X-Google-Smtp-Source: AGRyM1sZltUw/1JpGkrrx6xlT+Z5GjpcQ3KIeIf35T9nrHUA2Cz4hQ1u/67IaF4MBUiOqAfgRZNPTA== X-Received: by 2002:a17:90b:1bc7:b0:1f0:34e2:5c86 with SMTP id oa7-20020a17090b1bc700b001f034e25c86mr14843981pjb.136.1657884406842; Fri, 15 Jul 2022 04:26:46 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.26.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:26:46 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com, Krzysztof Kozlowski Subject: [PATCH v5 04/13] dt-bindings: leds: Add MediaTek MT6370 flashlight Date: Fri, 15 Jul 2022 19:25:58 +0800 Message-Id: <20220715112607.591-5-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: Alice Chen Add MediaTek MT6370 flashlight binding documentation. Signed-off-by: Alice Chen Reviewed-by: Krzysztof Kozlowski --- .../bindings/leds/mediatek,mt6370-flashlight.yaml | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml new file mode 100644 index 0000000..e9d02ed --- /dev/null +++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/mediatek,mt6370-flashlight.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Flash LED driver for MT6370 PMIC from MediaTek Integrated. + +maintainers: + - Alice Chen + +description: | + This module is part of the MT6370 MFD device. + Add MT6370 flash LED driver include 2-channel flash LED support Torch/Strobe Mode. + +properties: + compatible: + const: mediatek,mt6370-flashlight + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[0-1]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + enum: [0, 1] + +required: + - compatible + - "#address-cells" + - "#size-cells" + +additionalProperties: false From patchwork Fri Jul 15 11:25:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919067 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 512F4C43334 for ; Fri, 15 Jul 2022 11:27:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233202AbiGOL1N (ORCPT ); Fri, 15 Jul 2022 07:27:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46434 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232073AbiGOL06 (ORCPT ); Fri, 15 Jul 2022 07:26:58 -0400 Received: from mail-pg1-x52a.google.com (mail-pg1-x52a.google.com [IPv6:2607:f8b0:4864:20::52a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EBA9B87F51; Fri, 15 Jul 2022 04:26:52 -0700 (PDT) Received: by mail-pg1-x52a.google.com with SMTP id f65so4123190pgc.12; Fri, 15 Jul 2022 04:26:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1u5oyif5xJc6tf3rWTCcNAXqF09LYJdHLNTlsfB9J08=; b=qF6pWmeF0M4udMy4fnaDKGqlHpvWfnrSleUsZ1R3LvzAA164EL4eUuh21No19uTWwA 4Ncn12fEmplqmDy7Y1eNhwl3wGCNNNm2SdH6vTqBLEJ82FVKIhkbr2dJyuMLjYkk4AzC 3+iqQmtO9Aubo0Xz6rxLxPZ/g10BuYSZdOwPIOykslr7B2bNNhQhS2jvfU7rYgeNxka7 bbYB0AybPKmVCU2ZmVhxLoFB9J/GHwYRsfEeTmk0OpBlC8FAu+4EwMb7iHLyEHxJYcqu pIWkmCmfOIT2Fl0CvVjXYS7kjUcs+GbIFM1wdSRMcPXxDhiIhG6d3PLs0HfXut5ZbjFH KdIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1u5oyif5xJc6tf3rWTCcNAXqF09LYJdHLNTlsfB9J08=; b=Z8jbgJXMfF7leB3JyT4bw68mo5Zq0IgjmCBa/0ZaTnAmrrwurFTAKEel/mwZoiVEMN a0MuNVgZswtFxFjxjFeR7YzypAFKJ8/DsJ/E4DTF64ZD2UeOgysx2pSQOqC1It48c6F+ p592YAgbLIGFpJTsQtka8aJsBsElimsnPal2EGFzEzMJkrp8g2NwKRB+cSwGGDNS6E0w LtjpuFHa7DIQiasSZplhhTnUO7kPNHYWa8aQWhpw5e9H2kI4B3kVflBimkKgjkVeIR5w DCsWG3bNNAvxOSwCnq+sfO8uGnxYKyeBTXKzEN0OL6bFF8YJJdjnlfbqsVb+tvUQSYed U9Ig== X-Gm-Message-State: AJIora8x+M/Bqd+A17Fi1/rQx0rXAvz041vOJXXFZ8sfn+1oUrQ3VuOg mPqxB5blcXYMj4vYjl80mCc= X-Google-Smtp-Source: AGRyM1tn+1VSM0nJrDcicImUQfV+BJwlknSwvv/sZpqhQ8QXScW6TUatzKl62b43uUmVmtXsdqu/qQ== X-Received: by 2002:a62:4e04:0:b0:52b:30f5:59b8 with SMTP id c4-20020a624e04000000b0052b30f559b8mr5028844pfb.37.1657884412477; Fri, 15 Jul 2022 04:26:52 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.26.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:26:52 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com, Rob Herring Subject: [PATCH v5 05/13] dt-bindings: backlight: Add MediaTek MT6370 backlight Date: Fri, 15 Jul 2022 19:25:59 +0800 Message-Id: <20220715112607.591-6-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiYuan Huang Add MT6370 backlight binding documentation. Signed-off-by: ChiYuan Huang Reviewed-by: Rob Herring --- .../leds/backlight/mediatek,mt6370-backlight.yaml | 92 ++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml diff --git a/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml new file mode 100644 index 0000000..d674212 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/backlight/mediatek,mt6370-backlight.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT6370 Backlight + +maintainers: + - ChiaEn Wu + +description: | + This module is part of the MT6370 MFD device. + The MT6370 Backlight WLED driver supports up to a 29V output voltage for + 4 channels of 8 series WLEDs. Each channel supports up to 30mA of current + capability with 2048 current steps (11 bits) in exponential or linear + mapping curves. + +allOf: + - $ref: common.yaml# + +properties: + compatible: + const: mediatek,mt6370-backlight + + default-brightness: + minimum: 0 + maximum: 2048 + + max-brightness: + minimum: 0 + maximum: 2048 + + enable-gpios: + description: External backlight 'enable' pin + maxItems: 1 + + mediatek,bled-pwm-enable: + description: | + Enable external PWM input for backlight dimming + type: boolean + + mediatek,bled-pwm-hys-enable: + description: | + Enable the backlight input-hysteresis for PWM mode + type: boolean + + mediatek,bled-pwm-hys-input-th-steps: + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [1, 4, 16, 64] + description: | + The selection of the upper and lower bounds threshold of backlight + PWM resolution. If we choose selection 64, the variation of PWM + resolution needs more than 64 steps. + + mediatek,bled-ovp-shutdown: + description: | + Enable the backlight shutdown when OVP level triggered + type: boolean + + mediatek,bled-ovp-microvolt: + enum: [17000000, 21000000, 25000000, 29000000] + description: | + Backlight OVP level selection. + + mediatek,bled-ocp-shutdown: + description: | + Enable the backlight shutdown when OCP level triggerred. + type: boolean + + mediatek,bled-ocp-microamp: + enum: [900000, 1200000, 1500000, 1800000] + description: | + Backlight OC level selection. + + mediatek,bled-channel-use: + $ref: /schemas/types.yaml#/definitions/uint8 + description: | + Backlight LED channel to be used. + Each bit mapping to: + - 0: CH4 + - 1: CH3 + - 2: CH2 + - 3: CH1 + minimum: 1 + maximum: 15 + +required: + - compatible + - mediatek,bled-channel-use + +additionalProperties: false From patchwork Fri Jul 15 11:26:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919068 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2B2E0C433EF for ; Fri, 15 Jul 2022 11:27:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234074AbiGOL1T (ORCPT ); Fri, 15 Jul 2022 07:27:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46840 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232954AbiGOL1K (ORCPT ); Fri, 15 Jul 2022 07:27:10 -0400 Received: from mail-pj1-x102a.google.com (mail-pj1-x102a.google.com [IPv6:2607:f8b0:4864:20::102a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C58CC88779; Fri, 15 Jul 2022 04:26:58 -0700 (PDT) Received: by mail-pj1-x102a.google.com with SMTP id o31-20020a17090a0a2200b001ef7bd037bbso5843721pjo.0; Fri, 15 Jul 2022 04:26:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6XoP7u+DSv5yXz+NKLqpdZlrDfnRAwiLZBsnunnwVC0=; b=BVGZO4B7P/MJf8B5R/RdLYcCWCXsRUGSsJ5wCXaBzqH0ICrLXXthVaxaoZffz+0ZtN G+BsU017w7/3pdTTywISRWqeH8kAJAnXz249Vze+GvByGSPN4sdolS1O9IX/oFikH3SC 5CXboao+1FIiQ8KbdBkP0PoyJIDpx1LHko8hsyzhKZTvBN9KivVwsJI27h9eta0f4J04 YbIf5Vxn/1rmoxNsfMNNJQdrdqfPRlM77W58PYBsBjuJ3KK8dZlLvZm+Rx1SSrTNUF2w iE5v4KWCnLYBFaXoCoanGvp6HQ7Q70eYiUcjah0dftF702KAeUPd9zJMfJxH1K/6dxlz lpeQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6XoP7u+DSv5yXz+NKLqpdZlrDfnRAwiLZBsnunnwVC0=; b=XuckJde25PWziDk6ZZFSXIqmg5wLBefnsNJmisGNZz2kdOGaucfzpJqtkh3LLocdas pVgxPSJMp5n23UQQ6jb7vvDQn50nIn3oZ7DY2nkJcgBXyQRbZZOtRpv4wBLRNMJaFgZK MB9HIu9BOM3wZa4v7PCGMEioZgp8zYUcRrjmsywEiDNpvIEGxiiIQXONPRPTw+8ZbwYF uoaK3pLE3lXYxUu1JtNBh0Q+Ua5xRNUbq6+zjV/JJMWEPSaHo83sE8o4G2i/fkbu62iM 4qQIR7BMUWG61VLypni0gpBqznP2/fmG7+UN0i8+S9vzKIqXGwT452rwLe9ZQwu3dbd7 WgIQ== X-Gm-Message-State: AJIora+8cFgiFfepmP4jgNR9aTkCLpwKpcFRYyHOjw/ZeijnYqR0tE6r 9EDO+aAw5IpBmbQFReiWUrs= X-Google-Smtp-Source: AGRyM1vqrvvh0+UsvvyMf8oxM9Ez40MnE6y7xCStttYS8ewvVjrIvY40kFOfrKaJwSfaoyQxI4yZJA== X-Received: by 2002:a17:90b:3e8a:b0:1f0:4157:daf8 with SMTP id rj10-20020a17090b3e8a00b001f04157daf8mr14953626pjb.222.1657884418235; Fri, 15 Jul 2022 04:26:58 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.26.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:26:57 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com, Krzysztof Kozlowski Subject: [PATCH v5 06/13] dt-bindings: mfd: Add MediaTek MT6370 Date: Fri, 15 Jul 2022 19:26:00 +0800 Message-Id: <20220715112607.591-7-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiYuan Huang Add MediaTek MT6370 binding documentation. Signed-off-by: ChiYuan Huang Reviewed-by: Krzysztof Kozlowski --- .../devicetree/bindings/mfd/mediatek,mt6370.yaml | 280 +++++++++++++++++++++ include/dt-bindings/iio/adc/mediatek,mt6370_adc.h | 18 ++ 2 files changed, 298 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml new file mode 100644 index 0000000..410e2d4 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml @@ -0,0 +1,280 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/mediatek,mt6370.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT6370 SubPMIC + +maintainers: + - ChiYuan Huang + +description: | + MT6370 is a highly-integrated smart power management IC, which includes a + single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C & + Power Delivery (PD) controller, dual flash LED current sources, a RGB LED + driver, a backlight WLED driver, a display bias driver and a general LDO for + portable devices. + +properties: + compatible: + const: mediatek,mt6370 + + reg: + maxItems: 1 + + wakeup-source: true + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 1 + + adc: + type: object + description: | + Provides 9 channels for system monitoring, including VBUSDIV5 (lower + accuracy, higher measure range), VBUSDIV2 (higher accuracy, lower + measure range), VBAT, VSYS, CHG_VDDP, TS_BAT, IBUS, IBAT, and TEMP_JC. + + properties: + compatible: + const: mediatek,mt6370-adc + + "#io-channel-cells": + const: 1 + + required: + - compatible + - "#io-channel-cells" + + backlight: + type: object + $ref: /schemas/leds/backlight/mediatek,mt6370-backlight.yaml# + + charger: + type: object + $ref: /schemas/power/supply/mediatek,mt6370-charger.yaml# + + tcpc: + type: object + $ref: /schemas/usb/mediatek,mt6370-tcpc.yaml# + + indicator: + type: object + $ref: /schemas/leds/mediatek,mt6370-indicator.yaml# + + flashlight: + type: object + $ref: /schemas/leds/mediatek,mt6370-flashlight.yaml# + + regulators: + type: object + description: | + List all supported regulators, which support the control for DisplayBias + voltages and one general purpose LDO which commonly used to drive the + vibrator. + + patternProperties: + "^(dsvbst|vibldo)$": + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + "^(dsvpos|dsvneg)$": + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + properties: + enable-gpios: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - "#interrupt-cells" + - regulators + - adc + - backlight + - indicator + - tcpc + - charger + - flashlight + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@34 { + compatible = "mediatek,mt6370"; + reg = <0x34>; + wakeup-source; + interrupts-extended = <&gpio26 3 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <1>; + + mt6370_adc: adc { + compatible = "mediatek,mt6370-adc"; + #io-channel-cells = <1>; + }; + + backlight { + compatible = "mediatek,mt6370-backlight"; + mediatek,bled-channel-use = /bits/ 8 <15>; + }; + + charger { + compatible = "mediatek,mt6370-charger"; + interrupts = <48>, <68>, <6>; + interrupt-names = "attach_i", "uvp_d_evt", "mivr"; + io-channels = <&mt6370_adc MT6370_CHAN_IBUS>; + + mt6370_otg_vbus: usb-otg-vbus-regulator { + regulator-name = "mt6370-usb-otg-vbus"; + regulator-min-microvolt = <4350000>; + regulator-max-microvolt = <5800000>; + regulator-min-microamp = <500000>; + regulator-max-microamp = <3000000>; + }; + }; + + indicator { + compatible = "mediatek,mt6370-indicator"; + #address-cells = <1>; + #size-cells = <0>; + + multi-led@0 { + reg = <0>; + function = LED_FUNCTION_INDICATOR; + color = ; + led-max-microamp = <24000>; + #address-cells = <1>; + #size-cells = <0>; + led@0 { + reg = <0>; + color = ; + }; + led@1 { + reg = <1>; + color = ; + }; + led@2 { + reg = <2>; + color = ; + }; + }; + led@3 { + reg = <3>; + function = LED_FUNCTION_INDICATOR; + color = ; + led-max-microamp = <6000>; + }; + }; + + flashlight { + compatible = "mediatek,mt6370-flashlight"; + #address-cells = <1>; + #size-cells = <0>; + led@0 { + reg = <0>; + led-sources = <0>; + function = LED_FUNCTION_FLASH; + color = ; + function-enumerator = <1>; + led-max-microamp = <200000>; + flash-max-microamp = <500000>; + flash-max-timeout-us = <1248000>; + }; + led@1 { + reg = <1>; + led-sources = <1>; + function = LED_FUNCTION_FLASH; + color = ; + function-enumerator = <2>; + led-max-microamp = <200000>; + flash-max-microamp = <500000>; + flash-max-timeout-us = <1248000>; + }; + }; + + tcpc { + compatible = "mediatek,mt6370-tcpc"; + interrupts-extended = <&gpio26 4 IRQ_TYPE_LEVEL_LOW>; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + vbus-supply = <&mt6370_otg_vbus>; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <10000000>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&usb_hs>; + }; + }; + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&usb_ss>; + }; + }; + port@2 { + reg = <2>; + endpoint { + remote-endpoint = <&dp_aux>; + }; + }; + }; + }; + }; + + regulators { + dsvbst { + regulator-name = "mt6370-dsv-vbst"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6200000>; + }; + dsvpos { + regulator-name = "mt6370-dsv-vpos"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + regulator-boot-on; + }; + dsvneg { + regulator-name = "mt6370-dsv-vneg"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + regulator-boot-on; + }; + vibldo { + regulator-name = "mt6370-vib-ldo"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <4000000>; + }; + }; + }; + }; diff --git a/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h new file mode 100644 index 0000000..6ee7255 --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__ +#define __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__ + +/* ADC Channel Index */ +#define MT6370_CHAN_VBUSDIV5 0 +#define MT6370_CHAN_VBUSDIV2 1 +#define MT6370_CHAN_VSYS 2 +#define MT6370_CHAN_VBAT 3 +#define MT6370_CHAN_TS_BAT 4 +#define MT6370_CHAN_IBUS 5 +#define MT6370_CHAN_IBAT 6 +#define MT6370_CHAN_CHG_VDDP 7 +#define MT6370_CHAN_TEMP_JC 8 +#define MT6370_CHAN_MAX 9 + +#endif From patchwork Fri Jul 15 11:26:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919069 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 238D3CCA47F for ; Fri, 15 Jul 2022 11:27:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231967AbiGOL1Z (ORCPT ); Fri, 15 Jul 2022 07:27:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46898 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233147AbiGOL1M (ORCPT ); Fri, 15 Jul 2022 07:27:12 -0400 Received: from mail-pf1-x42e.google.com (mail-pf1-x42e.google.com [IPv6:2607:f8b0:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5FA7988CD4; Fri, 15 Jul 2022 04:27:04 -0700 (PDT) Received: by mail-pf1-x42e.google.com with SMTP id d10so4412164pfd.9; Fri, 15 Jul 2022 04:27:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1v4srGh3wxSL64fuDursxWbm2Om4PrT+XfvVhSSxfRI=; b=gsxNBAf6lT3hWMPqElzSL0p7hU+3rArhqsPSW6SXa9zQqNYJc5RvzWkYWXOgxzfxO5 HMoZN0rGD44ebXm13N3tqxmQJY50yvAvgu/MKmMyfnbSkO3wDne4zbeAozV7UCTeWH2N nY/KcSU6sD52g/h6PY8r2ZQipBqQbdkKy3hNwiqJ8pX1x9C2BhGzNpODLU9xCtQG2yVI 6h4OD/UttxHjN502X7s/7IsyRzsDuws7t85MVexjnFY0gfMeTXECoErmyBY21zX+eHFV we0YGg9C7PpnWqUhaXDDLWL6sDJ3zy0R3tv+f8jOpvRihsm4fJhajwjPoTM9SMYSQr11 jVbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1v4srGh3wxSL64fuDursxWbm2Om4PrT+XfvVhSSxfRI=; b=4UkyP5qL00cRLA2Hdn/WadRELzut5dl9AIhSbmRWdAhtcYpleXafDNk9kd/lfE1oaK pW9jMMPChUnJLb1DQBw409XjRgcIXU3Oa82eTYT9I7RHdHwbn1A0wj9aDriB/mTwLLIY HdHN9LDLfaNjucNNc/0csU1kD+K6Af1W4sbXwfU26lM0vfrkeLDfU75nufm1RnkCERAe kT5EqCjwht5TUhvWY8P2J03ZTvwJ/FvGzsm65Fap3XcIX1bQ4J+eSeVGjTRRuufHCfAb E18e/Ruz24B7SEPcbjwwxybmr4Spj5eIdXkNSZmE6n9Zz33i10ZNv6wX2jQKaWBrbRjb nzXQ== X-Gm-Message-State: AJIora/Cq6QWB4zwjXnaGHXXJceJyXIZFsWxgfkGzWeHay+0vui5tr/D ci3HUHgTRCo/D+xojWBXW3I= X-Google-Smtp-Source: AGRyM1th0n71iNMIcdyvPmxLnNqJWikNeIiOL9ZCPSc0kjSq+RT774hva6UnilcW7VqKFP0YFIRb7g== X-Received: by 2002:a63:e109:0:b0:419:c3bc:b89 with SMTP id z9-20020a63e109000000b00419c3bc0b89mr5617667pgh.176.1657884423785; Fri, 15 Jul 2022 04:27:03 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.26.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:27:03 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v5 07/13] mfd: mt6370: Add MediaTek MT6370 support Date: Fri, 15 Jul 2022 19:26:01 +0800 Message-Id: <20220715112607.591-8-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiYuan Huang This adds support for the MediaTek MT6370 SubPMIC. MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight driver, display bias voltage supply, one general purpose LDO, and the USB Type-C & PD controller complies with the latest USB Type-C and PD standards. Signed-off-by: ChiYuan Huang Reviewed-by: Andy Shevchenko --- v5 - Add the comma in the last REGMAP_IRQ_REG_LINE(), DEFINE_RES_IRQ_NAMED() and MFD_CELL_RES() - Add the prefix in the first parameter of all mfd_cell - Move enum and struct mt6370_info to mt6370.h - Remove struct device *dev in struct mt6370_info - Revise the description of Kconfig help text - Revise MODULE_DESCRIPTION() --- drivers/mfd/Kconfig | 16 +++ drivers/mfd/Makefile | 1 + drivers/mfd/mt6370.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/mfd/mt6370.h | 99 ++++++++++++++++++ 4 files changed, 397 insertions(+) create mode 100644 drivers/mfd/mt6370.c create mode 100644 drivers/mfd/mt6370.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3b59456..a9bcae3 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -937,6 +937,22 @@ config MFD_MT6360 PMIC part includes 2-channel BUCKs and 2-channel LDOs LDO part includes 4-channel LDOs +config MFD_MT6370 + tristate "MediaTek MT6370 SubPMIC" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C + help + Say Y here to enable MT6370 SubPMIC functional support. + It consists of a single cell battery charger with ADC monitoring, RGB + LEDs, dual channel flashlight, WLED backlight driver, display bias + voltage supply, one general purpose LDO, and the USB Type-C & PD + controller complies with the latest USB Type-C and PD standards. + + This driver can also be built as a module. If so, the module + will be called "mt6370". + config MFD_MT6397 tristate "MediaTek MT6397 PMIC Support" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 8c69867..81dbed3 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -173,6 +173,7 @@ obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o obj-$(CONFIG_MFD_MP2629) += mp2629.o obj-$(CONFIG_MFD_MT6360) += mt6360-core.o +obj-$(CONFIG_MFD_MT6370) += mt6370.o mt6397-objs := mt6397-core.o mt6397-irq.o mt6358-irq.o obj-$(CONFIG_MFD_MT6397) += mt6397.o diff --git a/drivers/mfd/mt6370.c b/drivers/mfd/mt6370.c new file mode 100644 index 0000000..070c1c7 --- /dev/null +++ b/drivers/mfd/mt6370.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiYuan Huang + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mt6370.h" + +#define MT6370_REG_DEV_INFO 0x100 +#define MT6370_REG_CHG_IRQ1 0x1C0 +#define MT6370_REG_CHG_MASK1 0x1E0 + +#define MT6370_VENID_MASK GENMASK(7, 4) + +#define MT6370_NUM_IRQREGS 16 +#define MT6370_USBC_I2CADDR 0x4E +#define MT6370_REG_ADDRLEN 2 +#define MT6370_REG_MAXADDR 0x1FF + +#define MT6370_VENID_RT5081 0x8 +#define MT6370_VENID_RT5081A 0xA +#define MT6370_VENID_MT6370 0xE +#define MT6370_VENID_MT6371 0xF +#define MT6370_VENID_MT6372P 0x9 +#define MT6370_VENID_MT6372CP 0xB + +static const struct regmap_irq mt6370_irqs[] = { + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHGON, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TREG, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_AICR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_MIVR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_PWR_RDY, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FL_CHG_VINOVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSUV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSOV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VBATOV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VINOVPCHG, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COLD, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COOL, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_WARM, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_HOT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_STATC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_FAULT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_STATC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TMR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_BATABS, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ADPBAD, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TSHUTDOWN, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IINMEAS, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ICCMEAS, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_WDTMR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_SSFINISH, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RECHG, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TERM, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IEOC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_ADC_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_PUMPX_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_BATUV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_MIDOV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_OLP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_ATTACH, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DETACH, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_STPDONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_VBUSDET_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_DET, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DCDT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_VGOK, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_WDTMR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_UC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_SWON, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP_D, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP_D, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_STRBPIN, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TORPIN, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TX, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_LVF, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_SHORT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_SHORT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_STRB, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB, 8), + REGMAP_IRQ_REG_LINE(mT6370_IRQ_FLED2_STRB_TO, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB_TO, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_TOR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_TOR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OTP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_OVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_UV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_LDO_OC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_BST_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_SCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_SCP, 8), +}; + +static const struct regmap_irq_chip mt6370_irq_chip = { + .name = "mt6370-irqs", + .status_base = MT6370_REG_CHG_IRQ1, + .mask_base = MT6370_REG_CHG_MASK1, + .num_regs = MT6370_NUM_IRQREGS, + .irqs = mt6370_irqs, + .num_irqs = ARRAY_SIZE(mt6370_irqs), +}; + +static const struct resource mt6370_regulator_irqs[] = { + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_SCP, "db_vpos_scp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_SCP, "db_vneg_scp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_BST_OCP, "db_vbst_ocp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_OCP, "db_vpos_ocp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_OCP, "db_vneg_ocp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_LDO_OC, "ldo_oc"), +}; + +static const struct mfd_cell mt6370_devices[] = { + MFD_CELL_OF("mt6370-adc", + NULL, NULL, 0, 0, "mediatek,mt6370-adc"), + MFD_CELL_OF("mt6370-charger", + NULL, NULL, 0, 0, "mediatek,mt6370-charger"), + MFD_CELL_OF("mt6370-backlight", + NULL, NULL, 0, 0, "mediatek,mt6370-backlight"), + MFD_CELL_OF("mt6370-flashlight", + NULL, NULL, 0, 0, "mediatek,mt6370-flashlight"), + MFD_CELL_OF("mt6370-indicator", + NULL, NULL, 0, 0, "mediatek,mt6370-indicator"), + MFD_CELL_OF("mt6370-tcpc", + NULL, NULL, 0, 0, "mediatek,mt6370-tcpc"), + MFD_CELL_RES("mt6370-regulator", mt6370_regulator_irqs), +}; + +static int mt6370_check_vendor_info(struct device *dev, struct regmap *rmap) +{ + unsigned int devinfo; + int ret; + + ret = regmap_read(rmap, MT6370_REG_DEV_INFO, &devinfo); + if (ret) + return ret; + + switch (FIELD_GET(MT6370_VENID_MASK, devinfo)) { + case MT6370_VENID_RT5081: + case MT6370_VENID_RT5081A: + case MT6370_VENID_MT6370: + case MT6370_VENID_MT6371: + case MT6370_VENID_MT6372P: + case MT6370_VENID_MT6372CP: + return 0; + default: + dev_err(dev, "Unknown Vendor ID 0x%02x\n", devinfo); + return -ENODEV; + } +} + +static int mt6370_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct mt6370_info *info = context; + const u8 *u8_buf = reg_buf; + u8 bank_idx, bank_addr; + int ret; + + bank_idx = u8_buf[0]; + bank_addr = u8_buf[1]; + + ret = i2c_smbus_read_i2c_block_data(info->i2c[bank_idx], bank_addr, + val_size, val_buf); + if (ret < 0) + return ret; + + if (ret != val_size) + return -EIO; + + return 0; +} + +static int mt6370_regmap_write(void *context, const void *data, size_t count) +{ + struct mt6370_info *info = context; + const u8 *u8_buf = data; + u8 bank_idx, bank_addr; + int len = count - MT6370_REG_ADDRLEN; + + bank_idx = u8_buf[0]; + bank_addr = u8_buf[1]; + + return i2c_smbus_write_i2c_block_data(info->i2c[bank_idx], bank_addr, + len, data + MT6370_REG_ADDRLEN); +} + +static const struct regmap_bus mt6370_regmap_bus = { + .read = mt6370_regmap_read, + .write = mt6370_regmap_write, +}; + +static const struct regmap_config mt6370_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .max_register = MT6370_REG_MAXADDR, +}; + +static int mt6370_probe(struct i2c_client *i2c) +{ + struct mt6370_info *info; + struct i2c_client *usbc_i2c; + struct regmap *regmap; + struct device *dev = &i2c->dev; + int ret; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + usbc_i2c = devm_i2c_new_dummy_device(dev, i2c->adapter, + MT6370_USBC_I2CADDR); + if (IS_ERR(usbc_i2c)) + return dev_err_probe(dev, PTR_ERR(usbc_i2c), + "Failed to register USBC I2C client\n"); + + /* Assign I2C client for PMU and TypeC */ + info->i2c[MT6370_PMU_I2C] = i2c; + info->i2c[MT6370_USBC_I2C] = usbc_i2c; + + regmap = devm_regmap_init(dev, &mt6370_regmap_bus, + info, &mt6370_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to init regmap\n"); + + ret = mt6370_check_vendor_info(dev, regmap); + if (ret) + return dev_err_probe(dev, ret, "Failed to check vendor info\n"); + + ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq, + IRQF_ONESHOT, -1, &mt6370_irq_chip, + &info->irq_data); + if (ret) + return dev_err_probe(dev, ret, "Failed to add irq chip\n"); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, + mt6370_devices, ARRAY_SIZE(mt6370_devices), + NULL, 0, + regmap_irq_get_domain(info->irq_data)); +} + +static const struct of_device_id mt6370_match_table[] = { + { .compatible = "mediatek,mt6370" }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_match_table); + +static struct i2c_driver mt6370_driver = { + .driver = { + .name = "mt6370", + .of_match_table = mt6370_match_table, + }, + .probe_new = mt6370_probe, +}; +module_i2c_driver(mt6370_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("MediaTek MT6370 SubPMIC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/mt6370.h b/drivers/mfd/mt6370.h new file mode 100644 index 0000000..094e59e --- /dev/null +++ b/drivers/mfd/mt6370.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiYuan Huang + */ + +#ifndef __MFD_MT6370_H__ +#define __MFD_MT6370_H__ + +/* IRQ definitions */ +#define MT6370_IRQ_DIRCHGON 0 +#define MT6370_IRQ_CHG_TREG 4 +#define MT6370_IRQ_CHG_AICR 5 +#define MT6370_IRQ_CHG_MIVR 6 +#define MT6370_IRQ_PWR_RDY 7 +#define MT6370_IRQ_FL_CHG_VINOVP 11 +#define MT6370_IRQ_CHG_VSYSUV 12 +#define MT6370_IRQ_CHG_VSYSOV 13 +#define MT6370_IRQ_CHG_VBATOV 14 +#define MT6370_IRQ_CHG_VINOVPCHG 15 +#define MT6370_IRQ_TS_BAT_COLD 20 +#define MT6370_IRQ_TS_BAT_COOL 21 +#define MT6370_IRQ_TS_BAT_WARM 22 +#define MT6370_IRQ_TS_BAT_HOT 23 +#define MT6370_IRQ_TS_STATC 24 +#define MT6370_IRQ_CHG_FAULT 25 +#define MT6370_IRQ_CHG_STATC 26 +#define MT6370_IRQ_CHG_TMR 27 +#define MT6370_IRQ_CHG_BATABS 28 +#define MT6370_IRQ_CHG_ADPBAD 29 +#define MT6370_IRQ_CHG_RVP 30 +#define MT6370_IRQ_TSHUTDOWN 31 +#define MT6370_IRQ_CHG_IINMEAS 32 +#define MT6370_IRQ_CHG_ICCMEAS 33 +#define MT6370_IRQ_CHGDET_DONE 34 +#define MT6370_IRQ_WDTMR 35 +#define MT6370_IRQ_SSFINISH 36 +#define MT6370_IRQ_CHG_RECHG 37 +#define MT6370_IRQ_CHG_TERM 38 +#define MT6370_IRQ_CHG_IEOC 39 +#define MT6370_IRQ_ADC_DONE 40 +#define MT6370_IRQ_PUMPX_DONE 41 +#define MT6370_IRQ_BST_BATUV 45 +#define MT6370_IRQ_BST_MIDOV 46 +#define MT6370_IRQ_BST_OLP 47 +#define MT6370_IRQ_ATTACH 48 +#define MT6370_IRQ_DETACH 49 +#define MT6370_IRQ_HVDCP_STPDONE 51 +#define MT6370_IRQ_HVDCP_VBUSDET_DONE 52 +#define MT6370_IRQ_HVDCP_DET 53 +#define MT6370_IRQ_CHGDET 54 +#define MT6370_IRQ_DCDT 55 +#define MT6370_IRQ_DIRCHG_VGOK 59 +#define MT6370_IRQ_DIRCHG_WDTMR 60 +#define MT6370_IRQ_DIRCHG_UC 61 +#define MT6370_IRQ_DIRCHG_OC 62 +#define MT6370_IRQ_DIRCHG_OV 63 +#define MT6370_IRQ_OVPCTRL_SWON 67 +#define MT6370_IRQ_OVPCTRL_UVP_D 68 +#define MT6370_IRQ_OVPCTRL_UVP 69 +#define MT6370_IRQ_OVPCTRL_OVP_D 70 +#define MT6370_IRQ_OVPCTRL_OVP 71 +#define MT6370_IRQ_FLED_STRBPIN 72 +#define MT6370_IRQ_FLED_TORPIN 73 +#define MT6370_IRQ_FLED_TX 74 +#define MT6370_IRQ_FLED_LVF 75 +#define MT6370_IRQ_FLED2_SHORT 78 +#define MT6370_IRQ_FLED1_SHORT 79 +#define MT6370_IRQ_FLED2_STRB 80 +#define MT6370_IRQ_FLED1_STRB 81 +#define mT6370_IRQ_FLED2_STRB_TO 82 +#define MT6370_IRQ_FLED1_STRB_TO 83 +#define MT6370_IRQ_FLED2_TOR 84 +#define MT6370_IRQ_FLED1_TOR 85 +#define MT6370_IRQ_OTP 93 +#define MT6370_IRQ_VDDA_OVP 94 +#define MT6370_IRQ_VDDA_UV 95 +#define MT6370_IRQ_LDO_OC 103 +#define MT6370_IRQ_BLED_OCP 118 +#define MT6370_IRQ_BLED_OVP 119 +#define MT6370_IRQ_DSV_VNEG_OCP 123 +#define MT6370_IRQ_DSV_VPOS_OCP 124 +#define MT6370_IRQ_DSV_BST_OCP 125 +#define MT6370_IRQ_DSV_VNEG_SCP 126 +#define MT6370_IRQ_DSV_VPOS_SCP 127 + +enum { + MT6370_USBC_I2C = 0, + MT6370_PMU_I2C, + MT6370_MAX_I2C +}; + +struct mt6370_info { + struct i2c_client *i2c[MT6370_MAX_I2C]; + struct regmap_irq_chip_data *irq_data; +}; + +#endif /* __MFD_MT6375_H__ */ From patchwork Fri Jul 15 11:26:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919070 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B29F1CCA480 for ; Fri, 15 Jul 2022 11:27:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233147AbiGOL1a (ORCPT ); Fri, 15 Jul 2022 07:27:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46498 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233658AbiGOL1O (ORCPT ); Fri, 15 Jul 2022 07:27:14 -0400 Received: from mail-pl1-x629.google.com (mail-pl1-x629.google.com [IPv6:2607:f8b0:4864:20::629]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7FC0C88CFC; Fri, 15 Jul 2022 04:27:10 -0700 (PDT) Received: by mail-pl1-x629.google.com with SMTP id r1so2984138plo.10; Fri, 15 Jul 2022 04:27:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Iz1yHTUnPBgwocXDviCRZ3bIk2PlWYQ9pJntR6S0OEs=; b=kAjAb5k7l0t9qqlOLpFTaEr3DiJ8oWuygMmxIRptH60n/6E8gtA5aY33Lil24Cdn8z 6Rrz7yOP4ybO8P2SFKl27Lq+jS43koGdaZCk56bB1ynewGLDYOOU4EeVlwdkJGl1EEgL FfSe14u3F3ucCWnK3tqbQGD4PPPLzE+ct1c7O4iOJPSQPGnnIHw7ppYX8miV2E/8/JwL DjW4uso/NjBizJB0NaEucU+mrR2GXualjCBR4SXw6tMyw5mphFyBIOTk5RDjkb9CqY9b N4iY34vLXdE2wculFHiHVxglJNPebAYYMuE3czxLsOpQDgajDZzb+5cf3h7V8XOGvSJ/ KMxA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Iz1yHTUnPBgwocXDviCRZ3bIk2PlWYQ9pJntR6S0OEs=; b=tkJjgihufKUb84F07eJ0cu4jNp3lYwSeVeH8NoaGvCqCcdeEnNTuQzdpo+nd1GA6Ka mE7H5H/SozWrtdf9xvNmm+54votnAShDvvnindOrMYE/f7n3dCO/vomoa1dETDOBAd7D 4dLhCLlEOirH3IOkJGhUIjPbW/PWzZ6UPAr/82sxa8GSzob44Ev+EmHYfPV4TBK3wFEV EJMCr40a3aXJ/piyU884xOQHrmBw3jaBFy7IvJvDux0mm0qUNX37dQ6X0CUX5f3FmOXl DH7mY6rCUrgSFJ2yWzXTaN9fuliWmm4slfBgGCd2F8zyWjQTQhO8yW0hutsYu4ZcemCG HdbQ== X-Gm-Message-State: AJIora8egdBukYllqEd5DhZYA4qZS9KY5ZsbqGna1gD9fDejbTwnxAS6 QWriLEeFd64InsDQ00TluQI= X-Google-Smtp-Source: AGRyM1tqmQFTBlfOr9O1H2+HhmLsHe9RYXjkBdWJxEgCj/jfr59WRY3t3vhljP/9JRbmPZ8PxtVgcA== X-Received: by 2002:a17:902:9b8b:b0:16a:14fa:cd27 with SMTP id y11-20020a1709029b8b00b0016a14facd27mr13193749plp.86.1657884429779; Fri, 15 Jul 2022 04:27:09 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.27.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:27:09 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v5 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver Date: Fri, 15 Jul 2022 19:26:02 +0800 Message-Id: <20220715112607.591-9-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiYuan Huang The MT6370 is a highly-integrated smart power management IC, which includes a single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C & Power Delivery (PD) controller, dual Flash LED current sources, a RGB LED driver, a backlight WLED driver, a display bias driver and a general LDO for portable devices. This commit add support for the Type-C & Power Delivery controller in MediaTek MT6370 IC. Signed-off-by: ChiYuan Huang Reviewed-by: AngeloGioacchino Del Regno --- v5 - Add comma for the last index of mt6370_reg_init. - Use dev_err_probe to decrease LOC. - Use 'dev' variable to make probe function more clean. - Refine kconfig text. - Remove both 'else' in set_vbus callback. - Remove comma for of_device_id if the assigned member is only one. --- drivers/usb/typec/tcpm/Kconfig | 11 ++ drivers/usb/typec/tcpm/Makefile | 1 + drivers/usb/typec/tcpm/tcpci_mt6370.c | 207 ++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index 073fd2e..e6b88ca 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -35,6 +35,17 @@ config TYPEC_MT6360 USB Type-C. It works with Type-C Port Controller Manager to provide USB PD and USB Type-C functionalities. +config TYPEC_TCPCI_MT6370 + tristate "MediaTek MT6370 Type-C driver" + depends on MFD_MT6370 + help + MediaTek MT6370 is a multi-functional IC that includes + USB Type-C. It works with Type-C Port Controller Manager + to provide USB PD and USB Type-C functionalities. + + This driver can also be built as a module. The module + will be called "tcpci_mt6370". + config TYPEC_TCPCI_MAXIM tristate "Maxim TCPCI based Type-C chip driver" help diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile index 7d499f3..906d9dc 100644 --- a/drivers/usb/typec/tcpm/Makefile +++ b/drivers/usb/typec/tcpm/Makefile @@ -6,4 +6,5 @@ typec_wcove-y := wcove.o obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o obj-$(CONFIG_TYPEC_MT6360) += tcpci_mt6360.o +obj-$(CONFIG_TYPEC_TCPCI_MT6370) += tcpci_mt6370.o obj-$(CONFIG_TYPEC_TCPCI_MAXIM) += tcpci_maxim.o diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c new file mode 100644 index 0000000..a08b0ba --- /dev/null +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiYuan Huang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tcpci.h" + +#define MT6370_REG_SYSCTRL8 0x9B + +#define MT6370_AUTOIDLE_MASK BIT(3) + +#define MT6370_VENDOR_ID 0x29CF +#define MT6370_TCPC_DID_A 0x2170 + +struct mt6370_priv { + struct device *dev; + struct regulator *vbus; + struct tcpci *tcpci; + struct tcpci_data tcpci_data; + int irq; +}; + +static const struct reg_sequence mt6370_reg_init[] = { + REG_SEQ(0xA0, 0x1, 1000), + REG_SEQ(0x81, 0x38, 0), + REG_SEQ(0x82, 0x82, 0), + REG_SEQ(0xBA, 0xFC, 0), + REG_SEQ(0xBB, 0x50, 0), + REG_SEQ(0x9E, 0x8F, 0), + REG_SEQ(0xA1, 0x5, 0), + REG_SEQ(0xA2, 0x4, 0), + REG_SEQ(0xA3, 0x4A, 0), + REG_SEQ(0xA4, 0x01, 0), + REG_SEQ(0x95, 0x01, 0), + REG_SEQ(0x80, 0x71, 0), + REG_SEQ(0x9B, 0x3A, 1000), +}; + +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data) +{ + u16 did; + int ret; + + ret = regmap_register_patch(data->regmap, mt6370_reg_init, + ARRAY_SIZE(mt6370_reg_init)); + if (ret) + return ret; + + ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16)); + if (ret) + return ret; + + if (did == MT6370_TCPC_DID_A) + return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80); + + return 0; +} + +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data, + bool enable) +{ + return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8, + MT6370_AUTOIDLE_MASK, + !enable ? MT6370_AUTOIDLE_MASK : 0); +} + +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data, + bool source, bool sink) +{ + struct mt6370_priv *priv = container_of(data, struct mt6370_priv, + tcpci_data); + int ret; + + ret = regulator_is_enabled(priv->vbus); + if (ret < 0) + return ret; + + if (ret && !source) + return regulator_disable(priv->vbus); + + if (!ret && source) + return regulator_enable(priv->vbus); + + return 0; +} + +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id) +{ + struct mt6370_priv *priv = dev_id; + + return tcpci_irq(priv->tcpci); +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + struct regmap *regmap = priv->tcpci_data.regmap; + u16 vid; + int ret; + + ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16)); + if (ret) + return ret; + + if (vid != MT6370_VENDOR_ID) + return dev_err_probe(priv->dev, -ENODEV, + "Vendor ID not correct 0x%02x\n", vid); + + return 0; +} + +static int mt6370_tcpc_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + struct device *dev = &pdev->dev; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + platform_set_drvdata(pdev, priv); + + priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL); + if (!priv->tcpci_data.regmap) + return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n"); + + ret = mt6370_check_vendor_info(priv); + if (ret) + return ret; + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) + return priv->irq; + + /* Assign TCPCI feature and ops */ + priv->tcpci_data.auto_discharge_disconnect = 1; + priv->tcpci_data.init = mt6370_tcpc_init; + priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn; + + priv->vbus = devm_regulator_get_optional(dev, "vbus"); + if (!IS_ERR(priv->vbus)) + priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus; + + priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data); + if (IS_ERR(priv->tcpci)) + return dev_err_probe(dev, PTR_ERR(priv->tcpci), + "Failed to register tcpci port\n"); + + ret = devm_request_threaded_irq(dev, priv->irq, NULL, + mt6370_irq_handler, IRQF_ONESHOT, + dev_name(dev), priv); + if (ret) { + tcpci_unregister_port(priv->tcpci); + return dev_err_probe(dev, ret, "Failed to allocate irq\n"); + } + + device_init_wakeup(dev, true); + dev_pm_set_wake_irq(dev, priv->irq); + + return 0; +} + +static int mt6370_tcpc_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + + disable_irq(priv->irq); + tcpci_unregister_port(priv->tcpci); + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + + return 0; +} + +static const struct of_device_id mt6370_tcpc_devid_table[] = { + { .compatible = "mediatek,mt6370-tcpc" }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table); + +static struct platform_driver mt6370_tcpc_driver = { + .driver = { + .name = "mt6370-tcpc", + .of_match_table = mt6370_tcpc_devid_table, + }, + .probe = mt6370_tcpc_probe, + .remove = mt6370_tcpc_remove, +}; +module_platform_driver(mt6370_tcpc_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Fri Jul 15 11:26:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919071 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E18D1CCA47F for ; Fri, 15 Jul 2022 11:28:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234399AbiGOL2G (ORCPT ); Fri, 15 Jul 2022 07:28:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46808 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233996AbiGOL1R (ORCPT ); Fri, 15 Jul 2022 07:27:17 -0400 Received: from mail-pl1-x62d.google.com (mail-pl1-x62d.google.com [IPv6:2607:f8b0:4864:20::62d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 02E1188764; Fri, 15 Jul 2022 04:27:16 -0700 (PDT) Received: by mail-pl1-x62d.google.com with SMTP id z1so2982508plb.1; Fri, 15 Jul 2022 04:27:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=h9YyLcaUHhtIVKJsWRCSEacu4lUh4k4rRanjcPIkZOI=; b=Vzw4BGmnuFjXFSeV5AcRf2ErjfeaGMg5BVZLOj4ZYrJqkXleX4i4fMFHEUr/xW8i3e KHLAYkQ4UP9MJESCHIAt4syerI4OL0gvqpoG3E8TojtJ9qhU2PREoMCh0mxPeUJuR9Lp pacjX9wHpzbTRAEEzmPM3ttJOSGoIYMjTdEKeTU/4D+UNLwrwWn73saYTXFC3Ojme6Us 29WQf+hzG2A4vKH+1j6qPOTaP/mEF5uoolaoCoZ5US7MU+j4Q5dMupsvZWTDBJrIFI/4 DozA3rU8LRffIw0bpQ1do1gNR7YYmcOptiDWmgTOqBBlMLNTe1rgCV4SWx0EcVL5OGRU ppSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=h9YyLcaUHhtIVKJsWRCSEacu4lUh4k4rRanjcPIkZOI=; b=oTQikT9Srp19vGdbcOF8+gmDOPqf7L7sb8eYVhF2sLY1WEdnjdtXbpdFM5Qi9BJngk zNVX+eTknCNIXN18ZfOvQPZ5hXcje9xT17pi8FTwbs4hlXrZPwoGgNujgRgz2LzRrjKl mEr4iv0ECqViRfyL8K+VXDz/UipRUD8gaO1rmR1UStHISAg7vXfzLG9rtlrIFMqKdYm3 udXmBWyl022Zy42YBYuOqzgsyZ8iXbLyqergOz6q27UuUNy+8iOheRH4qIoLMrU7txTN 02PD8l8pzGEM19wtmuZPNz0fCgN0Bi5IF4H0NPsEsUdy3swR8bF/91zjvKoXmtVzBBWh EoLA== X-Gm-Message-State: AJIora9nr8g7PV2WkXrL+2ucYsmUrp9i9z2myAcLXcCK1V2wc26dtnoU h0BqqtM4eHbqM+7gnWSeecc= X-Google-Smtp-Source: AGRyM1sNgyppmS/a4UDJL3XcApUNhFTXmUDUt8fGpPMV3LMZUHrGHBMLH81hIGMItys0+zvdgzIY7Q== X-Received: by 2002:a17:90b:1b0a:b0:1f0:4bb1:2928 with SMTP id nu10-20020a17090b1b0a00b001f04bb12928mr21203546pjb.14.1657884435583; Fri, 15 Jul 2022 04:27:15 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.27.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:27:15 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v5 09/13] iio: adc: mt6370: Add MediaTek MT6370 support Date: Fri, 15 Jul 2022 19:26:03 +0800 Message-Id: <20220715112607.591-10-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiaEn Wu MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight driver, display bias voltage supply, one general purpose LDO, and the USB Type-C & PD controller complies with the latest USB Type-C and PD standards. This adds support the MT6370 ADC driver for system monitoring, including charger current, voltage, and temperature. Signed-off-by: ChiaEn Wu Reviewed-by: AngeloGioacchino Del Regno --- v5 - Replace using snprintf() with sysfs_emit() in mt6370_adc_read_label() - Remove macro ADC_CONV_TIME_US - Revise all variable ordering - Revise the description of Kconfig help text - Revise MODULE_DESCRIPTION() --- drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mt6370-adc.c | 273 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+) create mode 100644 drivers/iio/adc/mt6370-adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 48ace74..60bcc28 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -737,6 +737,18 @@ config MEDIATEK_MT6360_ADC is used in smartphones and tablets and supports a 11 channel general purpose ADC. +config MEDIATEK_MT6370_ADC + tristate "MediaTek MT6370 ADC driver" + depends on MFD_MT6370 + help + Say yes here to enable MediaTek MT6370 ADC support. + + This ADC driver provides 9 channels for system monitoring (charger + current, voltage, and temperature). + + This driver can also be built as a module. If so, the module + will be called "mt6370-adc". + 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 39d806f..0ce285c 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -68,6 +68,7 @@ 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_MT6370_ADC) += mt6370-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/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c new file mode 100644 index 0000000..51ef133 --- /dev/null +++ b/drivers/iio/adc/mt6370-adc.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiaEn Wu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MT6370_REG_CHG_CTRL3 0x113 /* AICR */ +#define MT6370_REG_CHG_CTRL7 0x117 /* ICHG */ +#define MT6370_REG_CHG_ADC 0x121 +#define MT6370_REG_ADC_DATA_H 0x14C + +#define MT6370_ADC_START_MASK BIT(0) +#define MT6370_ADC_IN_SEL_MASK GENMASK(7, 4) +#define MT6370_AICR_ICHG_MASK GENMASK(7, 2) + +#define MT6370_AICR_400MA 0x6 +#define MT6370_ICHG_500MA 0x4 +#define MT6370_ICHG_900MA 0x8 + +#define ADC_CONV_TIME_MS 35 +#define ADC_CONV_POLLING_TIME_US 1000 + +struct mt6370_adc_data { + struct device *dev; + struct regmap *regmap; + /* + * This mutex lock is for preventing the different ADC channels + * from being read at the same time. + */ + struct mutex adc_lock; +}; + +static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan, + unsigned long addr, int *val) +{ + unsigned int reg_val; + __be16 be_val; + int ret; + + mutex_lock(&priv->adc_lock); + + reg_val = MT6370_ADC_START_MASK | + FIELD_PREP(MT6370_ADC_IN_SEL_MASK, addr); + ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val); + if (ret) + goto adc_unlock; + + msleep(ADC_CONV_TIME_MS); + + ret = regmap_read_poll_timeout(priv->regmap, + MT6370_REG_CHG_ADC, reg_val, + !(reg_val & MT6370_ADC_START_MASK), + ADC_CONV_POLLING_TIME_US, + ADC_CONV_TIME_MS * 1000 * 3); + if (ret) { + dev_err(priv->dev, "Failed to read ADC register (%d)\n", ret); + goto adc_unlock; + } + + ret = regmap_raw_read(priv->regmap, MT6370_REG_ADC_DATA_H, + &be_val, sizeof(be_val)); + if (ret) + goto adc_unlock; + + *val = be16_to_cpu(be_val); + ret = IIO_VAL_INT; + +adc_unlock: + mutex_unlock(&priv->adc_lock); + + return ret; +} + +static int mt6370_adc_read_scale(struct mt6370_adc_data *priv, + int chan, int *val1, int *val2) +{ + unsigned int reg_val; + int ret; + + switch (chan) { + case MT6370_CHAN_VBAT: + case MT6370_CHAN_VSYS: + case MT6370_CHAN_CHG_VDDP: + *val1 = 5; + return IIO_VAL_INT; + case MT6370_CHAN_IBUS: + ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL3, ®_val); + if (ret) + return ret; + + reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val); + if (reg_val < MT6370_AICR_400MA) + *val1 = 3350; + else + *val1 = 5000; + + *val2 = 100; + + return IIO_VAL_FRACTIONAL; + case MT6370_CHAN_IBAT: + ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL7, ®_val); + if (ret) + return ret; + + reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val); + if (reg_val < MT6370_ICHG_500MA) + *val1 = 2375; + else if (reg_val >= MT6370_ICHG_500MA && + reg_val < MT6370_ICHG_900MA) + *val1 = 2680; + else + *val1 = 5000; + + *val2 = 100; + + return IIO_VAL_FRACTIONAL; + case MT6370_CHAN_VBUSDIV5: + *val1 = 25; + return IIO_VAL_INT; + case MT6370_CHAN_VBUSDIV2: + *val1 = 50; + return IIO_VAL_INT; + case MT6370_CHAN_TS_BAT: + *val1 = 25; + *val2 = 10000; + return IIO_VAL_FRACTIONAL; + case MT6370_CHAN_TEMP_JC: + *val1 = 2000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } +} + +static int mt6370_adc_read_offset(struct mt6370_adc_data *priv, + int chan, int *val) +{ + *val = -20; + + return IIO_VAL_INT; +} + +static int mt6370_adc_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mt6370_adc_data *priv = iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return mt6370_adc_read_channel(priv, chan->channel, + chan->address, val); + case IIO_CHAN_INFO_SCALE: + return mt6370_adc_read_scale(priv, chan->channel, val, val2); + case IIO_CHAN_INFO_OFFSET: + return mt6370_adc_read_offset(priv, chan->channel, val); + default: + return -EINVAL; + } +} + +static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = { + [MT6370_CHAN_VBUSDIV5] = "vbusdiv5", + [MT6370_CHAN_VBUSDIV2] = "vbusdiv2", + [MT6370_CHAN_VSYS] = "vsys", + [MT6370_CHAN_VBAT] = "vbat", + [MT6370_CHAN_TS_BAT] = "ts_bat", + [MT6370_CHAN_IBUS] = "ibus", + [MT6370_CHAN_IBAT] = "ibat", + [MT6370_CHAN_CHG_VDDP] = "chg_vddp", + [MT6370_CHAN_TEMP_JC] = "temp_jc", +}; + +static int mt6370_adc_read_label(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, char *label) +{ + return sysfs_emit(label, "%s\n", mt6370_channel_labels[chan->channel]); +} + +static const struct iio_info mt6370_adc_iio_info = { + .read_raw = mt6370_adc_read_raw, + .read_label = mt6370_adc_read_label, +}; + +#define MT6370_ADC_CHAN(_idx, _type, _addr, _extra_info) { \ + .type = _type, \ + .channel = MT6370_CHAN_##_idx, \ + .address = _addr, \ + .scan_index = MT6370_CHAN_##_idx, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + _extra_info, \ +} + +static const struct iio_chan_spec mt6370_adc_channels[] = { + MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1, 0), + MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2, 0), + MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3, 0), + MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4, 0), + MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6, 0), + MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8, 0), + MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9, 0), + MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11, 0), + MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)), +}; + +static int mt6370_adc_probe(struct platform_device *pdev) +{ + struct mt6370_adc_data *priv; + struct iio_dev *indio_dev; + struct regmap *regmap; + int ret; + + regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "Failed to get regmap\n"); + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + priv = iio_priv(indio_dev); + priv->dev = &pdev->dev; + priv->regmap = regmap; + mutex_init(&priv->adc_lock); + + ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to reset ADC\n"); + + indio_dev->name = "mt6370-adc"; + indio_dev->info = &mt6370_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mt6370_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(mt6370_adc_channels); + + return devm_iio_device_register(&pdev->dev, indio_dev); +} + +static const struct of_device_id mt6370_adc_of_id[] = { + { .compatible = "mediatek,mt6370-adc", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_adc_of_id); + +static struct platform_driver mt6370_adc_driver = { + .driver = { + .name = "mt6370-adc", + .of_match_table = mt6370_adc_of_id, + }, + .probe = mt6370_adc_probe, +}; +module_platform_driver(mt6370_adc_driver); + +MODULE_AUTHOR("ChiaEn Wu "); +MODULE_DESCRIPTION("MT6370 ADC Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Fri Jul 15 11:26:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919072 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1D6F1C43334 for ; Fri, 15 Jul 2022 11:28:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234258AbiGOL2N (ORCPT ); Fri, 15 Jul 2022 07:28:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46474 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232344AbiGOL10 (ORCPT ); Fri, 15 Jul 2022 07:27:26 -0400 Received: from mail-pj1-x1032.google.com (mail-pj1-x1032.google.com [IPv6:2607:f8b0:4864:20::1032]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 583BB88F12; Fri, 15 Jul 2022 04:27:21 -0700 (PDT) Received: by mail-pj1-x1032.google.com with SMTP id 89-20020a17090a09e200b001ef7638e536so11271075pjo.3; Fri, 15 Jul 2022 04:27:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=K33rLB6DGvF9cfDTQ4Vx/57WmFMD9/ZvqfJKnqH2i/8=; b=SnyK4u2LmtP7bxjZMnYgbDpPj9h9Iv34YaKabwFpMrOg4CKwSzJumQpNq6EnYvs7qu Dtt6lcLgiMKjqtahgbdAH4T01cGkjY/KSKs6UIv5Q04a8fPDahG1sJjMrxpCtR9Bcff+ 8F0i1NI2x9SuhBGiuLKEl5mN4qrjkClnHpNUgGyImWlX9i3tVyJpu0avRubbk7p9CvF4 cmwuxwqVjx2/Ie9uxcMOTujAbEsVyBwMFlmgwO7/3uMikEmTNdI+3qdDrJIkQrv/V9fJ GKvG0+J8o0p3agAyB2Z8RvpS0B8cz2ghkMl6Vn7T13gu54dow5BYyLhnAFlqci4W+QQy IAWg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=K33rLB6DGvF9cfDTQ4Vx/57WmFMD9/ZvqfJKnqH2i/8=; b=oY+zGGxwFSGlwUQz/ECQeJ1b3ga7YjcqRbpmJmiRtu6xw2CPwajl46fcQjKHSH/GDo xAJVS03yNeeOcI0/yu1Eo8BKS+uD/aib0ZhoFrNdM9mvYvepa6yCa0fpyknv+nuv/0AU qmHUzmmbbT8zRjLZuCjLmk/zt1Ou98a0rAjEOeZECsIViTnLFbYkTfnHF8eUkcY/oauV CkpdJo/q5Ei5jHCj3RRavRrGtJBMZuk1TpTPJQTtLELjvnhbMfo+/xv6r8obqpWlMDqN dlmQmAKttHPg+VnHSVz3jsuNiEFXJsC2xhROSyvGzpCVqcH2LgTdgVf9GFPFDbDXiKh0 M3sw== X-Gm-Message-State: AJIora+eHP+4T/I7f15AV7EyuX4ikpt6eg+FpjzcJIVUNL7gbzxOAP6A ulEzEb7kMeMX/zxz16Qb7d0= X-Google-Smtp-Source: AGRyM1u6T0+Pc5dNfQqyGBK2JNlI85+pD6YFt/MN4+m+Bn7/1uz8oN+42aifmdfELsAOD9JggddE/w== X-Received: by 2002:a17:90b:28d:b0:1f0:47:ca83 with SMTP id az13-20020a17090b028d00b001f00047ca83mr21077605pjb.176.1657884441316; Fri, 15 Jul 2022 04:27:21 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.27.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:27:20 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v5 10/13] power: supply: mt6370: Add MediaTek MT6370 charger driver Date: Fri, 15 Jul 2022 19:26:04 +0800 Message-Id: <20220715112607.591-11-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiaEn Wu MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight driver, display bias voltage supply, one general purpose LDO, and the USB Type-C & PD controller complies with the latest USB Type-C and PD standards. This adds MediaTek MT6370 Charger driver support. The charger module of MT6370 supports High-Accuracy Voltage/Current Regulation, Average Input Current Regulation, Battery Temperature Sensing, Over-Temperature Protection, DPDM Detection for BC1.2. Signed-off-by: ChiaEn Wu --- v5 - Replace unsigned int type of pwr_rdy with bool in mt6370_chg_set_online() - Remove redundant 'else' in mt6370_chg_field_get() - Revise 'if-else' in mt6370_chg_field_set() - Revise 'if' condition in mt6370_chg_enable_irq() - Revise all text 'otg' --> 'OTG' - Revise MT6370_MIVR_IBUS_TH_100_MA --> MT6370_MIVR_IBUS_TH_100_mA - Revise the description of Kconfig help text --- drivers/power/supply/Kconfig | 14 + drivers/power/supply/Makefile | 1 + drivers/power/supply/mt6370-charger.c | 1062 +++++++++++++++++++++++++++++++++ 3 files changed, 1077 insertions(+) create mode 100644 drivers/power/supply/mt6370-charger.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 1aa8323..591deb8 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -619,6 +619,20 @@ config CHARGER_MT6360 Average Input Current Regulation, Battery Temperature Sensing, Over-Temperature Protection, DPDM Detection for BC1.2. +config CHARGER_MT6370 + tristate "MediaTek MT6370 Charger Driver" + depends on MFD_MT6370 + depends on REGULATOR + select LINEAR_RANGES + help + Say Y here to enable MT6370 Charger Part. + The device supports High-Accuracy Voltage/Current Regulation, + Average Input Current Regulation, Battery Temperature Sensing, + Over-Temperature Protection, DPDM Detection for BC1.2. + + This driver can also be built as a module. If so, the module + will be called "mt6370-charger". + config CHARGER_QCOM_SMBB tristate "Qualcomm Switch-Mode Battery Charger and Boost" depends on MFD_SPMI_PMIC || COMPILE_TEST diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 7f02f36..8c95276 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o +obj-$(CONFIG_CHARGER_MT6370) += mt6370-charger.o obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c new file mode 100644 index 0000000..76a8c91 --- /dev/null +++ b/drivers/power/supply/mt6370-charger.c @@ -0,0 +1,1062 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiaEn Wu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6370_REG_CHG_CTRL1 0x111 +#define MT6370_REG_CHG_CTRL2 0x112 +#define MT6370_REG_CHG_CTRL3 0x113 +#define MT6370_REG_CHG_CTRL4 0x114 +#define MT6370_REG_CHG_CTRL5 0x115 +#define MT6370_REG_CHG_CTRL6 0x116 +#define MT6370_REG_CHG_CTRL7 0x117 +#define MT6370_REG_CHG_CTRL8 0x118 +#define MT6370_REG_CHG_CTRL9 0x119 +#define MT6370_REG_CHG_CTRL10 0x11A +#define MT6370_REG_DEVICE_TYPE 0x122 +#define MT6370_REG_USB_STATUS1 0x127 +#define MT6370_REG_CHG_STAT 0x14A +#define MT6370_REG_FLED_EN 0x17E +#define MT6370_REG_CHG_STAT1 0X1D0 +#define MT6370_REG_OVPCTRL_STAT 0x1D8 + +#define MT6370_VOBST_MASK GENMASK(7, 2) +#define MT6370_OTG_PIN_EN_MASK BIT(1) +#define MT6370_OPA_MODE_MASK BIT(0) +#define MT6370_OTG_OC_MASK GENMASK(2, 0) + +#define MT6370_MIVR_IBUS_TH_100_mA 100000 +#define MT6370_ADC_CHAN_IBUS 5 +#define MT6370_ADC_CHAN_MAX 9 + +enum mt6370_chg_reg_field { + /* MT6370_REG_CHG_CTRL2 */ + F_IINLMTSEL, F_CFO_EN, F_CHG_EN, + /* MT6370_REG_CHG_CTRL3 */ + F_IAICR, F_AICR_EN, F_ILIM_EN, + /* MT6370_REG_CHG_CTRL4 */ + F_VOREG, + /* MT6370_REG_CHG_CTRL6 */ + F_VMIVR, + /* MT6370_REG_CHG_CTRL7 */ + F_ICHG, + /* MT6370_REG_CHG_CTRL8 */ + F_IPREC, + /* MT6370_REG_CHG_CTRL9 */ + F_IEOC, + /* MT6370_REG_DEVICE_TYPE */ + F_USBCHGEN, + /* MT6370_REG_USB_STATUS1 */ + F_USB_STAT, F_CHGDET, + /* MT6370_REG_CHG_STAT */ + F_CHG_STAT, F_BOOST_STAT, F_VBAT_LVL, + /* MT6370_REG_FLED_EN */ + F_FL_STROBE, + /* MT6370_REG_CHG_STAT1 */ + F_CHG_MIVR_STAT, + /* MT6370_REG_OVPCTRL_STAT */ + F_UVP_D_STAT, + F_MAX +}; + +struct mt6370_priv { + struct device *dev; + struct iio_channel *iio_adcs; + struct mutex attach_lock; + struct power_supply *psy; + struct power_supply_desc *psy_desc; + struct regmap *regmap; + struct regmap_field *rmap_fields[F_MAX]; + struct regulator_dev *rdev; + struct workqueue_struct *wq; + struct work_struct bc12_work; + struct delayed_work mivr_dwork; + int attach; + int psy_usb_type; + bool pwr_rdy; +}; + +enum mt6370_usb_status { + MT6370_USB_STAT_NO_VBUS = 0, + MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING, + MT6370_USB_STAT_SDP, + MT6370_USB_STAT_SDP_NSTD, + MT6370_USB_STAT_DCP, + MT6370_USB_STAT_CDP, + MT6370_USB_STAT_MAX +}; + +struct mt6370_chg_field { + const char *name; + const struct linear_range *range; + struct reg_field field; +}; + +enum { + MT6370_RANGE_F_IAICR = 0, + MT6370_RANGE_F_VOREG, + MT6370_RANGE_F_VMIVR, + MT6370_RANGE_F_ICHG, + MT6370_RANGE_F_IPREC, + MT6370_RANGE_F_IEOC, + MT6370_RANGE_F_MAX +}; + +#define MT6370_CHG_LINEAR_RANGE(_rfd, _min, _min_sel, _max_sel, _step) \ +[_rfd] = { \ + .min = _min, \ + .min_sel = _min_sel, \ + .max_sel = _max_sel, \ + .step = _step, \ +} + +/* unit: mA or mV */ +static const struct linear_range mt6370_chg_ranges[MT6370_RANGE_F_MAX] = { + MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IAICR, 100, 0x0, 0x3F, 50), + MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_VOREG, 3900, 0x0, 0x51, 10), + MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_VMIVR, 3900, 0x0, 0x5F, 100), + MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_ICHG, 900, 0x08, 0x31, 100), + MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IPREC, 100, 0x0, 0x0F, 50), + MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IEOC, 100, 0x0, 0x0F, 50), +}; + +#define MT6370_CHG_FIELD(_fd, _reg, _lsb, _msb) \ +[_fd] = { \ + .name = #_fd, \ + .range = NULL, \ + .field = REG_FIELD(_reg, _lsb, _msb), \ +} + +#define MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb) \ +[_fd] = { \ + .name = #_fd, \ + .range = &mt6370_chg_ranges[MT6370_RANGE_##_fd], \ + .field = REG_FIELD(_reg, _lsb, _msb), \ +} + +static const struct mt6370_chg_field mt6370_chg_fields[F_MAX] = { + MT6370_CHG_FIELD(F_IINLMTSEL, MT6370_REG_CHG_CTRL2, 2, 3), + MT6370_CHG_FIELD(F_CFO_EN, MT6370_REG_CHG_CTRL2, 1, 1), + MT6370_CHG_FIELD(F_CHG_EN, MT6370_REG_CHG_CTRL2, 0, 0), + MT6370_CHG_FIELD_RANGE(F_IAICR, MT6370_REG_CHG_CTRL3, 2, 7), + MT6370_CHG_FIELD(F_AICR_EN, MT6370_REG_CHG_CTRL3, 1, 1), + MT6370_CHG_FIELD(F_ILIM_EN, MT6370_REG_CHG_CTRL3, 0, 0), + MT6370_CHG_FIELD_RANGE(F_VOREG, MT6370_REG_CHG_CTRL4, 1, 7), + MT6370_CHG_FIELD_RANGE(F_VMIVR, MT6370_REG_CHG_CTRL6, 1, 7), + MT6370_CHG_FIELD_RANGE(F_ICHG, MT6370_REG_CHG_CTRL7, 2, 7), + MT6370_CHG_FIELD_RANGE(F_IPREC, MT6370_REG_CHG_CTRL8, 0, 3), + MT6370_CHG_FIELD_RANGE(F_IEOC, MT6370_REG_CHG_CTRL9, 4, 7), + MT6370_CHG_FIELD(F_USBCHGEN, MT6370_REG_DEVICE_TYPE, 7, 7), + MT6370_CHG_FIELD(F_USB_STAT, MT6370_REG_USB_STATUS1, 4, 6), + MT6370_CHG_FIELD(F_CHGDET, MT6370_REG_USB_STATUS1, 3, 3), + MT6370_CHG_FIELD(F_CHG_STAT, MT6370_REG_CHG_STAT, 6, 7), + MT6370_CHG_FIELD(F_BOOST_STAT, MT6370_REG_CHG_STAT, 3, 3), + MT6370_CHG_FIELD(F_VBAT_LVL, MT6370_REG_CHG_STAT, 5, 5), + MT6370_CHG_FIELD(F_FL_STROBE, MT6370_REG_FLED_EN, 2, 2), + MT6370_CHG_FIELD(F_CHG_MIVR_STAT, MT6370_REG_CHG_STAT1, 6, 6), + MT6370_CHG_FIELD(F_UVP_D_STAT, MT6370_REG_OVPCTRL_STAT, 4, 4), +}; + +static inline int mt6370_chg_field_get(struct mt6370_priv *priv, + enum mt6370_chg_reg_field fd, + unsigned int *val) +{ + int ret; + unsigned int reg_val; + + ret = regmap_field_read(priv->rmap_fields[fd], ®_val); + if (ret < 0) + return ret; + + if (mt6370_chg_fields[fd].range) + return linear_range_get_value(mt6370_chg_fields[fd].range, + reg_val, val); + + *val = reg_val; + return 0; +} + +static inline int mt6370_chg_field_set(struct mt6370_priv *priv, + enum mt6370_chg_reg_field fd, + unsigned int val) +{ + int ret; + bool f; + const struct linear_range *r; + + if (mt6370_chg_fields[fd].range) { + r = mt6370_chg_fields[fd].range; + + if (fd == F_VMIVR) { + ret = linear_range_get_selector_high(r, val, &val, &f); + if (!ret) + val = r->max_sel; + } else { + linear_range_get_selector_within(r, val, &val); + } + } + + return regmap_field_write(priv->rmap_fields[fd], val); +} + +enum { + MT6370_CHG_STAT_READY = 0, + MT6370_CHG_STAT_CHARGE_IN_PROGRESS, + MT6370_CHG_STAT_DONE, + MT6370_CHG_STAT_FAULT, + MT6370_CHG_STAT_MAX +}; + +enum { + MT6370_ATTACH_STAT_DETACH = 0, + MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE, + MT6370_ATTACH_STAT_ATTACH_BC12_DONE, + MT6370_ATTACH_STAT_ATTACH_MAX +}; + +static int mt6370_chg_otg_of_parse_cb(struct device_node *of, + const struct regulator_desc *rdesc, + struct regulator_config *rcfg) +{ + struct mt6370_priv *priv = rcfg->driver_data; + + rcfg->ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(of), + "enable", 0, GPIOD_OUT_LOW | + GPIOD_FLAGS_BIT_NONEXCLUSIVE, + rdesc->name); + if (IS_ERR(rcfg->ena_gpiod)) { + rcfg->ena_gpiod = NULL; + return 0; + } + + return regmap_update_bits(priv->regmap, MT6370_REG_CHG_CTRL1, + MT6370_OTG_PIN_EN_MASK, + MT6370_OTG_PIN_EN_MASK); +} + +static void mt6370_chg_bc12_work_func(struct work_struct *work) +{ + struct mt6370_priv *priv = container_of(work, struct mt6370_priv, + bc12_work); + int ret; + bool rpt_psy = false; + unsigned int attach, usb_stat; + + mutex_lock(&priv->attach_lock); + attach = priv->attach; + + switch (attach) { + case MT6370_ATTACH_STAT_DETACH: + usb_stat = 0; + break; + case MT6370_ATTACH_STAT_ATTACH_BC12_DONE: + ret = mt6370_chg_field_get(priv, F_USB_STAT, &usb_stat); + if (ret < 0) { + dev_err(priv->dev, "Failed to get USB status\n"); + goto bc12_work_func_out; + } + break; + case MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE: + ret = mt6370_chg_field_set(priv, F_USBCHGEN, attach); + if (ret < 0) + dev_err(priv->dev, "Failed to enable USB CHG EN\n"); + goto bc12_work_func_out; + default: + dev_err(priv->dev, "Invalid attach state\n"); + goto bc12_work_func_out; + } + + rpt_psy = true; + + switch (usb_stat) { + case MT6370_USB_STAT_SDP: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; + break; + case MT6370_USB_STAT_SDP_NSTD: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; + break; + case MT6370_USB_STAT_DCP: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB_DCP; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; + break; + case MT6370_USB_STAT_CDP: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB_CDP; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP; + break; + case MT6370_USB_STAT_NO_VBUS: + case MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING: + default: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; + break; + } + +bc12_work_func_out: + mutex_unlock(&priv->attach_lock); + + if (rpt_psy) + power_supply_changed(priv->psy); +} + +static inline void mt6370_chg_enable_irq(struct mt6370_priv *priv, + const char *irq_name, bool en) +{ + int irq_num; + struct platform_device *pdev = to_platform_device(priv->dev); + + irq_num = platform_get_irq_byname(pdev, irq_name); + if (irq_num < 0) + return; + + if (en) + enable_irq(irq_num); + else + disable_irq_nosync(irq_num); +} + +static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv) +{ + int ret; + unsigned int fl_strobe; + + /* check if flash led in strobe mode */ + ret = mt6370_chg_field_get(priv, F_FL_STROBE, &fl_strobe); + if (ret < 0) { + dev_err(priv->dev, "Failed to get FL_STROBE_EN\n"); + return ret; + } + + if (fl_strobe) { + dev_err(priv->dev, "Flash led is still in strobe mode\n"); + return ret; + } + + /* cfo off */ + ret = mt6370_chg_field_set(priv, F_CFO_EN, 0); + if (ret < 0) { + dev_err(priv->dev, "Failed to disable CFO_EN\n"); + return ret; + } + + /* cfo on */ + ret = mt6370_chg_field_set(priv, F_CFO_EN, 1); + if (ret < 0) + dev_err(priv->dev, "Failed to enable CFO_EN\n"); + + return ret; +} + +static int mt6370_chg_read_adc_chan(struct mt6370_priv *priv, unsigned int chan, + int *val) +{ + int ret; + + if (chan >= MT6370_ADC_CHAN_MAX) + return -EINVAL; + + ret = iio_read_channel_processed(&priv->iio_adcs[chan], val); + if (ret) + dev_err(priv->dev, "Failed to read ADC\n"); + + return ret; +} + +static void mt6370_chg_mivr_dwork_func(struct work_struct *work) +{ + struct mt6370_priv *priv = container_of(work, struct mt6370_priv, + mivr_dwork.work); + int ret; + unsigned int mivr_stat, ibus; + + ret = mt6370_chg_field_get(priv, F_CHG_MIVR_STAT, &mivr_stat); + if (ret < 0) { + dev_err(priv->dev, "Failed to get mivr state\n"); + goto mivr_handler_out; + } + + if (!mivr_stat) + goto mivr_handler_out; + + ret = mt6370_chg_read_adc_chan(priv, MT6370_ADC_CHAN_IBUS, &ibus); + if (ret) { + dev_err(priv->dev, "Failed to get ibus\n"); + goto mivr_handler_out; + } + + if (ibus < MT6370_MIVR_IBUS_TH_100_mA) { + ret = mt6370_chg_toggle_cfo(priv); + if (ret) + dev_err(priv->dev, "Failed to toggle cfo\n"); + } + +mivr_handler_out: + mt6370_chg_enable_irq(priv, "mivr", true); + pm_relax(priv->dev); +} + +static void mt6370_chg_pwr_rdy_check(struct mt6370_priv *priv) +{ + int ret; + unsigned int pwr_rdy, otg_en; + union power_supply_propval val; + + /* Check in OTG mode or not */ + ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en); + if (ret < 0) { + dev_err(priv->dev, "Failed to get OTG state\n"); + return; + } + + if (otg_en) + return; + + ret = mt6370_chg_field_get(priv, F_UVP_D_STAT, &pwr_rdy); + if (ret < 0) { + dev_err(priv->dev, "Failed to get pwr_rdy state reg\n"); + return; + } + + val.intval = !pwr_rdy; + + ret = power_supply_set_property(priv->psy, POWER_SUPPLY_PROP_ONLINE, + &val); + if (ret < 0) + dev_err(priv->dev, "Failed to start attach/detach flow\n"); +} + +static int mt6370_chg_get_online(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + mutex_lock(&priv->attach_lock); + val->intval = !!priv->attach; + mutex_unlock(&priv->attach_lock); + + return 0; +} + +static int mt6370_chg_get_status(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + int ret; + unsigned int chg_stat; + union power_supply_propval online; + + ret = power_supply_get_property(priv->psy, POWER_SUPPLY_PROP_ONLINE, + &online); + if (ret < 0) { + dev_err(priv->dev, "Failed to get online status\n"); + return ret; + } + + if (!online.intval) { + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + return 0; + } + + ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat); + if (ret < 0) + return ret; + + switch (chg_stat) { + case MT6370_CHG_STAT_READY: + case MT6370_CHG_STAT_FAULT: + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + return ret; + case MT6370_CHG_STAT_CHARGE_IN_PROGRESS: + val->intval = POWER_SUPPLY_STATUS_CHARGING; + return ret; + case MT6370_CHG_STAT_DONE: + val->intval = POWER_SUPPLY_STATUS_FULL; + return ret; + default: + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + return ret; + } +} + +static int mt6370_chg_get_charge_type(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + int type, ret; + unsigned int chg_stat, vbat_lvl; + + ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat); + if (ret < 0) + return ret; + + ret = mt6370_chg_field_get(priv, F_VBAT_LVL, &vbat_lvl); + if (ret < 0) + return ret; + + switch (chg_stat) { + case MT6370_CHG_STAT_CHARGE_IN_PROGRESS: + if (vbat_lvl) + type = POWER_SUPPLY_CHARGE_TYPE_FAST; + else + type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case MT6370_CHG_STAT_READY: + case MT6370_CHG_STAT_DONE: + case MT6370_CHG_STAT_FAULT: + default: + type = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + } + + val->intval = type; + + return 0; +} + +static int mt6370_chg_get_ichg(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_ICHG, &val->intval); +} + +static int mt6370_chg_get_max_ichg(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + val->intval = linear_range_get_max_value( + &mt6370_chg_ranges[MT6370_RANGE_F_ICHG]); + return 0; +} + +static int mt6370_chg_get_cv(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_VOREG, &val->intval); +} + +static int mt6370_chg_get_max_cv(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + val->intval = linear_range_get_max_value( + &mt6370_chg_ranges[MT6370_RANGE_F_VOREG]); + return 0; +} + +static int mt6370_chg_get_aicr(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_IAICR, &val->intval); +} + +static int mt6370_chg_get_mivr(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_VMIVR, &val->intval); +} + +static int mt6370_chg_get_iprechg(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_IPREC, &val->intval); +} + +static int mt6370_chg_get_ieoc(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_IEOC, &val->intval); +} + +static int mt6370_chg_set_online(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + bool pwr_rdy = !!val->intval; + + mutex_lock(&priv->attach_lock); + if (pwr_rdy == !!priv->attach) { + dev_err(priv->dev, "pwr_rdy is same(%d)\n", pwr_rdy); + mutex_unlock(&priv->attach_lock); + return 0; + } + + priv->attach = pwr_rdy; + mutex_unlock(&priv->attach_lock); + + if (!queue_work(priv->wq, &priv->bc12_work)) + dev_err(priv->dev, "bc12 work has already queued\n"); + + return 0; +} + +static int mt6370_chg_set_ichg(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_ICHG, val->intval); +} + +static int mt6370_chg_set_cv(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_VOREG, val->intval); +} + +static int mt6370_chg_set_aicr(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_IAICR, val->intval); +} + +static int mt6370_chg_set_mivr(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_VMIVR, val->intval); +} + +static int mt6370_chg_set_iprechg(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_IPREC, val->intval); +} + +static int mt6370_chg_set_ieoc(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_IEOC, val->intval); +} + +static int mt6370_chg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct mt6370_priv *priv = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + return mt6370_chg_get_online(priv, val); + case POWER_SUPPLY_PROP_STATUS: + return mt6370_chg_get_status(priv, val); + case POWER_SUPPLY_PROP_CHARGE_TYPE: + return mt6370_chg_get_charge_type(priv, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + return mt6370_chg_get_ichg(priv, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + return mt6370_chg_get_max_ichg(priv, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + return mt6370_chg_get_cv(priv, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + return mt6370_chg_get_max_cv(priv, val); + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return mt6370_chg_get_aicr(priv, val); + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + return mt6370_chg_get_mivr(priv, val); + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + return mt6370_chg_get_iprechg(priv, val); + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return mt6370_chg_get_ieoc(priv, val); + case POWER_SUPPLY_PROP_TYPE: + val->intval = priv->psy_desc->type; + return 0; + case POWER_SUPPLY_PROP_USB_TYPE: + val->intval = priv->psy_usb_type; + return 0; + default: + return -EINVAL; + } +} + +static int mt6370_chg_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct mt6370_priv *priv = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + return mt6370_chg_set_online(priv, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + return mt6370_chg_set_ichg(priv, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + return mt6370_chg_set_cv(priv, val); + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return mt6370_chg_set_aicr(priv, val); + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + return mt6370_chg_set_mivr(priv, val); + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + return mt6370_chg_set_iprechg(priv, val); + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return mt6370_chg_set_ieoc(priv, val); + default: + return -EINVAL; + } +} + +static int mt6370_chg_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return 1; + default: + return 0; + } +} + +static enum power_supply_property mt6370_chg_properties[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, + POWER_SUPPLY_PROP_TYPE, + POWER_SUPPLY_PROP_USB_TYPE, +}; + +static enum power_supply_usb_type mt6370_chg_usb_types[] = { + POWER_SUPPLY_USB_TYPE_UNKNOWN, + POWER_SUPPLY_USB_TYPE_SDP, + POWER_SUPPLY_USB_TYPE_CDP, + POWER_SUPPLY_USB_TYPE_DCP, +}; + +static struct power_supply_desc mt6370_chg_psy_desc = { + .type = POWER_SUPPLY_TYPE_USB, + .properties = mt6370_chg_properties, + .num_properties = ARRAY_SIZE(mt6370_chg_properties), + .get_property = mt6370_chg_get_property, + .set_property = mt6370_chg_set_property, + .property_is_writeable = mt6370_chg_property_is_writeable, + .usb_types = mt6370_chg_usb_types, + .num_usb_types = ARRAY_SIZE(mt6370_chg_usb_types), +}; + +static const struct regulator_ops mt6370_chg_otg_ops = { + .list_voltage = regulator_list_voltage_linear, + .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_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, +}; + +static const u32 mt6370_chg_otg_oc_ma[] = { + 500000, 700000, 1100000, 1300000, 1800000, 2100000, 2400000, +}; + +static const struct regulator_desc mt6370_chg_otg_rdesc = { + .of_match = "usb-otg-vbus-regulator", + .of_parse_cb = mt6370_chg_otg_of_parse_cb, + .name = "mt6370-usb-otg-vbus", + .ops = &mt6370_chg_otg_ops, + .owner = THIS_MODULE, + .type = REGULATOR_VOLTAGE, + .min_uV = 4425000, + .uV_step = 25000, + .n_voltages = 57, + .vsel_reg = MT6370_REG_CHG_CTRL5, + .vsel_mask = MT6370_VOBST_MASK, + .enable_reg = MT6370_REG_CHG_CTRL1, + .enable_mask = MT6370_OPA_MODE_MASK, + .curr_table = mt6370_chg_otg_oc_ma, + .n_current_limits = ARRAY_SIZE(mt6370_chg_otg_oc_ma), + .csel_reg = MT6370_REG_CHG_CTRL10, + .csel_mask = MT6370_OTG_OC_MASK, +}; + +static int mt6370_chg_init_rmap_fields(struct mt6370_priv *priv) +{ + int i; + const struct mt6370_chg_field *fds = mt6370_chg_fields; + + for (i = 0; i < F_MAX; i++) { + priv->rmap_fields[i] = devm_regmap_field_alloc(priv->dev, + priv->regmap, + fds[i].field); + if (IS_ERR(priv->rmap_fields[i])) + return dev_err_probe(priv->dev, + PTR_ERR(priv->rmap_fields[i]), + "Failed to allocate regmapfield[%s]\n", + fds[i].name); + } + + return 0; +} + +static int mt6370_chg_init_setting(struct mt6370_priv *priv) +{ + int ret; + + /* Disable usb_chg_en */ + ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0); + if (ret < 0) { + dev_err(priv->dev, "Failed to disable usb_chg_en\n"); + return ret; + } + + /* ICHG/IEOC Workaround, ICHG can not be set less than 900mA */ + ret = mt6370_chg_field_set(priv, F_ICHG, 900); + if (ret < 0) { + dev_err(priv->dev, "Failed to set ICHG to 900mA"); + return ret; + } + + /* Change input current limit selection to using IAICR results */ + ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 3); + if (ret < 0) { + dev_err(priv->dev, "Failed to set IINLMTSEL\n"); + return ret; + } + + return 0; +} + +#define MT6370_CHG_DT_PROP_DECL(_name, _type, _field) \ +{ \ + .name = "mediatek,chg-" #_name, \ + .type = MT6370_PARSE_TYPE_##_type, \ + .fd = _field, \ +} + +static int mt6370_chg_init_otg_regulator(struct mt6370_priv *priv) +{ + struct regulator_config rcfg = { + .dev = priv->dev, + .regmap = priv->regmap, + .driver_data = priv, + }; + + priv->rdev = devm_regulator_register(priv->dev, &mt6370_chg_otg_rdesc, + &rcfg); + + return PTR_ERR_OR_ZERO(priv->rdev); +} + +static int mt6370_chg_init_psy(struct mt6370_priv *priv) +{ + struct power_supply_config cfg = { + .drv_data = priv, + .of_node = dev_of_node(priv->dev), + }; + + priv->psy_desc = &mt6370_chg_psy_desc; + priv->psy_desc->name = dev_name(priv->dev); + priv->psy = devm_power_supply_register(priv->dev, priv->psy_desc, &cfg); + + return PTR_ERR_OR_ZERO(priv->psy); +} + +static irqreturn_t mt6370_attach_i_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + unsigned int otg_en; + int ret; + + /* Check in otg mode or not */ + ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en); + if (ret < 0) { + dev_err(priv->dev, "Failed to get otg state\n"); + return IRQ_NONE; + } + + if (otg_en) + return IRQ_HANDLED; + + mutex_lock(&priv->attach_lock); + priv->attach = MT6370_ATTACH_STAT_ATTACH_BC12_DONE; + mutex_unlock(&priv->attach_lock); + + if (!queue_work(priv->wq, &priv->bc12_work)) + dev_err(priv->dev, "bc12 work has already queued\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t mt6370_uvp_d_evt_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + + mt6370_chg_pwr_rdy_check(priv); + + return IRQ_HANDLED; +} + +static irqreturn_t mt6370_mivr_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + + pm_stay_awake(priv->dev); + mt6370_chg_enable_irq(priv, "mivr", false); + schedule_delayed_work(&priv->mivr_dwork, msecs_to_jiffies(200)); + + return IRQ_HANDLED; +} + +#define MT6370_CHG_IRQ(_name) \ +{ \ + .name = #_name, \ + .handler = mt6370_##_name##_handler, \ +} + +static int mt6370_chg_init_irq(struct mt6370_priv *priv) +{ + int i, ret; + const struct { + char *name; + irq_handler_t handler; + } mt6370_chg_irqs[] = { + MT6370_CHG_IRQ(attach_i), + MT6370_CHG_IRQ(uvp_d_evt), + MT6370_CHG_IRQ(mivr), + }; + + for (i = 0; i < ARRAY_SIZE(mt6370_chg_irqs); i++) { + ret = platform_get_irq_byname(to_platform_device(priv->dev), + mt6370_chg_irqs[i].name); + if (ret < 0) + return dev_err_probe(priv->dev, ret, + "Failed to get irq %s\n", + mt6370_chg_irqs[i].name); + + ret = devm_request_threaded_irq(priv->dev, ret, NULL, + mt6370_chg_irqs[i].handler, + IRQF_TRIGGER_FALLING, + dev_name(priv->dev), + priv); + + if (ret < 0) + return dev_err_probe(priv->dev, ret, + "Failed to request irq %s\n", + mt6370_chg_irqs[i].name); + } + + return 0; +} + +static int mt6370_chg_probe(struct platform_device *pdev) +{ + int ret; + struct mt6370_priv *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "Failed to get regmap\n"); + + ret = mt6370_chg_init_rmap_fields(priv); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to init regmap fields\n"); + + platform_set_drvdata(pdev, priv); + + priv->iio_adcs = devm_iio_channel_get_all(priv->dev); + if (IS_ERR(priv->iio_adcs)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->iio_adcs), + "Failed to get iio adc\n"); + + ret = mt6370_chg_init_otg_regulator(priv); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to init otg regulator\n"); + + ret = mt6370_chg_init_psy(priv); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to init psy\n"); + + mutex_init(&priv->attach_lock); + priv->attach = MT6370_ATTACH_STAT_DETACH; + + priv->wq = create_singlethread_workqueue(dev_name(priv->dev)); + if (IS_ERR(priv->wq)) + return dev_err_probe(priv->dev, PTR_ERR(priv->wq), + "Failed to create workqueue\n"); + + INIT_WORK(&priv->bc12_work, mt6370_chg_bc12_work_func); + INIT_DELAYED_WORK(&priv->mivr_dwork, mt6370_chg_mivr_dwork_func); + + ret = mt6370_chg_init_setting(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init mt6370 charger setting\n"); + goto probe_out; + } + + ret = mt6370_chg_init_irq(priv); + if (ret) + goto probe_out; + + mt6370_chg_pwr_rdy_check(priv); + + return 0; + +probe_out: + cancel_delayed_work_sync(&priv->mivr_dwork); + flush_workqueue(priv->wq); + destroy_workqueue(priv->wq); + mutex_destroy(&priv->attach_lock); + + return ret; +} + +static int mt6370_chg_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&priv->mivr_dwork); + flush_workqueue(priv->wq); + destroy_workqueue(priv->wq); + mutex_destroy(&priv->attach_lock); + + return 0; +} + +static const struct of_device_id mt6370_chg_of_match[] = { + { .compatible = "mediatek,mt6370-charger", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_chg_of_match); + +static struct platform_driver mt6370_chg_driver = { + .probe = mt6370_chg_probe, + .remove = mt6370_chg_remove, + .driver = { + .name = "mt6370-charger", + .of_match_table = mt6370_chg_of_match, + }, +}; +module_platform_driver(mt6370_chg_driver); + +MODULE_AUTHOR("ChiaEn Wu "); +MODULE_DESCRIPTION("MediaTek MT6370 Charger Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Fri Jul 15 11:26:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919073 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B1B38CCA47C for ; Fri, 15 Jul 2022 11:28:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233760AbiGOL2h (ORCPT ); Fri, 15 Jul 2022 07:28:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47022 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233798AbiGOL14 (ORCPT ); Fri, 15 Jul 2022 07:27:56 -0400 Received: from mail-pg1-x532.google.com (mail-pg1-x532.google.com [IPv6:2607:f8b0:4864:20::532]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 00B2288F17; Fri, 15 Jul 2022 04:27:27 -0700 (PDT) Received: by mail-pg1-x532.google.com with SMTP id e132so4144702pgc.5; Fri, 15 Jul 2022 04:27:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=bA9Jq/6VkI7qBgsQI9KSj8qgCe1Rp9dL2GNcaBsuXes=; b=naYy2zTfqnkykG4y2dgYwSg+KnD9cBztSkR216GDd4krEI/f7rhZdU9BWSN4H0Uh3C goz0dKPKJpwnuwi3ombZO4bYKpF3RTh/hGuhvlJxDSZWYzFggeklPkFtKGxlZjA/WcE+ iwc+sJ6YuhIhHlr1DLGGxqwY5RbJyNaYZJPHTjGSsonoW5dItCiaYaY21rjsp434uXhZ v2qupFxyhoNu5uXnFkDg3NSw+oTxOIymDcnwY8QVpPLzvcSYCfgbtoz62r0zIYpBIfkz 0BEpwmQfiMfFNARkW4ZmDKrnE7ErITUGBBaAWVrWBWzXAda36jHBlRmA1Tu365S3hs8G FmLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bA9Jq/6VkI7qBgsQI9KSj8qgCe1Rp9dL2GNcaBsuXes=; b=EWnXywH1Aa2wRl0shu6i8HQrAoTqQ4K+jWQaN498eKKfofbZCiuWOIV14WozfgGQnk HG04R/KRncpXRi15OnqZDw49iQt2gMzsnrx/h8EQh51oYxbG4Q2Gs+7iBojF71lycR6B FRgmpFzuePA0EkyquarMxZooUMCn2BqERZzucIZF5kD3LoQI7I9F3Es0eFtZLKgfUFtc R7cGnkYJWMEz1hQYOX5rqoXt1b9/q/YJzCCex4KyY0GjT81d7kXlbMQdmPz67ruIYyAo sll9djLzI1w1kTjJDgCrzWzZPu44X5bgZLKaJZFj/1Xwc3iGjl5SB92rS5TBu/7D7kex gW9g== X-Gm-Message-State: AJIora+YkBiNMLBI9kEqf0k6zXUjA6HvwoZoJkwCyCroWKzwVqeh1lm6 dwbFlRrc1iPnwpfwwSgB4XY= X-Google-Smtp-Source: AGRyM1vz3ttrBBY4A2QiBDAijD/PUXevrcvsjtrV6U+0KXYGFIeBgOXj1mAKp1EKWK0JXG+8hF8jlw== X-Received: by 2002:a63:4184:0:b0:412:a00d:e716 with SMTP id o126-20020a634184000000b00412a00de716mr11839157pga.414.1657884447177; Fri, 15 Jul 2022 04:27:27 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.27.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:27:26 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v5 11/13] leds: mt6370: Add MediaTek MT6370 current sink type LED Indicator support Date: Fri, 15 Jul 2022 19:26:05 +0800 Message-Id: <20220715112607.591-12-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiYuan Huang The MediaTek MT6370 is a highly-integrated smart power management IC, which includes a single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C & Power Delivery (PD) controller, dual Flash LED current sources, a RGB LED driver, a backlight WLED driver, a display bias driver and a general LDO for portable devices. In MediaTek MT6370, there are four channel current-sink RGB LEDs that support hardware pattern for constant current, PWM, and breath mode. Isink4 channel can also be used as a CHG_VIN power good indicator. Signed-off-by: ChiYuan Huang --- drivers/leds/Kconfig | 14 + drivers/leds/Makefile | 1 + drivers/leds/leds-mt6370.c | 994 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1009 insertions(+) create mode 100644 drivers/leds/leds-mt6370.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index a49979f..71bacb5 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -244,6 +244,20 @@ config LEDS_MT6323 This option enables support for on-chip LED drivers found on Mediatek MT6323 PMIC. +config LEDS_MT6370_RGB + tristate "LED Support for MediaTek MT6370 PMIC" + depends on LEDS_CLASS + depends on MFD_MT6370 + select LINEAR_RANGE + help + Say Y here to enable support for MT6370_RGB LED device. + In MT6370, there are four channel current-sink LED drivers that + support hardware pattern for constant current, PWM, and breath mode. + Isink4 channel can also be used as a CHG_VIN power good indicator. + + This driver can also be built as a module. If so the module + will be called "leds-mt6370.ko". + config LEDS_S3C24XX tristate "LED Support for Samsung S3C24XX GPIO LEDs" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 4fd2f92..557be42 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o +obj-$(CONFIG_LEDS_MT6370_RGB) += leds-mt6370.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o diff --git a/drivers/leds/leds-mt6370.c b/drivers/leds/leds-mt6370.c new file mode 100644 index 0000000..1038232 --- /dev/null +++ b/drivers/leds/leds-mt6370.c @@ -0,0 +1,994 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: Alice Chen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + MT6370_LED_ISNK1 = 0, + MT6370_LED_ISNK2, + MT6370_LED_ISNK3, + MT6370_LED_ISNK4, + MT6370_MAX_LEDS +}; + +enum mt6370_led_mode { + MT6370_LED_PWM_MODE = 0, + MT6370_LED_BREATH_MODE, + MT6370_LED_REG_MODE, + MT6370_LED_MAX_MODE +}; + +enum mt6370_led_field { + F_RGB_EN = 0, + F_CHGIND_EN, + F_LED1_CURR, + F_LED2_CURR, + F_LED3_CURR, + F_LED4_CURR, + F_LED1_MODE, + F_LED2_MODE, + F_LED3_MODE, + F_LED4_MODE, + F_LED1_DUTY, + F_LED2_DUTY, + F_LED3_DUTY, + F_LED4_DUTY, + F_LED1_FREQ, + F_LED2_FREQ, + F_LED3_FREQ, + F_LED4_FREQ, + F_MAX_FIELDS +}; + +enum mt6370_led_ranges { + R_LED123_CURR = 0, + R_LED4_CURR, + R_LED_TRFON, + R_LED_TOFF, + R_MAX_RANGES, +}; + +enum mt6370_pattern { + P_LED_TR1 = 0, + P_LED_TR2, + P_LED_TF1, + P_LED_TF2, + P_LED_TON, + P_LED_TOFF, + P_MAX_PATTERNS +}; + +#define MT6370_REG_DEV_INFO 0x100 +#define MT6370_REG_RGB1_DIM 0x182 +#define MT6370_REG_RGB2_DIM 0x183 +#define MT6370_REG_RGB3_DIM 0x184 +#define MT6370_REG_RGB_EN 0x185 +#define MT6370_REG_RGB1_ISNK 0x186 +#define MT6370_REG_RGB2_ISNK 0x187 +#define MT6370_REG_RGB3_ISNK 0x188 +#define MT6370_REG_RGB1_TR 0x189 +#define MT6370_REG_RGB_CHRIND_DIM 0x192 +#define MT6370_REG_RGB_CHRIND_CTRL 0x193 +#define MT6370_REG_RGB_CHRIND_TR 0x194 + +#define MT6372_REG_RGB_EN 0x182 +#define MT6372_REG_RGB1_ISNK 0x183 +#define MT6372_REG_RGB2_ISNK 0x184 +#define MT6372_REG_RGB3_ISNK 0x185 +#define MT6372_REG_RGB4_ISNK 0x186 +#define MT6372_REG_RGB1_DIM 0x187 +#define MT6372_REG_RGB2_DIM 0x188 +#define MT6372_REG_RGB3_DIM 0x189 +#define MT6372_REG_RGB4_DIM 0x18A +#define MT6372_REG_RGB12_FREQ 0x18B +#define MT6372_REG_RGB34_FREQ 0x18C +#define MT6372_REG_RGB1_TR 0x18D + +#define MT6370_VENID_MASK GENMASK(7, 4) +#define MT6370_CHEN_BIT(id) BIT(MT6370_LED_ISNK4 - id) +#define MT6370_VIRTUAL_MULTICOLOR 5 +#define MC_CHANNEL_NUM 3 +#define MT6370_PWM_DUTY 31 +#define MT6372_PMW_DUTY 255 + +#define STATE_OFF 0 +#define STATE_KEEP 1 +#define STATE_ON 2 + +struct mt6370_led { + union { + struct led_classdev isink; + struct led_classdev_mc mc; + }; + struct mt6370_priv *priv; + u32 default_state; + u32 index; +}; + +struct mt6370_priv { + /* Per LED access lock */ + struct mutex lock; + struct device *dev; + struct regmap *regmap; + struct regmap_field *fields[F_MAX_FIELDS]; + const struct reg_field *reg_fields; + const struct linear_range *ranges; + struct reg_cfg *reg_cfgs; + unsigned int leds_count; + unsigned int leds_active; + bool is_mt6372; + struct mt6370_led leds[]; +}; + +static const struct reg_field common_reg_fields[F_MAX_FIELDS] = { + [F_RGB_EN] = REG_FIELD(MT6370_REG_RGB_EN, 4, 7), + [F_CHGIND_EN] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 7, 7), + [F_LED1_CURR] = REG_FIELD(MT6370_REG_RGB1_ISNK, 0, 2), + [F_LED2_CURR] = REG_FIELD(MT6370_REG_RGB2_ISNK, 0, 2), + [F_LED3_CURR] = REG_FIELD(MT6370_REG_RGB3_ISNK, 0, 2), + [F_LED4_CURR] = REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 0, 1), + [F_LED1_MODE] = REG_FIELD(MT6370_REG_RGB1_DIM, 5, 6), + [F_LED2_MODE] = REG_FIELD(MT6370_REG_RGB2_DIM, 5, 6), + [F_LED3_MODE] = REG_FIELD(MT6370_REG_RGB3_DIM, 5, 6), + [F_LED4_MODE] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 5, 6), + [F_LED1_DUTY] = REG_FIELD(MT6370_REG_RGB1_DIM, 0, 4), + [F_LED2_DUTY] = REG_FIELD(MT6370_REG_RGB2_DIM, 0, 4), + [F_LED3_DUTY] = REG_FIELD(MT6370_REG_RGB3_DIM, 0, 4), + [F_LED4_DUTY] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 0, 4), + [F_LED1_FREQ] = REG_FIELD(MT6370_REG_RGB1_ISNK, 3, 5), + [F_LED2_FREQ] = REG_FIELD(MT6370_REG_RGB2_ISNK, 3, 5), + [F_LED3_FREQ] = REG_FIELD(MT6370_REG_RGB3_ISNK, 3, 5), + [F_LED4_FREQ] = REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 2, 4) +}; + +static const struct reg_field mt6372_reg_fields[F_MAX_FIELDS] = { + [F_RGB_EN] = REG_FIELD(MT6372_REG_RGB_EN, 4, 7), + [F_CHGIND_EN] = REG_FIELD(MT6372_REG_RGB_EN, 3, 3), + [F_LED1_CURR] = REG_FIELD(MT6372_REG_RGB1_ISNK, 0, 3), + [F_LED2_CURR] = REG_FIELD(MT6372_REG_RGB2_ISNK, 0, 3), + [F_LED3_CURR] = REG_FIELD(MT6372_REG_RGB3_ISNK, 0, 3), + [F_LED4_CURR] = REG_FIELD(MT6372_REG_RGB4_ISNK, 0, 3), + [F_LED1_MODE] = REG_FIELD(MT6372_REG_RGB1_ISNK, 6, 7), + [F_LED2_MODE] = REG_FIELD(MT6372_REG_RGB2_ISNK, 6, 7), + [F_LED3_MODE] = REG_FIELD(MT6372_REG_RGB3_ISNK, 6, 7), + [F_LED4_MODE] = REG_FIELD(MT6372_REG_RGB4_ISNK, 6, 7), + [F_LED1_DUTY] = REG_FIELD(MT6372_REG_RGB1_DIM, 0, 7), + [F_LED2_DUTY] = REG_FIELD(MT6372_REG_RGB2_DIM, 0, 7), + [F_LED3_DUTY] = REG_FIELD(MT6372_REG_RGB3_DIM, 0, 7), + [F_LED4_DUTY] = REG_FIELD(MT6372_REG_RGB4_DIM, 0, 7), + [F_LED1_FREQ] = REG_FIELD(MT6372_REG_RGB12_FREQ, 5, 7), + [F_LED2_FREQ] = REG_FIELD(MT6372_REG_RGB12_FREQ, 2, 4), + [F_LED3_FREQ] = REG_FIELD(MT6372_REG_RGB34_FREQ, 5, 7), + [F_LED4_FREQ] = REG_FIELD(MT6372_REG_RGB34_FREQ, 2, 4) +}; + +/* Current unit: microamp, time unit: millisecond */ +static const struct linear_range common_led_ranges[R_MAX_RANGES] = { + [R_LED123_CURR] = { 4000, 1, 6, 4000 }, + [R_LED4_CURR] = { 2000, 1, 3, 2000 }, + [R_LED_TRFON] = { 125, 0, 15, 200 }, + [R_LED_TOFF] = { 250, 0, 15, 400 } +}; + +static const struct linear_range mt6372_led_ranges[R_MAX_RANGES] = { + [R_LED123_CURR] = { 2000, 1, 14, 2000 }, + [R_LED4_CURR] = { 2000, 1, 14, 2000 }, + [R_LED_TRFON] = { 125, 0, 15, 250 }, + [R_LED_TOFF] = { 250, 0, 15, 500 } +}; + +static enum mt6370_led_field mt6370_get_led_current_field(unsigned int led_no) +{ + switch (led_no) { + case MT6370_LED_ISNK1: + return F_LED1_CURR; + case MT6370_LED_ISNK2: + return F_LED2_CURR; + case MT6370_LED_ISNK3: + return F_LED3_CURR; + default: + return F_LED4_CURR; + } +} + +static int mt6370_set_led_brightness(struct mt6370_priv *priv, + unsigned int led_no, unsigned int level) +{ + enum mt6370_led_field sel_field; + + sel_field = mt6370_get_led_current_field(led_no); + + return regmap_field_write(priv->fields[sel_field], level); +} + +static int mt6370_get_led_brightness(struct mt6370_priv *priv, + unsigned int led_no, unsigned int *level) +{ + enum mt6370_led_field sel_field; + + sel_field = mt6370_get_led_current_field(led_no); + + return regmap_field_read(priv->fields[sel_field], level); +} + +static int mt6370_set_led_duty(struct mt6370_priv *priv, unsigned int led_no, + unsigned int ton, unsigned int toff) +{ + enum mt6370_led_field sel_field; + unsigned int divisor, ratio; + + divisor = priv->is_mt6372 ? MT6372_PMW_DUTY : MT6370_PWM_DUTY; + ratio = ton * divisor / (ton + toff); + + switch (led_no) { + case MT6370_LED_ISNK1: + sel_field = F_LED1_DUTY; + break; + case MT6370_LED_ISNK2: + sel_field = F_LED2_DUTY; + break; + case MT6370_LED_ISNK3: + sel_field = F_LED3_DUTY; + break; + default: + sel_field = F_LED4_DUTY; + } + + return regmap_field_write(priv->fields[sel_field], ratio); +} + +static const unsigned int common_tfreqs[] = { + 10000, 5000, 2000, 1000, 500, 200, 5, 1, +}; + +static const unsigned int mt6372_tfreqs[] = { + 8000, 4000, 2000, 1000, 500, 250, 8, 4, +}; + +static int mt6370_set_led_freq(struct mt6370_priv *priv, unsigned int led_no, + unsigned int ton, unsigned int toff) +{ + enum mt6370_led_field sel_field; + const unsigned int *tfreq; + unsigned int tfreq_len, tsum; + int i; + + if (priv->is_mt6372) { + tfreq = mt6372_tfreqs; + tfreq_len = ARRAY_SIZE(mt6372_tfreqs); + } else { + tfreq = common_tfreqs; + tfreq_len = ARRAY_SIZE(common_tfreqs); + } + + tsum = ton + toff; + + if (tsum > tfreq[0] || tsum < tfreq[tfreq_len - 1]) + return -EOPNOTSUPP; + + for (i = 0; i < tfreq_len; i++) { + if (tsum >= tfreq[i]) + break; + } + + switch (led_no) { + case MT6370_LED_ISNK1: + sel_field = F_LED1_FREQ; + break; + case MT6370_LED_ISNK2: + sel_field = F_LED2_FREQ; + break; + case MT6370_LED_ISNK3: + sel_field = F_LED3_FREQ; + break; + default: + sel_field = F_LED4_FREQ; + } + + return regmap_field_write(priv->fields[sel_field], i); +} + +static void mt6370_get_breath_reg_base(struct mt6370_priv *priv, + unsigned int led_no, unsigned int *base) +{ + if (priv->is_mt6372) { + *base = MT6372_REG_RGB1_TR + led_no * 3; + return; + } + + switch (led_no) { + case MT6370_LED_ISNK1: + case MT6370_LED_ISNK2: + case MT6370_LED_ISNK3: + *base = MT6370_REG_RGB1_TR + led_no * 3; + break; + default: + *base = MT6370_REG_RGB_CHRIND_TR; + } +} + +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv, + struct led_pattern *pattern, u32 len, + u8 *pattern_val, u32 val_len) +{ + enum mt6370_led_ranges sel_range; + struct led_pattern *curr; + unsigned int sel; + u8 val[P_MAX_PATTERNS / 2] = {0}; + int i; + + if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2) + return -EINVAL; + + /* + * Pattern list + * tr1: byte 0, b'[7: 4] + * tr2: byte 0, b'[3: 0] + * tf1: byte 1, b'[7: 4] + * tf2: byte 1, b'[3: 0] + * ton: byte 2, b'[7: 4] + * toff: byte 2, b'[3: 0] + */ + for (i = 0; i < P_MAX_PATTERNS; i++) { + curr = pattern + i; + + sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON; + + linear_range_get_selector_within(priv->ranges + sel_range, + curr->delta_t, &sel); + + val[i / 2] |= sel << (4 * ((i + 1) % 2)); + } + + memcpy(pattern_val, val, 3); + return 0; +} + +static int mt6370_set_led_mode(struct mt6370_priv *priv, unsigned int led_no, + enum mt6370_led_mode mode) +{ + enum mt6370_led_field sel_field; + + switch (led_no) { + case MT6370_LED_ISNK1: + sel_field = F_LED1_MODE; + break; + case MT6370_LED_ISNK2: + sel_field = F_LED2_MODE; + break; + case MT6370_LED_ISNK3: + sel_field = F_LED3_MODE; + break; + default: + sel_field = F_LED4_MODE; + } + + return regmap_field_write(priv->fields[sel_field], mode); +} + +static int mt6370_mc_brightness_set(struct led_classdev *lcdev, + enum led_brightness level) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + unsigned int enable, disable; + int i, ret; + + mutex_lock(&priv->lock); + + led_mc_calc_color_components(mccdev, level); + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out; + + disable = enable; + + for (i = 0; i < mccdev->num_colors; i++) { + u32 brightness; + + subled = mccdev->subled_info + i; + brightness = min(subled->brightness, lcdev->max_brightness); + disable &= ~MT6370_CHEN_BIT(subled->channel); + + if (level == LED_OFF) { + enable &= ~MT6370_CHEN_BIT(subled->channel); + + ret = mt6370_set_led_mode(priv, subled->channel, + MT6370_LED_REG_MODE); + if (ret) + goto out; + + continue; + } + + if (brightness == LED_OFF) { + enable &= ~MT6370_CHEN_BIT(subled->channel); + continue; + } + + enable |= MT6370_CHEN_BIT(subled->channel); + + ret = mt6370_set_led_brightness(priv, subled->channel, + brightness); + if (ret) + goto out; + } + + ret = regmap_field_write(priv->fields[F_RGB_EN], disable); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_mc_blink_set(struct led_classdev *lcdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + unsigned int enable, disable; + int i, ret; + + mutex_lock(&priv->lock); + + if (!*delay_on && !*delay_off) + *delay_on = *delay_off = 500; + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out; + + disable = enable; + + for (i = 0; i < mccdev->num_colors; i++) { + subled = mccdev->subled_info + i; + + disable &= ~MT6370_CHEN_BIT(subled->channel); + + ret = mt6370_set_led_duty(priv, subled->channel, *delay_on, + *delay_off); + if (ret) + goto out; + + ret = mt6370_set_led_freq(priv, subled->channel, *delay_on, + *delay_off); + if (ret) + goto out; + + ret = mt6370_set_led_mode(priv, subled->channel, + MT6370_LED_PWM_MODE); + if (ret) + goto out; + } + + /* Toggle to make pattern timing the same */ + ret = regmap_field_write(priv->fields[F_RGB_EN], disable); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_mc_pattern_set(struct led_classdev *lcdev, + struct led_pattern *pattern, u32 len, int repeat) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + unsigned int reg_base, enable, disable; + u8 params[P_MAX_PATTERNS / 2]; + int i, ret; + + mutex_lock(&priv->lock); + + ret = mt6370_gen_breath_pattern(priv, pattern, len, params, + sizeof(params)); + if (ret) + goto out; + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out; + + disable = enable; + + for (i = 0; i < mccdev->num_colors; i++) { + subled = mccdev->subled_info + i; + + mt6370_get_breath_reg_base(priv, subled->channel, ®_base); + disable &= ~MT6370_CHEN_BIT(subled->channel); + + ret = regmap_raw_write(priv->regmap, reg_base, params, + sizeof(params)); + if (ret) + goto out; + + ret = mt6370_set_led_mode(priv, subled->channel, + MT6370_LED_BREATH_MODE); + if (ret) + goto out; + } + + /* Toggle to make pattern timing be the same */ + ret = regmap_field_write(priv->fields[F_RGB_EN], disable); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + int i, ret = 0; + + mutex_lock(&led->priv->lock); + + for (i = 0; i < mccdev->num_colors; i++) { + subled = mccdev->subled_info + i; + + ret = mt6370_set_led_mode(priv, subled->channel, + MT6370_LED_REG_MODE); + if (ret) + break; + } + + mutex_unlock(&led->priv->lock); + + return ret; +} + +static int mt6370_isnk_brightness_set(struct led_classdev *lcdev, + enum led_brightness level) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + unsigned int enable; + int ret; + + mutex_lock(&priv->lock); + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out; + + if (level == LED_OFF) { + enable &= ~MT6370_CHEN_BIT(led->index); + + ret = mt6370_set_led_mode(priv, led->index, + MT6370_LED_REG_MODE); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + } else { + enable |= MT6370_CHEN_BIT(led->index); + + ret = mt6370_set_led_brightness(priv, led->index, level); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + } + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_isnk_blink_set(struct led_classdev *lcdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + int ret; + + mutex_lock(&priv->lock); + + if (!*delay_on && !*delay_off) + *delay_on = *delay_off = 500; + + ret = mt6370_set_led_duty(priv, led->index, *delay_on, *delay_off); + if (ret) + goto out; + + ret = mt6370_set_led_freq(priv, led->index, *delay_on, *delay_off); + if (ret) + goto out; + + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_PWM_MODE); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_isnk_pattern_set(struct led_classdev *lcdev, + struct led_pattern *pattern, u32 len, + int repeat) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + unsigned int reg_base; + u8 params[P_MAX_PATTERNS / 2]; + int ret; + + mutex_lock(&priv->lock); + + ret = mt6370_gen_breath_pattern(priv, pattern, len, params, + sizeof(params)); + if (ret) + goto out; + + mt6370_get_breath_reg_base(priv, led->index, ®_base); + + ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params)); + if (ret) + goto out; + + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_BREATH_MODE); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static inline int mt6370_isnk_pattern_clear(struct led_classdev *lcdev) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + int ret; + + mutex_lock(&led->priv->lock); + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE); + mutex_unlock(&led->priv->lock); + + return ret; +} + +static int mt6370_init_led_properties(struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct mt6370_priv *priv = led->priv; + struct led_classdev *lcdev; + struct fwnode_handle *child; + enum mt6370_led_ranges sel_range; + u32 max_uA, max_level; + const char * const states[] = { "off", "keep", "on" }; + const char *stat_str; + int ret; + + if (led->index == MT6370_VIRTUAL_MULTICOLOR) { + struct mc_subled *sub_led; + u32 num_color = 0; + + sub_led = devm_kzalloc(priv->dev, + sizeof(*sub_led) * MC_CHANNEL_NUM, + GFP_KERNEL); + if (!sub_led) + return -ENOMEM; + + fwnode_for_each_child_node(init_data->fwnode, child) { + u32 reg, color; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret || reg > MT6370_LED_ISNK3 || + priv->leds_active & BIT(reg)) + return -EINVAL; + + ret = fwnode_property_read_u32(child, "color", &color); + if (ret) { + dev_err(priv->dev, + "led %d, no color specified\n", + led->index); + return ret; + } + + priv->leds_active |= BIT(reg); + sub_led[num_color].color_index = color; + sub_led[num_color].channel = reg; + num_color++; + } + + if (num_color < 2) { + dev_err(priv->dev, + "Multicolor must include 2 or more led channel\n"); + return -EINVAL; + } + + led->mc.num_colors = num_color; + led->mc.subled_info = sub_led; + + lcdev = &led->mc.led_cdev; + lcdev->brightness_set_blocking = mt6370_mc_brightness_set; + lcdev->blink_set = mt6370_mc_blink_set; + lcdev->pattern_set = mt6370_mc_pattern_set; + lcdev->pattern_clear = mt6370_mc_pattern_clear; + } else { + lcdev = &led->isink; + lcdev->brightness_set_blocking = mt6370_isnk_brightness_set; + lcdev->blink_set = mt6370_isnk_blink_set; + lcdev->pattern_set = mt6370_isnk_pattern_set; + lcdev->pattern_clear = mt6370_isnk_pattern_clear; + } + + ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", + &max_uA); + if (ret) { + dev_warn(priv->dev, + "Not specified led-max-microamp, config to the minimum\n"); + max_uA = 0; + } + + if (led->index == MT6370_LED_ISNK4) + sel_range = R_LED4_CURR; + else + sel_range = R_LED123_CURR; + + linear_range_get_selector_within(priv->ranges + sel_range, max_uA, + &max_level); + + lcdev->max_brightness = max_level; + + fwnode_property_read_string(init_data->fwnode, "linux,default-trigger", + &lcdev->default_trigger); + + if (!fwnode_property_read_string(init_data->fwnode, "default-state", + &stat_str)) { + ret = match_string(states, ARRAY_SIZE(states), stat_str); + if (ret < 0) + ret = STATE_OFF; + + led->default_state = ret; + } + + return 0; +} + +static int mt6370_isnk_init_default_state(struct mt6370_led *led) +{ + struct mt6370_priv *priv = led->priv; + unsigned int enable, level; + int ret; + + ret = mt6370_get_led_brightness(priv, led->index, &level); + if (ret) + return ret; + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + return ret; + + if (!(enable & MT6370_CHEN_BIT(led->index))) + level = LED_OFF; + + switch (led->default_state) { + case STATE_ON: + led->isink.brightness = led->isink.max_brightness; + break; + case STATE_KEEP: + led->isink.brightness = min(level, led->isink.max_brightness); + break; + default: + led->isink.brightness = LED_OFF; + } + + return mt6370_isnk_brightness_set(&led->isink, led->isink.brightness); +} + +static int mt6370_led_register(struct device *parent, struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct mt6370_priv *priv = led->priv; + int ret; + + if (led->index == MT6370_VIRTUAL_MULTICOLOR) { + ret = mt6370_mc_brightness_set(&led->mc.led_cdev, LED_OFF); + if (ret) { + dev_err(parent, "Couldn't set multicolor brightness\n"); + return ret; + } + + ret = devm_led_classdev_multicolor_register_ext(parent, + &led->mc, + init_data); + if (ret) { + dev_err(parent, "Couldn't register multicolor\n"); + return ret; + } + } else { + if (led->index == MT6370_LED_ISNK4) { + ret = regmap_field_write(priv->fields[F_CHGIND_EN], 1); + if (ret) { + dev_err(parent, "Failed to set CHRIND to SW\n"); + return ret; + } + } + + ret = mt6370_isnk_init_default_state(led); + if (ret) { + dev_err(parent, "Failed to init %d isnk state\n", + led->index); + return ret; + } + + ret = devm_led_classdev_register_ext(parent, &led->isink, + init_data); + if (ret) { + dev_err(parent, "Couldn't register isink %d\n", + led->index); + return ret; + } + } + + return 0; +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + unsigned int devinfo, vid; + int ret; + + ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &devinfo); + if (ret) + return ret; + + vid = FIELD_GET(MT6370_VENID_MASK, devinfo); + if (vid == 0x9 || vid == 0xb) { + priv->reg_fields = mt6372_reg_fields; + priv->ranges = mt6372_led_ranges; + priv->is_mt6372 = true; + } else { + priv->reg_fields = common_reg_fields; + priv->ranges = common_led_ranges; + } + + return 0; +} + +static int mt6370_leds_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + struct fwnode_handle *child; + size_t count; + int i = 0, ret; + + count = device_get_child_node_count(&pdev->dev); + if (!count || count > MT6370_MAX_LEDS) { + dev_err(&pdev->dev, + "No child node or node count over max led number %zu\n", + count); + return -EINVAL; + } + + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, leds, count), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->leds_count = count; + priv->dev = &pdev->dev; + mutex_init(&priv->lock); + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "Failed to get parent regmap\n"); + + ret = mt6370_check_vendor_info(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to check vendor info (%d)\n", ret); + return ret; + } + + ret = devm_regmap_field_bulk_alloc(&pdev->dev, priv->regmap, + priv->fields, priv->reg_fields, + F_MAX_FIELDS); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to allocate regmap field\n"); + + device_for_each_child_node(&pdev->dev, child) { + struct mt6370_led *led = priv->leds + i++; + struct led_init_data init_data = { .fwnode = child, }; + u32 reg, color; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to parse reg property\n"); + + if (reg >= MT6370_MAX_LEDS) + return dev_err_probe(&pdev->dev, -EINVAL, + "Error reg property number\n"); + + ret = fwnode_property_read_u32(child, "color", &color); + if (ret) { + dev_err(&pdev->dev, "Failed to parse color property\n"); + return ret; + } + + if (color == LED_COLOR_ID_RGB || color == LED_COLOR_ID_MULTI) + reg = MT6370_VIRTUAL_MULTICOLOR; + + if (priv->leds_active & BIT(reg)) + return dev_err_probe(&pdev->dev, -EINVAL, + "Duplicat reg property\n"); + + priv->leds_active |= BIT(reg); + + led->index = reg; + led->priv = priv; + + ret = mt6370_init_led_properties(led, &init_data); + if (ret) + return ret; + + ret = mt6370_led_register(&pdev->dev, led, &init_data); + if (ret) + return ret; + } + + return 0; +} + +static const struct of_device_id mt6370_rgbled_device_table[] = { + { .compatible = "mediatek,mt6370-indicator", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_rgbled_device_table); + +static struct platform_driver mt6370_rgbled_driver = { + .driver = { + .name = "mt6370-indicator", + .of_match_table = mt6370_rgbled_device_table, + }, + .probe = mt6370_leds_probe, +}; +module_platform_driver(mt6370_rgbled_driver); + +MODULE_AUTHOR("Alice Chen "); +MODULE_DESCRIPTION("MediaTek MT6370 RGB Led Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Fri Jul 15 11:26:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919074 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D2E45C433EF for ; Fri, 15 Jul 2022 11:28:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234375AbiGOL2o (ORCPT ); Fri, 15 Jul 2022 07:28:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46362 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234394AbiGOL2F (ORCPT ); Fri, 15 Jul 2022 07:28:05 -0400 Received: from mail-pf1-x433.google.com (mail-pf1-x433.google.com [IPv6:2607:f8b0:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9C2F289A84; Fri, 15 Jul 2022 04:27:33 -0700 (PDT) Received: by mail-pf1-x433.google.com with SMTP id y9so4401177pff.12; Fri, 15 Jul 2022 04:27:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=QkdQEiG9AVAXvkMpLU+05iZtC0aMuH0DXbcZYZ9awd4=; b=JDfr6KQNcL96cWVpHPsKgrwGwF/4z8IhoIM9ZrW6KxKyP0Q7dVMRnWSi1cYJm8o1jA TTGy0pkunUxusfcOBYx/1odQBo6qG3/fselB8zgQrAlKgiNx+/OiWkHeh28vGQWhB+8Z j++IgxJ0y0W8w+cjpJnm0ZcBHXQLpFqpnwkCKWc9zrLFwYanijswhDUWGSxeuym1o7kv 0J0NzGYSrbYfDH6wUib3GtqS16Ikfqy3EC0mDC8c4uWb9DaR8jZgoDfKaQVxszC98apl jymhjQ83Kx6A73O9mbk0c1d4yznnT6Y55NWbPZX7XoyEurahNHigWP2pvtP1/lcaJ0J7 ffPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=QkdQEiG9AVAXvkMpLU+05iZtC0aMuH0DXbcZYZ9awd4=; b=UTCYA1IYVbDKbIQcY1jkJxdUqLPAM/IZr1k18LS/fIt+olTV5ZS1xE1F+SLT4SgG6m RMds9Cvf4sHJvqkPRPUWDXaSRYI8cG5JjJnMSbO0JwWu/kcqr4/NFa82KL3NQYy11PQB zoCn3hc9NCUp3BG+wFpQtJVPgBaiKhkeHck80Ijc4ggDwL+nQndJ6QnzsYIYxuEjr+5M iYmU0WM1Io7YoOXuJMkjl4OALKjBqIhW3VJ51QS+1pVyDXkgZDfxbeXdOiiPQcqD6LqE wwdwg4pJiPG5/yy6YSUkOlYTtsXi7aDai3eAi2haCL1+p4bMWTdZfHadNHfUSiqHaq1f pVtQ== X-Gm-Message-State: AJIora89k9oQzxBoj7JVul7yT373j4lCb0Oq5xJOmqXDa/4ztiYP5GnU biIDWJJpsQ8XIQOpVATOGfk= X-Google-Smtp-Source: AGRyM1tQBmmlYqcGhM173BIy3f2dsWAIeCo42jG+5FQYtSKSei3rF8/tz5ZOkz31bC9Y3/faIDLvOQ== X-Received: by 2002:a63:ee14:0:b0:414:1a88:3b96 with SMTP id e20-20020a63ee14000000b004141a883b96mr11510467pgi.364.1657884452754; Fri, 15 Jul 2022 04:27:32 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.27.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:27:32 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v5 12/13] leds: flashlight: mt6370: Add MediaTek MT6370 flashlight support Date: Fri, 15 Jul 2022 19:26:06 +0800 Message-Id: <20220715112607.591-13-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: Alice Chen The MediaTek MT6370 is a highly-integrated smart power management IC, whichincludes a single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C & Power Delivery (PD) controller, dual Flash LED current sources, a RGB LED driver, a backlight WLED driver, a display bias driver and a general LDO for portable devices. The Flash LED in MT6370 has 2 channel and support torch/strobe mode. The commit add the support of MT6370 FLASH LED. Signed-off-by: Alice Chen --- v5 - Refine descriptions. - Refine the macro name. - Refine the brackets and blanks. --- drivers/leds/flash/Kconfig | 12 + drivers/leds/flash/Makefile | 1 + drivers/leds/flash/leds-mt6370-flash.c | 661 +++++++++++++++++++++++++++++++++ 3 files changed, 674 insertions(+) create mode 100644 drivers/leds/flash/leds-mt6370-flash.c diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig index d3eb689..d5761ed 100644 --- a/drivers/leds/flash/Kconfig +++ b/drivers/leds/flash/Kconfig @@ -90,4 +90,16 @@ config LEDS_SGM3140 This option enables support for the SGM3140 500mA Buck/Boost Charge Pump LED Driver. +config LEDS_MT6370_FLASHLIGHT + tristate "Flash LED Support for MediaTek MT6370 PMIC" + depends on LEDS_CLASS + depends on MFD_MT6370 + help + Support 2 channels and torch/strobe mode. + Say Y here to enable support for + MT6370_FLASH_LED device. + + This driver can also be built as a module. If so, the module + will be called "leds-mt6370-flash". + endif # LEDS_CLASS_FLASH diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile index 0acbddc..4c4c171 100644 --- a/drivers/leds/flash/Makefile +++ b/drivers/leds/flash/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o obj-$(CONFIG_LEDS_RT4505) += leds-rt4505.o obj-$(CONFIG_LEDS_RT8515) += leds-rt8515.o obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o +obj-$(CONFIG_LEDS_MT6370_FLASHLIGHT) += leds-mt6370-flash.o diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c new file mode 100644 index 0000000..eccda69 --- /dev/null +++ b/drivers/leds/flash/leds-mt6370-flash.c @@ -0,0 +1,661 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: Alice Chen +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +enum { + MT6370_LED_FLASH1, + MT6370_LED_FLASH2, + MT6370_MAX_LEDS +}; + +/* Virtual definition for multicolor */ + +#define MT6370_REG_FLEDEN 0x17E +#define MT6370_REG_STRBTO 0x173 +#define MT6370_REG_CHGSTAT2 0x1D1 +#define MT6370_REG_FLEDSTAT1 0x1D9 +#define MT6370_REG_FLEDISTRB(_id) (0x174 + 4 * _id) +#define MT6370_REG_FLEDITOR(_id) (0x175 + 4 * _id) +#define MT6370_ITORCH_MASK GENMASK(4, 0) +#define MT6370_ISTROBE_MASK GENMASK(6, 0) +#define MT6370_STRBTO_MASK GENMASK(6, 0) +#define MT6370_TORCHEN_MASK BIT(3) +#define MT6370_STROBEN_MASK BIT(2) +#define MT6370_FLCSEN_MASK(_id) BIT(MT6370_LED_FLASH2 - _id) +#define MT6370_FLCSEN_MASK_ALL (BIT(0) | BIT(1)) +#define MT6370_FLEDCHGVINOVP_MASK BIT(3) +#define MT6370_FLED1STRBTO_MASK BIT(11) +#define MT6370_FLED2STRBTO_MASK BIT(10) +#define MT6370_FLED1STRB_MASK BIT(9) +#define MT6370_FLED2STRB_MASK BIT(8) +#define MT6370_FLED1SHORT_MASK BIT(7) +#define MT6370_FLED2SHORT_MASK BIT(6) +#define MT6370_FLEDLVF_MASK BIT(3) + +#define MT6370_LED_JOINT 2 +#define MT6370_RANGE_FLED_REG 4 +#define MT6370_ITORCH_MIN_UA 25000 +#define MT6370_ITORCH_STEP_UA 12500 +#define MT6370_ITORCH_MAX_UA 400000 +#define MT6370_ITORCH_DOUBLE_MAX_UA 800000 +#define MT6370_ISTRB_MIN_UA 50000 +#define MT6370_ISTRB_STEP_UA 12500 +#define MT6370_ISTRB_MAX_UA 1500000 +#define MT6370_ISTRB_DOUBLE_MAX_UA 3000000 +#define MT6370_STRBTO_MIN_US 64000 +#define MT6370_STRBTO_STEP_US 32000 +#define MT6370_STRBTO_MAX_US 2432000 + +#define STATE_OFF 0 +#define STATE_KEEP 1 +#define STATE_ON 2 + +#define to_mt6370_led(ptr, member) container_of(ptr, struct mt6370_led, member) + +struct mt6370_led { + struct led_classdev_flash flash; + struct v4l2_flash *v4l2_flash; + struct mt6370_priv *priv; + u32 led_no; + u32 default_state; +}; + +struct mt6370_priv { + struct device *dev; + struct regmap *regmap; + struct mutex lock; + unsigned int fled_strobe_used; + unsigned int fled_torch_used; + unsigned int leds_active; + unsigned int leds_count; + struct mt6370_led leds[]; +}; + +static int mt6370_torch_brightness_set(struct led_classdev *lcdev, + enum led_brightness level) +{ + struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev); + struct mt6370_priv *priv = led->priv; + u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ? + MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask; + u32 val = level ? led_enable_mask : 0; + u32 prev = priv->fled_torch_used, curr; + int ret, i; + + mutex_lock(&priv->lock); + + /* + * Only one set of flash control logic, + * use the flag to avoid strobe is currently used. + */ + if (priv->fled_strobe_used) { + dev_warn(lcdev->dev, "Please disable strobe first [%d]\n", + priv->fled_strobe_used); + ret = -EBUSY; + goto unlock; + } + + if (level) + curr = prev | BIT(led->led_no); + else + curr = prev & ~BIT(led->led_no); + + if (curr) + val |= MT6370_TORCHEN_MASK; + + if (level) { + level -= 1; + if (led->led_no == MT6370_LED_JOINT) { + int flevel[MT6370_MAX_LEDS]; + + flevel[0] = level / 2; + flevel[1] = level - flevel[0]; + for (i = 0; i < MT6370_MAX_LEDS; i++) { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDITOR(i), + MT6370_ITORCH_MASK, flevel[i]); + if (ret) + goto unlock; + } + } else { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDITOR(led->led_no), + MT6370_ITORCH_MASK, level); + if (ret) + goto unlock; + } + } + + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, + enable_mask, val); + if (ret) + goto unlock; + + priv->fled_torch_used = curr; + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static int mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev, + u32 brightness) +{ + /* + * Due to the current spike when turning on flash, + * let brightness be kept by the framework. + * This empty function is used to + * prevent led_classdev_flash register ops check failure. + */ + return 0; +} + +static int _mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev, + u32 brightness) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s = &fl_cdev->brightness; + u32 val = (brightness - s->min) / s->step; + int ret, i; + + if (led->led_no == MT6370_LED_JOINT) { + int flevel[MT6370_MAX_LEDS]; + + flevel[0] = val / 2; + flevel[1] = val - flevel[0]; + for (i = 0; i < MT6370_MAX_LEDS; i++) { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDISTRB(i), + MT6370_ISTROBE_MASK, flevel[i]); + if (ret) + return ret; + } + } else { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDISTRB(led->led_no), + MT6370_ISTROBE_MASK, val); + } + return ret; +} + +static int mt6370_strobe_set(struct led_classdev_flash *fl_cdev, bool state) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + struct led_classdev *lcdev = &fl_cdev->led_cdev; + struct led_flash_setting *s = &fl_cdev->brightness; + u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ? + MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 enable_mask = MT6370_STROBEN_MASK | led_enable_mask; + u32 val = state ? led_enable_mask : 0; + u32 prev = priv->fled_strobe_used, curr; + int ret; + + mutex_lock(&priv->lock); + + /* + * Only one set of flash control logic, + * use the flag to avoid torch is currently used + */ + if (priv->fled_torch_used) { + dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n", + priv->fled_torch_used); + ret = -EBUSY; + goto unlock; + } + + if (state) + curr = prev | BIT(led->led_no); + else + curr = prev & ~BIT(led->led_no); + + if (curr) + val |= MT6370_STROBEN_MASK; + + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask, + val); + if (ret) { + dev_err(lcdev->dev, "[%d] control current source %d fail\n", + led->led_no, state); + goto unlock; + } + + /* + * If the flash need to be on, + * config the flash current ramping up to the setting value. + * Else, always recover back to the minimum one. + */ + ret = _mt6370_flash_brightness_set(fl_cdev, state ? s->val : s->min); + if (ret) + goto unlock; + + /* For the flash turn on/off, need to wait HW ramping up/down time + * 5ms/500us to prevent the unexpected problem. + */ + + if (!prev && curr) + usleep_range(5000, 6000); + else if (prev && !curr) + udelay(500); + + priv->fled_strobe_used = curr; + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static int mt6370_strobe_get(struct led_classdev_flash *fl_cdev, bool *state) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + + mutex_lock(&priv->lock); + *state = !!(priv->fled_strobe_used & BIT(led->led_no)); + mutex_unlock(&priv->lock); + + return 0; +} + +static int mt6370_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s = &fl_cdev->timeout; + u32 val = (timeout - s->min) / s->step; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_update_bits(priv->regmap, MT6370_REG_STRBTO, + MT6370_STRBTO_MASK, val); + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + u16 fled_stat; + unsigned int chg_stat, strobe_timeout_mask, fled_short_mask; + u32 rfault = 0; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_read(priv->regmap, MT6370_REG_CHGSTAT2, &chg_stat); + if (ret) + goto unlock; + + ret = regmap_raw_read(priv->regmap, MT6370_REG_FLEDSTAT1, &fled_stat, + sizeof(fled_stat)); + if (ret) + goto unlock; + + switch (led->led_no) { + case MT6370_LED_FLASH1: + strobe_timeout_mask = MT6370_FLED1STRBTO_MASK; + fled_short_mask = MT6370_FLED1SHORT_MASK; + break; + + case MT6370_LED_FLASH2: + strobe_timeout_mask = MT6370_FLED2STRBTO_MASK; + fled_short_mask = MT6370_FLED2SHORT_MASK; + break; + + case MT6370_LED_JOINT: + strobe_timeout_mask = MT6370_FLED1STRBTO_MASK | + MT6370_FLED2STRBTO_MASK; + fled_short_mask = MT6370_FLED1SHORT_MASK | + MT6370_FLED2SHORT_MASK; + } + + if (chg_stat & MT6370_FLEDCHGVINOVP_MASK) + rfault |= LED_FAULT_INPUT_VOLTAGE; + + if (fled_stat & strobe_timeout_mask) + rfault |= LED_FAULT_TIMEOUT; + + if (fled_stat & fled_short_mask) + rfault |= LED_FAULT_SHORT_CIRCUIT; + + if (fled_stat & MT6370_FLEDLVF_MASK) + rfault |= LED_FAULT_UNDER_VOLTAGE; + + *fault = rfault; +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static const struct led_flash_ops mt6370_flash_ops = { + .flash_brightness_set = mt6370_flash_brightness_set, + .strobe_set = mt6370_strobe_set, + .strobe_get = mt6370_strobe_get, + .timeout_set = mt6370_timeout_set, + .fault_get = mt6370_fault_get, +}; + +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) +static int mt6370_flash_external_strobe_set(struct v4l2_flash *v4l2_flash, + bool enable) +{ + struct led_classdev_flash *flash = v4l2_flash->fled_cdev; + struct mt6370_led *led = to_mt6370_led(flash, flash); + struct mt6370_priv *priv = led->priv; + u32 mask = (led->led_no == MT6370_LED_JOINT) ? MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 val = enable ? mask : 0; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, mask, val); + if (ret) + goto unlock; + + if (enable) + priv->fled_strobe_used |= BIT(led->led_no); + else + priv->fled_strobe_used &= ~BIT(led->led_no); + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static const struct v4l2_flash_ops v4l2_flash_ops = { + .external_strobe_set = mt6370_flash_external_strobe_set, +}; + +static void mt6370_init_v4l2_flash_config(struct mt6370_led *led, + struct v4l2_flash_config *config) +{ + struct led_classdev *lcdev; + struct led_flash_setting *s = &config->intensity; + + lcdev = &led->flash.led_cdev; + + s->min = MT6370_ITORCH_MIN_UA; + s->step = MT6370_ITORCH_STEP_UA; + s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step; + + config->has_external_strobe = 1; + strscpy(config->dev_name, lcdev->dev->kobj.name, + sizeof(config->dev_name)); + + config->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT | + LED_FAULT_INPUT_VOLTAGE | + LED_FAULT_UNDER_VOLTAGE; +} +#else +static const struct v4l2_flash_ops v4l2_flash_ops; +static void mt6370_init_v4l2_flash_config(struct mt6370_led *led, + struct v4l2_flash_config *config) +{ +} +#endif + +static int mt6370_led_register(struct device *parent, struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct v4l2_flash_config v4l2_config = {0}; + int ret; + + ret = devm_led_classdev_flash_register_ext(parent, &led->flash, + init_data); + if (ret) { + dev_err(parent, "Couldn't register flash %d\n", led->led_no); + return ret; + } + + mt6370_init_v4l2_flash_config(led, &v4l2_config); + led->v4l2_flash = v4l2_flash_init(parent, init_data->fwnode, + &led->flash, &v4l2_flash_ops, + &v4l2_config); + if (IS_ERR(led->v4l2_flash)) { + dev_err(parent, "Failed to register %d v4l2 sd\n", led->led_no); + return PTR_ERR(led->v4l2_flash); + } + + return 0; +} + +static u32 clamp_align(u32 val, u32 min, u32 max, u32 step) +{ + u32 retval; + + retval = clamp_val(val, min, max); + if (step > 1) + retval = rounddown(retval - min, step) + min; + + return retval; +} + +static int mt6370_init_flash_properties(struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct led_classdev_flash *flash = &led->flash; + struct led_classdev *lcdev = &flash->led_cdev; + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s; + u32 sources[MT6370_MAX_LEDS]; + u32 max_uA, val; + int i, ret, num; + + num = fwnode_property_count_u32(init_data->fwnode, "led-sources"); + if (num < 1 || num > MT6370_MAX_LEDS) { + dev_err(priv->dev, + "Not specified or wrong number of led-sources\n"); + return -EINVAL; + } + + ret = fwnode_property_read_u32_array(init_data->fwnode, + "led-sources", sources, num); + if (ret) + return ret; + + for (i = 0; i < num; i++) { + if (sources[i] >= MT6370_MAX_LEDS) + return -EINVAL; + if (priv->leds_active & BIT(sources[i])) + return -EINVAL; + priv->leds_active |= BIT(sources[i]); + + } + led->led_no = (num == MT6370_MAX_LEDS) ? MT6370_LED_JOINT : + sources[0]; + + max_uA = (num == 2) ? MT6370_ITORCH_DOUBLE_MAX_UA : MT6370_ITORCH_MAX_UA; + ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", + &val); + if (ret) { + dev_warn(priv->dev, + "Not specified led-max-microamp, config to the minimum\n"); + val = MT6370_ITORCH_MIN_UA; + } else { + val = clamp_align(val, MT6370_ITORCH_MIN_UA, max_uA, + MT6370_ITORCH_STEP_UA); + } + + lcdev->max_brightness = (val - MT6370_ITORCH_MIN_UA) / + MT6370_ITORCH_STEP_UA + 1; + lcdev->brightness_set_blocking = mt6370_torch_brightness_set; + lcdev->flags |= LED_DEV_CAP_FLASH; + + max_uA = (num == 2) ? MT6370_ISTRB_DOUBLE_MAX_UA : MT6370_ISTRB_MAX_UA; + ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", + &val); + if (ret) { + dev_warn(priv->dev, + "Not specified flash-max-microamp, config to the minimum\n"); + val = MT6370_ISTRB_MIN_UA; + } else { + val = clamp_align(val, MT6370_ISTRB_MIN_UA, max_uA, + MT6370_ISTRB_STEP_UA); + } + + s = &flash->brightness; + s->min = MT6370_ISTRB_MIN_UA; + s->step = MT6370_ISTRB_STEP_UA; + s->val = s->max = val; + + /* + * Always configure as min level when off to + * prevent flash current spike + */ + ret = _mt6370_flash_brightness_set(flash, s->min); + if (ret) + return ret; + + ret = fwnode_property_read_u32(init_data->fwnode, + "flash-max-timeout-us", &val); + if (ret) { + dev_warn(priv->dev, + "Not specified flash-max-timeout-us, config to the minimum\n"); + val = MT6370_STRBTO_MIN_US; + } else { + val = clamp_align(val, MT6370_STRBTO_MIN_US, MT6370_STRBTO_MAX_US, + MT6370_STRBTO_STEP_US); + } + + s = &flash->timeout; + s->min = MT6370_STRBTO_MIN_US; + s->step = MT6370_STRBTO_STEP_US; + s->val = s->max = val; + + flash->ops = &mt6370_flash_ops; + + return 0; +} + +static int mt6370_init_common_properties(struct mt6370_led *led, + struct led_init_data *init_data) +{ + const char * const states[] = { "off", "keep", "on" }; + const char *str = states[STATE_OFF]; + int ret; + + fwnode_property_read_string(init_data->fwnode, "default-state", &str); + ret = match_string(states, ARRAY_SIZE(states), str); + if (ret >= 0) + led->default_state = ret; + + return 0; +} + +static void mt6370_v4l2_flash_release(struct mt6370_priv *priv) +{ + int i; + + for (i = 0; i < priv->leds_count; i++) { + struct mt6370_led *led = priv->leds + i; + + if (led->v4l2_flash) + v4l2_flash_release(led->v4l2_flash); + } +} + +static int mt6370_led_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + struct fwnode_handle *child; + size_t count; + int i = 0, ret; + + count = device_get_child_node_count(&pdev->dev); + if (!count || count > MT6370_MAX_LEDS) + return dev_err_probe(&pdev->dev, -EINVAL, + "No child node or node count over max led number %zu\n", + count); + + priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, count), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->leds_count = count; + priv->dev = &pdev->dev; + mutex_init(&priv->lock); + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "Failed to get parent regmap\n"); + + device_for_each_child_node(&pdev->dev, child) { + struct mt6370_led *led = priv->leds + i; + struct led_init_data init_data = { .fwnode = child, }; + + led->priv = priv; + ret = mt6370_init_common_properties(led, &init_data); + if (ret) + goto out_flash_release; + + ret = mt6370_init_flash_properties(led, &init_data); + + if (ret) + goto out_flash_release; + + ret = mt6370_led_register(&pdev->dev, led, &init_data); + if (ret) + goto out_flash_release; + + i++; + } + + platform_set_drvdata(pdev, priv); + return 0; + +out_flash_release: + mt6370_v4l2_flash_release(priv); + return ret; +} + +static int mt6370_led_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + + mt6370_v4l2_flash_release(priv); + return 0; +} + +static const struct of_device_id __maybe_unused mt6370_led_of_id[] = { + { .compatible = "mediatek,mt6370-flashlight", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_led_of_id); + +static struct platform_driver mt6370_led_driver = { + .driver = { + .name = "mt6370-flashlight", + .of_match_table = mt6370_led_of_id, + }, + .probe = mt6370_led_probe, + .remove = mt6370_led_remove, +}; +module_platform_driver(mt6370_led_driver); + +MODULE_AUTHOR("Alice Chen "); +MODULE_DESCRIPTION("MT6370 FLASH LED Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Fri Jul 15 11:26:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12919117 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 763BBCCA47C for ; Fri, 15 Jul 2022 11:29:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234297AbiGOL3J (ORCPT ); Fri, 15 Jul 2022 07:29:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46186 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234522AbiGOL2k (ORCPT ); Fri, 15 Jul 2022 07:28:40 -0400 Received: from mail-pf1-x42b.google.com (mail-pf1-x42b.google.com [IPv6:2607:f8b0:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E037C89E89; Fri, 15 Jul 2022 04:27:43 -0700 (PDT) Received: by mail-pf1-x42b.google.com with SMTP id b133so636393pfb.6; Fri, 15 Jul 2022 04:27:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CP+vaJpVQjG+FSy8YpXt902GbJyD5d2vCEqArJODpX8=; b=I3orQZU8wezre3N/4NneP6D5O9AhmuA+6TzikynF607lL/3JfeTO5pKrreTG03hg7y KHLAqbfKAuIn4MSX6b7BpFqvLGAVwl+d4QrCEVZdwFyPRRfmqzWsgbzMSQ1WN+4xAlPM 5h9jMXCvt7hvhV8n395qsNDnvOObDNKBoTJ64IYWg5lOzXQ3OxfGKyCnadwlK6IzHkku ZNif6hAmiLzHYcV2Nqvo7xrtQRW5rJr1eLAXagwXpI5WEa0/0UYiVcCVnbcKTXaHlb6j Yk25+nLumVIMMeK7V09fLTT9dsYI1aWZBSlADkAVW8NsoFWnkjvpQWBCe0lvsFaFOXl6 +5kQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CP+vaJpVQjG+FSy8YpXt902GbJyD5d2vCEqArJODpX8=; b=EXA4So5QUGlHYDnA0yMej/durgfcvw0jMQSm8+QwYA5kvz6CpnnZirXGgvkADEYeWS 32JjPIfjlhd0PQK7iZPsBGAraobFT+4ulMCi75q78gKwwhHmGrrwTbYdxBMEzDd/hhg/ TtWLZ1qQ+SqCioJsqMWwnAXJzb+Mu/jdfO6DPTrxOCi66oYnTUdb0cEzYhr3zljbH838 BJUXKCsjOliWEhyzzwn7GeSESf54eN5sT9Lz3yV8wfIXQWPsIAplNUlicdfNyZhhaJEx mHxY87//zoueZOg5YnzLZa4tEOvkBykT5gASovCXd/8KgH53N6llyQOpFhpWPXrgunpm 2pZA== X-Gm-Message-State: AJIora8aHYwGhdIr4Dr9TYAR3JqjLhfXVJvb6lnkTVLcctFsZ2gSTxvH fg0qpWOuD1CRKMz6eASMbRw= X-Google-Smtp-Source: AGRyM1sxTZ1zZxGwFhvOExqgUPUa8bzLV8nDTIvSlsJ3ycJrXGo/wiFZhKvnMO5xoA5Cxy8XSFzdxw== X-Received: by 2002:a63:1921:0:b0:412:407f:f012 with SMTP id z33-20020a631921000000b00412407ff012mr11446266pgl.125.1657884458423; Fri, 15 Jul 2022 04:27:38 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-159-86.emome-ip.hinet.net. [42.72.159.86]) by smtp.gmail.com with ESMTPSA id a5-20020aa78e85000000b00525b61f4792sm3550604pfr.109.2022.07.15.04.27.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jul 2022 04:27:38 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v5 13/13] video: backlight: mt6370: Add MediaTek MT6370 support Date: Fri, 15 Jul 2022 19:26:07 +0800 Message-Id: <20220715112607.591-14-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220715112607.591-1-peterwu.pub@gmail.com> References: <20220715112607.591-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org From: ChiaEn Wu MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight driver, display bias voltage supply, one general purpose LDO, and the USB Type-C & PD controller complies with the latest USB Type-C and PD standards. This adds support for MediaTek MT6370 Backlight driver. It's commonly used to drive the display WLED. There are 4 channels inside, and each channel supports up to 30mA of current capability with 2048 current steps in exponential or linear mapping curves. Signed-off-by: ChiaEn Wu --- v5 - Add missed - Add struct device *dev in probe() to make code cleaning - Remove useless including header file , - Remove useless variable uasage in mt6370_init_backlight_properties() - Remove redundant checking enable_gpio in mt6370_bl_update_status() - Remove redundant parentheses in mt6370_bl_get_brightness() - Revise the description of Kconfig help text - Revise the calculation of hys_th_steps --- drivers/video/backlight/Kconfig | 12 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/mt6370-backlight.c | 339 +++++++++++++++++++++++++++++ 3 files changed, 352 insertions(+) create mode 100644 drivers/video/backlight/mt6370-backlight.c diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index a003e02..846dbe7 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925 If you have a LCD backlight connected to the WLED output of MAX8925 WLED output, say Y here to enable this driver. +config BACKLIGHT_MT6370 + tristate "MediaTek MT6370 Backlight Driver" + depends on MFD_MT6370 + help + This enables support for Mediatek MT6370 Backlight driver. + It's commonly used to drive the display WLED. There are 4 channels + inside, and each channel supports up to 30mA of current capability + with 2048 current steps in exponential or linear mapping curves. + + This driver can also be built as a module. If so, the module + will be called "mt6370-backlight". + config BACKLIGHT_APPLE tristate "Apple Backlight Driver" depends on X86 && ACPI diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index cae2c83..e815f3f 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o +obj-$(CONFIG_BACKLIGHT_MT6370) += mt6370-backlight.o obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c new file mode 100644 index 0000000..ba00a8f --- /dev/null +++ b/drivers/video/backlight/mt6370-backlight.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiaEn Wu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6370_REG_DEV_INFO 0x100 +#define MT6370_REG_BL_EN 0x1A0 +#define MT6370_REG_BL_BSTCTRL 0x1A1 +#define MT6370_REG_BL_PWM 0x1A2 +#define MT6370_REG_BL_DIM2 0x1A4 + +#define MT6370_VENID_MASK GENMASK(7, 4) +#define MT6370_BL_EXT_EN_MASK BIT(7) +#define MT6370_BL_EN_MASK BIT(6) +#define MT6370_BL_CONFIG_MASK BIT(0) +#define MT6370_BL_CH_MASK GENMASK(5, 2) +#define MT6370_BL_DIM2_MASK GENMASK(2, 0) +#define MT6370_BL_DUMMY_6372_MASK GENMASK(2, 0) +#define MT6370_BL_DIM2_6372_SHIFT 3 +#define MT6370_BL_PWM_EN_MASK BIT(7) +#define MT6370_BL_PWM_HYS_EN_MASK BIT(2) +#define MT6370_BL_PWM_HYS_SEL_MASK GENMASK(1, 0) +#define MT6370_BL_OVP_EN_MASK BIT(7) +#define MT6370_BL_OVP_SEL_MASK GENMASK(6, 5) +#define MT6370_BL_OC_EN_MASK BIT(3) +#define MT6370_BL_OC_SEL_MASK GENMASK(2, 1) + +#define MT6370_BL_PWM_HYS_TH_MIN_STEP 1 +#define MT6370_BL_PWM_HYS_TH_MAX_STEP 64 +#define MT6370_BL_OVP_MIN_UV 17000000 +#define MT6370_BL_OVP_MAX_UV 29000000 +#define MT6370_BL_OVP_STEP_UV 4000000 +#define MT6370_BL_OCP_MIN_UA 900000 +#define MT6370_BL_OCP_MAX_UA 1800000 +#define MT6370_BL_OCP_STEP_UA 300000 +#define MT6370_BL_MAX_BRIGHTNESS 2048 +#define MT6370_BL_MAX_CH 15 + +enum { + MT6370_VID_COMMON = 0, + MT6370_VID_6372, +}; + +struct mt6370_priv { + int vid_type; + struct backlight_device *bl; + struct device *dev; + struct gpio_desc *enable_gpio; + struct regmap *regmap; +}; + +static int mt6370_bl_update_status(struct backlight_device *bl_dev) +{ + struct mt6370_priv *priv = bl_get_data(bl_dev); + int brightness = backlight_get_brightness(bl_dev); + unsigned int enable_val; + u8 brightness_val[2]; + int ret; + + if (brightness) { + brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK; + brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK); + + /* + * To make MT6372 using 14 bits to control the brightness + * backward compatible with 11 bits brightness control + * (like MT6370 and MT6371 do), we left shift the value + * and pad with 1 to remaining bits. Hence, the MT6372's + * backlight brightness will be almost the same as MT6370's + * and MT6371's. + */ + if (priv->vid_type == MT6370_VID_6372) { + brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT; + brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK; + } + + ret = regmap_raw_write(priv->regmap, MT6370_REG_BL_DIM2, + brightness_val, sizeof(brightness_val)); + if (ret) + return ret; + } + + gpiod_set_value(priv->enable_gpio, brightness ? 1 : 0); + + enable_val = brightness ? MT6370_BL_EN_MASK : 0; + return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN, + MT6370_BL_EN_MASK, enable_val); +} + +static int mt6370_bl_get_brightness(struct backlight_device *bl_dev) +{ + struct mt6370_priv *priv = bl_get_data(bl_dev); + unsigned int enable; + u8 brightness_val[2]; + int brightness, ret; + + ret = regmap_read(priv->regmap, MT6370_REG_BL_EN, &enable); + if (ret) + return ret; + + if (!(enable & MT6370_BL_EN_MASK)) + return 0; + + ret = regmap_raw_read(priv->regmap, MT6370_REG_BL_DIM2, + brightness_val, sizeof(brightness_val)); + if (ret) + return ret; + + if (priv->vid_type == MT6370_VID_6372) + brightness_val[0] >>= MT6370_BL_DIM2_6372_SHIFT; + + brightness = brightness_val[1] << fls(MT6370_BL_DIM2_MASK); + brightness += brightness_val[0] & MT6370_BL_DIM2_MASK; + + return brightness + 1; +} + +static const struct backlight_ops mt6370_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = mt6370_bl_update_status, + .get_brightness = mt6370_bl_get_brightness, +}; + +static int mt6370_init_backlight_properties(struct mt6370_priv *priv, + struct backlight_properties *props) +{ + struct device *dev = priv->dev; + u8 prop_val; + u32 brightness, ovp_uV, ocp_uA; + unsigned int mask, val; + int ret; + + /* Vendor optional properties */ + val = 0; + if (device_property_read_bool(dev, "mediatek,bled-pwm-enable")) + val |= MT6370_BL_PWM_EN_MASK; + + if (device_property_read_bool(dev, "mediatek,bled-pwm-hys-enable")) + val |= MT6370_BL_PWM_HYS_EN_MASK; + + ret = device_property_read_u8(dev, + "mediatek,bled-pwm-hys-input-th-steps", + &prop_val); + if (!ret) { + prop_val = clamp_val(prop_val, + MT6370_BL_PWM_HYS_TH_MIN_STEP, + MT6370_BL_PWM_HYS_TH_MAX_STEP); + prop_val = prop_val <= 1 ? 0 : + prop_val <= 4 ? 1 : + prop_val <= 16 ? 2 : 3; + val |= prop_val << (ffs(MT6370_BL_PWM_HYS_SEL_MASK) - 1); + } + + ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_PWM, + val, val); + if (ret) + return ret; + + val = 0; + if (device_property_read_bool(dev, "mediatek,bled-ovp-shutdown")) + val |= MT6370_BL_OVP_EN_MASK; + + ret = device_property_read_u32(dev, "mediatek,bled-ovp-microvolt", + &ovp_uV); + if (!ret) { + ovp_uV = clamp_val(ovp_uV, MT6370_BL_OVP_MIN_UV, + MT6370_BL_OVP_MAX_UV); + ovp_uV = DIV_ROUND_UP(ovp_uV - MT6370_BL_OVP_MIN_UV, + MT6370_BL_OVP_STEP_UV); + val |= ovp_uV << (ffs(MT6370_BL_OVP_SEL_MASK) - 1); + } + + if (device_property_read_bool(dev, "mediatek,bled-ocp-shutdown")) + val |= MT6370_BL_OC_EN_MASK; + + ret = device_property_read_u32(dev, "mediatek,bled-ocp-microamp", + &ocp_uA); + if (!ret) { + ocp_uA = clamp_val(ocp_uA, MT6370_BL_OCP_MIN_UA, + MT6370_BL_OCP_MAX_UA); + ocp_uA = DIV_ROUND_UP(ocp_uA - MT6370_BL_OCP_MIN_UA, + MT6370_BL_OCP_STEP_UA); + val |= ocp_uA << (ffs(MT6370_BL_OC_SEL_MASK) - 1); + } + + ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_BSTCTRL, + val, val); + if (ret) + return ret; + + /* Common properties */ + ret = device_property_read_u32(dev, "max-brightness", &brightness); + if (ret) + brightness = MT6370_BL_MAX_BRIGHTNESS; + + props->max_brightness = min_t(u32, brightness, MT6370_BL_MAX_BRIGHTNESS); + + ret = device_property_read_u32(dev, "default-brightness", &brightness); + if (ret) + brightness = props->max_brightness; + + props->brightness = min_t(u32, brightness, props->max_brightness); + + ret = device_property_read_u8(dev, "mediatek,bled-channel-use", + &prop_val); + if (ret) { + dev_err(dev, "mediatek,bled-channel-use DT property missing\n"); + return ret; + } + + if (!prop_val || prop_val > MT6370_BL_MAX_CH) { + dev_err(dev, + "No channel specified or over than upper bound (%d)\n", + prop_val); + return -EINVAL; + } + + mask = MT6370_BL_EXT_EN_MASK | MT6370_BL_CH_MASK; + val = prop_val << (ffs(MT6370_BL_CH_MASK) - 1); + + if (priv->enable_gpio) + val |= MT6370_BL_EXT_EN_MASK; + + return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN, mask, val); +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + /* + * MT6372 uses 14 bits to control the brightness but MT6370 and MT6371 + * use 11 bits. They are different so we have to use this function to + * check the vendor ID and use different methods to calculate the + * brightness. + */ + unsigned int dev_info, vid; + int ret; + + ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &dev_info); + if (ret) + return ret; + + vid = FIELD_GET(MT6370_VENID_MASK, dev_info); + if (vid == 0x9 || vid == 0xb) + priv->vid_type = MT6370_VID_6372; + else + priv->vid_type = MT6370_VID_COMMON; + + return 0; +} + +static int mt6370_bl_probe(struct platform_device *pdev) +{ + struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .scale = BACKLIGHT_SCALE_LINEAR, + }; + struct device *dev = &pdev->dev; + struct mt6370_priv *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + priv->regmap = dev_get_regmap(dev->parent, NULL); + if (!priv->regmap) + return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n"); + + ret = mt6370_check_vendor_info(priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to check vendor info\n"); + + priv->enable_gpio = devm_gpiod_get_optional(dev, "enable", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->enable_gpio)) + dev_err(dev, "Failed to get 'enable' gpio\n"); + + ret = mt6370_init_backlight_properties(priv, &props); + if (ret) + return dev_err_probe(dev, ret, + "Failed to init backlight properties\n"); + + priv->bl = devm_backlight_device_register(dev, pdev->name, dev, priv, + &mt6370_bl_ops, &props); + if (IS_ERR(priv->bl)) + return dev_err_probe(dev, PTR_ERR(priv->bl), + "Failed to register backlight\n"); + + backlight_update_status(priv->bl); + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int mt6370_bl_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + struct backlight_device *bl_dev = priv->bl; + + bl_dev->props.brightness = 0; + backlight_update_status(priv->bl); + + return 0; +} + +static const struct of_device_id __maybe_unused mt6370_bl_of_match[] = { + { .compatible = "mediatek,mt6370-backlight", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_bl_of_match); + +static struct platform_driver mt6370_bl_driver = { + .driver = { + .name = "mt6370-backlight", + .of_match_table = mt6370_bl_of_match, + }, + .probe = mt6370_bl_probe, + .remove = mt6370_bl_remove, +}; +module_platform_driver(mt6370_bl_driver); + +MODULE_AUTHOR("ChiaEn Wu "); +MODULE_DESCRIPTION("MediaTek MT6370 Backlight Driver"); +MODULE_LICENSE("GPL v2");