From patchwork Thu Jun 23 11:56:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 584358 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 643EFCCA480 for ; Thu, 23 Jun 2022 11:57:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231614AbiFWL50 (ORCPT ); Thu, 23 Jun 2022 07:57:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41290 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231592AbiFWL5S (ORCPT ); Thu, 23 Jun 2022 07:57:18 -0400 Received: from mail-pj1-x102d.google.com (mail-pj1-x102d.google.com [IPv6:2607:f8b0:4864:20::102d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DE3A14D26D; Thu, 23 Jun 2022 04:57:17 -0700 (PDT) Received: by mail-pj1-x102d.google.com with SMTP id dw10-20020a17090b094a00b001ed00a16eb4so2338431pjb.2; Thu, 23 Jun 2022 04:57:17 -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=pUBtsagIsVkX8Y3XaZ3P+E6UwRwPnXULrf1i7+CDAYk=; b=HUqGrLrAyQxEgyQxCKoJIayS2tvkFNjWmplRFdMK1iO8SGvV4tEinbq75vS0cBu5PL XgH273UsGvrqERUSGbu1r2oXrED2leZrGYtEVo7qB3dvfMdJkIM4QNUiOCViKrqBKKgX +qDBGXPT+Bmxkeqj6riTOkA5nfRjIzvi0v/2xZQ94J62XosDTuvDJ+1o441hzQbp4wEi 1sp+DfsLwVjXFCMItlbeV6Zp3Fjs1t673VTr81jY6v6sDO5ISthwJ7oAib9DPrpPwqEB gJxrgu+AL5vyQnvSC5RyMwUirmtWNXgEGoSuXIIfbAFnbcho4bJx66zLGRJtwJyw6vHI 38Ww== 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=pUBtsagIsVkX8Y3XaZ3P+E6UwRwPnXULrf1i7+CDAYk=; b=SNM8RDR11DhWCYIOuNJuZiH7QMToD2+83OdaCDbaMCgT0DLl13rddng8sQoLdgqkTp K3an4xE8umTbkdqGlv7jo5s+ActW2NaGejBZE5MvKyEH7aw1OlIDC4DuCTolOe3RDWaf TWshq3L0EHFLXJmEZXg9uTw5jK5SskUtLeBvf7++9HSGPHmxLCQ/Sqh1FOEXrCW0JQn/ gMN56/KxoxB1OSZUlWSc71WhiMYYOpq2/S8l8sk4uCOeCEue+HnO6oukp9p2kzygAI6q sdrM1yljBnKwGXB6mmaEEhsa4Oa0Ka6rPoKuhtpNGgBflPrywOmGFOi+AHghtxC2hm89 DtXg== X-Gm-Message-State: AJIora9BB/Jx+nt3SCsid/xUY5yQzHw2AqtObjSLU4daQvDHr3GXrKOE 54gTvQx8uAseYhRikqZISfct2aHt8rk= X-Google-Smtp-Source: AGRyM1vhaWgaoShKoMGABtGUhnYLtLbNBz5rjPqyBvlkLjDrmroIA6VhBGVRXbYC4LbB1KTob0Elvw== X-Received: by 2002:a17:902:ea04:b0:16a:1f33:cb0d with SMTP id s4-20020a170902ea0400b0016a1f33cb0dmr21465257plg.103.1655985437347; Thu, 23 Jun 2022 04:57:17 -0700 (PDT) Received: from RD-3580-24288.rt.l (111-71-94-93.emome-ip.hinet.net. [111.71.94.93]) by smtp.gmail.com with ESMTPSA id t6-20020a63b246000000b003fbfe88be17sm15016516pgo.24.2022.06.23.04.57.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jun 2022 04:57:17 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v3 02/14] dt-bindings: power: supply: Add Mediatek MT6370 Charger Date: Thu, 23 Jun 2022 19:56:19 +0800 Message-Id: <20220623115631.22209-3-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220623115631.22209-1-peterwu.pub@gmail.com> References: <20220623115631.22209-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org From: ChiaEn Wu Add Mediatek MT6370 Charger binding documentation. Signed-off-by: ChiaEn Wu --- v3 - Add items and remove maxItems of io-channels - Add io-channel-names and describe each item - Add "unevaluatedProperties: false" in "usb-otg-vbus-regulator" - Rename "enable-gpio" to "enable-gpios" in "usb-otg-vbus-regulator" --- .../power/supply/mediatek,mt6370-charger.yaml | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml diff --git a/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml new file mode 100644 index 0000000..f138db6 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/mediatek,mt6370-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek MT6370 Battery Charger + +maintainers: + - ChiaEn Wu + +description: | + This module is part of the MT6370 MFD device. + Provides Battery Charger, Boost for OTG devices and BC1.2 detection. + +properties: + compatible: + const: mediatek,mt6370-charger + + interrupts: + description: | + Specify what irqs are needed to be handled by MT6370 Charger driver. IRQ + "MT6370_IRQ_CHG_MIVR", "MT6370_IRQ_ATTACH" and "MT6370_IRQ_OVPCTRL_UVP_D" + are required. + items: + - description: BC1.2 done irq + - description: usb plug in irq + - description: mivr irq + + interrupt-names: + items: + - const: attach_i + - const: uvp_d_evt + - const: mivr + + io-channels: + description: | + Use ADC channel to read VBUS, IBUS, IBAT, etc., info. + minItems: 1 + items: + - description: | + VBUS voltage with lower accuracy (+-75mV) but higher measure + range (1~22V) + - description: | + VBUS voltage with higher accuracy (+-30mV) but lower measure + range (1~9.76V) + - description: the main system input voltage + - description: battery voltage + - description: battery temperature-sense input voltage + - description: IBUS current (required) + - description: battery current + - description: | + regulated output voltage to supply for the PWM low-side gate driver + and the bootstrap capacitor + - description: IC junction temperature + + io-channel-names: + items: + - const: vbusdiv5 + - const: vbusdiv2 + - const: vsys + - const: vbat + - const: ts_bat + - const: ibus + - const: ibat + - const: chg_vddp + - const: temp_jc + + usb-otg-vbus-regulator: + type: object + description: OTG boost regulator. + unevaluatedProperties: false + $ref: /schemas/regulator/regulator.yaml# + + properties: + enable-gpios: + maxItems: 1 + +required: + - compatible + - interrupts + - interrupt-names + - io-channels + +additionalProperties: false + +... From patchwork Thu Jun 23 11:56:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 584357 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 C2647C433EF for ; Thu, 23 Jun 2022 11:58:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230053AbiFWL6P (ORCPT ); Thu, 23 Jun 2022 07:58:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42032 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231673AbiFWL5n (ORCPT ); Thu, 23 Jun 2022 07:57:43 -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 CAF504D278; Thu, 23 Jun 2022 04:57:36 -0700 (PDT) Received: by mail-pj1-x102f.google.com with SMTP id n16-20020a17090ade9000b001ed15b37424so452102pjv.3; Thu, 23 Jun 2022 04:57:36 -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=q9mqbhZoMmE2UGeXYY/i+9oRbxA8kCBRP28mwUFzZ1c=; b=qRTVC2ywxT1/qxvRJKAAT+rtvj71hyQm21AvxxJe1uv3ptO9m3pvGeREZp++I03axd 30X4cyu3w2QD3JckP/q3Y+aB4TIXTj13WQlliKAzlE0gBQ2upW3h+cnCIwrICcsqKOMy 8JguM9hpd8ReKzGu0CwHNwk5pptUEVfXuDnYLneCQC3HDQUaP6gFeKle7yHwLCKt7Bo8 fX7VIBQt1pdA+Vh16LC+H0UZS5IRqZGPg9Cwmcy8nzxfDI89mrYnFg/KfuS01nTK8c1y k0qn3lz5Yn0AxnSCot09dQ0CvRD/ZYEMrp2oZSI1K/oV/coFmNHJNhL41LBviiijSqRz M8lA== 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=q9mqbhZoMmE2UGeXYY/i+9oRbxA8kCBRP28mwUFzZ1c=; b=kqhYQBczWAHyJhVO5/vsfXmdCiKJS3plMM7P8OEYFW1TmJ7GR8tzCdr0XxKQasmcW8 vaDDqd7bWuNlU8ISpdDvjl5VZKK+8pf0PEFcC7rtPncwtaKAOXiXXnvXodW7Fq1qK0nP q+30470sqO2YFpz7b5uUeSq8Moq3jf8dVz5OU+iYUe5xkvjPVP+ktqN8CVZmDxdAKMpS Th/l5WXfm7tAWpv5Zpd8ereLuZxnuuYS+MY5JdiyZPOmMHaLKmXYOsFsHw267lTeeCYG 2umGVWQEX7ignp2C2UMIwuQei28hRAclsq25vFziWMmFSCUIPRePUwI5CXp++s0n1IU5 FSiQ== X-Gm-Message-State: AJIora+BYeKj+/7vQ6F8x+t6Kff1Hk7uUR3ePOMe1qyUogEk64aWJHSs 9EgHPnFook6YEZeVLKTw3yw= X-Google-Smtp-Source: AGRyM1vkUp4DtpsTn2hg/SKsugyEWOTzH7LnpFRhRrqqEuoqcKYA/inTXAsFFb1PabSzgpqRwIY4Yw== X-Received: by 2002:a17:902:d58a:b0:16a:3139:5ff7 with SMTP id k10-20020a170902d58a00b0016a31395ff7mr16262584plh.118.1655985455815; Thu, 23 Jun 2022 04:57:35 -0700 (PDT) Received: from RD-3580-24288.rt.l (111-71-94-93.emome-ip.hinet.net. [111.71.94.93]) by smtp.gmail.com with ESMTPSA id t6-20020a63b246000000b003fbfe88be17sm15016516pgo.24.2022.06.23.04.57.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jun 2022 04:57:35 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v3 05/14] dt-bindings: backlight: Add Mediatek MT6370 backlight Date: Thu, 23 Jun 2022 19:56:22 +0800 Message-Id: <20220623115631.22209-6-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220623115631.22209-1-peterwu.pub@gmail.com> References: <20220623115631.22209-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org From: ChiYuan Huang Add mt6370 backlight binding documentation. Signed-off-by: ChiYuan Huang --- v3 - Rename "mediatek,bled-pwm-hys-input-threshold-steps" to "mediatek,bled-pwm-hys-input-th-steps" - Refine "bled-pwm-hys-input-th-steps", "bled-ovp-microvolt", "bled-ocp-microamp" enum values --- .../leds/backlight/mediatek,mt6370-backlight.yaml | 92 ++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml diff --git a/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml new file mode 100644 index 0000000..26563ae --- /dev/null +++ b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/backlight/mediatek,mt6370-backlight.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek MT6370 Backlight + +maintainers: + - ChiaEn Wu + +description: | + This module is part of the MT6370 MFD device. + The MT6370 Backlight WLED driver supports up to a 29V output voltage for + 4 channels of 8 series WLEDs. Each channel supports up to 30mA of current + capability with 2048 current steps (11 bits) in exponential or linear + mapping curves. + +allOf: + - $ref: common.yaml# + +properties: + compatible: + const: mediatek,mt6370-backlight + + default-brightness: + minimum: 0 + maximum: 2048 + + max-brightness: + minimum: 0 + maximum: 2048 + + enable-gpios: + description: External backlight 'enable' pin + maxItems: 1 + + mediatek,bled-pwm-enable: + description: | + Enable external PWM input for backlight dimming + type: boolean + + mediatek,bled-pwm-hys-enable: + description: | + Enable the backlight input-hysteresis for PWM mode + type: boolean + + mediatek,bled-pwm-hys-input-th-steps: + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [1, 4, 16, 64] + description: | + The selection of the upper and lower bounds threshold of backlight + PWM resolution. If we choose selection 64, the variation of PWM + resolution needs over than 64 steps. + + mediatek,bled-ovp-shutdown: + description: | + Enable the backlight shutdown when OVP level triggered + type: boolean + + mediatek,bled-ovp-microvolt: + enum: [17000000, 21000000, 25000000, 29000000] + description: | + Backlight OVP level selection. + + mediatek,bled-ocp-shutdown: + description: | + Enable the backlight shutdown when OCP level triggerred. + type: boolean + + mediatek,bled-ocp-microamp: + enum: [900000, 1200000, 1500000, 1800000] + description: | + Backlight OC level selection. + + mediatek,bled-channel-use: + $ref: /schemas/types.yaml#/definitions/uint8 + description: | + Backlight LED channel to be used. + Each bit mapping to: + - 0: CH4 + - 1: CH3 + - 2: CH2 + - 3: CH1 + minimum: 1 + maximum: 15 + +required: + - compatible + - mediatek,bled-channel-use + +additionalProperties: false From patchwork Thu Jun 23 11:56:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 584356 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 5A42BCCA480 for ; Thu, 23 Jun 2022 11:58:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230160AbiFWL60 (ORCPT ); Thu, 23 Jun 2022 07:58:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42668 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231651AbiFWL6B (ORCPT ); Thu, 23 Jun 2022 07:58:01 -0400 Received: from mail-pg1-x52e.google.com (mail-pg1-x52e.google.com [IPv6:2607:f8b0:4864:20::52e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C1C3C4D9CD; Thu, 23 Jun 2022 04:57:42 -0700 (PDT) Received: by mail-pg1-x52e.google.com with SMTP id r66so12985743pgr.2; Thu, 23 Jun 2022 04:57:42 -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=yU16YAvzrOJ2TAixJ6ajh3C/Sa2TgM1x5KAZlW3Jd6U=; b=d5zJrbp5ZJsOD/u+Zp03Z1Un03WOATHJ+W+SufwY7uHpxjubdveeUyhAwVs7BIVKba O7ifiBqieF4zHFcMEx5Krz+LU37S5Y3i9FpbUA7w/iHjsGhtsfiXa66KgknAK0VynbFp Gc9RRaunks9dYuX/fsbDUKOoGz41OLddyhZL2/z17iGEqerolxqydul8xbAR4ucCpH4J s4iGf0fygxmJgmKOaeaVp11ElpaovQ2Lo8OBjo93ma7DYiyRjQWUVhqteKMm5Nt34JXH A2/SG99LQfov8qLbkvWleeZvn1mCjLpdIq3Nfhi/yG3BupYlbEPnIuPQ0x4TADzWyVpo 6GAw== 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=yU16YAvzrOJ2TAixJ6ajh3C/Sa2TgM1x5KAZlW3Jd6U=; b=vYOyqQwNtnnm6YqSgEVdO84oOnNZxD4nxqhLrbQZxRxXjawTsQ6Noe8e8jHh16kVHY Y+2aSxOiBgFnCgCRa3C/RqP9o8JsgrSgQ5OckIZO25q8QiBSDG5dCi967y5zpLs0FK26 4StCFU8vlF1wSpqSQDpeQMbJEAxpDasRyZLQVpGztUvjHIU4h7z3Vdngn8izBm6dqkI9 gvriNKdULbVHVYooAPK7c2c9DLM22d5t1TsutaxFXNeIoajUXV3Blu1lpJmEzgnouGki l3mGf6qNRRI8szjs0Da1Io29DDzZmvF5K/3EQmb2ZUVD6PzdDI4qu7ShCN2/g86mK56O vhbQ== X-Gm-Message-State: AJIora8n/e01LqSUFCIuSmLIvubg+0oLo43YW4zykyXPFkoDyFBglHnU P/plerYQNRIbgxof4YoBMKA= X-Google-Smtp-Source: AGRyM1upqQ1Rvcis2aaPHOGSrWF5KiEnDw+NSNBEMWIWzMnsRCSywYavLfHmqra7pf9YE8N01iHhmQ== X-Received: by 2002:a05:6a00:1591:b0:525:3b0d:85d7 with SMTP id u17-20020a056a00159100b005253b0d85d7mr12241115pfk.51.1655985461850; Thu, 23 Jun 2022 04:57:41 -0700 (PDT) Received: from RD-3580-24288.rt.l (111-71-94-93.emome-ip.hinet.net. [111.71.94.93]) by smtp.gmail.com with ESMTPSA id t6-20020a63b246000000b003fbfe88be17sm15016516pgo.24.2022.06.23.04.57.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jun 2022 04:57:41 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v3 06/14] dt-bindings: mfd: Add Mediatek MT6370 Date: Thu, 23 Jun 2022 19:56:23 +0800 Message-Id: <20220623115631.22209-7-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220623115631.22209-1-peterwu.pub@gmail.com> References: <20220623115631.22209-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org From: ChiYuan Huang Add Mediatek MT6370 binding documentation. Signed-off-by: ChiYuan Huang --- v3 - Use " in entire patchset - Refine ADC description - Rename "enable-gpio" to "enable-gpios" in "regualtor" - Change "/schemas/" to "../" in every reference of all MT6370 modules --- .../devicetree/bindings/mfd/mediatek,mt6370.yaml | 280 +++++++++++++++++++++ include/dt-bindings/iio/adc/mediatek,mt6370_adc.h | 18 ++ 2 files changed, 298 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml new file mode 100644 index 0000000..fa9da13 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml @@ -0,0 +1,280 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/mediatek,mt6370.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek MT6370 SubPMIC + +maintainers: + - ChiYuan Huang + +description: | + MT6370 is a highly-integrated smart power management IC, which includes a + single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C & + Power Delivery (PD) controller, dual flash LED current sources, a RGB LED + driver, a backlight WLED driver, a display bias driver and a general LDO for + portable devices. + +properties: + compatible: + const: mediatek,mt6370 + + reg: + maxItems: 1 + + wakeup-source: true + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 1 + + adc: + type: object + description: | + Provides 9 channels for system monitoring, including VBUSDIV5 (lower + accuracy, higher measure range), VBUSDIV2 (higher accuracy, lower + measure range), VBAT, VSYS, CHG_VDDP, TS_BAT, IBUS, IBAT, and TEMP_JC. + + properties: + compatible: + const: mediatek,mt6370-adc + + "#io-channel-cells": + const: 1 + + required: + - compatible + - "#io-channel-cells" + + backlight: + type: object + $ref: ../leds/backlight/mediatek,mt6370-backlight.yaml# + + charger: + type: object + $ref: ../power/supply/mediatek,mt6370-charger.yaml# + + tcpc: + type: object + $ref: ../usb/mediatek,mt6370-tcpc.yaml# + + indicator: + type: object + $ref: ../leds/mediatek,mt6370-indicator.yaml# + + flashlight: + type: object + $ref: ../leds/mediatek,mt6370-flashlight.yaml# + + regulators: + type: object + description: | + List all supported regulators, which support the control for DisplayBias + voltages and one general purpose LDO which commonly used to drive the + vibrator. + + patternProperties: + "^(dsvbst|vibldo)$": + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + "^(dsvpos|dsvneg)$": + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + properties: + enable-gpios: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - "#interrupt-cells" + - regulators + - adc + - backlight + - indicator + - tcpc + - charger + - flashlight + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@34 { + compatible = "mediatek,mt6370"; + reg = <0x34>; + wakeup-source; + interrupts-extended = <&gpio26 3 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <1>; + + mt6370_adc: adc { + compatible = "mediatek,mt6370-adc"; + #io-channel-cells = <1>; + }; + + backlight { + compatible = "mediatek,mt6370-backlight"; + mediatek,bled-channel-use = /bits/ 8 <15>; + }; + + charger { + compatible = "mediatek,mt6370-charger"; + interrupts = <48>, <68>, <6>; + interrupt-names = "attach_i", "uvp_d_evt", "mivr"; + io-channels = <&mt6370_adc MT6370_CHAN_IBUS>; + + mt6370_otg_vbus: usb-otg-vbus-regulator { + regulator-name = "mt6370-usb-otg-vbus"; + regulator-min-microvolt = <4350000>; + regulator-max-microvolt = <5800000>; + regulator-min-microamp = <500000>; + regulator-max-microamp = <3000000>; + }; + }; + + indicator { + compatible = "mediatek,mt6370-indicator"; + #address-cells = <1>; + #size-cells = <0>; + + multi-led@0 { + reg = <0>; + function = LED_FUNCTION_INDICATOR; + color = ; + led-max-microamp = <24000>; + #address-cells = <1>; + #size-cells = <0>; + led@0 { + reg = <0>; + color = ; + }; + led@1 { + reg = <1>; + color = ; + }; + led@2 { + reg = <2>; + color = ; + }; + }; + led@3 { + reg = <3>; + function = LED_FUNCTION_INDICATOR; + color = ; + led-max-microamp = <6000>; + }; + }; + + flashlight { + compatible = "mediatek,mt6370-flashlight"; + #address-cells = <1>; + #size-cells = <0>; + led@0 { + reg = <0>; + led-sources = <0>; + function = LED_FUNCTION_FLASH; + color = ; + function-enumerator = <1>; + led-max-microamp = <200000>; + flash-max-microamp = <500000>; + flash-max-timeout-us = <1248000>; + }; + led@1 { + reg = <1>; + led-sources = <1>; + function = LED_FUNCTION_FLASH; + color = ; + function-enumerator = <2>; + led-max-microamp = <200000>; + flash-max-microamp = <500000>; + flash-max-timeout-us = <1248000>; + }; + }; + + tcpc { + compatible = "mediatek,mt6370-tcpc"; + interrupts-extended = <&gpio26 4 IRQ_TYPE_LEVEL_LOW>; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + vbus-supply = <&mt6370_otg_vbus>; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <10000000>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&usb_hs>; + }; + }; + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&usb_ss>; + }; + }; + port@2 { + reg = <2>; + endpoint { + remote-endpoint = <&dp_aux>; + }; + }; + }; + }; + }; + + regulators { + dsvbst { + regulator-name = "mt6370-dsv-vbst"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6200000>; + }; + dsvpos { + regulator-name = "mt6370-dsv-vpos"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + regulator-boot-on; + }; + dsvneg { + regulator-name = "mt6370-dsv-vneg"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + regulator-boot-on; + }; + vibldo { + regulator-name = "mt6370-vib-ldo"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <4000000>; + }; + }; + }; + }; diff --git a/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h new file mode 100644 index 0000000..6ee7255 --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__ +#define __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__ + +/* ADC Channel Index */ +#define MT6370_CHAN_VBUSDIV5 0 +#define MT6370_CHAN_VBUSDIV2 1 +#define MT6370_CHAN_VSYS 2 +#define MT6370_CHAN_VBAT 3 +#define MT6370_CHAN_TS_BAT 4 +#define MT6370_CHAN_IBUS 5 +#define MT6370_CHAN_IBAT 6 +#define MT6370_CHAN_CHG_VDDP 7 +#define MT6370_CHAN_TEMP_JC 8 +#define MT6370_CHAN_MAX 9 + +#endif From patchwork Thu Jun 23 11:56:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 584354 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 2E270C433EF for ; Thu, 23 Jun 2022 11:59:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230050AbiFWL7M (ORCPT ); Thu, 23 Jun 2022 07:59:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43130 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231534AbiFWL6j (ORCPT ); Thu, 23 Jun 2022 07:58:39 -0400 Received: from mail-pf1-x42a.google.com (mail-pf1-x42a.google.com [IPv6:2607:f8b0:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2CB9A12ABC; Thu, 23 Jun 2022 04:58:06 -0700 (PDT) Received: by mail-pf1-x42a.google.com with SMTP id t21so12629392pfq.1; Thu, 23 Jun 2022 04:58:06 -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=twoX90vjNZ5TJVryjZwIV5usboeuJvKudWY5Eq7pX2s=; b=Yu7r2PkQT35giInU8omF0mxG27zUw+oY0/yY1UNdyqA0McCyZswDO6SuiqyhMqw8jp LsiKgOUPrRM4OuJPWb73hTBZo759/H+evuq/oJq7pqcYhXPyoEW3LWsiXRhxZPGus9kD 6uBjIadWhcRvel96bTc/0Okm3yjffom4UT2gZGH+5H6+w1OL90ON2mY2f6RgMrdXPegb sm+IyDIsRkLdqAQ6+Bu931eNbnvxAU2wmXK8neVanNagsEiMfOzBctQ5cTZIOCUXYpdt Hsg4YkqnGrM1shtQnIdBIfCDZ+KU8j/1oQKRGkgJz6Nb0uVDxrwkMy5jsXgMN0M6lqVN sgpg== 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=twoX90vjNZ5TJVryjZwIV5usboeuJvKudWY5Eq7pX2s=; b=qC7RGysyCJnTMJnz1YUvIeee9qmD7gxMktRDV5trLUk8L5Orp0BDzJSinu+iM2f/LX coyBvcnyt73dILi4GQW8TZ8aoIuRfH8Pl4j6N1Ty4PDxnsiOvYs3I2iyldUz2PW0FM6f tzeT3vumAfyXC1R9DlMbGb04NBhm3r3HjsfrKfnR/BaMNZCCIqRqaJv7bXJLIgm7FTz8 ZVXOdBKjLZTsUD94Gj/yaZiLiigYupjgKh+cyztjLtQw0QNdWWRST5lCnpr1Wq0iPtbX iMsPwCno/WA+V3j8uFXH/DhZyV869hJSrXY0eiVW24sceQIgfUrvh3lUM+WaljxG1iL1 zNxg== X-Gm-Message-State: AJIora8fcN+wCDNXxSstosLS7Rqn6sJk1q49n7Mull4PojZpqjbLV4NP 4OwLafqiUhpZtR5MlG6WBcY= X-Google-Smtp-Source: AGRyM1sDJESM2kA9i+aKrOwizpVH5nHvPIj+9yIwNXqrO5I8a0DrRwgjsOWNA89htMIvZYHMUO16Bw== X-Received: by 2002:a63:5248:0:b0:402:de14:ab74 with SMTP id s8-20020a635248000000b00402de14ab74mr7336620pgl.18.1655985485965; Thu, 23 Jun 2022 04:58:05 -0700 (PDT) Received: from RD-3580-24288.rt.l (111-71-94-93.emome-ip.hinet.net. [111.71.94.93]) by smtp.gmail.com with ESMTPSA id t6-20020a63b246000000b003fbfe88be17sm15016516pgo.24.2022.06.23.04.58.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jun 2022 04:58:05 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v3 10/14] iio: adc: mt6370: Add Mediatek MT6370 support Date: Thu, 23 Jun 2022 19:56:27 +0800 Message-Id: <20220623115631.22209-11-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220623115631.22209-1-peterwu.pub@gmail.com> References: <20220623115631.22209-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org From: ChiaEn Wu Add Mediatek MT6370 ADC support. Signed-off-by: ChiaEn Wu --- v3 - Refine Kconfig help text - Refine all channel value in read_scale() a. current: uA --> mA b. voltage: uV --> mV c. temperature: degrees Celsius --> milli degrees Celsius - Add "default:" condition of switch statement in read_scale() and read_raw() - Add error message for reading ADC register failed - Add the comment for adc_lock - Add header file for struct of_device_id - Replace "adc" text with "ADC" in all of the error messages --- drivers/iio/adc/Kconfig | 9 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mt6370-adc.c | 275 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+) create mode 100644 drivers/iio/adc/mt6370-adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 48ace74..c36b640 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 yes here to enable Mediatek MT6370 ADC support. + + This ADC driver provides 9 channels for system monitoring (charger + current, voltage, and temperature). + config MEDIATEK_MT6577_AUXADC tristate "MediaTek AUXADC driver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 39d806f..0ce285c 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MCP3911) += mcp3911.o obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o +obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_MESON_SARADC) += meson_saradc.o diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c new file mode 100644 index 0000000..ed7f1b3 --- /dev/null +++ b/drivers/iio/adc/mt6370-adc.c @@ -0,0 +1,275 @@ +// 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_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; + /* + * This mutex lock is for preventing the different ADC channels + * from being read at the same time. + */ + struct mutex adc_lock; +}; + +static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan, + unsigned long addr, int *val) +{ + __be16 be_val; + unsigned int reg_val; + int ret; + + mutex_lock(&priv->adc_lock); + + reg_val = MT6370_ADC_START_MASK | + FIELD_PREP(MT6370_ADC_IN_SEL_MASK, addr); + ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val); + if (ret) + goto adc_unlock; + + msleep(ADC_CONV_TIME_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"); + else + dev_err(priv->dev, + "Failed to read ADC register (%d)\n", ret); + + goto adc_unlock; + } + + ret = regmap_raw_read(priv->regmap, MT6370_REG_ADC_DATA_H, + &be_val, sizeof(be_val)); + if (ret) + goto adc_unlock; + + *val = be16_to_cpu(be_val); + ret = IIO_VAL_INT; + +adc_unlock: + mutex_unlock(&priv->adc_lock); + + return ret; +} + +static int mt6370_adc_read_scale(struct mt6370_adc_data *priv, + int chan, int *val1, int *val2) +{ + unsigned int reg_val; + int ret; + + switch (chan) { + case MT6370_CHAN_VBAT: + case MT6370_CHAN_VSYS: + case MT6370_CHAN_CHG_VDDP: + *val1 = 5; + return IIO_VAL_INT; + case MT6370_CHAN_IBUS: + ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL3, ®_val); + if (ret) + return ret; + + reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val); + if (reg_val < MT6370_AICR_400MA) + *val1 = 3350; + else + *val1 = 5000; + + *val2 = 100; + + return IIO_VAL_FRACTIONAL; + case MT6370_CHAN_IBAT: + ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL7, ®_val); + if (ret) + return ret; + + reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val); + if (reg_val < MT6370_ICHG_500MA) + *val1 = 2375; + else if (reg_val >= MT6370_ICHG_500MA && + reg_val < MT6370_ICHG_900MA) + *val1 = 2680; + else + *val1 = 5000; + + *val2 = 100; + + return IIO_VAL_FRACTIONAL; + case MT6370_CHAN_VBUSDIV5: + *val1 = 25; + return IIO_VAL_INT; + case MT6370_CHAN_VBUSDIV2: + *val1 = 50; + return IIO_VAL_INT; + case MT6370_CHAN_TS_BAT: + *val1 = 25; + *val2 = 10000; + return IIO_VAL_FRACTIONAL; + case MT6370_CHAN_TEMP_JC: + *val1 = 2000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } +} + +static int mt6370_adc_read_offset(struct mt6370_adc_data *priv, + int chan, int *val) +{ + *val = -20; + + return IIO_VAL_INT; +} + +static int mt6370_adc_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mt6370_adc_data *priv = iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return mt6370_adc_read_channel(priv, chan->channel, + chan->address, val); + case IIO_CHAN_INFO_SCALE: + return mt6370_adc_read_scale(priv, chan->channel, val, val2); + case IIO_CHAN_INFO_OFFSET: + return mt6370_adc_read_offset(priv, chan->channel, val); + default: + return -EINVAL; + } +} + +static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = { + [MT6370_CHAN_VBUSDIV5] = "vbusdiv5", + [MT6370_CHAN_VBUSDIV2] = "vbusdiv2", + [MT6370_CHAN_VSYS] = "vsys", + [MT6370_CHAN_VBAT] = "vbat", + [MT6370_CHAN_TS_BAT] = "ts_bat", + [MT6370_CHAN_IBUS] = "ibus", + [MT6370_CHAN_IBAT] = "ibat", + [MT6370_CHAN_CHG_VDDP] = "chg_vddp", + [MT6370_CHAN_TEMP_JC] = "temp_jc", +}; + +static int mt6370_adc_read_label(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, char *label) +{ + return 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, _extra_info) { \ + .type = _type, \ + .channel = MT6370_CHAN_##_idx, \ + .address = _addr, \ + .scan_index = MT6370_CHAN_##_idx, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + _extra_info \ +} + +static const struct iio_chan_spec mt6370_adc_channels[] = { + MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1, 0), + MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2, 0), + MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3, 0), + MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4, 0), + MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6, 0), + MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8, 0), + MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9, 0), + MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11, 0), + MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)), +}; + +static int mt6370_adc_probe(struct platform_device *pdev) +{ + 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->adc_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 = "mt6370-adc"; + indio_dev->info = &mt6370_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mt6370_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(mt6370_adc_channels); + + return devm_iio_device_register(&pdev->dev, indio_dev); +} + +static const struct of_device_id mt6370_adc_of_id[] = { + { .compatible = "mediatek,mt6370-adc", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_adc_of_id); + +static struct platform_driver mt6370_adc_driver = { + .driver = { + .name = "mt6370-adc", + .of_match_table = mt6370_adc_of_id, + }, + .probe = mt6370_adc_probe, +}; +module_platform_driver(mt6370_adc_driver); + +MODULE_AUTHOR("ChiaEn Wu "); +MODULE_DESCRIPTION("MT6370 ADC Drvier"); +MODULE_LICENSE("GPL v2"); From patchwork Thu Jun 23 11:56:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 584355 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 44CF6CCA480 for ; Thu, 23 Jun 2022 11:59:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231709AbiFWL7I (ORCPT ); Thu, 23 Jun 2022 07:59:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42850 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231788AbiFWL6Z (ORCPT ); Thu, 23 Jun 2022 07:58:25 -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 77FBA2C65C; Thu, 23 Jun 2022 04:58:13 -0700 (PDT) Received: by mail-pj1-x1031.google.com with SMTP id p3-20020a17090a428300b001ec865eb4a2so2337540pjg.3; Thu, 23 Jun 2022 04:58:13 -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=oH/S693qQrH6qbVafZRzApl9zZFKxZoWCPplq0jVgpw=; b=EqhaVe7d+vTWvrHfRQAd01WHVaZ0pNkelpsC0fxbpvKARZZ0p5CEctrYX/4i49OIEM LW+9+yPN0NuTJ6MedFtYDveI23KyCNWM7OMotkZpWa50U/0/MH65RkBh+GbgzHw0qT9d g0Y1120tREU8ENTg+tuC1JRwUbwFq9UNrvre+XXuaQhkZloxcUtVaGh4TCbvtl194qT1 G0pT5v/ze4jE7A65cmrmX02GqoBgDbXxhFXzZwYC8ZHF4Ike6hVMn+JP2qeJu57DUUeK 8PwXadv3OeV8/2UKVzXVbfthHDutdCJxMFe5+K+fseiM1pW38I6YfL8r/z1In3tteUz5 AdCA== 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=oH/S693qQrH6qbVafZRzApl9zZFKxZoWCPplq0jVgpw=; b=LZDEvHxvqWTXNnJYY5XMcv9f+aNO857mDsQsfApnX/ae0ofW/zEBgKkksZCkgrLd4o fyEtzEYKg2Wz6tf202P843LQE1zbcjihtiTRGa0QkbBaPQxRXuNr4RBBmH4KH9CWt9cf D79EmIY0xflMUko6ljpJDKXes7ybAY69V+GiTL0E3976HSRYP0TQXKyMXvRE6WWaVYL7 QLJ1y2ZdeRYabtkZVL1LCjIhmdcZrxPiOxsCTIPZ5JU5OfPwSUbHRSkCzimnS0lq+z0J +ew4bmdZZ1iXN6iMo4B+3bA5EmaSBONwiKrTQ8KtHmTkArqHlQiGKhDsjhozhwQ6DQ/s /Cfg== X-Gm-Message-State: AJIora+K2GDo+fWei+LHuT2qgwp6cQJhJScw7NTr0cgwPuriQNdlh1aZ 3V0FA8y6vFX8+ZiS3rJScHw= X-Google-Smtp-Source: AGRyM1vcmOI4jaSPOMY2DG+YJG2Ll4B3edKTwcLmiw2HQTRcjQap8PLzHkeurggD+juZKlIndT2stw== X-Received: by 2002:a17:902:dac5:b0:164:13b2:4916 with SMTP id q5-20020a170902dac500b0016413b24916mr39163350plx.32.1655985492417; Thu, 23 Jun 2022 04:58:12 -0700 (PDT) Received: from RD-3580-24288.rt.l (111-71-94-93.emome-ip.hinet.net. [111.71.94.93]) by smtp.gmail.com with ESMTPSA id t6-20020a63b246000000b003fbfe88be17sm15016516pgo.24.2022.06.23.04.58.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jun 2022 04:58:12 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v3 11/14] power: supply: mt6370: Add Mediatek MT6370 charger driver Date: Thu, 23 Jun 2022 19:56:28 +0800 Message-Id: <20220623115631.22209-12-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220623115631.22209-1-peterwu.pub@gmail.com> References: <20220623115631.22209-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@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 1aa8323..54d8c3a 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 7f02f36..8c95276 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o +obj-$(CONFIG_CHARGER_MT6370) += mt6370-charger.o obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c new file mode 100644 index 0000000..539da62d --- /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 = "usb-otg-vbus-regulator", + .of_parse_cb = mt6370_chg_otg_of_parse_cb, + .name = "mt6370-usb-otg-vbus", + .ops = &mt6370_chg_otg_ops, + .owner = THIS_MODULE, + .type = REGULATOR_VOLTAGE, + .min_uV = 4425000, + .uV_step = 25000, + .n_voltages = 57, + .vsel_reg = MT6370_REG_CHG_CTRL5, + .vsel_mask = MT6370_VOBST_MASK, + .enable_reg = MT6370_REG_CHG_CTRL1, + .enable_mask = MT6370_OPA_MODE_MASK, + .curr_table = mt6370_chg_otg_oc_ma, + .n_current_limits = ARRAY_SIZE(mt6370_chg_otg_oc_ma), + .csel_reg = MT6370_REG_CHG_CTRL10, + .csel_mask = MT6370_OTG_OC_MASK, +}; + +static int mt6370_chg_init_rmap_fields(struct mt6370_priv *priv) +{ + int i; + const struct mt6370_chg_field *fds = mt6370_chg_fields; + + for (i = 0; i < F_MAX; i++) { + priv->rmap_fields[i] = devm_regmap_field_alloc(priv->dev, + priv->regmap, + fds[i].field); + if (IS_ERR(priv->rmap_fields[i])) { + 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 Thu Jun 23 11:56:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 584352 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 97095CCA481 for ; Thu, 23 Jun 2022 12:00:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230503AbiFWMAE (ORCPT ); Thu, 23 Jun 2022 08:00:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42396 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231430AbiFWL7e (ORCPT ); Thu, 23 Jun 2022 07:59:34 -0400 Received: from mail-pj1-x1029.google.com (mail-pj1-x1029.google.com [IPv6:2607:f8b0:4864:20::1029]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8455D2644; Thu, 23 Jun 2022 04:58:41 -0700 (PDT) Received: by mail-pj1-x1029.google.com with SMTP id t3-20020a17090a510300b001ea87ef9a3dso2336919pjh.4; Thu, 23 Jun 2022 04:58: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=q118JwwO2zwpxCEQobTvwARsQK6VzT6oso5CC0CqaZo=; b=M++qK+Qh8iAtlyjB5598/dqpm4gOWgSUcIND0fS1oE9moX1F2yEo6E8XOGPAeVxyqc FF/GizAHSRP6TJ1aL2ZpKzvxShAXLiKHUWWW/tmXlIJRK3LLTUszMlYWOImJH3ORlVSe NRnW4bWhyw43Y+sbwFPMjsWnMhcCr5JNCt0HMuOI8+y6bll1Ibp0qkVGrugKnusUl98b Zx0Pxy6Pave51SdMbyf2XvperW5nr/0+nuOXqsADo2IEl1ezWZkY57/O+H3Ep5X4OGqj vjGwijywyon3MjkNm0rmJNpL8HTuzkEZECNFtjrC2vcx/wx8rvCjIgjgChw6iVcrU6VP Rz5A== 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=q118JwwO2zwpxCEQobTvwARsQK6VzT6oso5CC0CqaZo=; b=YWiGcqc8SfLBcrpruv3d2qCXrjvfsiGdpLQs1Kl54CtscpaSPubeCq0iZPJkqpdT2b +digDvXn5F33+RDqn2WSYSSS6hxQeNGkYTpr4eyJ/Elk9kAO/zm1Fhqz9+Gx/NKo9yDQ 21hO/lIeSX6Lwqsd8YB6Pcn+rSm0XYbJxDeqek7IbYNnHGCRMkYzfqnM1G6W2PgTj+0z baHeDtGk37G1u0oZu/nAHARwGRE8lpdODJ9tM/MLR+e/JXH0enpLS/0ccZzf/+z3ow+L UvjD2bnhwCHTtoDQ+duGwE/9Zs4bxLgYxP8bAc0Grzo7OmEK5MCQ3gpUinJ9sJr82lcJ wXkQ== X-Gm-Message-State: AJIora+jsKLK0MKGS7gfRdzYb5Ah78g3+t6f1zl7WqYZcNl1b2p/ObaP 6hBqHkcpxLgRBEGmYuTZcg4= X-Google-Smtp-Source: AGRyM1uJ7yRlwCE7ce/DmaPr197YrtZJxPeazTdaQJeGh4H1ViVDQoSG5VtCTqv/9+OwWGYNso40Ng== X-Received: by 2002:a17:902:c115:b0:16a:1848:89e0 with SMTP id 21-20020a170902c11500b0016a184889e0mr24585784pli.44.1655985506010; Thu, 23 Jun 2022 04:58:26 -0700 (PDT) Received: from RD-3580-24288.rt.l (111-71-94-93.emome-ip.hinet.net. [111.71.94.93]) by smtp.gmail.com with ESMTPSA id t6-20020a63b246000000b003fbfe88be17sm15016516pgo.24.2022.06.23.04.58.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jun 2022 04:58:24 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v3 13/14] leds: flashlight: mt6370: Add Mediatek MT6370 flashlight support Date: Thu, 23 Jun 2022 19:56:30 +0800 Message-Id: <20220623115631.22209-14-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220623115631.22209-1-peterwu.pub@gmail.com> References: <20220623115631.22209-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@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 | 657 +++++++++++++++++++++++++++++++++ 3 files changed, 667 insertions(+) create mode 100644 drivers/leds/flash/leds-mt6370-flash.c diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig index d3eb689..d38e263 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 0acbddc..4c4c171 100644 --- a/drivers/leds/flash/Makefile +++ b/drivers/leds/flash/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o obj-$(CONFIG_LEDS_RT4505) += leds-rt4505.o obj-$(CONFIG_LEDS_RT8515) += leds-rt8515.o obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o +obj-$(CONFIG_LEDS_MT6370_FLASHLIGHT) += leds-mt6370-flash.o diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c new file mode 100644 index 0000000..97c69e1 --- /dev/null +++ b/drivers/leds/flash/leds-mt6370-flash.c @@ -0,0 +1,657 @@ +// 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 + +#define to_mt6370_led(ptr, member) container_of(ptr, struct mt6370_led, member) + +struct mt6370_led { + struct led_classdev_flash flash; + struct v4l2_flash *v4l2_flash; + struct mt6370_priv *priv; + u32 led_no; + u32 default_state; +}; + +struct mt6370_priv { + struct device *dev; + struct regmap *regmap; + struct mutex lock; + unsigned int fled_strobe_used; + unsigned int fled_torch_used; + unsigned int leds_active; + unsigned int leds_count; + struct mt6370_led leds[]; +}; + +static int mt6370_torch_brightness_set(struct led_classdev *lcdev, + enum led_brightness level) +{ + struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev); + struct mt6370_priv *priv = led->priv; + u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ? + MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask; + u32 val = level ? led_enable_mask : 0; + u32 prev = priv->fled_torch_used, curr; + int ret, i; + + mutex_lock(&priv->lock); + + /* + * Only one set of flash control logic, + * use the flag to avoid strobe is currently used. + */ + if (priv->fled_strobe_used) { + dev_warn(lcdev->dev, "Please disable strobe first [%d]\n", + priv->fled_strobe_used); + ret = -EBUSY; + goto unlock; + } + + if (level) + curr = prev | BIT(led->led_no); + else + curr = prev & ~BIT(led->led_no); + + if (curr) + val |= MT6370_TORCHEN_MASK; + + + if (level) { + level -= 1; + if (led->led_no == MT6370_LED_JOINT) { + int flevel[MT6370_MAX_LEDS]; + + flevel[0] = level / 2; + flevel[1] = level - flevel[0]; + for (i = 0; i < MT6370_MAX_LEDS; i++) { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDITOR(i), + MT6370_ITORCH_MASK, flevel[i]); + if (ret) + goto unlock; + } + } else { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDITOR(led->led_no), + MT6370_ITORCH_MASK, level); + if (ret) + goto unlock; + } + } + + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, + enable_mask, val); + if (ret) + goto unlock; + + priv->fled_torch_used = curr; + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static int mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev, + u32 brightness) +{ + /* + * Due to the current spike when turning on flash, + * let brightness 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 = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s = &fl_cdev->brightness; + u32 val = (brightness - s->min) / s->step; + int ret, i; + + if (led->led_no == MT6370_LED_JOINT) { + int flevel[MT6370_MAX_LEDS]; + + flevel[0] = val / 2; + flevel[1] = val - flevel[0]; + for (i = 0; i < MT6370_MAX_LEDS; i++) { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDISTRB(i), + MT6370_ISTROBE_MASK, flevel[i]); + if (ret) + return ret; + } + } else { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDISTRB(led->led_no), + MT6370_ISTROBE_MASK, val); + if (ret) + return ret; + } + return ret; +} + +static int mt6370_strobe_set(struct led_classdev_flash *fl_cdev, bool state) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + struct led_classdev *lcdev = &fl_cdev->led_cdev; + struct led_flash_setting *s = &fl_cdev->brightness; + u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ? + MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 enable_mask = MT6370_STROBEN_MASK | led_enable_mask; + u32 val = state ? led_enable_mask : 0; + u32 prev = priv->fled_strobe_used, curr; + int ret; + + mutex_lock(&priv->lock); + + /* + * Only one set of flash control logic, + * use the flag to avoid torch is currently used + */ + if (priv->fled_torch_used) { + dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n", + priv->fled_torch_used); + ret = -EBUSY; + goto unlock; + } + + if (state) + curr = prev | BIT(led->led_no); + else + curr = prev & ~BIT(led->led_no); + + if (curr) + val |= MT6370_STROBEN_MASK; + + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask, + val); + if (ret) { + dev_err(lcdev->dev, "[%d] control current source %d fail\n", + led->led_no, state); + goto unlock; + } + + /* + * If the flash need to be on, + * config the flash current ramping up to the setting value + * Else, always recover back to the minimum one + */ + ret = _mt6370_flash_brightness_set(fl_cdev, state ? s->val : s->min); + if (ret) + goto unlock; + + /* + * For the flash turn on/off, HW ramping 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 = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + + mutex_lock(&priv->lock); + *state = !!(priv->fled_strobe_used & BIT(led->led_no)); + mutex_unlock(&priv->lock); + + return 0; +} + +static int mt6370_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s = &fl_cdev->timeout; + u32 val = (timeout - s->min) / s->step; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_update_bits(priv->regmap, MT6370_REG_STRBTO, + MT6370_STRBTO_MASK, val); + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + u16 fled_stat; + unsigned int chg_stat, strobe_timeout_mask, fled_short_mask; + u32 rfault = 0; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_read(priv->regmap, MT6370_REG_CHGSTAT2, &chg_stat); + if (ret) + goto unlock; + + ret = regmap_raw_read(priv->regmap, MT6370_REG_FLEDSTAT1, &fled_stat, + sizeof(fled_stat)); + if (ret) + goto unlock; + + switch (led->led_no) { + case MT6370_LED_FLASH1: + strobe_timeout_mask = MT6370_FLED1STRBTO_MASK; + fled_short_mask = MT6370_FLED1SHORT_MASK; + break; + + case MT6370_LED_FLASH2: + strobe_timeout_mask = MT6370_FLED2STRBTO_MASK; + fled_short_mask = MT6370_FLED2SHORT_MASK; + break; + + case MT6370_LED_JOINT: + strobe_timeout_mask = MT6370_FLED1STRBTO_MASK | + MT6370_FLED2STRBTO_MASK; + fled_short_mask = MT6370_FLED1SHORT_MASK | + MT6370_FLED2SHORT_MASK; + } + + if (chg_stat & MT6370_FLEDCHGVINOVP_MASK) + rfault |= LED_FAULT_INPUT_VOLTAGE; + + if (fled_stat & strobe_timeout_mask) + rfault |= LED_FAULT_TIMEOUT; + + if (fled_stat & fled_short_mask) + rfault |= LED_FAULT_SHORT_CIRCUIT; + + if (fled_stat & MT6370_FLEDLVF_MASK) + rfault |= LED_FAULT_UNDER_VOLTAGE; + + *fault = rfault; +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static const struct led_flash_ops mt6370_flash_ops = { + .flash_brightness_set = mt6370_flash_brightness_set, + .strobe_set = mt6370_strobe_set, + .strobe_get = mt6370_strobe_get, + .timeout_set = mt6370_timeout_set, + .fault_get = mt6370_fault_get, +}; + +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) +static int mt6370_flash_external_strobe_set(struct v4l2_flash *v4l2_flash, + bool enable) +{ + struct led_classdev_flash *flash = v4l2_flash->fled_cdev; + struct mt6370_led *led = to_mt6370_led(flash, flash); + struct mt6370_priv *priv = led->priv; + u32 mask = (led->led_no == MT6370_LED_JOINT) ? MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 val = enable ? mask : 0; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, mask, val); + if (ret) + goto unlock; + + if (enable) + priv->fled_strobe_used |= BIT(led->led_no); + else + priv->fled_strobe_used &= ~BIT(led->led_no); + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static const struct v4l2_flash_ops v4l2_flash_ops = { + .external_strobe_set = mt6370_flash_external_strobe_set, +}; + +static void mt6370_init_v4l2_flash_config(struct mt6370_led *led, + struct v4l2_flash_config *config) +{ + struct led_classdev *lcdev; + struct led_flash_setting *s = &config->intensity; + + lcdev = &led->flash.led_cdev; + + s->min = MT6370_ITORCH_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 = states[STATE_OFF]; + int ret; + + fwnode_property_read_string(init_data->fwnode, "default-state", &str); + ret = match_string(states, ARRAY_SIZE(states), str); + if (ret >= 0) + led->default_state = ret; + + return 0; +} + +static void mt6370_v4l2_flash_release(struct mt6370_priv *priv) +{ + int i; + + for (i = 0; i < priv->leds_count; i++) { + struct mt6370_led *led = priv->leds + i; + + if (led->v4l2_flash) + v4l2_flash_release(led->v4l2_flash); + } +} + +static int mt6370_led_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + struct fwnode_handle *child; + size_t count; + int i = 0, ret; + + count = device_get_child_node_count(&pdev->dev); + if (!count || count > MT6370_MAX_LEDS) + return dev_err_probe(&pdev->dev, -EINVAL, + "No child node or node count over max led number %zu\n", + count); + + priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, count), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->leds_count = count; + priv->dev = &pdev->dev; + mutex_init(&priv->lock); + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "Failed to get parent regmap\n"); + + device_for_each_child_node(&pdev->dev, child) { + struct mt6370_led *led = priv->leds + i; + struct led_init_data init_data = { .fwnode = child, }; + + led->priv = priv; + ret = mt6370_init_common_properties(led, &init_data); + if (ret) + goto out_flash_release; + + ret = mt6370_init_flash_properties(led, &init_data); + + if (ret) + goto out_flash_release; + + ret = mt6370_led_register(&pdev->dev, led, &init_data); + if (ret) + goto out_flash_release; + + i++; + } + + platform_set_drvdata(pdev, priv); + return 0; + +out_flash_release: + mt6370_v4l2_flash_release(priv); + return ret; +} + +static int mt6370_led_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + + mt6370_v4l2_flash_release(priv); + return 0; +} + +static const struct of_device_id __maybe_unused mt6370_led_of_id[] = { + { .compatible = "mediatek,mt6370-flashlight", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_led_of_id); + +static struct platform_driver mt6370_led_driver = { + .driver = { + .name = "mt6370-flashlight", + .of_match_table = mt6370_led_of_id, + }, + .probe = mt6370_led_probe, + .remove = mt6370_led_remove, +}; +module_platform_driver(mt6370_led_driver); + +MODULE_AUTHOR("Alice Chen "); +MODULE_DESCRIPTION("MT6370 FLASH LED Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Thu Jun 23 11:56:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 584353 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 B5597C433EF for ; Thu, 23 Jun 2022 11:59:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231703AbiFWL7n (ORCPT ); Thu, 23 Jun 2022 07:59:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42988 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231758AbiFWL7K (ORCPT ); Thu, 23 Jun 2022 07:59:10 -0400 Received: from mail-pf1-x42a.google.com (mail-pf1-x42a.google.com [IPv6:2607:f8b0:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 139614DF61; Thu, 23 Jun 2022 04:58:32 -0700 (PDT) Received: by mail-pf1-x42a.google.com with SMTP id p14so13206648pfh.6; Thu, 23 Jun 2022 04:58:32 -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=a7GXYn5rKkvEUotNDztIkIhNm6MA/8dsUTEnwEI1gNU=; b=o+0Wa53zTV1uyFaCoWaTrEOzodPyOVApNu/2UJ3dvsm2wAEKNwOAKXzF0J2vnq/bJr 3zu5OXBBLh/Ux66mi9fjjjBrzG9cdRV8dDqiaK+ttrzcAp981Ds25mVFXm+gjsb6mXAS OLhJqjLom+2A0Vmi7H5So7ocleGDkXjb5JBW3G5zRlJu1A/UN2G5DCi3e0d61aTwiZKo X1L1Iph9/YIqZBQ9DU/3OdSgZB10qZWS8ZmfHxEyVwb1MOl2U7xtrsz1ipucqL5UfyJA CzuK3ESN/FmncgBlzGV7V1XAjp5JV7ZDKnk3+UQBHe5zbcbOQQjn/YbN6NTZmayy6Bx3 C2fg== 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=a7GXYn5rKkvEUotNDztIkIhNm6MA/8dsUTEnwEI1gNU=; b=H+6A0PEaVIwYUwebbB5ZapAs6WMqVZcuWuyeRQv6SvWBBZfjoDDeFae2rtLwcQ4Vez EbSUObGvFAsekYU6v92ctm84thrvYJIIGzWSXEa85KZ2TzuvAS8SYOaBBDNKR/tproqW 9uO91qO2gdXOQNXIbk/OY9T5mmEt7QZJdY6WLZmv/J8chFf/gOPF2sAMyROmPDxsetOd VmGAH4MAGvE8jWRZ4xyk1wim3dDa5NArR0qLq98ix3QSholL1CV/d/DO+O9BwMWAs/kx MsYNWNs9md4sGs30c2E75GO7mKYIBzpKyF2OG0LtoSN6+PerCZzA0rCKHT2hIdso/O4g UyZw== X-Gm-Message-State: AJIora8tdfQYbFMxm9Pw6WZl+laclm+XSgMScV7goiafjhExQGhvHLhz ECTKLLDoSYNjCKEUuSQOc3bslMcR0Pc= X-Google-Smtp-Source: AGRyM1vT/0PFSzRdbbE0OHeCOoudfWfuzy1UKXPrhg8oPMEcKCUz7qfwtfsdxSj/unanuyEAqCR2LA== X-Received: by 2002:a63:3f48:0:b0:40c:f2ca:4769 with SMTP id m69-20020a633f48000000b0040cf2ca4769mr7315452pga.205.1655985512230; Thu, 23 Jun 2022 04:58:32 -0700 (PDT) Received: from RD-3580-24288.rt.l (111-71-94-93.emome-ip.hinet.net. [111.71.94.93]) by smtp.gmail.com with ESMTPSA id t6-20020a63b246000000b003fbfe88be17sm15016516pgo.24.2022.06.23.04.58.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jun 2022 04:58: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: chiaen_wu@richtek.com, alice_chen@richtek.com, cy_huang@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org, szunichen@gmail.com Subject: [PATCH v3 14/14] video: backlight: mt6370: Add Mediatek MT6370 support Date: Thu, 23 Jun 2022 19:56:31 +0800 Message-Id: <20220623115631.22209-15-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220623115631.22209-1-peterwu.pub@gmail.com> References: <20220623115631.22209-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org From: ChiaEn Wu Add Mediatek MT6370 Backlight support. Signed-off-by: ChiaEn Wu --- v3 - Refine bool properties parsing (pwm-enable, ovp-shutdown, ocp-shutdown) in DT parsing function - Refine u32 and u8 properties parsing (pwm-hys-input-th-steps, ovp-microvolt, ocp-microamp), from using register value to using actual value - Refine error string of "channle-use" parsing failed - Refine Kconfig help text --- drivers/video/backlight/Kconfig | 9 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/mt6370-backlight.c | 346 +++++++++++++++++++++++++++++ 3 files changed, 356 insertions(+) create mode 100644 drivers/video/backlight/mt6370-backlight.c diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index a003e02..7cd823d 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -268,6 +268,15 @@ config BACKLIGHT_MAX8925 If you have a LCD backlight connected to the WLED output of MAX8925 WLED output, say Y here to enable this driver. +config BACKLIGHT_MT6370 + tristate "Mediatek MT6370 Backlight Driver" + depends on MFD_MT6370 + help + This enables support for Mediatek MT6370 Backlight driver. + It's commonly used to drive the display WLED. There are 4 channels + inside, and each channel supports up to 30mA of current capability + with 2048 current steps in exponential or linear mapping curves. + config BACKLIGHT_APPLE tristate "Apple Backlight Driver" depends on X86 && ACPI diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index cae2c83..e815f3f 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o +obj-$(CONFIG_BACKLIGHT_MT6370) += mt6370-backlight.o obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c new file mode 100644 index 0000000..c2ba09d --- /dev/null +++ b/drivers/video/backlight/mt6370-backlight.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6370_REG_DEV_INFO 0x100 +#define MT6370_REG_BL_EN 0x1A0 +#define MT6370_REG_BL_BSTCTRL 0x1A1 +#define MT6370_REG_BL_PWM 0x1A2 +#define MT6370_REG_BL_DIM2 0x1A4 + +#define MT6370_VENID_MASK GENMASK(7, 4) +#define MT6370_BL_EXT_EN_MASK BIT(7) +#define MT6370_BL_EN_MASK BIT(6) +#define MT6370_BL_CONFIG_MASK BIT(0) +#define MT6370_BL_CH_MASK GENMASK(5, 2) +#define MT6370_BL_DIM2_MASK GENMASK(2, 0) +#define MT6370_BL_DUMMY_6372_MASK GENMASK(2, 0) +#define MT6370_BL_DIM2_6372_SHIFT 3 +#define MT6370_BL_PWM_EN_MASK BIT(7) +#define MT6370_BL_PWM_HYS_EN_MASK BIT(2) +#define MT6370_BL_PWM_HYS_SEL_MASK GENMASK(1, 0) +#define MT6370_BL_OVP_EN_MASK BIT(7) +#define MT6370_BL_OVP_SEL_MASK GENMASK(6, 5) +#define MT6370_BL_OC_EN_MASK BIT(3) +#define MT6370_BL_OC_SEL_MASK GENMASK(2, 1) + +#define MT6370_BL_PWM_HYS_TH_MIN_STEP 1 +#define MT6370_BL_PWM_HYS_TH_MAX_STEP 64 +#define MT6370_BL_OVP_MIN_UV 17000000 +#define MT6370_BL_OVP_MAX_UV 29000000 +#define MT6370_BL_OVP_STEP_UV 4000000 +#define MT6370_BL_OCP_MIN_UA 900000 +#define MT6370_BL_OCP_MAX_UA 1800000 +#define MT6370_BL_OCP_STEP_UA 300000 +#define MT6370_BL_MAX_BRIGHTNESS 2048 +#define MT6370_BL_MAX_CH 15 + +enum { + MT6370_VID_COMMON = 0, + MT6370_VID_6372, +}; + +struct mt6370_priv { + int vid_type; + struct backlight_device *bl; + struct device *dev; + struct gpio_desc *enable_gpio; + struct regmap *regmap; +}; + +static int mt6370_bl_update_status(struct backlight_device *bl_dev) +{ + struct mt6370_priv *priv = bl_get_data(bl_dev); + int brightness = backlight_get_brightness(bl_dev); + unsigned int enable_val; + u8 brightness_val[2]; + int ret; + + if (brightness) { + brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK; + brightness_val[1] = (brightness - 1) + >> fls(MT6370_BL_DIM2_MASK); + + /* + * To make MT6372 using 14 bits to control the brightness + * backward compatible with 11 bits brightness control + * (like MT6370 and MT6371 do), we left shift the value + * and pad with 1 to remaining bits. Hence, the MT6372's + * backlight brightness will be almost the same as MT6370's + * and MT6371's. + */ + if (priv->vid_type == MT6370_VID_6372) { + brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT; + brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK; + } + + ret = regmap_raw_write(priv->regmap, MT6370_REG_BL_DIM2, + brightness_val, sizeof(brightness_val)); + if (ret) + return ret; + } + + 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, +}; + +static int mt6370_init_backlight_properties(struct mt6370_priv *priv, + struct backlight_properties *props) +{ + struct device *dev = priv->dev; + u8 prop_val; + u32 brightness, ovp_uV, ocp_uA; + unsigned int mask, val; + int ret; + + /* Vendor optional properties */ + val = 0; + if (device_property_read_bool(dev, "mediatek,bled-pwm-enable")) + val |= MT6370_BL_PWM_EN_MASK; + + if (device_property_read_bool(dev, "mediatek,bled-pwm-hys-enable")) + val |= MT6370_BL_PWM_HYS_EN_MASK; + + ret = device_property_read_u8(dev, + "mediatek,bled-pwm-hys-input-th-steps", + &prop_val); + if (!ret) { + prop_val = clamp_val(prop_val, + MT6370_BL_PWM_HYS_TH_MIN_STEP, + MT6370_BL_PWM_HYS_TH_MAX_STEP); + /* + * prop_val = 1 --> 1 steps --> 0x00 + * prop_val = 2 ~ 4 --> 4 steps --> 0x01 + * prop_val = 5 ~ 16 --> 16 steps --> 0x10 + * prop_val = 17 ~ 64 --> 64 steps --> 0x11 + */ + prop_val = (ilog2(roundup_pow_of_two(prop_val)) + 1) >> 1; + val |= prop_val << (ffs(MT6370_BL_PWM_HYS_SEL_MASK) - 1); + } + + ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_PWM, + val, val); + if (ret) + return ret; + + val = 0; + if (device_property_read_bool(dev, "mediatek,bled-ovp-shutdown")) + val |= MT6370_BL_OVP_EN_MASK; + + ret = device_property_read_u32(dev, "mediatek,bled-ovp-microvolt", + &ovp_uV); + if (!ret) { + ovp_uV = clamp_val(ovp_uV, MT6370_BL_OVP_MIN_UV, + MT6370_BL_OVP_MAX_UV); + ovp_uV = DIV_ROUND_UP(ovp_uV - MT6370_BL_OVP_MIN_UV, + MT6370_BL_OVP_STEP_UV); + val |= ovp_uV << (ffs(MT6370_BL_OVP_SEL_MASK) - 1); + } + + if (device_property_read_bool(dev, "mediatek,bled-ocp-shutdown")) + val |= MT6370_BL_OC_EN_MASK; + + ret = device_property_read_u32(dev, "mediatek,bled-ocp-microamp", + &ocp_uA); + if (!ret) { + ocp_uA = clamp_val(ocp_uA, MT6370_BL_OCP_MIN_UA, + MT6370_BL_OCP_MAX_UA); + ocp_uA = DIV_ROUND_UP(ocp_uA - MT6370_BL_OCP_MIN_UA, + MT6370_BL_OCP_STEP_UA); + val |= ocp_uA << (ffs(MT6370_BL_OC_SEL_MASK) - 1); + } + + ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_BSTCTRL, + val, val); + if (ret) + return ret; + + /* Common properties */ + ret = device_property_read_u32(dev, "max-brightness", &brightness); + if (ret) + brightness = MT6370_BL_MAX_BRIGHTNESS; + + props->max_brightness = min_t(u32, brightness, + MT6370_BL_MAX_BRIGHTNESS); + + ret = device_property_read_u32(dev, "default-brightness", &brightness); + if (ret) + brightness = props->max_brightness; + + props->brightness = min_t(u32, brightness, props->max_brightness); + + val = 0; + prop_val = 0; + ret = device_property_read_u8(dev, "mediatek,bled-channel-use", + &prop_val); + if (ret) { + dev_err(dev, "mediatek,bled-channel-use DT property missing\n"); + return ret; + } + + if (!prop_val || prop_val > MT6370_BL_MAX_CH) { + dev_err(dev, + "No channel specified or over than upper bound (%d)\n", + prop_val); + return -EINVAL; + } + + mask = MT6370_BL_EXT_EN_MASK | MT6370_BL_CH_MASK; + val = prop_val << (ffs(MT6370_BL_CH_MASK) - 1); + + if (priv->enable_gpio) + val |= MT6370_BL_EXT_EN_MASK; + + return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN, mask, val); +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + /* + * MT6372 uses 14 bits to control the brightness but MT6370 and MT6371 + * use 11 bits. They are different so we have to use this function to + * check the vendor ID and use different methods to calculate the + * brightness. + */ + unsigned int dev_info, vid; + int ret; + + ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &dev_info); + if (ret) + return ret; + + vid = FIELD_GET(MT6370_VENID_MASK, dev_info); + if (vid == 0x9 || vid == 0xb) + priv->vid_type = MT6370_VID_6372; + else + priv->vid_type = MT6370_VID_COMMON; + + return 0; +} + +static int mt6370_bl_probe(struct platform_device *pdev) +{ + struct 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_probe(&pdev->dev, -ENODEV, "Failed to get regmap\n"); + + ret = mt6370_check_vendor_info(priv); + if (ret) + dev_err_probe(&pdev->dev, ret, "Failed to check vendor info\n"); + + priv->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->enable_gpio)) + dev_err_probe(&pdev->dev, PTR_ERR(priv->enable_gpio), + "Failed to get 'enable' gpio\n"); + + ret = mt6370_init_backlight_properties(priv, &props); + if (ret) + dev_err_probe(&pdev->dev, ret, + "Failed to init backlight properties\n"); + + priv->bl = devm_backlight_device_register(&pdev->dev, pdev->name, + &pdev->dev, priv, + &mt6370_bl_ops, &props); + if (IS_ERR(priv->bl)) + dev_err_probe(&pdev->dev, PTR_ERR(priv->bl), + "Failed to register backlight\n"); + + backlight_update_status(priv->bl); + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int mt6370_bl_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + struct backlight_device *bl_dev = priv->bl; + + bl_dev->props.brightness = 0; + backlight_update_status(priv->bl); + + return 0; +} + +static const struct of_device_id __maybe_unused mt6370_bl_of_match[] = { + { .compatible = "mediatek,mt6370-backlight", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_bl_of_match); + +static struct platform_driver mt6370_bl_driver = { + .driver = { + .name = "mt6370-backlight", + .of_match_table = mt6370_bl_of_match, + }, + .probe = mt6370_bl_probe, + .remove = mt6370_bl_remove, +}; +module_platform_driver(mt6370_bl_driver); + +MODULE_AUTHOR("ChiaEn Wu "); +MODULE_DESCRIPTION("Mediatek MT6370 Backlight Driver"); +MODULE_LICENSE("GPL v2");