From patchwork Tue May 31 11:18:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12865597 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 814D1C433FE for ; Tue, 31 May 2022 13:08:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344544AbiEaNIG (ORCPT ); Tue, 31 May 2022 09:08:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53932 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231451AbiEaNIF (ORCPT ); Tue, 31 May 2022 09:08:05 -0400 Received: from mail-oi1-x241.google.com (mail-oi1-x241.google.com [IPv6:2607:f8b0:4864:20::241]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 72F0751324; Tue, 31 May 2022 06:07:54 -0700 (PDT) Received: by mail-oi1-x241.google.com with SMTP id y131so9882963oia.6; Tue, 31 May 2022 06:07:54 -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=WjL5ChPbIi7K/V0MdTfM2rPQhvrdOuYsXgOFgMyivaI=; b=WmEqihZdq4LKwV2jTDPCqYBvw9n0DRGIq4RQ7wYrno4HYN5lt3eH4qZDaQTWUHqXVE b8kC+BH6VHErKiVz4/M6PdWldjxCdPMXwoZaJy5mcfAaj/61IzPllr2pjGhtE226tIKp 3g8DyvJ2eSUv9HqWtrJMauqYG7IRTb03st1dgUtoPD8MzdXIFGv9FjbNd8b9aa6G6Qvk CK73YGmE24rmOzbwEGXdqwYi3bosJbRJzTuJMuQuk7e87+QK7CNxrvTT/vOoZC3o3/JQ ZA8x5trG+NpI0u9i2JaTtnqB+LA6Kd5J8Ld5nyp41nUyuudbZrk6OWs3brs1crItb4FY 1SVw== 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=WjL5ChPbIi7K/V0MdTfM2rPQhvrdOuYsXgOFgMyivaI=; b=keHxbmlo9G/JVyt3AlN46WnexYd8BqiCqiGIkeX1uZEYaR7EdZ7CfTyCMve+jSQwX4 +TeGJr0Qa+KqhbB/wo7GZk8KcY6IRNbrWBfK07w/gMcU6viF98ZuvFeVIsdazLFq68YX D1JqiYOacs+iYpU2q4iFOsAdL3So2j+RZI1arqpodsB86wUFA8TsL/XaeharkOt9Wsw+ at1m731K65lyGxTHxtsbFLqNfJ6SPg7ixkCkoLQPHeYfIB/CcTNx9U4reBRN2wX3KXAV eAFb5kTsapWxtzXdqKUGSZfFc9V3oUGWcLGH7XoKL6FRfltMP6HLGEB9xEoQYWB4tiBx 5Zlg== X-Gm-Message-State: AOAM533v8rVVfCIXmmGSBHgd/zpWjf+MAZwuN7vef1G/qD+5dtiHmmSC XPW6U7ohIEeVv1mGElQcLbrbU3W/xSM= X-Google-Smtp-Source: ABdhPJwQQg/OzLXNx/Hq3Xv0QAqdEOXRvSI1uqk1PNeKMu66slAGcZdztnBeofE6iyRo6FC0bhehIw== X-Received: by 2002:a17:90a:8914:b0:1dc:20c0:40f4 with SMTP id u20-20020a17090a891400b001dc20c040f4mr28485260pjn.11.1653995954965; Tue, 31 May 2022 04:19:14 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.19.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:19:14 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 01/14] dt-bindings: usb: Add Mediatek MT6370 TCPC binding Date: Tue, 31 May 2022 19:18:47 +0800 Message-Id: <20220531111900.19422-2-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 --- .../bindings/usb/mediatek,mt6370-tcpc.yaml | 35 +++++++++++++++++++ 1 file changed, 35 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 000000000000..49316633f92f --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml @@ -0,0 +1,35 @@ +# 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: Mediatek MT6370 Type-C Port Switch and Power Delivery controller DT bindings + +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# + description: + Properties for usb c connector. + +additionalProperties: false + +required: + - compatible + - interrupts From patchwork Tue May 31 11:18:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12865598 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 48F13C433F5 for ; Tue, 31 May 2022 13:08:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237981AbiEaNIm (ORCPT ); Tue, 31 May 2022 09:08:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56944 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231451AbiEaNIl (ORCPT ); Tue, 31 May 2022 09:08:41 -0400 Received: from mail-vs1-xe44.google.com (mail-vs1-xe44.google.com [IPv6:2607:f8b0:4864:20::e44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 40A4757158; Tue, 31 May 2022 06:08:40 -0700 (PDT) Received: by mail-vs1-xe44.google.com with SMTP id 67so13525104vsh.2; Tue, 31 May 2022 06:08:40 -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=0sCP0jkvIeE07R1+RmlM9MygA92ez6zp1dtKYb5AvDE=; b=nXmORH65SpUjbhTvE2/X4vleVvzj6HP+vuXT2wdUKKV3uYzPcGvjjNbaiQXbwG8qzK uPv/BkQ+TkqS/c/pTyH3MEcmQTjImLnIAQwYIywCz9eE2DXVRcjWE2BFU0DaPWbtLi/6 JIvwS/TtGLCo09S6g+UL6qkaUK2oeoCMkdiukx7QIlym1KreWmFGviLxAhPsUcZHmlSM OSkgJCSvXdBwmw4Gici4yb0fk/qD+ZeAOnsOxdBN99m27wOxY2bmru3yqNJ3C7pNDS41 mUuOOYgxXC4RL+LYjsYCmgj2KzDBSJcjDqVJDm+H+8YT3Rf9D+evD4SgQIcZFSpWOpWa kFAA== 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=0sCP0jkvIeE07R1+RmlM9MygA92ez6zp1dtKYb5AvDE=; b=gIE8T/4cc/fzHJr84j0g+Vp91Jia1A4vhVIoG66D7tqU+yLt58Y+aCy1vlyZ4eRUMb 3uKMKG0NutKwIlwBjZVonRoKgzBpk4Pyl3Gf8iRpl6HRpRw5fqzQsKpuymtQQ/7LfPJ7 CUvvtBmkarqVkhCA30VXCu18WbJxFtJ+UoVevayrjWxiGHq3fos9eKdSOlAQ5pouwas1 eDlhIDPwvX6RxqbGzRBC08dfLjjU7wWQ1YdvnfaTVpvILz2wMyMFYUhNBLcFnw99ofby mA2lI35Igge6bQCeDuWTNxXwrlbTHRXoftG+kDUlFr7NUEm5+6vvDGXR419YffhHUFU9 UzeQ== X-Gm-Message-State: AOAM532QGd37gNDIVzvVpXC4wFt8O524l7Slk9GxNC1Qt/qg7+rANg/r IhDlOrxOEFyfcIof1Ulyy6/LikhW8LQ= X-Google-Smtp-Source: ABdhPJxJCbqOi6bcKGG2j8vTrhwclOHUg/eFfbPHJw6XvHla1B8QXbEiVn8d3/yztpo6Xy5/cUsecA== X-Received: by 2002:a17:902:e5c4:b0:163:4c5e:5b39 with SMTP id u4-20020a170902e5c400b001634c5e5b39mr33395049plf.69.1653995961377; Tue, 31 May 2022 04:19:21 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.19.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:19:21 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 02/14] dt-bindings: power: supply: Add Mediatek MT6370 Charger binding Date: Tue, 31 May 2022 19:18:48 +0800 Message-Id: <20220531111900.19422-3-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 --- .../power/supply/mediatek,mt6370-charger.yaml | 60 +++++++++++++++++++ 1 file changed, 60 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 000000000000..9d5c4487ca9c --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml @@ -0,0 +1,60 @@ +# 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 for mt6370 charger + - description: usb plug in irq for mt6370 charger + - description: mivr irq for mt6370 charger + + 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. Ibus ADC channel + is required. + + usb-otg-vbus: + type: object + description: OTG boost regulator. + $ref: /schemas/regulator/regulator.yaml# + + properties: + enable-gpio: + maxItems: 1 + description: | + Specify a valid 'enable' gpio for the regulator and it's optional + +required: + - compatible + - interrupts + - interrupt-names + - io-channels + +additionalProperties: false + +... From patchwork Tue May 31 11:18:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12865581 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 99266C433F5 for ; Tue, 31 May 2022 13:01:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344506AbiEaNBh (ORCPT ); Tue, 31 May 2022 09:01:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35332 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344481AbiEaNBd (ORCPT ); Tue, 31 May 2022 09:01:33 -0400 Received: from mail-io1-xd42.google.com (mail-io1-xd42.google.com [IPv6:2607:f8b0:4864:20::d42]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ACE7C78EF9; Tue, 31 May 2022 06:01:29 -0700 (PDT) Received: by mail-io1-xd42.google.com with SMTP id a10so13987151ioe.9; Tue, 31 May 2022 06:01:29 -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=NLlQWPmyPhz9LkYQh7iizThmB3DZjfxS2yfzbAOphFg=; b=c0XNKUscB1zMhi+CiKfzPAgi33gB/WNqZWTgiA6e6T/74Bc+S+2rt3VJ3UsRfE0t0Z atH9jyvYzC0EuHULZHe7WGzjQCb5VogDsom7nT+y02vKhMq0PK6qK2zKgULSu7mQCNOt 3cUrkF/0FasX84M0+5XuHDd6yond+mMNlk5/zXu1Pm6xb/1W8a/7IYavW6Z5dEL/BLAi 5pIQ9L6xn8925ggiqoLynT5VVlHrpmBo5ejz931C0Tgf9wQpG2sWForIN55zdE/CujQr /xY8y+2ZbC2EyFElWyMT8ivNm8PaWwGA2Dg8LLlmNA3TLB6fz9aecy0Tx9vI4rMPT8mO 4gIw== 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=NLlQWPmyPhz9LkYQh7iizThmB3DZjfxS2yfzbAOphFg=; b=2kXGe3Ak+x4KvGrwvDguJ372dF4eKKRwrXBVRbFhnT/KhZyqdQcNJlI8SibgubmQPk prH8A3Vl6WjfKThKN0cGp98LgO7WCVLmOq6jlX4qpMr1vtAhbEtpw93nl0+YWJMgU9K1 fkKdaPuObMKGkW21vYCXgqXTOuDsp24l62d0GGXKrN7Gkf8iiwqN+g4Ww11tS8mAJ5nP I+Eq/jZ/nexY7NSfyNKfEVGssqZG3+tV4Q8a2PK7dFDeRHrdSwuBEme3kWtBsQosQt2f TGf6D/yvrYO9NOAlKmnQnbi5FQJ3bZKJm6jIAAbJyfGDFQaHMCgMl5HqeRAMZHl22Ghs 7T3A== X-Gm-Message-State: AOAM533ByA793vSXMLu7kc37H/OUwExzaavKgnCjG3dtBEwZzXvC8biN sUXQ0b3QFktknGP/JJIe4Tf3HXKdlFI= X-Google-Smtp-Source: ABdhPJy21tg5SBP0FImL71dOB56WQUiWGSqoTOYD2ff2cgdAz5FYkYg+kGU6v5K00Bt1Va+nB4MDaw== X-Received: by 2002:a63:4:0:b0:3c6:cce2:8457 with SMTP id 4-20020a630004000000b003c6cce28457mr51332560pga.612.1653995967138; Tue, 31 May 2022 04:19:27 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.19.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:19: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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 03/14] dt-bindings: leds: mt6370: Add Mediatek mt6370 indicator Date: Tue, 31 May 2022 19:18:49 +0800 Message-Id: <20220531111900.19422-4-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 indicator documentation. Signed-off-by: ChiYuan Huang --- .../leds/mediatek,mt6370-indicator.yaml | 57 +++++++++++++++++++ 1 file changed, 57 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 000000000000..823be3add097 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml @@ -0,0 +1,57 @@ +# 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. + see Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml + Add MT6370 LED driver include 4-channel RGB LED support Register/PWM/Breath Mode + +properties: + compatible: + const: mediatek,mt6370-indicator + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^(multi-)?led@[0-3]$": + description: | + Properties for a single LED. + $ref: common.yaml# + type: object + + properties: + reg: + description: | + Index of the LED. + enum: + - 0 # LED output ISINK1 + - 1 # LED output ISINK2 + - 2 # LED output ISINK3 + - 3 # LED output ISINK4 + + mediatek,soft-start: + description: | + soft start step control, support /0.5ms/1ms/1.5ms/2ms. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + + unevaluatedProperties: false + +required: + - compatible + - "#address-cells" + - "#size-cells" + +additionalProperties: false From patchwork Tue May 31 11:18:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12865596 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 BEEF2C4332F for ; Tue, 31 May 2022 13:07:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344530AbiEaNHp (ORCPT ); Tue, 31 May 2022 09:07:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52404 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231451AbiEaNHo (ORCPT ); Tue, 31 May 2022 09:07:44 -0400 Received: from mail-qv1-xf43.google.com (mail-qv1-xf43.google.com [IPv6:2607:f8b0:4864:20::f43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0D9AE4CD50; Tue, 31 May 2022 06:07:41 -0700 (PDT) Received: by mail-qv1-xf43.google.com with SMTP id j2so4624241qvp.9; Tue, 31 May 2022 06:07: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=U7ahqBydDZnP+CjyjsQFK3suIZ5X/7W6Ul5AL8gL7a4=; b=gY4IDX6Of6Gq9PA3f1jZGTS5g7DSpVEowE1SjgpLLb07Ek5O3bUa1AT3+cfdS6UCd8 8Xt+NMoxOJuIk1S99ITLMNeJSVAIWnxd9ngnf4E663cBpINBrMmGDXNRpdw8PQO9ESN0 731JEaDVv5f30evjoU7f4yAGsARRqv7GDBqzFnJF0rzOI9cPUCcO5ApJXoM2duaDE0f5 fj8i3/Kpt7FIQOYfCSd45IYis8XPGGX3uAMe2IUBvzNCFMPsb0Au7CuvCnnQPXwZzS+b 0RWSns/CRrkU8x5/UqEZiAzlBoLt3ZRjybQHALkf6vqASoClAAn6hcUxRm+1zZAddYJi ZVeg== 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=U7ahqBydDZnP+CjyjsQFK3suIZ5X/7W6Ul5AL8gL7a4=; b=2ZAK9a+raAjavZxrHmrLUYWZGigCXyjKWJhiodqMOeOkh94VjwPa1IJWxhZhr5gzge JRv6cUDEi4HA8ChwOH7rr2C50QfNinHUM0eVlMVaT66klc1VUKuE6ZSgIYCVhjwRMu92 07UjULDyV4D095m/76hQzrFNJm7xdt3cvBM3qZUT8IBtVfte1ycDQFa+dIJ1N+7zOGh0 k1Jt20YkFWP+XfXr2xUUflJ+L1Yv3GTLPN+PolNJ62wngJV3rlrdsFM7Fyvydq8gd98d FUAE3lyjSj6TsQo1IjElh5w3OHJiltdOjK8A6pSMIUAlRWoXS+/J9TldmSspXZUN+x+3 kTtw== X-Gm-Message-State: AOAM531YfAHysroXncsAtVOkrLuz60u+5udtyddEYnUjgHQ8oAG8Cc1O lRr8P2V801jUI7iNg99f+PrMobKWL2c= X-Google-Smtp-Source: ABdhPJwXXdpvzfH0OHWambVU4ULlh4L9pgITiSW26L4OAZncDI72140qTyXM7wFe+JzlcNO/h+5R7w== X-Received: by 2002:a05:6a00:a04:b0:51b:6ea0:43ca with SMTP id p4-20020a056a000a0400b0051b6ea043camr3778065pfh.78.1653995972975; Tue, 31 May 2022 04:19:32 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.19.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:19: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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 04/14] dt-bindings: leds: Add Mediatek MT6370 flashlight binding Date: Tue, 31 May 2022 19:18:50 +0800 Message-Id: <20220531111900.19422-5-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 --- .../leds/mediatek,mt6370-flashlight.yaml | 48 +++++++++++++++++++ 1 file changed, 48 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 000000000000..b1b11bd3d410 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/leds-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. + see Documentation/devicetree/bindings/mfd/mt6370.yaml + 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# + description: + Properties for a single flash LED. + + properties: + reg: + description: Index of the flash LED. + enum: + - 0 #Address of LED1 + - 1 #Address of LED2 + + unevaluatedProperties: false + +required: + - compatible + - "#address-cells" + - "#size-cells" + +additionalProperties: false From patchwork Tue May 31 11:18:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12865580 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 4B667C433FE for ; Tue, 31 May 2022 13:01:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344189AbiEaNB0 (ORCPT ); Tue, 31 May 2022 09:01:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35224 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244078AbiEaNBZ (ORCPT ); Tue, 31 May 2022 09:01:25 -0400 Received: from mail-oa1-x41.google.com (mail-oa1-x41.google.com [IPv6:2001:4860:4864:20::41]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 49DE177F22; Tue, 31 May 2022 06:01:24 -0700 (PDT) Received: by mail-oa1-x41.google.com with SMTP id 586e51a60fabf-e93bbb54f9so18172128fac.12; Tue, 31 May 2022 06:01:24 -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=JSIsAVF9fVkTehhsFum2qIaOiKUkDyLxbABQD3He3l0=; b=hKih9lAOW8MRbbBGfOx7kiRTjz9QfEd3eSIsmozQoYetBrC+t6l22jSihqFRc12+Xm vm7gh7oP1PcUjMLC+CnfQsZGCRDHQzpDYCVe4SM1p5AKYCAg5+kuYV4IfOv3NmsBxCss 7YG0ROpBieoxvaS2AVVkWoMEgzSjP8Q4MHJtD90Su22yuchHnMBHN2kYeHQjcAKUqPh+ fcX1MaYIdZzOtul5ziWofq+/Kiip9n3rw51FxR1QAqdrDC5veq6VVK/6j9X92G9Hm8mp 0N4LfQ2aWVG+WFVKCJfp1DpxXQSHB4/w8Ri2BU+4MT7fum/8hgvDqYI07FZLkP9abiy8 yujg== 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=JSIsAVF9fVkTehhsFum2qIaOiKUkDyLxbABQD3He3l0=; b=mvIJ+jRWWdgr2Mn4qQVDXHZE1bs0gckn+xFMBOYGeT2TmZb59UKr4nMzNOBUykVMHA reM+NiyONU5XaQk05W7s3Kx0WQPLphYfuJDhcohdPVSGt7EEby85wE+pfG42uMmQBci1 Tnkx+DB1nsaP27V/o5f0CoQtO+vTv7tktMelueupCg/afkfABg/zJNYs0ukkMUS/W1lz mfzTogyYK+Q3d0S8IIyMd7QDNXw2TbSQkffHmuEdVFQxz1JFS8GcNPToL23r1pEj3TYN wrCJHKzx8OuyXOxvDqxvDdJdhho0/f2RyD1sOy2CS6h4Abmse2aEACGjHjfh13JS6shc GAgw== X-Gm-Message-State: AOAM533ClDQVUtgOfTvdUQ/cf+NuAeySIrPwNh1Px7TBvCzC4A+zRTxr T84eidrftFGf4C75+uNhGiLbR4Zh4Xc= X-Google-Smtp-Source: ABdhPJzuEbDwbQWGn3CV/zE1vb9aceaeVtHBN5Ja0Ci/sA7YgIw7LlW8QzYq/gP7Sxq9ui9vU3D1gg== X-Received: by 2002:a17:90b:17c6:b0:1e2:ab17:a8f9 with SMTP id me6-20020a17090b17c600b001e2ab17a8f9mr17018922pjb.68.1653995978760; Tue, 31 May 2022 04:19:38 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.19.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:19: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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 05/14] dt-bindings: backlight: Add Mediatek MT6370 backlight binding Date: Tue, 31 May 2022 19:18:51 +0800 Message-Id: <20220531111900.19422-6-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 --- .../backlight/mediatek,mt6370-backlight.yaml | 110 ++++++++++++++++++ 1 file changed, 110 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 000000000000..81d72ed44be4 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml @@ -0,0 +1,110 @@ +# 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: | + 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. + + For the LCD backlight, it can provide 4 channel WLED driving capability. + Each channel driving current is up to 30mA + +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-sel: + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [0, 1, 2, 3] + description: | + Backlight PWM hysteresis input level selection. + value mapping: + - 0: 1bit + - 1: 2bit + - 2: 4bit + - 3: 6bit + + mediatek,bled-ovp-shutdown: + description: | + Enable the backlight shutdown when OVP level triggered + type: boolean + + mediatek,bled-ovp-level-sel: + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [0, 1, 2, 3] + description: | + Backlight OVP level selection. + value mapping: + - 0: 17V + - 1: 21V + - 2: 25V + - 3: 29V + + mediatek,bled-ocp-shutdown: + description: | + Enable the backlight shutdown when OCP level triggerred. + type: boolean + + mediatek,bled-ocp-level-sel: + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [0, 1, 2, 3] + description: | + Backlight OC level selection. + value mapping: + - 0: 900mA + - 1: 1200mA + - 2: 1500mA + - 3: 1800mA + + 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 Tue May 31 11:18:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12865611 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 7AD12C433FE for ; Tue, 31 May 2022 13:13:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344481AbiEaNNT (ORCPT ); Tue, 31 May 2022 09:13:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42018 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245683AbiEaNNS (ORCPT ); Tue, 31 May 2022 09:13:18 -0400 Received: from mail-oi1-x244.google.com (mail-oi1-x244.google.com [IPv6:2607:f8b0:4864:20::244]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 57BF860D9D; Tue, 31 May 2022 06:13:15 -0700 (PDT) Received: by mail-oi1-x244.google.com with SMTP id w130so17410183oig.0; Tue, 31 May 2022 06:13: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=2QW6EAQHfNGL3WRo5wHoHfZuTn8wkaAQDQ0iJvuyzQA=; b=OLVbMS5aoY87mxnSycXmD2wtXm2Mw0QCuyvLSgjQpa0QfWDFCWo7nuiee+CNmHScUn qqEl1yimn/40zQQ+utzsNWdhbJbUBVNdiDA65W2lMKxTZG2VxmLjgPMht0pk33pCKkYh +EpNEoRwxbYzDOKIdgGdBceTbwhNgbzL+I8xMt6aQuC7H9ngLmVwNe1ReMsd+VJhHXIm TNrFS8jUl5cLZ1ySfr6b/1mlHPAYcbx3ro5xO6IZeVWuphrY0/36XgT1BBp095nZBtZm 8WsSnBTI7hQuh0LyQTmMv0N/rDuNMtIUD4mNdUrrC5tqwMI5eyMp+UwSakNaNyG0xCua BA+A== 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=2QW6EAQHfNGL3WRo5wHoHfZuTn8wkaAQDQ0iJvuyzQA=; b=fgcD1irPdwQ0pDQyqs5R9rlRaF17ePRtYzpQjNhcpxzNpECniVdaUsXO1SRP90zwaK 5Jrwpb9NP/8nkwO+cIz2wzxp88yxcgmYothfTZtWDCe5e7es57ygn23WDkHMMyPXFqkO KJsyk2Lf6WOu9J8S5V8jgGW/Jt1JkLRao5X4jDOrMSyq4BYheS7bRAZ/bhrDz6fPvAHR tejeheSc0O7C9MXHMOqB5LSYiSVN8pN9NTMkoXZmTDKcpkSgIk8JVs9GNGuoigmKuRha Dg42XMgyJ9Oj02a9swTaV0Y41SkgLpw0KAhUMBocdNSIubSDyR33Nb+Cw6JDmUQikkYX HdPA== X-Gm-Message-State: AOAM531Gue3F4g6k9b/9VpAexDAgoEOD0YXHwSv8MubX89faBX1uxCW+ 1W4aCPxlUlkt0TH23VhYxoQeZV0umSg= X-Google-Smtp-Source: ABdhPJxsuxDHP/pmK6/ZpzwirH4LQRf2G5qEDeq0z6Qvx0oDoCGu5cKrPHsiVYN87QI7Qo3UTb+JCA== X-Received: by 2002:a17:90a:1150:b0:1e3:2d6b:7a8e with SMTP id d16-20020a17090a115000b001e32d6b7a8emr4843817pje.188.1653995984469; Tue, 31 May 2022 04:19:44 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.19.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:19:44 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 06/14] dt-bindings: mfd: Add Mediatek MT6370 binding Date: Tue, 31 May 2022 19:18:52 +0800 Message-Id: <20220531111900.19422-7-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 --- .../bindings/mfd/mediatek,mt6370.yaml | 282 ++++++++++++++++++ .../dt-bindings/iio/adc/mediatek,mt6370_adc.h | 18 ++ include/dt-bindings/mfd/mediatek,mt6370.h | 83 ++++++ 3 files changed, 383 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h create mode 100644 include/dt-bindings/mfd/mediatek,mt6370.h diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml new file mode 100644 index 000000000000..96a12dce0108 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml @@ -0,0 +1,282 @@ +# 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: | + List the compatible configurations of MT6370 ADC. + + 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 + + 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-gpio: + maxItems: 1 + description: | + Specify a valid 'enable' gpio for the regulator and it's optional + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - '#interrupt-cells' + - regulators + - adc + - backlight + - indicator + - tcpc + - charger + - flashlight + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + mt6370@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 = , , + ; + interrupt-names = "attach_i", "uvp_d_evt", "mivr"; + io-channels = <&mt6370_adc MT6370_CHAN_IBUS>; + + mt6370_otg_vbus: usb-otg-vbus { + regulator-compatible = "mt6370,otg-vbus"; + regulator-name = "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>; + mediatek,soft-start = <3>; + 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 000000000000..18ce2fef8f9e --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#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 diff --git a/include/dt-bindings/mfd/mediatek,mt6370.h b/include/dt-bindings/mfd/mediatek,mt6370.h new file mode 100644 index 000000000000..df641e5d651f --- /dev/null +++ b/include/dt-bindings/mfd/mediatek,mt6370.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __DT_BINDINGS_MEDIATEK_MT6370_H__ +#define __DT_BINDINGS_MEDIATEK_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 + +#endif /* __DT_BINDINGS_MEDIATEK_MT6370_H__ */ From patchwork Tue May 31 11:18:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12865415 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 E5212C433EF for ; Tue, 31 May 2022 11:19:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245114AbiEaLTy (ORCPT ); Tue, 31 May 2022 07:19:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47402 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243100AbiEaLTw (ORCPT ); Tue, 31 May 2022 07:19:52 -0400 Received: from mail-pj1-x102f.google.com (mail-pj1-x102f.google.com [IPv6:2607:f8b0:4864:20::102f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 47FE764D17; Tue, 31 May 2022 04:19:51 -0700 (PDT) Received: by mail-pj1-x102f.google.com with SMTP id o6-20020a17090a0a0600b001e2c6566046so2342885pjo.0; Tue, 31 May 2022 04:19:51 -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=lVCUf7UwKal2eUwczXgEX6YxihaKUqsjAaTp8vrMqa8=; b=q8GZYSvNTidEWkuBQIIpkA5unaMsxo6MwA5dYmrK+Nf+cMdnmzv3dt7lwy+A+C85uK kFvmZTZNOsS9PT4ZYBCm2FhlxPclbIUJj7HVrdmM/MpEYK03QA14a/3FxfOs70hO60VJ B/0TsOD6e3dtGD5jkhahF0C/GYZ7p9CN2qAUov9LQlx5fL2Jou9EEgTk4ksruQbvWKiF dv6RF4v0ZiI2O4A0PK/tStysCqsFnMw8/Be7JEgjcPdFBuZaUopE+zhJ5ISK5Iz6Kx5z nrm4br+c4cukJbIfMPFt04HxD3iKTsSWhEn3LSN8s8oJJBXR/cq5rzmAGCfzOHn3wzKe 7DKQ== 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=lVCUf7UwKal2eUwczXgEX6YxihaKUqsjAaTp8vrMqa8=; b=SGkzHiK7C0hCfSLrOy+wd54xS2hJDdLDBbKeUU9MoOopL6/PE6rrgDDdBBbRchBol4 Yp5le+MjQ8TIxU/oCAo5lD6zpDrpvzLKLRNf+nDp+B/ZouN+jtDJFNwC5UalP2DVhl8a oLgK3kTK6yhJ0PUu27SccZyJG8NaN/54rkTdGFaqEPD53dj4+jOw71thAUSOkmtasByJ Vvbf6uDoBIRV4F7RALES88KkLs5aVPUlfU+aHc+wj3DfW/R1hEhcwmkjSYKVgGIU+zzX 7gfjB/+4whNkhVKr8Lz/fXtaBApSVV+4iLjo4eDN/0GSNFm8tDdCG8YtUL2vzl5jw0ih /4Dg== X-Gm-Message-State: AOAM532wAZu9V/UPyGql9smX+1YykNtG9TqcBtnnzkI1yBwC2ETKhvbQ Aia1suwewM8NeL/8S/l7pwc= X-Google-Smtp-Source: ABdhPJz9scdkoQc9wAnHKjY3ELARtEhi14aWXx6SrBSlCoPMHLIyvPIPOOoNGZw71TgwL2jbrBrl1A== X-Received: by 2002:a17:90b:4f82:b0:1e0:4852:bc5d with SMTP id qe2-20020a17090b4f8200b001e04852bc5dmr28231877pjb.64.1653995990802; Tue, 31 May 2022 04:19:50 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.19.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:19:50 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 07/14] mfd: mt6370: Add Mediatek MT6370 support Date: Tue, 31 May 2022 19:18:53 +0800 Message-Id: <20220531111900.19422-8-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 MFD support. Signed-off-by: ChiYuan Huang --- drivers/mfd/Kconfig | 13 +++ drivers/mfd/Makefile | 1 + drivers/mfd/mt6370.c | 273 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 drivers/mfd/mt6370.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3b59456f5545..d9a7524a3e0e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -937,6 +937,19 @@ 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 integrate single cell battery charger with adc monitoring, RGB + LEDs, dual channel flashlight, WLED backlight driver, display bias + voltage supply, one general purpose LDO, and cc logic + controller with USBPD commmunication capable. + config MFD_MT6397 tristate "MediaTek MT6397 PMIC Support" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 858cacf659d6..62b27125420e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -242,6 +242,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.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 obj-$(CONFIG_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o diff --git a/drivers/mfd/mt6370.c b/drivers/mfd/mt6370.c new file mode 100644 index 000000000000..a5a07be7ccc2 --- /dev/null +++ b/drivers/mfd/mt6370.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + MT6370_USBC_I2C = 0, + MT6370_PMU_I2C, + MT6370_MAX_I2C +}; + +#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 + +struct mt6370_info { + struct i2c_client *i2c[MT6370_MAX_I2C]; + struct device *dev; + struct regmap *regmap; + struct regmap_irq_chip_data *irq_data; +}; + +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("adc", NULL, NULL, 0, 0, "mediatek,mt6370-adc"), + MFD_CELL_OF("charger", NULL, NULL, 0, 0, "mediatek,mt6370-charger"), + MFD_CELL_OF("backlight", NULL, NULL, 0, 0, "mediatek,mt6370-backlight"), + MFD_CELL_OF("flashlight", NULL, NULL, 0, 0, "mediatek,mt6370-flashlight"), + MFD_CELL_OF("indicator", NULL, NULL, 0, 0, "mediatek,mt6370-indicator"), + MFD_CELL_OF("tcpc", NULL, NULL, 0, 0, "mediatek,mt6370-tcpc"), + MFD_CELL_RES("regulator", mt6370_regulator_irqs) +}; + +static int mt6370_check_vendor_info(struct mt6370_info *info) +{ + unsigned int devinfo; + int ret; + + ret = regmap_read(info->regmap, MT6370_REG_DEV_INFO, &devinfo); + if (ret) + return ret; + + switch (FIELD_GET(MT6370_VENID_MASK, devinfo)) { + case 0x8: /* RT5081 */ + case 0xA: /* RT5081A */ + case 0xE: /* MT6370 */ + case 0xF: /* MT6371 */ + case 0x9: /* MT6372P */ + case 0xB: /* MT6372CP */ + break; + default: + dev_err(info->dev, "Not invalid value 0x%02x\n", devinfo); + return -ENODEV; + } + + return 0; +} + +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; + u8 bank_idx = *(u8 *)reg_buf, bank_addr = *(u8 *)(reg_buf + 1); + int ret; + + ret = i2c_smbus_read_i2c_block_data(info->i2c[bank_idx], bank_addr, + val_size, val_buf); + if (ret != val_size) + return ret; + + return 0; +} + +static int mt6370_regmap_write(void *context, const void *data, size_t count) +{ + struct mt6370_info *info = context; + u8 bank_idx = *(u8 *)data, bank_addr = *(u8 *)(data + 1); + int len = count - MT6370_REG_ADDRLEN; + + 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; + int ret; + + info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = &i2c->dev; + + usbc_i2c = devm_i2c_new_dummy_device(&i2c->dev, i2c->adapter, + MT6370_USBC_I2CADDR); + if (IS_ERR(usbc_i2c)) { + ret = PTR_ERR(usbc_i2c); + dev_err(&i2c->dev, "Failed to register usbc i2c client %d\n", ret); + return ret; + } + + /* Assign I2C client for PMU and TypeC */ + info->i2c[MT6370_PMU_I2C] = i2c; + info->i2c[MT6370_USBC_I2C] = usbc_i2c; + + info->regmap = devm_regmap_init(&i2c->dev, &mt6370_regmap_bus, info, + &mt6370_regmap_config); + if (IS_ERR(info->regmap)) { + ret = PTR_ERR(info->regmap); + dev_err(&i2c->dev, "Failed to register regmap (%d)\n", ret); + return ret; + } + + ret = mt6370_check_vendor_info(info); + if (ret) { + dev_err(&i2c->dev, "Failed to check vendor info (%d)\n", ret); + return ret; + } + + ret = devm_regmap_add_irq_chip(&i2c->dev, info->regmap, i2c->irq, + IRQF_ONESHOT, -1, &mt6370_irq_chip, + &info->irq_data); + if (ret) { + dev_err(&i2c->dev, "Failed to add irq chip (%d)\n", ret); + return ret; + } + + return devm_mfd_add_devices(&i2c->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("MT6370 I2C MFD Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 11:18:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 12865418 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 CF17CC41535 for ; Tue, 31 May 2022 11:20:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343791AbiEaLUT (ORCPT ); Tue, 31 May 2022 07:20:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47482 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343742AbiEaLT6 (ORCPT ); Tue, 31 May 2022 07:19:58 -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 0AA0095DCE; Tue, 31 May 2022 04:19:56 -0700 (PDT) Received: by mail-pj1-x1032.google.com with SMTP id d12-20020a17090abf8c00b001e2eb431ce4so1957576pjs.1; Tue, 31 May 2022 04:19:56 -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=QTCg5JULGIw2Y2CEYchomvyXaPsSNLMR9ooYVVdBZ18=; b=f80pJjbcKhcG0CN7S5ImfXbMlUkPpHhR6whKzXTj8GwE0sj/nMZcScogMBLYSCxSaD jKiSGwbtonPp1K3AWmd45rKa0nCYSRj3JUvVcyxbhwadXmlUHLXg5dmfZGc4wx3HnIsx udyITFEdnpQwkeXFBRkFXpOLOAacecld0Em95PhwM6ku6hKUhyZ8O6XtXxHMMlQ2d4X1 MEiw4jPrARFbmgXhJNNqAnoOPXYbk+iUZriTSZ7WbK5xDWSinFU5ENPH3ZmfKI18YdBL TPCpzz78uL9v1VCF1n0ZC3efTwFKb9Y+ABqcR9X/tfTkyBWDr0zKtExQwG0+glxiMbs0 v24A== 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=QTCg5JULGIw2Y2CEYchomvyXaPsSNLMR9ooYVVdBZ18=; b=VUtJRbvQbg8CzhFGzwLu1/or6PBZcJ+GOpbAndwZ48X4+Azou7J/tTJQJbrBzcTmhc 96rVlPAGFidVIKjl3CZaPvGf3O8WI4chjLSoFW3VEMzQZJnY811rZ/+xg1gbpeJt1JOz iEATiU1z/WgywvEXX2corebp0aHQNZimtri7/BHybIjqTRxNs8W0faNLQ3b8p9VFUdYi p+u3PrFrWAAcyRKUDW1gkBXbL0TG/WWjs4DTwraV5/vucaujlOl42UrBeiY1b6JIIL6p gzn5fmZaIhRxwQrxMgLSU7zkKPnfB6Rplqm19IN3hC6pIOj2G2sD3eZP2rk2hSkdsxf6 QRJg== X-Gm-Message-State: AOAM532/9S0bQsVLlS9Eor8Ec8qGy8lVl3xkcnnWnWdCbNY7gqXgfGYp 8WF2PiL7YSa7SuNIcnV1Cfc= X-Google-Smtp-Source: ABdhPJx/euaOz6v7OyJx1iCsp3yZg8ssyOfS/BSRPF0+39f4j60vmbMwZG2ot54aIzIR2b735Bfx6A== X-Received: by 2002:a17:902:b418:b0:15f:713:c914 with SMTP id x24-20020a170902b41800b0015f0713c914mr61117474plr.171.1653995996375; Tue, 31 May 2022 04:19:56 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.19.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:19:56 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 08/14] usb: typec: tcpci_mt6370: Add Mediatek MT6370 tcpci driver Date: Tue, 31 May 2022 19:18:54 +0800 Message-Id: <20220531111900.19422-9-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 chip level mt6370 tcpci driver. Signed-off-by: ChiYuan Huang --- drivers/usb/typec/tcpm/Kconfig | 8 + drivers/usb/typec/tcpm/Makefile | 1 + drivers/usb/typec/tcpm/tcpci_mt6370.c | 212 ++++++++++++++++++++++++++ 3 files changed, 221 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 557f392fe24d..f4b7363bc7e9 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -35,6 +35,14 @@ 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. + 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 7d499f3569fd..906d9dced8e7 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 000000000000..ce7f5e03fd10 --- /dev/null +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#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) { + ret = regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80); + if (ret) + return ret; + } + + 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) + ret = regulator_disable(priv->vbus); + else if (!ret && source) + ret = regulator_enable(priv->vbus); + else + ret = 0; + + return ret; +} + +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) { + dev_err(priv->dev, "Vendor ID not correct 0x%02x\n", vid); + return -ENODEV; + } + + return 0; +} + +static int mt6370_tcpc_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + platform_set_drvdata(pdev, priv); + + priv->tcpci_data.regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->tcpci_data.regmap) { + dev_err(&pdev->dev, "Failed to init regmap\n"); + return -ENODEV; + } + + ret = mt6370_check_vendor_info(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to check vendor info (%d)\n", ret); + return ret; + } + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) { + dev_err(&pdev->dev, "Failed to get TCPC irq (%d)\n", priv->irq); + 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(&pdev->dev, "vbus"); + if (!IS_ERR(priv->vbus)) + priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus; + + priv->tcpci = tcpci_register_port(&pdev->dev, &priv->tcpci_data); + if (IS_ERR(priv->tcpci)) { + dev_err(&pdev->dev, "Failed to register tcpci port\n"); + return PTR_ERR(priv->tcpci); + } + + ret = devm_request_threaded_irq(&pdev->dev, priv->irq, NULL, + mt6370_irq_handler, IRQF_ONESHOT, + dev_name(&pdev->dev), priv); + if (ret) { + dev_err(&pdev->dev, "Failed to allocate irq (%d)\n", ret); + tcpci_unregister_port(priv->tcpci); + return ret; + } + + device_init_wakeup(&pdev->dev, true); + dev_pm_set_wake_irq(&pdev->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 Tue May 31 11:18: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: 12865599 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 9CFC2C4321E for ; Tue, 31 May 2022 13:12:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344619AbiEaNMk (ORCPT ); Tue, 31 May 2022 09:12:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38954 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344433AbiEaNMj (ORCPT ); Tue, 31 May 2022 09:12:39 -0400 Received: from mail-qv1-xf41.google.com (mail-qv1-xf41.google.com [IPv6:2607:f8b0:4864:20::f41]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1731B60045; Tue, 31 May 2022 06:12:37 -0700 (PDT) Received: by mail-qv1-xf41.google.com with SMTP id v5so11881380qvs.10; Tue, 31 May 2022 06:12:37 -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=sePt3x7ON3JH7CeHoCRuD6Euif4kN7Rj2nuq+sT7jGM=; b=L4iT7jcD7Aa8BTMEzLrmBs/dijnsKXYuJpmDX+VrrhWXGY1NSQT7XFlOk2NFy2FOkB 3HkGY2epADf5bMF2k1JAHGRqwybDCcFirS2uL0l5JVwiP26KQZ8O3LhzLSFuyzH+mAdJ q+4vUxHJyKAuLVRwmMizAawEl1xEgv3rKJ/wVnrse+o51och7ltoZENTIr/s5PpdneKd mP9XDSCyLbWECcF+HzpldUgRqeUb+DOP8dl/O5xI2bQxxRU6TfFNL1hCeETRbt7zR0qL sbrfd1Uq4u0erc+Hd4UiTcqcn3hd0fVlz1kcf1B6d0+ksVF7HH+DWsRmoxgkwS7Qcwqy /8Cw== 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=sePt3x7ON3JH7CeHoCRuD6Euif4kN7Rj2nuq+sT7jGM=; b=gufSbh7om6ONFr+lG0tWRS7tWtmjiChRJ/ABOomIZ6h2WaLA9Uakj7JkmL00oaR3JE p+dWZuuzQjE7FNZ0ZlBOhOBLzHianOSy87doRvw/SfsSkz4i0C/6iFcXji7/Ea/jRmXM eZhCWyBcWJPiwR+r3YZsZ1DfASBEW7CxEnEO2JYwPZrIXIwUtAqJQRdiG7OSRN3z3X9f VGJeSpk/GQZzzVsJwMZgZwS47R8V3KTpGBV3ROHkyycZADpYYXC3RTGe1yzx70LQC/6h p0Eh6I6E7lkeTdTX0fxb+1qFzE5dCaA1MKPGQmrKofYxlf5TzuJ9xUOzcPOL9toM1edX NMVA== X-Gm-Message-State: AOAM531XAPxrz+/PJ4nrwQBoLgZDMN5rpn7Rd/xl/+cue3wJfyPSWYeD 3jNcYx8LlsrGItjYY6InmHWcHIXqhQc= X-Google-Smtp-Source: ABdhPJwIqOcoNUOpeyqsTh9oOgeAWS0oQhQ0+DT4YxHpbXee3CjQRtoHo2X2J6oUELTc2qP/1v0NRA== X-Received: by 2002:a05:6a00:811:b0:518:b0eb:9132 with SMTP id m17-20020a056a00081100b00518b0eb9132mr40359775pfk.57.1653996001942; Tue, 31 May 2022 04:20:01 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.19.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:20:01 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 09/14] regulator: mt6370: Add mt6370 DisplayBias and VibLDO support Date: Tue, 31 May 2022 19:18:55 +0800 Message-Id: <20220531111900.19422-10-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 DisplayBias and VibLDO support. Signed-off-by: ChiYuan Huang --- drivers/regulator/Kconfig | 8 + drivers/regulator/Makefile | 1 + drivers/regulator/mt6370-regulator.c | 389 +++++++++++++++++++++++++++ 3 files changed, 398 insertions(+) create mode 100644 drivers/regulator/mt6370-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index cbe0f96ca342..dcb6866dab53 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -804,6 +804,14 @@ config REGULATOR_MT6360 2-channel buck with Thermal Shutdown and Overload Protection 6-channel High PSRR and Low Dropout LDO. +config REGULATOR_MT6370 + tristate "MT6370 SubPMIC Regulator" + depends on MFD_MT6370 + help + Say Y here to enable MT6370 regulator support. + This driver support the control for DisplayBias voltages and one + general purpose LDO which commonly used to drive the vibrator. + config REGULATOR_MT6380 tristate "MediaTek MT6380 PMIC" depends on MTK_PMIC_WRAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 8d3ee8b6d41d..f1cbff21843e 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o +obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o diff --git a/drivers/regulator/mt6370-regulator.c b/drivers/regulator/mt6370-regulator.c new file mode 100644 index 000000000000..949b2c7b5556 --- /dev/null +++ b/drivers/regulator/mt6370-regulator.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + MT6370_IDX_DSVBOOST = 0, + MT6370_IDX_DSVPOS, + MT6370_IDX_DSVNEG, + MT6370_IDX_VIBLDO, + MT6370_MAX_IDX +}; + +#define MT6370_REG_LDO_CFG 0x180 +#define MT6370_REG_LDO_VOUT 0x181 +#define MT6370_REG_DB_CTRL1 0x1B0 +#define MT6370_REG_DB_CTRL2 0x1B1 +#define MT6370_REG_DB_VBST 0x1B2 +#define MT6370_REG_DB_VPOS 0x1B3 +#define MT6370_REG_DB_VNEG 0x1B4 +#define MT6370_REG_LDO_STAT 0x1DC +#define MT6370_REG_DB_STAT 0x1DF + +#define MT6370_LDOOMS_MASK BIT(7) +#define MT6370_LDOEN_MASK BIT(7) +#define MT6370_LDOVOUT_MASK GENMASK(3, 0) +#define MT6370_DBPERD_MASK (BIT(7) | BIT(4)) +#define MT6370_DBEXTEN_MASK BIT(0) +#define MT6370_DBVPOSEN_MASK BIT(6) +#define MT6370_DBVPOSDISG_MASK BIT(5) +#define MT6370_DBVNEGEN_MASK BIT(3) +#define MT6370_DBVNEGDISG_MASK BIT(2) +#define MT6370_DBALLON_MASK (MT6370_DBVPOSEN_MASK | MT6370_DBVNEGEN_MASK) +#define MT6370_DBSLEW_MASK GENMASK(7, 6) +#define MT6370_DBVOUT_MASK GENMASK(5, 0) +#define MT6370_LDOOC_EVT_MASK BIT(7) +#define MT6370_POSSCP_EVT_MASK BIT(7) +#define MT6370_NEGSCP_EVT_MASK BIT(6) +#define MT6370_BSTOCP_EVT_MASK BIT(5) +#define MT6370_POSOCP_EVT_MASK BIT(4) +#define MT6370_NEGOCP_EVT_MASK BIT(3) + +#define MT6370_LDO_MINUV 1600000 +#define MT6370_LDO_STPUV 200000 +#define MT6370_LDO_N_VOLT 13 +#define MT6370_DBVBOOST_MINUV 4000000 +#define MT6370_DBVBOOST_STPUV 50000 +#define MT6370_DBVBOOST_N_VOLT 45 +#define MT6370_DBVOUT_MINUV 4000000 +#define MT6370_DBVOUT_STPUV 50000 +#define MT6370_DBVOUT_N_VOLT 41 + +struct mt6370_priv { + struct device *dev; + struct regmap *regmap; + struct regulator_dev *rdev[MT6370_MAX_IDX]; + bool use_external_ctrl; +}; + +static const unsigned int mt6370_vpos_ramp_tbl[] = { 8540, 5840, 4830, 3000 }; +static const unsigned int mt6370_vneg_ramp_tbl[] = { 10090, 6310, 5050, 3150 }; + +static int mt6370_get_error_flags(struct regulator_dev *rdev, + unsigned int *flags) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int stat_reg, stat, rpt_flags = 0; + int rid = rdev_get_id(rdev), ret; + + if (rid == MT6370_IDX_VIBLDO) + stat_reg = MT6370_REG_LDO_STAT; + else + stat_reg = MT6370_REG_DB_STAT; + + ret = regmap_read(regmap, stat_reg, &stat); + if (ret) + return ret; + + switch (rid) { + case MT6370_IDX_DSVBOOST: + if (stat & MT6370_BSTOCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + case MT6370_IDX_DSVPOS: + if (stat & MT6370_POSSCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE; + + if (stat & MT6370_POSOCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + case MT6370_IDX_DSVNEG: + if (stat & MT6370_NEGSCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE; + + if (stat & MT6370_NEGOCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + default: + if (stat & MT6370_LDOOC_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + } + + *flags = rpt_flags; + return 0; +} + +static const struct regulator_ops mt6370_dbvboost_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_bypass = regulator_get_bypass_regmap, + .set_bypass = regulator_set_bypass_regmap, + .get_error_flags = mt6370_get_error_flags, +}; + +static const struct regulator_ops mt6370_dbvout_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .get_error_flags = mt6370_get_error_flags, +}; + +static const struct regulator_ops mt6370_ldo_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .get_error_flags = mt6370_get_error_flags, +}; + +static int mt6370_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct mt6370_priv *priv = config->driver_data; + struct gpio_desc *enable_gpio; + int ret; + + enable_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np), "enable", 0, + GPIOD_OUT_HIGH | + GPIOD_FLAGS_BIT_NONEXCLUSIVE, + desc->name); + if (IS_ERR(enable_gpio)) { + config->ena_gpiod = NULL; + return 0; + } + + /* + * RG control by default + * Only if all are using external pin, change all by external control + */ + if (priv->use_external_ctrl) { + ret = regmap_update_bits(priv->regmap, MT6370_REG_DB_CTRL1, + MT6370_DBEXTEN_MASK, + MT6370_DBEXTEN_MASK); + if (ret) + return ret; + } + + config->ena_gpiod = enable_gpio; + priv->use_external_ctrl = true; + return 0; +} + +static const struct regulator_desc mt6370_regulator_descs[] = { + { + .name = "mt6370-dsv-vbst", + .of_match = of_match_ptr("dsvbst"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_DSVBOOST, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &mt6370_dbvboost_ops, + .min_uV = MT6370_DBVBOOST_MINUV, + .uV_step = MT6370_DBVBOOST_STPUV, + .n_voltages = MT6370_DBVBOOST_N_VOLT, + .vsel_reg = MT6370_REG_DB_VBST, + .vsel_mask = MT6370_DBVOUT_MASK, + .bypass_reg = MT6370_REG_DB_CTRL1, + .bypass_mask = MT6370_DBPERD_MASK, + .bypass_val_on = MT6370_DBPERD_MASK, + }, + { + .name = "mt6370-dsv-vpos", + .of_match = of_match_ptr("dsvpos"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_DSVPOS, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .of_parse_cb = mt6370_of_parse_cb, + .ops = &mt6370_dbvout_ops, + .min_uV = MT6370_DBVOUT_MINUV, + .uV_step = MT6370_DBVOUT_STPUV, + .n_voltages = MT6370_DBVOUT_N_VOLT, + .vsel_reg = MT6370_REG_DB_VPOS, + .vsel_mask = MT6370_DBVOUT_MASK, + .enable_reg = MT6370_REG_DB_CTRL2, + .enable_mask = MT6370_DBVPOSEN_MASK, + .ramp_reg = MT6370_REG_DB_VPOS, + .ramp_mask = MT6370_DBSLEW_MASK, + .ramp_delay_table = mt6370_vpos_ramp_tbl, + .n_ramp_values = ARRAY_SIZE(mt6370_vpos_ramp_tbl), + .active_discharge_reg = MT6370_REG_DB_CTRL2, + .active_discharge_mask = MT6370_DBVPOSDISG_MASK, + .active_discharge_on = MT6370_DBVPOSDISG_MASK, + }, + { + .name = "mt6370-dsv-vneg", + .of_match = of_match_ptr("dsvneg"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_DSVNEG, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .of_parse_cb = mt6370_of_parse_cb, + .ops = &mt6370_dbvout_ops, + .min_uV = MT6370_DBVOUT_MINUV, + .uV_step = MT6370_DBVOUT_STPUV, + .n_voltages = MT6370_DBVOUT_N_VOLT, + .vsel_reg = MT6370_REG_DB_VNEG, + .vsel_mask = MT6370_DBVOUT_MASK, + .enable_reg = MT6370_REG_DB_CTRL2, + .enable_mask = MT6370_DBVNEGEN_MASK, + .ramp_reg = MT6370_REG_DB_VNEG, + .ramp_mask = MT6370_DBSLEW_MASK, + .ramp_delay_table = mt6370_vneg_ramp_tbl, + .n_ramp_values = ARRAY_SIZE(mt6370_vneg_ramp_tbl), + .active_discharge_reg = MT6370_REG_DB_CTRL2, + .active_discharge_mask = MT6370_DBVNEGDISG_MASK, + .active_discharge_on = MT6370_DBVNEGDISG_MASK, + }, + { + .name = "mt6370-vib-ldo", + .of_match = of_match_ptr("vibldo"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_VIBLDO, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &mt6370_ldo_ops, + .min_uV = MT6370_LDO_MINUV, + .uV_step = MT6370_LDO_STPUV, + .n_voltages = MT6370_LDO_N_VOLT, + .vsel_reg = MT6370_REG_LDO_VOUT, + .vsel_mask = MT6370_LDOVOUT_MASK, + .enable_reg = MT6370_REG_LDO_VOUT, + .enable_mask = MT6370_LDOEN_MASK, + .active_discharge_reg = MT6370_REG_LDO_CFG, + .active_discharge_mask = MT6370_LDOOMS_MASK, + .active_discharge_on = MT6370_LDOOMS_MASK, + } +}; + +static irqreturn_t mt6370_scp_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE, + NULL); + return IRQ_HANDLED; +} + +static irqreturn_t mt6370_ocp_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL); + return IRQ_HANDLED; +} + +static int mt6370_regulator_irq_register(struct mt6370_priv *priv) +{ + struct platform_device *pdev = to_platform_device(priv->dev); + static const struct { + const char *name; + int rid; + irq_handler_t handler; + } mt6370_irqs[] = { + { "db_vpos_scp", MT6370_IDX_DSVPOS, mt6370_scp_handler }, + { "db_vneg_scp", MT6370_IDX_DSVNEG, mt6370_scp_handler }, + { "db_vbst_ocp", MT6370_IDX_DSVBOOST, mt6370_ocp_handler }, + { "db_vpos_ocp", MT6370_IDX_DSVPOS, mt6370_ocp_handler }, + { "db_vneg_ocp", MT6370_IDX_DSVNEG, mt6370_ocp_handler }, + { "ldo_oc", MT6370_IDX_VIBLDO, mt6370_ocp_handler } + }; + struct regulator_dev *rdev; + int i, irq, ret; + + for (i = 0; i < ARRAY_SIZE(mt6370_irqs); i++) { + irq = platform_get_irq_byname(pdev, mt6370_irqs[i].name); + + rdev = priv->rdev[mt6370_irqs[i].rid]; + + ret = devm_request_threaded_irq(priv->dev, irq, NULL, + mt6370_irqs[i].handler, 0, + mt6370_irqs[i].name, rdev); + if (ret) { + dev_err(priv->dev, + "Failed to register (%d) interrupt\n", i); + return ret; + } + } + + return 0; +} + +static int mt6370_regualtor_register(struct mt6370_priv *priv) +{ + struct regulator_dev *rdev; + struct regulator_config cfg = {}; + struct device *parent = priv->dev->parent; + int i; + + cfg.dev = parent; + cfg.driver_data = priv; + + for (i = 0; i < MT6370_MAX_IDX; i++) { + rdev = devm_regulator_register(priv->dev, + mt6370_regulator_descs + i, + &cfg); + if (IS_ERR(rdev)) { + dev_err(priv->dev, + "Failed to register (%d) regulator\n", i); + return PTR_ERR(rdev); + } + + priv->rdev[i] = rdev; + } + + return 0; +} + +static int mt6370_regulator_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + int ret; + + 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) { + dev_err(&pdev->dev, "Failed to init regmap\n"); + return -ENODEV; + } + + ret = mt6370_regualtor_register(priv); + if (ret) + return ret; + + return mt6370_regulator_irq_register(priv); +} + +static const struct platform_device_id mt6370_devid_table[] = { + { "mt6370-regulator", 0}, + {} +}; +MODULE_DEVICE_TABLE(platform, mt6370_devid_table); + +static struct platform_driver mt6370_regulator_driver = { + .driver = { + .name = "mt6370-regulator", + }, + .id_table = mt6370_devid_table, + .probe = mt6370_regulator_probe, +}; +module_platform_driver(mt6370_regulator_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("Mediatek MT6370 Regulator Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 11:18: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: 12865416 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 22CD9C433F5 for ; Tue, 31 May 2022 11:20:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343741AbiEaLUS (ORCPT ); Tue, 31 May 2022 07:20:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47746 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343786AbiEaLUK (ORCPT ); Tue, 31 May 2022 07:20:10 -0400 Received: from mail-pj1-x1031.google.com (mail-pj1-x1031.google.com [IPv6:2607:f8b0:4864:20::1031]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 62E3069CCA; Tue, 31 May 2022 04:20:08 -0700 (PDT) Received: by mail-pj1-x1031.google.com with SMTP id a10so4172666pju.3; Tue, 31 May 2022 04:20:08 -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=SkB25f3Zqc7wiMdR8YRJzsTcyth+4OQXoMwAgvK1QoA=; b=NuhOZvlfGiUZpSCuZu3LgpOfjTmTb1xgF6pQsbJmP69cAqEoMMSZZemcWt1Q2REQ/m Aaf9qRz4i0UG/6zH1BR0PMzQJiiZL+9OvAaoEIACZ0U1X/hYNUaYPJqEeCTh7fNmW0ej DTRFSKyINYsq52FcDqxfoZrB0eKv5Y+DgiXJhEOI/LciAHL7U+f035JGr0jmHKdDq3zE ykBKaAR+YcPjoiWs80HwDzV6srpiHM6FtCvC4WdkY+Q/wZz2kl3mNAOi0bSgVkjuWwhR boCmjAkgmPBn0sEkE0eYObxegUxyMkECYbb79R0M0byygcjkMdkCP8cXaIn4t+BU6fcj hx7w== 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=SkB25f3Zqc7wiMdR8YRJzsTcyth+4OQXoMwAgvK1QoA=; b=IjL8a+WeY4ehSOBe869CZA+KwGFIxUTMf46So3MZsJU52gbIffdX2v0JCU8MegoYuC HYu+ywFvboCTD9jYN4fybk/v6/aVc0YvOgCRvyb5QBFeWS/m1O2El2WI9uIAQOVrQorq UDTSpVRG/iBHbIlNm7fX660yfYahLpuyABwjBXSDFht2v0yVpgu8Ay1c9omfbICe+fRH +GsH0BeHatnj6R40Fei6YjDUwJCkCItmoN3PvJsGhc3bBZixNZO1mZ1RiiccEbR/hr4u ojoBlDqtzWJA7aqvVf56O/7hJpXMNh+1GkOyO8+RDcYnVuhvFZZFcaZPpuXOh4kZVEa4 T/Tg== X-Gm-Message-State: AOAM5338sYVHWqnbapGLWlak0bT4r3/yMX6Dw/96g87ptkVRWdh87pO9 HlGWbYeziS/YtO0U5tixkKA= X-Google-Smtp-Source: ABdhPJxkcgE7hjPhSnCEnACKJC9S8UsI5VkS1wzDN0T2a2DfJ8k9aNnwhxffmczd9cDbFvFjdKD3cA== X-Received: by 2002:a17:902:a988:b0:158:9877:6c2c with SMTP id bh8-20020a170902a98800b0015898776c2cmr61035260plb.80.1653996007859; Tue, 31 May 2022 04:20:07 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.20.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:20:07 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 10/14] iio: adc: mt6370: Add Mediatek MT6370 support Date: Tue, 31 May 2022 19:18:56 +0800 Message-Id: <20220531111900.19422-11-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 ADC support. Signed-off-by: ChiaEn Wu --- drivers/iio/adc/Kconfig | 9 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mt6370-adc.c | 257 +++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 drivers/iio/adc/mt6370-adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 71ab0a06aa82..d7932dd9b773 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -737,6 +737,15 @@ 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 Y here to enable MT6370 ADC support. + Integrated for System Monitoring includes + is used in smartphones and tablets and supports a 9 channel + general purpose 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 39d806f6d457..0ce285c7e2d0 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 000000000000..3320ebca17ad --- /dev/null +++ b/drivers/iio/adc/mt6370-adc.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 + +#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_ADC_CHAN_SHIFT 4 + +#define MT6370_AICR_400MA 0x6 +#define MT6370_ICHG_500MA 0x4 +#define MT6370_ICHG_900MA 0x8 + +#define ADC_CONV_TIME_US 35000 +#define ADC_CONV_POLLING_TIME 1000 + +struct mt6370_adc_data { + struct device *dev; + struct regmap *regmap; + struct mutex lock; +}; + +static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan, + unsigned long addr, int *val) +{ + __be16 be_val; + unsigned int reg_val; + int ret; + + mutex_lock(&priv->lock); + + reg_val = MT6370_ADC_START_MASK | (addr << MT6370_ADC_CHAN_SHIFT); + ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val); + if (ret) + goto adc_unlock; + + msleep(ADC_CONV_TIME_US / 1000); + + ret = regmap_read_poll_timeout(priv->regmap, + MT6370_REG_CHG_ADC, reg_val, + !(reg_val & MT6370_ADC_START_MASK), + ADC_CONV_POLLING_TIME, + ADC_CONV_TIME_US * 3); + if (ret) { + if (ret == -ETIMEDOUT) + dev_err(priv->dev, "Failed to wait adc conversion\n"); + 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->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 = 5000; + 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 = 33500; + else + *val1 = 50000; + + return IIO_VAL_INT; + 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 = 23750; + else if (reg_val >= MT6370_ICHG_500MA && + reg_val < MT6370_ICHG_900MA) + *val1 = 26800; + else + *val1 = 50000; + + return IIO_VAL_INT; + case MT6370_CHAN_VBUSDIV5: + *val1 = 25000; + return IIO_VAL_INT; + case MT6370_CHAN_VBUSDIV2: + *val1 = 50000; + return IIO_VAL_INT; + case MT6370_CHAN_TS_BAT: + *val1 = 25; + *val2 = 10000; + return IIO_VAL_FRACTIONAL; + case MT6370_CHAN_TEMP_JC: + *val1 = 2; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int mt6370_adc_read_offset(struct mt6370_adc_data *priv, + int chan, int *val) +{ + *val = (chan == MT6370_CHAN_TEMP_JC) ? -20 : 0; + 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); + } + + return -EINVAL; +} + +static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = { + "vbusdiv5", "vbusdiv2", "vsys", "vbat", + "ts_bat", "ibus", "ibat", "chg_vddp", + "temp_jc", +}; + +static int mt6370_adc_read_label(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, char *label) +{ + return snprintf(label, PAGE_SIZE, "%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) { \ + .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) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ +} + +static const struct iio_chan_spec mt6370_adc_channels[] = { + MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1), + MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2), + MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3), + MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4), + MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6), + MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8), + MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9), + MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11), + MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12), +}; + +static int mt6370_adc_probe(struct platform_device *pdev) +{ + int ret; + struct mt6370_adc_data *priv; + struct regmap *regmap; + struct iio_dev *indio_dev; + + regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!regmap) { + dev_err(&pdev->dev, "Failed to get regmap\n"); + return -ENODEV; + } + + 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->lock); + + ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0); + if (ret) { + dev_err(&pdev->dev, "Failed to reset adc\n"); + return ret; + } + + indio_dev->name = dev_name(&pdev->dev); + 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 Drvier"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 11:18: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: 12865417 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 3C6D6C43217 for ; Tue, 31 May 2022 11:20:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343748AbiEaLUS (ORCPT ); Tue, 31 May 2022 07:20:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343813AbiEaLUQ (ORCPT ); Tue, 31 May 2022 07:20:16 -0400 Received: from mail-pj1-x102c.google.com (mail-pj1-x102c.google.com [IPv6:2607:f8b0:4864:20::102c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 708B095DCE; Tue, 31 May 2022 04:20:14 -0700 (PDT) Received: by mail-pj1-x102c.google.com with SMTP id n10so13432202pjh.5; Tue, 31 May 2022 04:20:14 -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=7rETQ+FkwMIdlpu81TFS0C/5rmkhteGjy6EXUj0C1Zk=; b=IV/oiPf/r0RP4fuoF69BFx4fmYN4dhvxrHReuDehru46c/+qtopEaXan0dZ1sXIdIN QBS9YfOuGa98+0FLT8qB47GzjyGYBx5mc15wMZXkDaucPzU/IzOLuzEayzt6rQcpmo1E 64sTRw13OlH9VwJ+/kwzfnEGnVrNGpTwlUvnIjtmlqRc/JocEWjkPMS7r92lmS04flnF 61zHpIHbrNNIKT3G+V7FEyOSzwT1YQK7Mnd7ExzDCIRg+TzjYrvcGZzsNNLKrnTXYvcQ EAQsDgmeb5l2kgXRSiz1wFv9A171nXYHQuf7cJeKXQbeGdhlfWYL5dd5vELXKdUh2Jqn CrBw== 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=7rETQ+FkwMIdlpu81TFS0C/5rmkhteGjy6EXUj0C1Zk=; b=hiqGQsQjjSuoCjZf3KywPG6vHNDEdgce2qp+auwB9LAOKSvXmyv1MOa8DevezsBc1o SgASB3NEwy36Nd2nEEhB+QijbZ0wNaObiAJxHIwfoOIkcAMUNvvJyLkUtYlc2qXGVDUz XElTnsBIPoHWzsX5Go75wn09s70qNUcr8nuypX0zbCatbyTans2TtVK9sXinoG57XrZL BCWP7QMBQPpubY4RFshuvyOYW3ZmC2ynQMp1atMPgJXTU79+fcv5wEM+yoWK3cfn2Gzc JzXmdU3rys5W30jDPcUZr+LAn8ll9VDns4lFnw74JpvfBh/CSXI2b4M73zE2i0LU/+s8 0GCA== X-Gm-Message-State: AOAM531DWLW1DaNu46MuTPC/7A0Tf5XuDrp2IjENLrrU7j9qf/dCigbm 812nWhXJyUah2UsGxNLcu7M= X-Google-Smtp-Source: ABdhPJyw3pnx0NX0S8Il3x4kszw8LgD3t3buJRPTxq0pGYYyhyQjNyoihJveL2zRbRuYHqsDedoyRg== X-Received: by 2002:a17:90b:380b:b0:1e0:2639:6e2d with SMTP id mq11-20020a17090b380b00b001e026396e2dmr27930830pjb.203.1653996013736; Tue, 31 May 2022 04:20:13 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.20.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:20:13 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 11/14] power: supply: mt6370: Add Mediatek MT6370 charger driver Date: Tue, 31 May 2022 19:18:57 +0800 Message-Id: <20220531111900.19422-12-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 driver Signed-off-by: ChiaEn Wu --- drivers/power/supply/Kconfig | 11 + drivers/power/supply/Makefile | 1 + drivers/power/supply/mt6370-charger.c | 1132 +++++++++++++++++++++++++ 3 files changed, 1144 insertions(+) create mode 100644 drivers/power/supply/mt6370-charger.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 1aa8323ad9f6..54d8c3ab01cc 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -619,6 +619,17 @@ 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. + 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 7f02f36aea55..8c9527643c86 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 000000000000..1cfa4deeb28e --- /dev/null +++ b/drivers/power/supply/mt6370-charger.c @@ -0,0 +1,1132 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#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 100000 /* 100 mA */ + +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_CTRL5 */ + F_VOBST, + /* 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; + atomic_t 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_range { + u32 min; + u32 max; + u16 step; + u8 offset; + const u32 *table; + u16 num_table; + bool round_up; +}; + +struct mt6370_chg_field { + const char *name; + const struct mt6370_chg_range *range; + struct reg_field field; +}; + +static const u32 mt6370_chg_otg_oc_ma[] = { + 500000, 700000, 1100000, 1300000, 1800000, 2100000, 2400000, +}; + +#define MT6370_CHG_RANGE(_min, _max, _step, _offset, _ru) \ +{ \ + .min = _min, \ + .max = _max, \ + .step = _step, \ + .offset = _offset, \ + .round_up = _ru, \ +} + +#define MT6370_CHG_RANGE_T(_table, _ru) \ +{ \ + .table = _table, \ + .num_table = ARRAY_SIZE(_table), \ + .round_up = _ru, \ +} + +static const struct mt6370_chg_range mt6370_chg_ranges[F_MAX] = { + [F_IAICR] = MT6370_CHG_RANGE(100, 3250, 50, 0, false), + [F_VOREG] = MT6370_CHG_RANGE(3900, 4710, 10, 0, false), + [F_VOBST] = MT6370_CHG_RANGE(4425, 5825, 25, 0, false), + [F_VMIVR] = MT6370_CHG_RANGE(3900, 13400, 100, 0, true), + [F_ICHG] = MT6370_CHG_RANGE(900, 5000, 100, 8, false), + [F_IPREC] = MT6370_CHG_RANGE(100, 850, 50, 0, false), + [F_IEOC] = MT6370_CHG_RANGE(100, 850, 50, 0, false), +}; + +#define MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb, _range) \ +[_fd] = { \ + .name = #_fd, \ + .range = _range ? &mt6370_chg_ranges[_fd] : NULL, \ + .field = REG_FIELD(_reg, _lsb, _msb), \ +} + +#define MT6370_CHG_FIELD(_fd, _reg, _lsb, _msb) \ + MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb, (_msb > _lsb)) + +static const struct mt6370_chg_field mt6370_chg_fields[F_MAX] = { + MT6370_CHG_FIELD_RANGE(F_IINLMTSEL, MT6370_REG_CHG_CTRL2, 2, 3, false), + 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(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(F_VOREG, MT6370_REG_CHG_CTRL4, 1, 7), + MT6370_CHG_FIELD(F_VOBST, MT6370_REG_CHG_CTRL5, 2, 7), + MT6370_CHG_FIELD(F_VMIVR, MT6370_REG_CHG_CTRL6, 1, 7), + MT6370_CHG_FIELD(F_ICHG, MT6370_REG_CHG_CTRL7, 2, 7), + MT6370_CHG_FIELD(F_IPREC, MT6370_REG_CHG_CTRL8, 0, 3), + MT6370_CHG_FIELD(F_IEOC, MT6370_REG_CHG_CTRL9, 4, 7), + MT6370_CHG_FIELD(F_USBCHGEN, MT6370_REG_DEVICE_TYPE, 7, 7), + MT6370_CHG_FIELD_RANGE(F_USB_STAT, MT6370_REG_USB_STATUS1, 4, 6, false), + MT6370_CHG_FIELD(F_CHGDET, MT6370_REG_USB_STATUS1, 3, 3), + MT6370_CHG_FIELD_RANGE(F_CHG_STAT, MT6370_REG_CHG_STAT, 6, 7, false), + 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 u32 mt6370_chg_val_to_reg(const struct mt6370_chg_range *range, + u32 val) +{ + int i; + u8 reg; + + if (!range) + return val; + + if (range->table) { + if (val <= range->table[0]) + return 0; + + for (i = 1; i < range->num_table - 1; i++) { + if (val == range->table[i]) + return i; + if (val > range->table[i] && + val < range->table[i + 1]) + return range->round_up ? i + 1 : i; + } + + return range->num_table - 1; + } + + if (val <= range->min) + reg = 0; + else if (val >= range->max) + reg = (range->max - range->min) / range->step; + else if (range->round_up) + reg = DIV_ROUND_UP(val - range->min, range->step); + else + reg = (val - range->min) / range->step; + + return reg + range->offset; +} + +static inline u32 mt6370_chg_reg_to_val(const struct mt6370_chg_range *range, + u8 reg) +{ + if (!range) + return reg; + + return range->table ? range->table[reg] : + range->min + range->step * (reg - range->offset); +} + +static inline int mt6370_chg_field_get(struct mt6370_priv *priv, + enum mt6370_chg_reg_field fd, u32 *val) +{ + int ret; + u32 reg_val; + + ret = regmap_field_read(priv->rmap_fields[fd], ®_val); + if (ret < 0) + return ret; + + *val = mt6370_chg_reg_to_val(mt6370_chg_fields[fd].range, reg_val); + + return 0; +} + +static inline int mt6370_chg_field_set(struct mt6370_priv *priv, + enum mt6370_chg_reg_field fd, u32 val) +{ + val = mt6370_chg_val_to_reg(mt6370_chg_fields[fd].range, 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; + unsigned int val; + int ret = 0; + + 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)) { + dev_err(priv->dev, "Failed to requeset OTG EN Pin\n"); + rcfg->ena_gpiod = NULL; + } else { + val = MT6370_OPA_MODE_MASK | MT6370_OTG_PIN_EN_MASK; + ret = regmap_update_bits(priv->regmap, MT6370_REG_CHG_CTRL1, + val, val); + if (ret) + dev_err(priv->dev, "Failed to set otg bits\n"); + } + + return ret; +} + +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, attach; + bool rpt_psy = false; + u32 usb_stat; + + mutex_lock(&priv->attach_lock); + attach = atomic_read(&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) { + dev_err(priv->dev, "Failed to get platform resource\n"); + } else { + if (en) + enable_irq(irq_num); + else + disable_irq_nosync(irq_num); + } +} + +static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv) +{ + int ret; + u32 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"); + goto toggle_cfo_exit; + } + + if (fl_strobe) { + dev_err(priv->dev, "Flash led is still in strobe mode\n"); + goto toggle_cfo_exit; + } + + /* 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"); + goto toggle_cfo_exit; + } + + /* 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"); + goto toggle_cfo_exit; + } + +toggle_cfo_exit: + return ret; +} + +static int mt6370_chg_read_adc_chan(struct mt6370_priv *priv, unsigned int chan, + int *val) +{ + int ret; + + if (chan >= MT6370_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; + u32 mivr_stat; + unsigned int 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_CHAN_IBUS, &ibus); + if (ret) { + dev_err(priv->dev, "Failed to get ibus\n"); + goto mivr_handler_out; + } + + if (ibus < MT6370_MIVR_IBUS_TH) { + 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; + u32 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) + 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 = !!atomic_read(&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; + u32 chg_stat; + + ret = mt6370_chg_get_online(priv, val); + if (!val->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; + break; + case MT6370_CHG_STAT_CHARGE_IN_PROGRESS: + val->intval = POWER_SUPPLY_STATUS_CHARGING; + break; + case MT6370_CHG_STAT_DONE: + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + default: + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + break; + } + + return ret; +} + +static int mt6370_chg_get_charge_type(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + int type, ret; + u32 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) +{ + return mt6370_chg_ranges[F_ICHG].max; +} + +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) +{ + return mt6370_chg_ranges[F_VOREG].max; +} + +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) +{ + int attach; + u32 pwr_rdy = !!val->intval; + + mutex_lock(&priv->attach_lock); + attach = atomic_read(&priv->attach); + if (pwr_rdy == !!attach) { + dev_err(priv->dev, "pwr_rdy is same(%d)\n", pwr_rdy); + mutex_unlock(&priv->attach_lock); + return 0; + } + + atomic_set(&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); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + ret = mt6370_chg_get_online(priv, val); + break; + case POWER_SUPPLY_PROP_STATUS: + ret = mt6370_chg_get_status(priv, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + ret = mt6370_chg_get_charge_type(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = mt6370_chg_get_ichg(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + ret = mt6370_chg_get_max_ichg(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = mt6370_chg_get_cv(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + ret = mt6370_chg_get_max_cv(priv, val); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = mt6370_chg_get_aicr(priv, val); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = mt6370_chg_get_mivr(priv, val); + break; + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + ret = mt6370_chg_get_iprechg(priv, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + ret = mt6370_chg_get_ieoc(priv, val); + break; + case POWER_SUPPLY_PROP_TYPE: + val->intval = priv->psy_desc->type; + break; + case POWER_SUPPLY_PROP_USB_TYPE: + val->intval = priv->psy_usb_type; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +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); + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + ret = mt6370_chg_set_online(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = mt6370_chg_set_ichg(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = mt6370_chg_set_cv(priv, val); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = mt6370_chg_set_aicr(priv, val); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = mt6370_chg_set_mivr(priv, val); + break; + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + ret = mt6370_chg_set_iprechg(priv, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + ret = mt6370_chg_set_ieoc(priv, val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +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 struct regulator_desc mt6370_chg_otg_rdesc = { + .of_match = "mt6370,otg-vbus", + .of_parse_cb = mt6370_chg_otg_of_parse_cb, + .name = "mt6370,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])) { + dev_err(priv->dev, + "Failed to allocate regmap field [%s]\n", + fds[i].name); + return PTR_ERR(priv->rmap_fields[i]); + } + } + + return 0; +} + +static int mt6370_chg_init_setting(struct mt6370_priv *priv) +{ + int ret; + + priv->wq = create_singlethread_workqueue(dev_name(priv->dev)); + if (IS_ERR(priv->wq)) { + dev_err(priv->dev, "Failed to create workqueue\n"); + return PTR_ERR(priv->wq); + } + + INIT_WORK(&priv->bc12_work, mt6370_chg_bc12_work_func); + INIT_DELAYED_WORK(&priv->mivr_dwork, mt6370_chg_mivr_dwork_func); + mutex_init(&priv->attach_lock); + atomic_set(&priv->attach, 0); + + /* 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 Workaroud, 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 IS_ERR(priv->rdev) ? PTR_ERR(priv->rdev) : 0; +} + +static int mt6370_chg_init_psy(struct mt6370_priv *priv) +{ + struct power_supply_config cfg = { + .drv_data = priv, + .of_node = priv->dev->of_node, + }; + + 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 IS_ERR(priv->psy) ? PTR_ERR(priv->psy) : 0; +} + +static irqreturn_t mt6370_attach_i_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + u32 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_HANDLED; + } + + if (otg_en) + return IRQ_HANDLED; + + mutex_lock(&priv->attach_lock); + atomic_set(&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) { + dev_err(priv->dev, "Failed to get irq %s\n", + mt6370_chg_irqs[i].name); + return ret; + } + + 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) { + dev_err(priv->dev, "Failed to request irq %s\n", + mt6370_chg_irqs[i].name); + return ret; + } + } + + 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) { + dev_err(&pdev->dev, "Failed to get regmap\n"); + return -ENODEV; + } + + ret = mt6370_chg_init_rmap_fields(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init regmap fields\n"); + return ret; + } + + platform_set_drvdata(pdev, priv); + + priv->iio_adcs = devm_iio_channel_get_all(priv->dev); + if (IS_ERR(priv->iio_adcs)) { + dev_err(&pdev->dev, "Failed to get iio adc\n"); + return PTR_ERR(priv->iio_adcs); + } + + ret = mt6370_chg_init_otg_regulator(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init otg regulator\n"); + return ret; + } + + ret = mt6370_chg_init_psy(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init psy\n"); + return ret; + } + + ret = mt6370_chg_init_setting(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init mt6370 private data\n"); + goto probe_out; + } + + ret = mt6370_chg_init_irq(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init irq\n"); + goto probe_out; + } + + mt6370_chg_pwr_rdy_check(priv); + + return 0; + +probe_out: + 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); + + if (priv) { + mt6370_chg_enable_irq(priv, "mivr", false); + cancel_delayed_work_sync(&priv->mivr_dwork); + 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 = of_match_ptr(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 Tue May 31 11:18: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: 12865419 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 DE174C43219 for ; Tue, 31 May 2022 11:20:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343790AbiEaLU1 (ORCPT ); Tue, 31 May 2022 07:20:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47950 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343825AbiEaLUW (ORCPT ); Tue, 31 May 2022 07:20:22 -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 BACED996AB; Tue, 31 May 2022 04:20:20 -0700 (PDT) Received: by mail-pj1-x1032.google.com with SMTP id n13-20020a17090a394d00b001e30a60f82dso2294465pjf.5; Tue, 31 May 2022 04:20:20 -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=6XRfvkGn1CSxkqOOGSIlgNisWraQte9YHtsokeaF/pA=; b=KnVHMLONHfoUWGzDBi42UAxJ0PZRIUdzDjNUJ6Vkp6JcAgkCGL9+gjVjFGlfS4LLVb Y31nqkUrzqEJFmXkAjwy3ZdPKjGjuetM5cCxtQOkNapc4yRZHowGKG2GFPWi0SPd2ngC hZBIOKRqi59/zWGIPxrECI8mPKvJ7XsaaJh/Rrbwje2od0dtqBplgrVVXp4QkpvN+ue2 2qkzDdvTduE2xorEXaSKU5CjANN6cFyw3PpR0C31qGH9pAAaINb7qZPQ/zSzT8iUi9t5 4NeodY0UWaNkSFbADiEJSHZ87uDHjI8c1t6+C+dWzms2+ySzkMgHfpLxrJPytPviIJO9 ATUA== 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=6XRfvkGn1CSxkqOOGSIlgNisWraQte9YHtsokeaF/pA=; b=V9wZtdNHIvUAxZUKMWnEykYOp6f+46rJPI2KAZAwBH0aqNkYzGnzCxqayvVIvABo+0 34z+Qlj26D0faldwa6iqnwGwpb5cNaof/YgUzQD3X/Qau9qIELWLBnu/GGJelAGVbMdK 9xrapucEAo17TXqO9GCesHpPbaTfJHfG5Le6N/YZxlIoVnnOFjnE4xEkz3E6OCEGDIru rihA0KhAbM9UyNXf63TXSk5QP5YpF3nElT61uv95UZweAoUcHvkwtXJmEhSBZFivr7jH /tcW9l4FbpuNH00XgqvtQEAbbu0aWQp761jbM5mt3oNv9LhSLkRxOQnuGdXHS8WTiFPq uXbQ== X-Gm-Message-State: AOAM533eMrP9xEn1C1wlv+03/oJaSfb07qTvfqsnKQLH0KlBe8+Reskb ZmUkIqvvoCaZ7LneJrA7mT3UYKPGAqg= X-Google-Smtp-Source: ABdhPJz5oJKc+9d4EYebGdxyx9IBvm+LBaffFntTZsDrAVXTOV/lfoRe1duaa4qE9K29K64dwdR2cA== X-Received: by 2002:a17:902:9308:b0:15f:12dc:7c7c with SMTP id bc8-20020a170902930800b0015f12dc7c7cmr60943687plb.141.1653996020059; Tue, 31 May 2022 04:20:20 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.20.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:20:19 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 12/14] leds: mt6370: Add Mediatek MT6370 Indicator support Date: Tue, 31 May 2022 19:18:58 +0800 Message-Id: <20220531111900.19422-13-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 Indicator support Signed-off-by: Alice Chen --- drivers/leds/Kconfig | 11 + drivers/leds/Makefile | 1 + drivers/leds/leds-mt6370.c | 994 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1006 insertions(+) create mode 100644 drivers/leds/leds-mt6370.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 6090e647daee..0cb2294b3431 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -244,6 +244,17 @@ 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 + Support 4 channels and reg/pwm/breath mode. + Isink4 can also use as a CHG_VIN power good Indicator. + Say Y here to enable support for + MT6370_RGB_LED device. + 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 e58ecb36360f..b641fd83f49a 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 000000000000..54f654d4f4fc --- /dev/null +++ b/drivers/leds/leds-mt6370.c @@ -0,0 +1,994 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#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 { + 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) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + 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) { + dev_err(&pdev->dev, "Failed to allocate regmap field\n"); + return ret; + } + + 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) { + dev_err(&pdev->dev, "Failed to parse reg property\n"); + return ret; + } + + if (reg >= MT6370_MAX_LEDS) { + dev_err(&pdev->dev, "Error reg property number\n"); + return -EINVAL; + } + + 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)) { + dev_err(&pdev->dev, "Duplicat reg property\n"); + return -EINVAL; + } + + 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 Tue May 31 11:18: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: 12865579 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 A44F4C433FE for ; Tue, 31 May 2022 13:00:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344444AbiEaNAM (ORCPT ); Tue, 31 May 2022 09:00:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344504AbiEaM77 (ORCPT ); Tue, 31 May 2022 08:59:59 -0400 Received: from mail-vk1-xa42.google.com (mail-vk1-xa42.google.com [IPv6:2607:f8b0:4864:20::a42]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C8BEA78EF9; Tue, 31 May 2022 05:59:57 -0700 (PDT) Received: by mail-vk1-xa42.google.com with SMTP id b144so2409671vkb.13; Tue, 31 May 2022 05:59:57 -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=BSdr8+r5Ds9gs2IXE1+eZosXCCxyKF7WbPPTygW5JnM=; b=UOlAMqqdHDSM6DUm5CbYG9mbxWLPGg9ew/44fK2M2utSbZcg9o9VJCdrSMVLW+tbo6 Ov0Y3DEYAcjb5CLXvu0aChpvgq0Xm8VUKq79i/L58rprXQaad7Fk6L6OvzJ0IwOn5zSr sfLB/bWrKD+p1dW9jQ48ZIVCSxn1ckNNofLfvhbakyNyAZsWVVE+akToB2jy/PNi70uK LUOuDcz2lZQa4If3ShQGV00e/nmZ3PObg7ln3yDwWai8C54HoEFTzWEYbhrizaiZ1vQO qHHMEkDNtZn0JK9TncA+I9gsB6XDjkP8Y/DhjEQb41nPoafmsovKRQ+/mWwsP0lOXf8N 9kEA== 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=BSdr8+r5Ds9gs2IXE1+eZosXCCxyKF7WbPPTygW5JnM=; b=8F1tR25grV8eQAvvDfFcmnaN/SPLmAE1E8kN5BaNJvmMJO9q+3+l4liZV0CxUwbq9J eL4/BwGWGEV/iS9/0BCSpz5Pf0SnEq73UafEPDf91Gd05iOtsQERv051/7oD1CuI3AhL zre90agHJT452bsXoPQsm8UjIbaZWWRPliUrudWM0ZeF+u9g3FkRTNDM93oG3jQxz/bl VrC7POgnxwzCJZOGrKJOU1J1tlxsajeXI+4Yb6UjGtRsn9NA0Lk3hm/vjRjUZEvqzN84 xV+n/SUg7qlkoLquoaHMzrFryipUm3mb2Ia4LS/IXi+G49Z3rJYXMAfzce3jHQg0Lt+r N3eg== X-Gm-Message-State: AOAM532qyl6WjWDD3ht0I4wza4Rtv5PAGH806beflrvs6OHaNgd1fCkQ mbmNhWcgpoHMQXD6ZRwp5Sr7yZvLUh8= X-Google-Smtp-Source: ABdhPJxDHl7MTFnizRaoNOaUtazwfxXXFmY2GgIpZbdyILLqkYdowKfhJ+aUsJrFR9Ma4+rOtO04FQ== X-Received: by 2002:a62:7b4c:0:b0:51b:9c0e:a03d with SMTP id w73-20020a627b4c000000b0051b9c0ea03dmr1107901pfc.54.1653996025788; Tue, 31 May 2022 04:20:25 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.20.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:20:25 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 13/14] leds: flashlight: mt6370: Add Mediatek MT6370 flashlight support Date: Tue, 31 May 2022 19:18:59 +0800 Message-Id: <20220531111900.19422-14-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 support Signed-off-by: Alice Chen --- drivers/leds/flash/Kconfig | 9 + drivers/leds/flash/Makefile | 1 + drivers/leds/flash/leds-mt6370-flash.c | 665 +++++++++++++++++++++++++ 3 files changed, 675 insertions(+) create mode 100644 drivers/leds/flash/leds-mt6370-flash.c diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig index d3eb689b193c..d38e263aaf09 100644 --- a/drivers/leds/flash/Kconfig +++ b/drivers/leds/flash/Kconfig @@ -90,4 +90,13 @@ 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. + endif # LEDS_CLASS_FLASH diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile index 0acbddc0b91b..4c4c1710f506 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 000000000000..8f6796aae3e1 --- /dev/null +++ b/drivers/leds/flash/leds-mt6370-flash.c @@ -0,0 +1,665 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#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_MINUA 25000 +#define MT6370_ITORCH_STEPUA 12500 +#define MT6370_ITORCH_MAXUA 400000 +#define MT6370_ITORCH_DOUBLE_MAXUA 800000 +#define MT6370_ISTRB_MINUA 50000 +#define MT6370_ISTRB_STEPUA 12500 +#define MT6370_ISTRB_MAXUA 1500000 +#define MT6370_ISTRB_DOUBLE_MAXUA 3000000 +#define MT6370_STRBTO_MINUS 64000 +#define MT6370_STRBTO_STEPUS 32000 +#define MT6370_STRBTO_MAXUS 2432000 + +#define STATE_OFF 0 +#define STATE_KEEP 1 +#define STATE_ON 2 + +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 = + container_of(lcdev, struct mt6370_led, 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 to be kept by 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 = container_of(fl_cdev, struct mt6370_led, + 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); + if (ret) + return ret; + } + return ret; +} + +static int mt6370_strobe_set(struct led_classdev_flash *fl_cdev, bool state) +{ + struct mt6370_led *led = container_of(fl_cdev, struct mt6370_led, + 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, HW rampping up/down time is 5ms/500us, + * respectively + */ + 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 = container_of(fl_cdev, struct mt6370_led, + 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 = container_of(fl_cdev, struct mt6370_led, + 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 = container_of(fl_cdev, struct mt6370_led, + 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 = container_of(flash, struct mt6370_led, 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_MINUA; + s->step = MT6370_ITORCH_STEPUA; + 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_MAXUA : MT6370_ITORCH_MAXUA; + 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_MINUA; + } else + val = clamp_align(val, MT6370_ITORCH_MINUA, max_uA, + MT6370_ITORCH_STEPUA); + + lcdev->max_brightness = (val - MT6370_ITORCH_MINUA) / + MT6370_ITORCH_STEPUA + 1; + lcdev->brightness_set_blocking = mt6370_torch_brightness_set; + lcdev->flags |= LED_DEV_CAP_FLASH; + + max_uA = (num == 2) ? MT6370_ISTRB_DOUBLE_MAXUA : MT6370_ISTRB_MAXUA; + 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_MINUA; + } else + val = clamp_align(val, MT6370_ISTRB_MINUA, max_uA, + MT6370_ISTRB_STEPUA); + + s = &flash->brightness; + s->min = MT6370_ISTRB_MINUA; + s->step = MT6370_ISTRB_STEPUA; + 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_MINUS; + } else + val = clamp_align(val, MT6370_STRBTO_MINUS, MT6370_STRBTO_MAXUS, + MT6370_STRBTO_STEPUS); + + + s = &flash->timeout; + s->min = MT6370_STRBTO_MINUS; + s->step = MT6370_STRBTO_STEPUS; + 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; + int ret; + + if (!fwnode_property_read_string(init_data->fwnode, + "default-state", &str)) { + ret = match_string(states, ARRAY_SIZE(states), str); + if (ret < 0) + ret = STATE_OFF; + + 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) { + dev_err(&pdev->dev, + "No child node or node count over max led number %lu\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) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + 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 Tue May 31 11:19: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: 12865420 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 86277C433FE for ; Tue, 31 May 2022 11:21:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343860AbiEaLUw (ORCPT ); Tue, 31 May 2022 07:20:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48640 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237509AbiEaLUp (ORCPT ); Tue, 31 May 2022 07:20:45 -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 519D29C2CB; Tue, 31 May 2022 04:20:32 -0700 (PDT) Received: by mail-pg1-x52a.google.com with SMTP id j21so12518224pga.13; Tue, 31 May 2022 04:20:31 -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=gSHJ8cU7Tk4Hdo/isRqfWUjlGNskb5R2AVQxrPbbCvI=; b=BAwE+FQYcm+QAHZOVYkrf1nJgkUejNVR41Y0KW3Z9RYjFyVS44A5/iQucDrf6PObF+ Dj2Bn7e7NSSXExIVfJPqPKOyb3QFSqleH97sXuhEEMXdOoako0WiPecFNlqdu2fcuLEb vbylEsHv+QpXjytqQ41XjANm1w34AID2kHRhIsM/LGh01dDw223buOMMLMNZvfgdPuRn 9yT0uTRtSzOoJ+3RJjvqlIk6HUeYxt/sSfVIG1CuoO536TPUZem+tBqzKS1kD45jQ2sn YsHio3ALB3X3a3Rrr5Lnu9fJtsdjlTwxQqtMVuuIae3rE+X+9j/sEN8NQy4cqSTYcLz4 28Dw== 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=gSHJ8cU7Tk4Hdo/isRqfWUjlGNskb5R2AVQxrPbbCvI=; b=2bYg2GC6r8GccO1XXt+8GX/EZaRkPJZh+jjzi+CT8upV5rByusTCB+R4qjGwIMchJR NSBKGKqNZE2kO6vxT6rn2xli30D257285Nj9Y9fR8pS52yfYfrPedQK5jqy07zBAgN97 YmwbP4+ymZ3oeDOWAWoUAJli0RJNnEkDIqJkit4Qjat6eMLrWldHG5NsmaM057F5Phdm hn9xvHkm+ugfE2C/qbMPsjv/YD303J2b2lz081RKGxlM7hAuQMFTtGSpGOOI/2+KbpZb pGWUKJIUQjaGd6DHwl+dgT0XCCyf0GjDGTsl1HeUNIT1FSiRjLYDSXUHpkqca6Shoyoh hBnQ== X-Gm-Message-State: AOAM533ReLcrOD7QApGdjeGhtXO2UdeY1rA47tbvYMN+ChxWszuVTNYR /HermnAC3cEKiz/q3SSRn9Y= X-Google-Smtp-Source: ABdhPJxq4e3rx0PBYsn6k0kwujhUVNgwq1gpO37ByimBz2DIkgl7BDjHmSLvQJwi+DoDr7CHhAPbvA== X-Received: by 2002:a05:6a00:2287:b0:518:85ee:9992 with SMTP id f7-20020a056a00228700b0051885ee9992mr47584234pfe.62.1653996031463; Tue, 31 May 2022 04:20:31 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id cm24-20020a056a00339800b00518142f8c37sm10751608pfb.171.2022.05.31.04.20.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 04:20:31 -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: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, peterwu.pub@gmail.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 Subject: [RESEND 14/14] video: backlight: mt6370: Add Mediatek MT6370 support Date: Tue, 31 May 2022 19:19:00 +0800 Message-Id: <20220531111900.19422-15-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531111900.19422-1-peterwu.pub@gmail.com> References: <20220531111900.19422-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 Backlight support. Signed-off-by: ChiaEn Wu --- drivers/video/backlight/Kconfig | 8 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/mt6370-backlight.c | 338 +++++++++++++++++++++ 3 files changed, 347 insertions(+) create mode 100644 drivers/video/backlight/mt6370-backlight.c diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index a003e02e13ce..d9868fbe7488 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -268,6 +268,14 @@ 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 + Say Y here to enable MT6370 Backlight support. + It's commonly used to drive the display WLED. There're 4 channels + inisde, and each channel can provide up to 30mA current. + config BACKLIGHT_APPLE tristate "Apple Backlight Driver" depends on X86 && ACPI diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index cae2c83422ae..e815f3f1deff 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 000000000000..f8a8d33203ed --- /dev/null +++ b/drivers/video/backlight/mt6370-backlight.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0 + +#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_MAX_BRIGHTNESS 2048 + +enum { + MT6370_VID_COMMON = 0, + MT6370_VID_6372, + MT6370_VID_MAX, +}; + +enum mt6370_prop_type { + MT6370_PARSE_TYPE_BOOL = 0, + MT6370_PARSE_TYPE_U8, + MT6370_PARSE_TYPE_MAX, +}; + +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); + + 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; + } + + if (priv->enable_gpio) + 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, +}; + +#define MT6370_DT_PROP_DECL(_name, _type, _reg, _mask, _max, _inv) \ +{ \ + .name = "mediatek,bled-" #_name, \ + .type = MT6370_PARSE_TYPE_##_type, \ + .reg = _reg, \ + .mask = _mask, \ + .max_val = _max, \ + .invert = _inv, \ +} + +static int mt6370_init_backlight_properties(struct mt6370_priv *priv, + struct backlight_properties *props) +{ + struct device *dev = priv->dev; + u8 prop_val; + u32 brightness; + unsigned int mask, val; + static const struct { + char *name; + enum mt6370_prop_type type; + unsigned int reg; + unsigned int mask; + u8 max_val; + bool invert; + } vendor_opt_props[] = { + MT6370_DT_PROP_DECL(pwm-enable, BOOL, MT6370_REG_BL_PWM, + MT6370_BL_PWM_EN_MASK, 1, false), + MT6370_DT_PROP_DECL(pwm-hys-enable, BOOL, MT6370_REG_BL_PWM, + MT6370_BL_PWM_HYS_EN_MASK, 1, false), + MT6370_DT_PROP_DECL(pwm-hys-sel, U8, MT6370_REG_BL_PWM, + MT6370_BL_PWM_HYS_SEL_MASK, 3, false), + MT6370_DT_PROP_DECL(ovp-level-sel, U8, MT6370_REG_BL_BSTCTRL, + MT6370_BL_OVP_SEL_MASK, 3, false), + MT6370_DT_PROP_DECL(ovp-shutdown, BOOL, MT6370_REG_BL_BSTCTRL, + MT6370_BL_OVP_EN_MASK, 1, true), + MT6370_DT_PROP_DECL(ocp-level-sel, U8, MT6370_REG_BL_BSTCTRL, + MT6370_BL_OC_SEL_MASK, 3, false), + MT6370_DT_PROP_DECL(ocp-shutdown, BOOL, MT6370_REG_BL_BSTCTRL, + MT6370_BL_OC_EN_MASK, 1, true), + }, *prop_now; + int i, ret; + + /* vendor optional properties */ + for (i = 0; i < ARRAY_SIZE(vendor_opt_props); i++) { + prop_now = vendor_opt_props + i; + + switch (prop_now->type) { + case MT6370_PARSE_TYPE_BOOL: + if (device_property_read_bool(dev, prop_now->name)) + val = 1; + else + val = 0; + break; + case MT6370_PARSE_TYPE_U8: + ret = device_property_read_u8(dev, prop_now->name, + &prop_val); + /* Property not exist, keep value in default */ + if (ret) + continue; + + val = min_t(u8, prop_val, prop_now->max_val); + break; + default: + return -EINVAL; + } + + if (prop_now->invert) + val = prop_now->max_val - val; + + val <<= ffs(prop_now->mask) - 1; + + ret = regmap_update_bits(priv->regmap, prop_now->reg, + prop_now->mask, 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) { + dev_err(dev, "No channel specified\n"); + 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) +{ + 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 mt6370_priv *priv; + struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .scale = BACKLIGHT_SCALE_LINEAR, + }; + int ret; + + 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) { + dev_err(&pdev->dev, "Failed to get regmap\n"); + return -ENODEV; + } + + ret = mt6370_check_vendor_info(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to check vendor info (%d)\n", ret); + return ret; + } + + priv->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->enable_gpio)) { + dev_err(&pdev->dev, "Failed to get 'enable' gpio\n"); + return PTR_ERR(priv->enable_gpio); + } + + ret = mt6370_init_backlight_properties(priv, &props); + if (ret) { + dev_err(&pdev->dev, "Failed to init backlight properties\n"); + return ret; + } + + priv->bl = devm_backlight_device_register(&pdev->dev, pdev->name, + &pdev->dev, priv, + &mt6370_bl_ops, &props); + if (IS_ERR(priv->bl)) { + dev_err(&pdev->dev, "Failed to register backlight\n"); + return PTR_ERR(priv->bl); + } + + 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");