From patchwork Fri Sep 15 05:01:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikita Travkin X-Patchwork-Id: 13386346 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 E594DEEB581 for ; Fri, 15 Sep 2023 05:02:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232043AbjIOFCE (ORCPT ); Fri, 15 Sep 2023 01:02:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33652 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231997AbjIOFCB (ORCPT ); Fri, 15 Sep 2023 01:02:01 -0400 Received: from box.trvn.ru (box.trvn.ru [194.87.146.52]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5E4C52718; Thu, 14 Sep 2023 22:01:55 -0700 (PDT) Received: from authenticated-user (box.trvn.ru [194.87.146.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.trvn.ru (Postfix) with ESMTPSA id 8A9CC42264; Fri, 15 Sep 2023 10:01:49 +0500 (+05) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=trvn.ru; s=mail; t=1694754109; bh=Gl5DvmVj086xnyzDaqlZ88oRMAhoEK8Os/bTYN02ZMI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=1C8JozA3QaTBXohhDDVDkzC5EyVkH43YxO0Em8b9bfk+kXf2t4yG1Vj5t3xesrpbc p7ToOAjIjOexG+8qSrD1zudsK+kQdmcKq5lYeFx16oYRXMG2x2bNr4Budna7MjYzYT hLMQ9LY5E25dk9ALkIWglfpmtmuYAcIzzg+tNsT9TSpJZ8jcU8nuk5AxDwWey5B8p5 TUOJDUasywhCbNB6n7HbyFP5jDI8LOYH0UVKd6cBCgg0EZer0UQwzet9gMcUyB24NE vsZpvIsT2bMbULZjvup3OvvaptSHUmVN3pxZCBTIrElWkRMnqSO4GKVT8gjIujglIu Oo/vmpuylqgkA== From: Nikita Travkin Date: Fri, 15 Sep 2023 10:01:18 +0500 Subject: [PATCH v3 1/4] dt-bindings: power: supply: Add pm8916 VM-BMS MIME-Version: 1.0 Message-Id: <20230915-pm8916-bms-lbc-v3-1-f30881e951a0@trvn.ru> References: <20230915-pm8916-bms-lbc-v3-0-f30881e951a0@trvn.ru> In-Reply-To: <20230915-pm8916-bms-lbc-v3-0-f30881e951a0@trvn.ru> To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, Nikita Travkin , Rob Herring X-Developer-Signature: v=1; a=openpgp-sha256; l=2924; i=nikita@trvn.ru; h=from:subject:message-id; bh=Gl5DvmVj086xnyzDaqlZ88oRMAhoEK8Os/bTYN02ZMI=; b=owEBbQKS/ZANAwAIAUMc7O4oGb91AcsmYgBlA+U7tGo/Utzh6z/qN1R/oNKh0bnlFd4/O5ele zb6mZY4m4qJAjMEAAEIAB0WIQTAhK9UUj+qg34uxUdDHOzuKBm/dQUCZQPlOwAKCRBDHOzuKBm/ dUyzD/9LWazefx635QmVxNQPwp7s/tG+BSHoNbrm8rR538owfXzkFj8WVpRz8COset9KWtvmX68 bPcgNTbe9KoDXijWR3bYdU3wl1g8RI+1fN3ukypkAZLgtG0ooE85s2CSDwi6SeEJ9b/1fybW3Lo ggB9rbGkgH6ixTNuJgoBkgQFtS+hyIfFjEGDyvKJ6eXDAPFtMbJIYaoTh7iDFy4MWXmhxu3oger /1GkaQrJgbNx6AJkW5qHOUXT7fUa69WZ0m90W5ghJsH6M5utmQZ1ANbsdW5mOy06Zr582h4P1Hy 1PzWzmwM9zb2y+ZfhGwVcpZNrKu0FKR2U9UiZSnlYu/bnjcbhxpmKT0rUVADLTN2Vci/Pmj7JM1 e2esONMHuavgB8n5WuUjw0sxO9fIe8zQSYK9vEsEdvUkcHj/5JUx2XuyVRRpih6WoyQTGJ1b9RT WCcrdxq6xijEmRk/CmsOgaCvC64WLfBZexyrjOHfNwpT3Qc3prbQrvpaQ6III46ur8vJjCuqo99 3tpcAQFswDcLX5OV6UMvuPEso+rS0Sy6fmsbE1AWAWCBKBhUbf+guktNQG65hSNuT1b9w4o2/ym uKrwgBpb28KBcPq0DEdjx/HFxew8jvjQZkmrptxNCKh+2xj/6wkGJVkldWZPm7h1r/vhhXwZXq/ ZsA0eIqQ5z4nVWQ== X-Developer-Key: i=nikita@trvn.ru; a=openpgp; fpr=C084AF54523FAA837E2EC547431CECEE2819BF75 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Qualcomm Voltage Mode BMS is a battery monitoring block in PM8916 PMIC. Document it's DT binding. Signed-off-by: Nikita Travkin Reviewed-by: Rob Herring --- v2: Describe all interrupts. (Conor) --- .../bindings/power/supply/qcom,pm8916-bms-vm.yaml | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/qcom,pm8916-bms-vm.yaml b/Documentation/devicetree/bindings/power/supply/qcom,pm8916-bms-vm.yaml new file mode 100644 index 000000000000..ad764e69ab57 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom,pm8916-bms-vm.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/qcom,pm8916-bms-vm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Voltage Mode BMS + +maintainers: + - Nikita Travkin + +description: + Voltage Mode BMS is a hardware block found in some Qualcomm PMICs + such as pm8916. This block performs battery voltage monitoring. + +allOf: + - $ref: power-supply.yaml# + +properties: + compatible: + const: qcom,pm8916-bms-vm + + reg: + maxItems: 1 + + interrupts: + items: + - description: BMS FSM left S3 mode + - description: BMS FSM entered S2 mode + - description: OCV measured in S3 mode + - description: OCV below threshold + - description: FIFO update done + - description: BMS FSM switched state + + interrupt-names: + items: + - const: cv_leave + - const: cv_enter + - const: ocv_good + - const: ocv_thr + - const: fifo + - const: state_chg + + monitored-battery: true + + power-supplies: true + +required: + - compatible + - reg + - interrupts + - interrupt-names + - monitored-battery + +additionalProperties: false + +examples: + - | + #include + pmic { + #address-cells = <1>; + #size-cells = <0>; + + battery@4000 { + compatible = "qcom,pm8916-bms-vm"; + reg = <0x4000>; + interrupts = <0x0 0x40 0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 5 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "cv_leave", + "cv_enter", + "ocv_good", + "ocv_thr", + "fifo", + "state_chg"; + + monitored-battery = <&battery>; + power-supplies = <&pm8916_charger>; + }; + }; From patchwork Fri Sep 15 05:01:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikita Travkin X-Patchwork-Id: 13386345 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 D496CEE3F2E for ; Fri, 15 Sep 2023 05:02:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232016AbjIOFCD (ORCPT ); Fri, 15 Sep 2023 01:02:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33640 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232003AbjIOFCB (ORCPT ); Fri, 15 Sep 2023 01:02:01 -0400 Received: from box.trvn.ru (box.trvn.ru [194.87.146.52]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFD7C2710; Thu, 14 Sep 2023 22:01:54 -0700 (PDT) Received: from authenticated-user (box.trvn.ru [194.87.146.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.trvn.ru (Postfix) with ESMTPSA id 6F70F424AE; Fri, 15 Sep 2023 10:01:50 +0500 (+05) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=trvn.ru; s=mail; t=1694754110; bh=rGP+tXUnWOMGHdQJ8R0srdv2Kny66mnF5MC7ifV715k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=lXRm7QUV1IYXq/QeuTPCugFytuP2FrCDCNtJ73bE2ayi/Gh7Q0pHZGmLjvcvuVTQD hBi2u3FTzNq5ZcLnvcFZCOzx9QbHPWDQNi16/CBWi9x+CwddhlkbaMX0odDAJE3TfS 2RNYQmWc2WYkse6hbQd7gX6eWI2YbPeI2VZrWpmIyachwjf1L62YFslUJDbuN78itk KSPBmVJxuSzQp5sDZyFrV9GivFbP1L/g2ayUJ20iMSZXsn8RruAMLQf0s6vOqnb3dB uVlCFpdD9eKKebNgH8uDnFpv6ZKQTRc0wMXpQBrFbW6YR0nPAxhhaBADpccQ1jzN5t vYNcaAMUp4Rsg== From: Nikita Travkin Date: Fri, 15 Sep 2023 10:01:19 +0500 Subject: [PATCH v3 2/4] dt-bindings: power: supply: Add pm8916 LBC MIME-Version: 1.0 Message-Id: <20230915-pm8916-bms-lbc-v3-2-f30881e951a0@trvn.ru> References: <20230915-pm8916-bms-lbc-v3-0-f30881e951a0@trvn.ru> In-Reply-To: <20230915-pm8916-bms-lbc-v3-0-f30881e951a0@trvn.ru> To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, Nikita Travkin , Rob Herring X-Developer-Signature: v=1; a=openpgp-sha256; l=4501; i=nikita@trvn.ru; h=from:subject:message-id; bh=rGP+tXUnWOMGHdQJ8R0srdv2Kny66mnF5MC7ifV715k=; b=owEBbQKS/ZANAwAIAUMc7O4oGb91AcsmYgBlA+U78/A2JnnlDCpflyrOzd5BNNlzgR8hOvd4w CkCp1IC6BaJAjMEAAEIAB0WIQTAhK9UUj+qg34uxUdDHOzuKBm/dQUCZQPlOwAKCRBDHOzuKBm/ dYGOD/9yiqmvm1IdeYt3zmmsn4Bos6U3t5HGejjkolM32oggULuD+g1Hum8m+vC++bdvPit5bhA lM1qH8FzdfDa8AXIe7LNqhKdb3Y+Kh/6d3DSZuZ53yet8Tqcn1RKe78d4lIzkAGbWhXq1VdgjOw DthtOHSMu4dyo9IYnGYprD//6ttuwM3y6vSpiguC1mHbq0104TtgGWHgPF0THFwO94qrnMx1YxT snKVkn9GUEomrGsb4e+c35J6tdjNspPSmHatQvmWwitixWdVUSJC3bAi3CuuH7f5oufUwVYPRiv 9s4KUgdtXo7igFKucSmCtevBF99tUmNJzQR8ZKPrb0reCJjQ8PpduO2ASQxSPIz6AOkJHK527fo aEjCfotm/LHUS/L3DgirzQyMtr2qolBuO66yUmvn/vbxhVABk/p5/BIIxrBYT27/AuSTaZhECmV zqugOlM12NvePEOVhZ92GjxV3TmDa7dIm/jNZ/dV+Qh7nm8dzp2wNPU4y0MnEQ9WO5LCitruity HkVTv6NhRQAQTeVC/JKott/YKn+BN+irW9tD0Js3NswsO0BUhPvFbuDyWzU0bQgkKcI5vMfrrhd Mwzdk9pj/4Xm2w8pPxE7yjBRzFLrV9LXy+QDkEso9kYumX5zds+GrPyhG74ARiV0CO1arCHHCxQ Xzw1nk+mnQC3eCw== X-Developer-Key: i=nikita@trvn.ru; a=openpgp; fpr=C084AF54523FAA837E2EC547431CECEE2819BF75 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Qualcomm Linear Battery Charger is a CC/CV charger block in PM8916 PMIC. Document it's DT binding. Signed-off-by: Nikita Travkin Reviewed-by: Rob Herring --- v2: List all interrupts (Conor) --- .../bindings/power/supply/qcom,pm8916-lbc.yaml | 128 +++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/qcom,pm8916-lbc.yaml b/Documentation/devicetree/bindings/power/supply/qcom,pm8916-lbc.yaml new file mode 100644 index 000000000000..cdf14e5ed119 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom,pm8916-lbc.yaml @@ -0,0 +1,128 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/qcom,pm8916-lbc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Linear Battery Charger + +maintainers: + - Nikita Travkin + +description: + Linear Battery Charger hardware block, found in some Qualcomm PMICs + such as pm8916. Implements a simple, autonomous CC/CV charger. + +allOf: + - $ref: power-supply.yaml# + +properties: + compatible: + const: qcom,pm8916-lbc + + reg: + items: + - description: Charger + - description: Battery + - description: USB + - description: MISC + + reg-names: + items: + - const: chgr + - const: bat_if + - const: usb + - const: misc + + interrupts: + items: + - description: Battery detection + - description: Fast charging + - description: Charging failed + - description: Charging done + - description: Battery present + - description: Battery temperature OK + - description: USB coarse detection + - description: USB IN valid + - description: Charger gone + - description: Overtemperature + + interrupt-names: + items: + - const: vbat_det + - const: fast_chg + - const: chg_fail + - const: chg_done + - const: bat_pres + - const: temp_ok + - const: coarse_det + - const: usb_vbus + - const: chg_gone + - const: overtemp + + qcom,fast-charge-safe-voltage: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 4000000 + maximum: 4775000 + description: + Maximum safe battery voltage in uV; May be pre-set by bootloader, + in which case, setting this will harmlessly fail. + + qcom,fast-charge-safe-current: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 90000 + maximum: 1440000 + description: + Maximum safe battery charge current in uA; May be pre-set by + bootloader, in which case setting this will harmlessly fail. + + monitored-battery: true + +required: + - compatible + - reg + - interrupts + - interrupt-names + - qcom,fast-charge-safe-voltage + - qcom,fast-charge-safe-current + +additionalProperties: false + +examples: + - | + #include + pmic { + #address-cells = <1>; + #size-cells = <0>; + + charger@1000 { + compatible = "qcom,pm8916-lbc"; + reg = <0x1000>, <0x1200>, <0x1300>, <0x1600>; + reg-names = "chgr", "bat_if", "usb", "misc"; + + interrupts = <0x0 0x10 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 6 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 4 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "vbat_det", + "fast_chg", + "chg_fail", + "chg_done", + "bat_pres", + "temp_ok", + "coarse_det", + "usb_vbus", + "chg_gone", + "overtemp"; + monitored-battery = <&battery>; + + qcom,fast-charge-safe-current = <900000>; + qcom,fast-charge-safe-voltage = <4300000>; + }; + }; From patchwork Fri Sep 15 05:01:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikita Travkin X-Patchwork-Id: 13386347 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 B39BEEE021D for ; Fri, 15 Sep 2023 05:02:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232050AbjIOFCE (ORCPT ); Fri, 15 Sep 2023 01:02:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33688 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231998AbjIOFCC (ORCPT ); Fri, 15 Sep 2023 01:02:02 -0400 Received: from box.trvn.ru (box.trvn.ru [194.87.146.52]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B9901271C; Thu, 14 Sep 2023 22:01:55 -0700 (PDT) Received: from authenticated-user (box.trvn.ru [194.87.146.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.trvn.ru (Postfix) with ESMTPSA id 08B3B424AF; Fri, 15 Sep 2023 10:01:51 +0500 (+05) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=trvn.ru; s=mail; t=1694754111; bh=OR/0+PNWCI1ThG5+btkJbl8fhYjaosObwKJhq9vZJq8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=1QQQL/G+HlBo8vXXetu/UvTDfJ24SqiqBYKvKR19NDTnZgQkNhMYTKvjkztSBTW0Q IjSz009NZC811VXGO5LqYZx/MPbaVZvjqNaxTLtLTM79mSYPWKjHOmV120eRKGwgBz x9OjjRNuppPklfpqPgOe18MW9GlyleacEiRuWMk6/tLP19v/6/fMdA7L+5VqmnFZh6 bl6iN0mrRJzlENmG83FSzb8RzK9bAhqQkvc1jPcgZmKlkMLZX2X/461MqX2czD3ZQa NiGsEHYZZrU200LWoj9nMxl8f02JOmTz5kjWSfxDqAGdmJmiR2r6jSugmUYjNHbUED 5hXt2L4s+eHmQ== From: Nikita Travkin Date: Fri, 15 Sep 2023 10:01:20 +0500 Subject: [PATCH v3 3/4] power: supply: Add pm8916 VM-BMS support MIME-Version: 1.0 Message-Id: <20230915-pm8916-bms-lbc-v3-3-f30881e951a0@trvn.ru> References: <20230915-pm8916-bms-lbc-v3-0-f30881e951a0@trvn.ru> In-Reply-To: <20230915-pm8916-bms-lbc-v3-0-f30881e951a0@trvn.ru> To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, Nikita Travkin X-Developer-Signature: v=1; a=openpgp-sha256; l=11568; i=nikita@trvn.ru; h=from:subject:message-id; bh=OR/0+PNWCI1ThG5+btkJbl8fhYjaosObwKJhq9vZJq8=; b=owEBbQKS/ZANAwAIAUMc7O4oGb91AcsmYgBlA+U7M1eGKdRGinZCWrPmdtdoxyxGIKhokAR3f 18D4FnXceWJAjMEAAEIAB0WIQTAhK9UUj+qg34uxUdDHOzuKBm/dQUCZQPlOwAKCRBDHOzuKBm/ dU7DEACm1ecVGMYvz6DLOlHzPqn8yFAX9WghsqOjYCS2+NHLQLwWin65jetJaDiq9qlbQZJikeF 3SqpwQq+Fw0ioS/STzOJeK6yCNJikAcAbYONJU883n8MTu0sEoouAwdFVbtx5nSZMETXHMtF3+m kERXeKVTG3fUhgjI4thez9aDte7mGOyjOTCeOrgsizlgHTHsvn7Cfa3zu1PijgslPAvuRpFGLgt /2d/huMQLK9049utR+FSCQo8kjKxxAh/NF2/15icPvv8coXtIBtOqLjFO7Q8gYUeAsPWVqeYic1 8h2TzMGoP66Uuv9GEP/zgnigTCx0Zv4+BQk4Yemv+c3bAb0cvU1lUYKEMiJjvWoervC4vFPVZWS zW22/ssTe7CdDmpTq39TeD/O/xCpYvCeR13E3JyN0RdLOsghhpYSufmixSFX3FE4Xt6NCUOziOg KExxSIcqYx8aLa65LJj5U5jgkVta41LnL7jxwsfDEQ9op+p31/ybkwEixGaUNox7Su+Oj8ObQxa NS6hMY+P+JDFK88Ql8QhQ5/giGBsvlFkQS5wTi3/oq2GcqvamcEUXG1Y4Ix6x4wqrFLd+nGOzVA 9K3W4GjRRuIl/jRH74krcajYq31Z9wzoRZ+nsZ7PVQ7fO0R+bK9Z8BZe2Mv5tMyFvHpefmPZxqn YpYDnOgHaeOPU6A== X-Developer-Key: i=nikita@trvn.ru; a=openpgp; fpr=C084AF54523FAA837E2EC547431CECEE2819BF75 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org This driver adds basic support for VM-BMS found in pm8916. VM-BMS is a very basic fuel-gauge hardware block that is, sadly, incapable of any gauging. The hardware supports measuring OCV in sleep mode, where the battery is not in use, or measuring average voltage over time when the device is active. This driver implements basic value readout from this block. Signed-off-by: Nikita Travkin --- v2: Get irq by name v3: Use device_property_read, report OCV with timeout, minor styling --- drivers/power/supply/Kconfig | 11 ++ drivers/power/supply/Makefile | 1 + drivers/power/supply/pm8916_bms_vm.c | 305 +++++++++++++++++++++++++++++++++++ 3 files changed, 317 insertions(+) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 0c80c68fb0d7..c6375c03e5ce 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -629,6 +629,17 @@ config CHARGER_QCOM_SMBB documentation for more detail. The base name for this driver is 'pm8941_charger'. +config BATTERY_PM8916_BMS_VM + tristate "Qualcomm PM8916 BMS-VM support" + depends on MFD_SPMI_PMIC || COMPILE_TEST + help + Say Y to add support for Voltage Mode BMS block found in some + Qualcomm PMICs such as PM8916. This hardware block provides + battery voltage monitoring for the system. + + To compile this driver as module, choose M here: the + module will be called pm8916_bms_vm. + config CHARGER_BQ2415X tristate "TI BQ2415x battery charger driver" depends on I2C diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index a8a9fa6de1e9..fdf7916f80ed 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -84,6 +84,7 @@ 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_BATTERY_PM8916_BMS_VM) += pm8916_bms_vm.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o diff --git a/drivers/power/supply/pm8916_bms_vm.c b/drivers/power/supply/pm8916_bms_vm.c new file mode 100644 index 000000000000..5d0dd842509c --- /dev/null +++ b/drivers/power/supply/pm8916_bms_vm.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Nikita Travkin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PM8916_PERPH_TYPE 0x04 +#define PM8916_BMS_VM_TYPE 0x020D + +#define PM8916_SEC_ACCESS 0xD0 +#define PM8916_SEC_MAGIC 0xA5 + +#define PM8916_BMS_VM_STATUS1 0x08 +#define PM8916_BMS_VM_FSM_STATE(x) (((x) & 0b00111000) >> 3) +#define PM8916_BMS_VM_FSM_STATE_S2 0x2 + +#define PM8916_BMS_VM_MODE_CTL 0x40 +#define PM8916_BMS_VM_MODE_FORCE_S3 (BIT(0) | BIT(1)) +#define PM8916_BMS_VM_MODE_NORMAL (BIT(1) | BIT(3)) + +#define PM8916_BMS_VM_EN_CTL 0x46 +#define PM8916_BMS_ENABLED BIT(7) + +#define PM8916_BMS_VM_FIFO_LENGTH_CTL 0x47 +#define PM8916_BMS_VM_S1_SAMPLE_INTERVAL_CTL 0x55 +#define PM8916_BMS_VM_S2_SAMPLE_INTERVAL_CTL 0x56 +#define PM8916_BMS_VM_S3_S7_OCV_DATA0 0x6A +#define PM8916_BMS_VM_BMS_FIFO_REG_0_LSB 0xC0 + +/* Using only 1 fifo is broken in hardware */ +#define PM8916_BMS_VM_FIFO_COUNT 2 /* 2 .. 8 */ + +#define PM8916_BMS_VM_S1_SAMPLE_INTERVAL 10 +#define PM8916_BMS_VM_S2_SAMPLE_INTERVAL 10 + +struct pm8916_bms_vm_battery { + struct device *dev; + struct power_supply *battery; + struct power_supply_battery_info *info; + struct regmap *regmap; + unsigned int reg; + unsigned int last_ocv; + time64_t last_ocv_time; + unsigned int vbat_now; +}; + +static int pm8916_bms_vm_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct pm8916_bms_vm_battery *bat = power_supply_get_drvdata(psy); + struct power_supply_battery_info *info = bat->info; + int supplied; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + supplied = power_supply_am_i_supplied(psy); + + if (supplied < 0 && supplied != -ENODEV) + return supplied; + else if (supplied && supplied != -ENODEV) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + return 0; + + case POWER_SUPPLY_PROP_HEALTH: + if (bat->vbat_now < info->voltage_min_design_uv) + val->intval = POWER_SUPPLY_HEALTH_DEAD; + else if (bat->vbat_now > info->voltage_max_design_uv) + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + else + val->intval = POWER_SUPPLY_HEALTH_GOOD; + return 0; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = bat->vbat_now; + return 0; + + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + /* + * Hardware only reliably measures OCV when the system is off or suspended. + * We expose the last known OCV value on boot, invalidating it after 180 seconds. + */ + if (ktime_get_seconds() - bat->last_ocv_time > 180) + return -ENODATA; + + val->intval = bat->last_ocv; + return 0; + + default: + return -EINVAL; + } +} + +static enum power_supply_property pm8916_bms_vm_battery_properties[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_OCV, + POWER_SUPPLY_PROP_HEALTH, +}; + +static irqreturn_t pm8916_bms_vm_fifo_update_done_irq(int irq, void *data) +{ + struct pm8916_bms_vm_battery *bat = data; + u16 vbat_data[PM8916_BMS_VM_FIFO_COUNT]; + int ret; + + ret = regmap_bulk_read(bat->regmap, bat->reg + PM8916_BMS_VM_BMS_FIFO_REG_0_LSB, + &vbat_data, PM8916_BMS_VM_FIFO_COUNT * 2); + if (ret) + return IRQ_HANDLED; + + /* + * The VM-BMS hardware only collects voltage data and the software + * has to process it to calculate the OCV and SoC. Hardware provides + * up to 8 averaged measurements for software to take in account. + * + * Just use the last measured value for now to report the current + * battery voltage. + */ + bat->vbat_now = vbat_data[PM8916_BMS_VM_FIFO_COUNT - 1] * 300; + + power_supply_changed(bat->battery); + + return IRQ_HANDLED; +} + +static const struct power_supply_desc pm8916_bms_vm_battery_psy_desc = { + .name = "pm8916-bms-vm", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = pm8916_bms_vm_battery_properties, + .num_properties = ARRAY_SIZE(pm8916_bms_vm_battery_properties), + .get_property = pm8916_bms_vm_battery_get_property, +}; + +static int pm8916_bms_vm_battery_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pm8916_bms_vm_battery *bat; + struct power_supply_config psy_cfg = {}; + int ret, irq; + unsigned int tmp; + + bat = devm_kzalloc(dev, sizeof(*bat), GFP_KERNEL); + if (!bat) + return -ENOMEM; + + bat->dev = dev; + + bat->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!bat->regmap) + return -ENODEV; + + ret = device_property_read_u32(dev, "reg", &bat->reg); + if (ret < 0) + return -EINVAL; + + irq = platform_get_irq_byname(pdev, "fifo"); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_bms_vm_fifo_update_done_irq, + IRQF_ONESHOT, "pm8916_vm_bms", bat); + if (ret) + return ret; + + ret = regmap_bulk_read(bat->regmap, bat->reg + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + + if (tmp != PM8916_BMS_VM_TYPE) + return dev_err_probe(dev, -ENODEV, "Device reported wrong type: 0x%X\n", tmp); + + ret = regmap_write(bat->regmap, bat->reg + PM8916_BMS_VM_S1_SAMPLE_INTERVAL_CTL, + PM8916_BMS_VM_S1_SAMPLE_INTERVAL); + if (ret) + goto comm_error; + ret = regmap_write(bat->regmap, bat->reg + PM8916_BMS_VM_S2_SAMPLE_INTERVAL_CTL, + PM8916_BMS_VM_S2_SAMPLE_INTERVAL); + if (ret) + goto comm_error; + ret = regmap_write(bat->regmap, bat->reg + PM8916_BMS_VM_FIFO_LENGTH_CTL, + PM8916_BMS_VM_FIFO_COUNT << 4 | PM8916_BMS_VM_FIFO_COUNT); + if (ret) + goto comm_error; + ret = regmap_write(bat->regmap, + bat->reg + PM8916_BMS_VM_EN_CTL, PM8916_BMS_ENABLED); + if (ret) + goto comm_error; + + ret = regmap_bulk_read(bat->regmap, + bat->reg + PM8916_BMS_VM_S3_S7_OCV_DATA0, &tmp, 2); + if (ret) + goto comm_error; + + bat->last_ocv_time = ktime_get_seconds(); + bat->last_ocv = tmp * 300; + bat->vbat_now = bat->last_ocv; + + psy_cfg.drv_data = bat; + psy_cfg.of_node = dev->of_node; + + bat->battery = devm_power_supply_register(dev, &pm8916_bms_vm_battery_psy_desc, &psy_cfg); + if (IS_ERR(bat->battery)) + return dev_err_probe(dev, PTR_ERR(bat->battery), "Unable to register battery\n"); + + ret = power_supply_get_battery_info(bat->battery, &bat->info); + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + + platform_set_drvdata(pdev, bat); + + return 0; + +comm_error: + return dev_err_probe(dev, ret, "Unable to communicate with device\n"); +} + +static int pm8916_bms_vm_battery_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct pm8916_bms_vm_battery *bat = platform_get_drvdata(pdev); + int ret; + + /* + * Due to a hardware quirk the FSM doesn't switch states normally. + * Instead we unlock the debug registers and force S3 (Measure OCV/Sleep) + * mode every time we suspend. + */ + + ret = regmap_write(bat->regmap, + bat->reg + PM8916_SEC_ACCESS, PM8916_SEC_MAGIC); + if (ret) + goto error; + ret = regmap_write(bat->regmap, + bat->reg + PM8916_BMS_VM_MODE_CTL, PM8916_BMS_VM_MODE_FORCE_S3); + if (ret) + goto error; + + return 0; + +error: + dev_err(bat->dev, "Failed to force S3 mode: %pe\n", ERR_PTR(ret)); + return ret; +} + +static int pm8916_bms_vm_battery_resume(struct platform_device *pdev) +{ + struct pm8916_bms_vm_battery *bat = platform_get_drvdata(pdev); + int ret; + unsigned int tmp; + + ret = regmap_bulk_read(bat->regmap, + bat->reg + PM8916_BMS_VM_S3_S7_OCV_DATA0, &tmp, 2); + + bat->last_ocv_time = ktime_get_seconds(); + bat->last_ocv = tmp * 300; + + ret = regmap_write(bat->regmap, + bat->reg + PM8916_SEC_ACCESS, PM8916_SEC_MAGIC); + if (ret) + goto error; + ret = regmap_write(bat->regmap, + bat->reg + PM8916_BMS_VM_MODE_CTL, PM8916_BMS_VM_MODE_NORMAL); + if (ret) + goto error; + + return 0; + +error: + dev_err(bat->dev, "Failed to return normal mode: %pe\n", ERR_PTR(ret)); + return ret; +} + +static const struct of_device_id pm8916_bms_vm_battery_of_match[] = { + { .compatible = "qcom,pm8916-bms-vm", }, + {} +}; +MODULE_DEVICE_TABLE(of, pm8916_bms_vm_battery_of_match); + +static struct platform_driver pm8916_bms_vm_battery_driver = { + .driver = { + .name = "pm8916-bms-vm", + .of_match_table = pm8916_bms_vm_battery_of_match, + }, + .probe = pm8916_bms_vm_battery_probe, + .suspend = pm8916_bms_vm_battery_suspend, + .resume = pm8916_bms_vm_battery_resume, +}; +module_platform_driver(pm8916_bms_vm_battery_driver); + +MODULE_DESCRIPTION("pm8916 BMS-VM driver"); +MODULE_AUTHOR("Nikita Travkin "); +MODULE_LICENSE("GPL"); From patchwork Fri Sep 15 05:01:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikita Travkin X-Patchwork-Id: 13386348 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 42B4CEEB59A for ; Fri, 15 Sep 2023 05:02:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232021AbjIOFCG (ORCPT ); Fri, 15 Sep 2023 01:02:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42730 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232027AbjIOFCD (ORCPT ); Fri, 15 Sep 2023 01:02:03 -0400 Received: from box.trvn.ru (box.trvn.ru [194.87.146.52]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E2DF02720; Thu, 14 Sep 2023 22:01:55 -0700 (PDT) Received: from authenticated-user (box.trvn.ru [194.87.146.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.trvn.ru (Postfix) with ESMTPSA id 8C56A424B0; Fri, 15 Sep 2023 10:01:51 +0500 (+05) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=trvn.ru; s=mail; t=1694754112; bh=49MaGxNQqyAPhOgveIuAGVdV6GmbhsB4KycALCG40Ns=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=iDiDsx1m068luOVjQClVdWY2bJdlgk4nUzBHYhT71OHfXnef7REhdtdLRm0G90THh QdfLb8AVZLxT6k+tdkTRHQzp6FcJU5Q6oE51nGKLyjtVdU/Jt45PqdWjOzEkFHSbip mudzeH4zUGo/e334iXB3lOWryIvfPnerIwaUfAqVOVTxLiDMEawk2e63kTb1aHwW7x 6h9Yrs6ItEP3gmxXVN3xnIsxirKDbCrhvTGOdsH1AZZTA19twVpMX9b/mdvgeQlprx eHtSOtFYBfTEjy8TTc7hPuVPS6/DtkR/NGgAESYcbADkEoisOGPqfrkVouzbZgC7Np sfiaDA5fFo7tg== From: Nikita Travkin Date: Fri, 15 Sep 2023 10:01:21 +0500 Subject: [PATCH v3 4/4] power: supply: Add driver for pm8916 lbc MIME-Version: 1.0 Message-Id: <20230915-pm8916-bms-lbc-v3-4-f30881e951a0@trvn.ru> References: <20230915-pm8916-bms-lbc-v3-0-f30881e951a0@trvn.ru> In-Reply-To: <20230915-pm8916-bms-lbc-v3-0-f30881e951a0@trvn.ru> To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, Nikita Travkin X-Developer-Signature: v=1; a=openpgp-sha256; l=13852; i=nikita@trvn.ru; h=from:subject:message-id; bh=49MaGxNQqyAPhOgveIuAGVdV6GmbhsB4KycALCG40Ns=; b=owEBbQKS/ZANAwAIAUMc7O4oGb91AcsmYgBlA+U7xqFwtrvgnaPf9znUOoIED+nLJnMDFVlni wrnoh/H61uJAjMEAAEIAB0WIQTAhK9UUj+qg34uxUdDHOzuKBm/dQUCZQPlOwAKCRBDHOzuKBm/ dVKmEACStgqDq6p2UvOMcGb5V8AhZUAsrUqApHzvDgIqZaxXvkv7Z0MMMFuR1wfC6mOHmCSJz9L no9VR8fZaZ3VH0jUu5TYvxV/GHuTqyfI0pgFiAaVEQedNjTWG+FB1sWg9QOo0UdxoMdsrqlOCI/ JsH792mxSpF6FjDjAD0GuVBLI8zDOn+Zad8VDoTQ1B01/Hsn1aH7P1IEFLHcEwmhKH7TMcDOPvM 1GNOWcLbs29gzeJeuMoNrnO65t87Yee/ImroFoKwepnhr5xZQ5TxN6sUEYhBmhqCx99gNOLMook 3LvR1OWYf1VQ7wMOnIlWRCp/lEo8/aXAXURhOgPC/V6Tqx5Ln7R5q+zK14PG9czMI3yRMtcc1Yx L8e+iu9whjKs8gI6eWLFGEge38xkDtaxwOSBr5GJUi4uhBLLKICZcZ8E6ObtD8RKjus+p1jEDl7 pMVmkcZUL15l+tPbj9V8CI2KNbg3hxbVphVzfcDXKN5YO7k1++mp5lsfPN26cQhSv2S0/CXT0BC SU+EOb1rAhBSGTQDud/f8bjO2l+OziJfC5xkP6xw3QqejVLJP/MGhXroaAAlHnoARxjGs1bPwV6 Sf8XlM+hYCHiuuHPbupeWuGRdZ/54cZkLlZXcSmMV7xOPzc3ip9iScWFuKlnhGpz/IJ7C6cJhys s589nn4l1J5auvg== X-Developer-Key: i=nikita@trvn.ru; a=openpgp; fpr=C084AF54523FAA837E2EC547431CECEE2819BF75 Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org pm8916 LBC is a Linear Battery Charger hardware block in pm8916 PMIC. This block implements simple CC/CV charging for Li-Po batteries. The hardware has internal state machine to switch between modes and works mostly autonomously, only needing the limits and targets to be set to operate. This driver allows setting limits and enabling the LBC block, monitoring it's state. Signed-off-by: Nikita Travkin --- v2: Fix missed warnings, get irq by name v3: INPUT_CURRENT_LIMIT -> CONSTANT_CHARGE_CURRENT, use device_property_* --- drivers/power/supply/Kconfig | 11 ++ drivers/power/supply/Makefile | 1 + drivers/power/supply/pm8916_lbc.c | 381 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 393 insertions(+) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index c6375c03e5ce..95e296b80550 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -640,6 +640,17 @@ config BATTERY_PM8916_BMS_VM To compile this driver as module, choose M here: the module will be called pm8916_bms_vm. +config CHARGER_PM8916_LBC + tristate "Qualcomm PM8916 Linear Battery Charger support" + depends on MFD_SPMI_PMIC || COMPILE_TEST + help + Say Y here to add support for Linear Battery Charger block + found in some Qualcomm PMICs such as PM8916. This hardware + blokc provides simple CC/CV battery charger. + + To compile this driver as module, choose M here: the + module will be called pm8916_lbc. + config CHARGER_BQ2415X tristate "TI BQ2415x battery charger driver" depends on I2C diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index fdf7916f80ed..e4bd9eb1261b 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -85,6 +85,7 @@ obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o obj-$(CONFIG_CHARGER_MT6370) += mt6370-charger.o obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o obj-$(CONFIG_BATTERY_PM8916_BMS_VM) += pm8916_bms_vm.o +obj-$(CONFIG_CHARGER_PM8916_LBC) += pm8916_lbc.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c new file mode 100644 index 000000000000..6d92e98cbecc --- /dev/null +++ b/drivers/power/supply/pm8916_lbc.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Nikita Travkin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Two bytes: type + subtype */ +#define PM8916_PERPH_TYPE 0x04 +#define PM8916_LBC_CHGR_TYPE 0x1502 +#define PM8916_LBC_BAT_IF_TYPE 0x1602 +#define PM8916_LBC_USB_TYPE 0x1702 +#define PM8916_LBC_MISC_TYPE 0x1802 + +#define PM8916_LBC_CHGR_CHG_OPTION 0x08 +#define PM8916_LBC_CHGR_PMIC_CHARGER BIT(7) + +#define PM8916_LBC_CHGR_CHG_STATUS 0x09 + +#define PM8916_INT_RT_STS 0x10 + +#define PM8916_LBC_USB_USBIN_VALID BIT(1) + +#define PM8916_LBC_CHGR_VDD_MAX 0x40 +#define PM8916_LBC_CHGR_VDD_SAFE 0x41 +#define PM8916_LBC_CHGR_IBAT_MAX 0x44 +#define PM8916_LBC_CHGR_IBAT_SAFE 0x45 + +#define PM8916_LBC_CHGR_TCHG_MAX_EN 0x60 +#define PM8916_LBC_CHGR_TCHG_MAX_ENABLED BIT(7) +#define PM8916_LBC_CHGR_TCHG_MAX 0x61 + +#define PM8916_LBC_CHGR_CHG_CTRL 0x49 +#define PM8916_LBC_CHGR_CHG_EN BIT(7) +#define PM8916_LBC_CHGR_PSTG_EN BIT(5) + +#define PM8916_LBC_CHGR_MIN_CURRENT 90000 +#define PM8916_LBC_CHGR_MAX_CURRENT 1440000 + +#define PM8916_LBC_CHGR_MIN_VOLTAGE 4000000 +#define PM8916_LBC_CHGR_MAX_VOLTAGE 4775000 +#define PM8916_LBC_CHGR_VOLTAGE_STEP 25000 + +#define PM8916_LBC_CHGR_MIN_TIME 4 +#define PM8916_LBC_CHGR_MAX_TIME 256 + +struct pm8916_lbc_charger { + struct device *dev; + struct extcon_dev *edev; + struct power_supply *charger; + struct power_supply_battery_info *info; + struct regmap *regmap; + unsigned int reg[4]; + bool online; + unsigned int charge_voltage_max; + unsigned int charge_voltage_safe; + unsigned int charge_current_max; + unsigned int charge_current_safe; +}; + +static const unsigned int pm8916_lbc_charger_cable[] = { + EXTCON_USB, + EXTCON_NONE, +}; + +enum { + LBC_CHGR = 0, + LBC_BAT_IF, + LBC_USB, + LBC_MISC, +}; + +static int pm8916_lbc_charger_configure(struct pm8916_lbc_charger *chg) +{ + int ret = 0; + unsigned int tmp; + + chg->charge_voltage_max = clamp_t(u32, chg->charge_voltage_max, + PM8916_LBC_CHGR_MIN_VOLTAGE, chg->charge_voltage_safe); + + tmp = chg->charge_voltage_max - PM8916_LBC_CHGR_MIN_VOLTAGE; + tmp /= PM8916_LBC_CHGR_VOLTAGE_STEP; + chg->charge_voltage_max = PM8916_LBC_CHGR_MIN_VOLTAGE + tmp * PM8916_LBC_CHGR_VOLTAGE_STEP; + + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_VDD_MAX, tmp); + if (ret) + goto error; + + chg->charge_current_max = min(chg->charge_current_max, chg->charge_current_safe); + + tmp = clamp_t(u32, chg->charge_current_max, + PM8916_LBC_CHGR_MIN_CURRENT, PM8916_LBC_CHGR_MAX_CURRENT); + + tmp = chg->charge_current_max / PM8916_LBC_CHGR_MIN_CURRENT - 1; + chg->charge_current_max = (tmp + 1) * PM8916_LBC_CHGR_MIN_CURRENT; + + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_IBAT_MAX, tmp); + if (ret) + goto error; + + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_CHG_CTRL, + PM8916_LBC_CHGR_CHG_EN | PM8916_LBC_CHGR_PSTG_EN); + if (ret) + goto error; + + return ret; + +error: + dev_err(chg->dev, "Failed to configure charging: %pe\n", ERR_PTR(ret)); + return ret; +} + +static int pm8916_lbc_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct pm8916_lbc_charger *chg = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = chg->online; + return 0; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + val->intval = chg->charge_voltage_max; + return 0; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + val->intval = chg->charge_current_max; + return 0; + + default: + return -EINVAL; + }; +} + +static int pm8916_lbc_charger_set_property(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + struct pm8916_lbc_charger *chg = power_supply_get_drvdata(psy); + + switch (prop) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + chg->charge_current_max = val->intval; + return pm8916_lbc_charger_configure(chg); + default: + return -EINVAL; + } +} + +static int pm8916_lbc_charger_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + return true; + default: + return false; + } +} + +static enum power_supply_property pm8916_lbc_charger_properties[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, +}; + +static irqreturn_t pm8916_lbc_charger_state_changed_irq(int irq, void *data) +{ + struct pm8916_lbc_charger *chg = data; + unsigned int tmp; + int ret; + + ret = regmap_read(chg->regmap, chg->reg[LBC_USB] + PM8916_INT_RT_STS, &tmp); + if (ret) + return IRQ_HANDLED; + + chg->online = !!(tmp & PM8916_LBC_USB_USBIN_VALID); + extcon_set_state_sync(chg->edev, EXTCON_USB, chg->online); + + power_supply_changed(chg->charger); + + return IRQ_HANDLED; +} + +static int pm8916_lbc_charger_probe_dt(struct pm8916_lbc_charger *chg) +{ + struct device *dev = chg->dev; + int ret = 0; + unsigned int tmp; + + ret = device_property_read_u32(dev, "qcom,fast-charge-safe-voltage", &chg->charge_voltage_safe); + if (ret) + return ret; + if (chg->charge_voltage_safe < PM8916_LBC_CHGR_MIN_VOLTAGE) + return -EINVAL; + + chg->charge_voltage_safe = clamp_t(u32, chg->charge_voltage_safe, + PM8916_LBC_CHGR_MIN_VOLTAGE, PM8916_LBC_CHGR_MAX_VOLTAGE); + + tmp = chg->charge_voltage_safe - PM8916_LBC_CHGR_MIN_VOLTAGE; + tmp /= PM8916_LBC_CHGR_VOLTAGE_STEP; + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_VDD_SAFE, tmp); + if (ret) + return ret; + + ret = device_property_read_u32(dev, "qcom,fast-charge-safe-current", &chg->charge_current_safe); + if (ret) + return ret; + if (chg->charge_current_safe < PM8916_LBC_CHGR_MIN_CURRENT) + return -EINVAL; + + chg->charge_current_safe = clamp_t(u32, chg->charge_current_safe, + PM8916_LBC_CHGR_MIN_CURRENT, PM8916_LBC_CHGR_MAX_CURRENT); + + chg->charge_current_max = chg->charge_current_safe; + + tmp = chg->charge_current_safe / PM8916_LBC_CHGR_MIN_CURRENT - 1; + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_IBAT_SAFE, tmp); + if (ret) + return ret; + + /* Disable charger timeout. */ + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_TCHG_MAX_EN, 0x00); + if (ret) + return ret; + + return ret; +} + +static const struct power_supply_desc pm8916_lbc_charger_psy_desc = { + .name = "pm8916-lbc-chgr", + .type = POWER_SUPPLY_TYPE_USB, + .properties = pm8916_lbc_charger_properties, + .num_properties = ARRAY_SIZE(pm8916_lbc_charger_properties), + .get_property = pm8916_lbc_charger_get_property, + .set_property = pm8916_lbc_charger_set_property, + .property_is_writeable = pm8916_lbc_charger_property_is_writeable, +}; + +static int pm8916_lbc_charger_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pm8916_lbc_charger *chg; + struct power_supply_config psy_cfg = {}; + int ret, len, irq; + unsigned int tmp; + + chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL); + if (!chg) + return -ENOMEM; + + chg->dev = dev; + + chg->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chg->regmap) + return -ENODEV; + + len = device_property_count_u32(dev, "reg"); + if (len < 0) + return len; + if (len != 4) + return dev_err_probe(dev, -EINVAL, + "Wrong amount of reg values: %d (4 expected)\n", len); + + irq = platform_get_irq_byname(pdev, "usb_vbus"); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, + IRQF_ONESHOT, "pm8916_lbc", chg); + if (ret) + return ret; + + ret = device_property_read_u32_array(dev, "reg", chg->reg, len); + if (ret) + return ret; + + ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_CHGR] + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_CHGR_TYPE) + goto type_error; + + ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_BAT_IF] + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_BAT_IF_TYPE) + goto type_error; + + ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_USB] + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_USB_TYPE) + goto type_error; + + ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_MISC] + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_MISC_TYPE) + goto type_error; + + ret = regmap_read(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_CHG_OPTION, &tmp); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_CHGR_PMIC_CHARGER) + dev_err_probe(dev, -ENODEV, "The system is using an external charger\n"); + + ret = pm8916_lbc_charger_probe_dt(chg); + if (ret) + dev_err_probe(dev, ret, "Error while parsing device tree\n"); + + psy_cfg.drv_data = chg; + psy_cfg.of_node = dev->of_node; + + chg->charger = devm_power_supply_register(dev, &pm8916_lbc_charger_psy_desc, &psy_cfg); + if (IS_ERR(chg->charger)) + return dev_err_probe(dev, PTR_ERR(chg->charger), "Unable to register charger\n"); + + ret = power_supply_get_battery_info(chg->charger, &chg->info); + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + + chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable); + if (IS_ERR(chg->edev)) + return PTR_ERR(chg->edev); + + ret = devm_extcon_dev_register(dev, chg->edev); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to register extcon device\n"); + + ret = regmap_read(chg->regmap, chg->reg[LBC_USB] + PM8916_INT_RT_STS, &tmp); + if (ret) + goto comm_error; + + chg->online = !!(tmp & PM8916_LBC_USB_USBIN_VALID); + extcon_set_state_sync(chg->edev, EXTCON_USB, chg->online); + + chg->charge_voltage_max = chg->info->voltage_max_design_uv; + ret = pm8916_lbc_charger_configure(chg); + if (ret) + return ret; + + return 0; + +comm_error: + return dev_err_probe(dev, ret, "Unable to communicate with device\n"); + +type_error: + return dev_err_probe(dev, -ENODEV, "Device reported wrong type: 0x%X\n", tmp); +} + +static const struct of_device_id pm8916_lbc_charger_of_match[] = { + { .compatible = "qcom,pm8916-lbc", }, + {} +}; +MODULE_DEVICE_TABLE(of, pm8916_lbc_charger_of_match); + +static struct platform_driver pm8916_lbc_charger_driver = { + .driver = { + .name = "pm8916-lbc", + .of_match_table = pm8916_lbc_charger_of_match, + }, + .probe = pm8916_lbc_charger_probe, +}; +module_platform_driver(pm8916_lbc_charger_driver); + +MODULE_DESCRIPTION("pm8916 LBC driver"); +MODULE_AUTHOR("Nikita Travkin "); +MODULE_LICENSE("GPL");