From nobody Sun Feb 8 11:21:47 2026 Received: from mail.andi.de1.cc (mail.andi.de1.cc [178.238.236.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A9B882D73B4; Thu, 13 Nov 2025 23:11:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.238.236.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763075473; cv=none; b=X1fMcaaiPuPBqsJV8OBQVhlfPlvYd1rRThi4XqgqadbOV7sPo5XJL0AEG9xF26QD9zMCTsXdYLwibqsP0B0S2cPzu2CxLNxbNJ3TD8vsCbtth1UQVNgEYJnyTTT/5LwxoZCRa1Gkwg0ighhC4t3Fyocs1LDVZHtVYU/19+9ZgoA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763075473; c=relaxed/simple; bh=ESJOVsvQMV+Nlbwka+JA47fsy0mxjuf5UFlf+q4arIU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=X3mFr5ffPqCt8f9+BVkfEMcusG5Q3LLMmV+PKMAuQ+ZUYeVtZWoYLi7EgX5s/M1fTWVkFQV98xS6vdlRF+mFkhv35UIkgffX3MOaR/O+hnF2eqIxeLSZjMpCB20SJQQQG6mDcGIa9Zp6oW8o/defQVVWo1IiefJDkjW5y1SGqi4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=kemnade.info; spf=pass smtp.mailfrom=kemnade.info; dkim=pass (2048-bit key) header.d=kemnade.info header.i=@kemnade.info header.b=IRBjYX2s; arc=none smtp.client-ip=178.238.236.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=kemnade.info Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=kemnade.info Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kemnade.info header.i=@kemnade.info header.b="IRBjYX2s" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=kemnade.info; s=20220719; h=Cc:In-Reply-To:References:From:Sender:Reply-To: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID; bh=H3aN2Oz9OTCWDSvMMZ8cu+gOgAg+yIuIQU/GOb23lKk=; b=IRBjYX2seZiJs6O12rYz+gcefU frcj2C4x3j73W9HhqEefjxmwNpzrNkfbzSr1qSF2s7tkpQq4zoWIhL7xwH0CffTCVqwBiXK6QZDtv 2FY1N0VHSDq/bEdvXloR0A0TxXN4rRY7jpoGtoWzQMunFx9fWkiQZxGLW0+3hYk5rpI9dYv9ci6BS 8VjQ0e9BH8mgjOJ+X09z9/ilnz21XuPVY17PEyKxCq59//AD69K01IS+CWxz5oQtYvma0aTO0Kwzf knbMHVV2zJYeU+opaHtYzFHXr2vJ8zr3en3Cm8x7TDxHPmDO6WEufQ0HPVo5O3uTr3vViLzs5+xra pHVIl4iQ==; From: Andreas Kemnade Date: Fri, 14 Nov 2025 00:06:41 +0100 Subject: [PATCH v2 1/3] dt-bindings: vendor-prefixes: Add Fitipower Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251114-fp9931-submit-v2-1-cd6998932c4c@kemnade.info> References: <20251114-fp9931-submit-v2-0-cd6998932c4c@kemnade.info> In-Reply-To: <20251114-fp9931-submit-v2-0-cd6998932c4c@kemnade.info> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Guenter Roeck Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, Andreas Kemnade X-Mailer: b4 0.15-dev-a6db3 X-Developer-Signature: v=1; a=openpgp-sha256; l=818; i=andreas@kemnade.info; h=from:subject:message-id; bh=ESJOVsvQMV+Nlbwka+JA47fsy0mxjuf5UFlf+q4arIU=; b=owGbwMvMwCUm/rzkS6lq2x3G02pJDJliKWd3fUg3nzjTxXCv+fYqSUcRm4Qpt+NWNXs9PFbUy fDM8uX8jlIWBjEuBlkxRZZf1gpun1Se5QZPjbCHmcPKBDKEgYtTACai2crIsGuj/+ftMqaubC6i fT4SvIe0j67Nit7+2XWimuKiF5tulzH8z322Zu72/MKIb2qBiUoHbr16zve0KPW6zqS69GD9GRK NzAA= X-Developer-Key: i=andreas@kemnade.info; a=openpgp; fpr=EEC0DB858E66C0DA70620AC07DBD6AC74DE29324 Add Fitipower Integrated Technology Inc. to the vendor prefixes. Signed-off-by: Andreas Kemnade Acked-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Docum= entation/devicetree/bindings/vendor-prefixes.yaml index f1d1882009ba..80fbde5ac48f 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -570,6 +570,8 @@ patternProperties: description: Foxconn Industrial Internet "^firefly,.*": description: Firefly + "^fitipower,.*": + description: Fitipower Integrated Technology Inc. "^flipkart,.*": description: Flipkart Inc. "^focaltech,.*": --=20 2.47.3 From nobody Sun Feb 8 11:21:47 2026 Received: from mail.andi.de1.cc (mail.andi.de1.cc [178.238.236.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6219F2F6585; Thu, 13 Nov 2025 23:11:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.238.236.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763075500; cv=none; b=sO86KvHp4SrLbm4ruUtNCgkJe3kLQnFa6j4i3Y03fKv6PgF8uudQ5az6l6tjtfmCut/cfsn5SHf/MwCM+DyephkCo2E+672LCLyBqwD2+65ftS1m/G2q1FnpM2RXIHjp7gdrXvvHg/lOECsolloYoYIoYoyJBXxs4rqPiMfPGMg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763075500; c=relaxed/simple; bh=eW434AzTthzShhSP9k4agJhCm8IckIw44BA0AY/lGNg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZCn6DsFXUiF1yzfvUfhcPN7jUScYqeK2S7z76w8IPs5XLwQUhjjDrK0KUneBpQCCxHCE9BWA3PbmsSGYVsoJ8/MhSpfcjcvwIIvx37Qb840LiXAnVyTrb41jRzxP62mxKjUYcKXI0KnpB3caO0nMFnEe2JqjKezCliD0URJKbEQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=kemnade.info; spf=pass smtp.mailfrom=kemnade.info; dkim=pass (2048-bit key) header.d=kemnade.info header.i=@kemnade.info header.b=8JZ3odAk; arc=none smtp.client-ip=178.238.236.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=kemnade.info Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=kemnade.info Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kemnade.info header.i=@kemnade.info header.b="8JZ3odAk" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=kemnade.info; s=20220719; h=Cc:In-Reply-To:References:From:Sender:Reply-To: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID; bh=awmJtLJBvhAfwJnDUR/tVhpFnJ0yeqggY8R7Yl2jinA=; b=8JZ3odAkDwIxRt0Sbmf1ehIxnk ixxd7/wA4mpFm7dvsT8xGyG9PxNgUqPcdVT3vazbgiU1XSiGISF2p3ojkIJ1bgGmyKW7ATalnD0f0 MvZv6R6RoUuYjN/0kAbuhjMe+LfXJkVusUedvBilvdcM2YtPZUpxK4DWzy4UxnvJtPSmt/SwuJTzh YHq9t7nkDuOSBPyF5gQcNH7fY/ZT3f6K4b9d3llFI9+cxlQjufB8qCoi+J7x75ax9P2lt9qlhfWUo AtCR/WdTHwIWL82Smn+aiV6n2/MLTpIR6k1S0Ke8MgqTzuXjn8dqWSOENPJo8AhQGFuB1H04I/7Jw JTifXStw==; From: Andreas Kemnade Date: Fri, 14 Nov 2025 00:06:42 +0100 Subject: [PATCH v2 2/3] dt-bindings: regulator: Add Fitipower FP9931/JD9930 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251114-fp9931-submit-v2-2-cd6998932c4c@kemnade.info> References: <20251114-fp9931-submit-v2-0-cd6998932c4c@kemnade.info> In-Reply-To: <20251114-fp9931-submit-v2-0-cd6998932c4c@kemnade.info> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Guenter Roeck Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, Andreas Kemnade X-Mailer: b4 0.15-dev-a6db3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3561; i=andreas@kemnade.info; h=from:subject:message-id; bh=eW434AzTthzShhSP9k4agJhCm8IckIw44BA0AY/lGNg=; b=owGbwMvMwCUm/rzkS6lq2x3G02pJDJliKWd1d/34WelteL7DeuKUJJ1Zq7ace7ZwzfNay9VGD Gp85dIqHSUsDGJcDLJiiiy/rBXcPqk8yw2eGmEPM4eVCWQIAxenAEzE5BIjw4HQimwu06T+8//U J29rOpHrL/HyzZF7Uh/CTEJuGscWrGP4whFUJOvnOWt60qwGkwCvtVe1jY3XP+sX+8le+MC59SE HAA== X-Developer-Key: i=andreas@kemnade.info; a=openpgp; fpr=EEC0DB858E66C0DA70620AC07DBD6AC74DE29324 Document the FP9931/JD9930. As the FP9931 is a clear subset of the JD9930, define it as a fallback compatible. GPIO names are same as in the datasheet except for the EN pad which is described as "enable". Signed-off-by: Andreas Kemnade Reviewed-by: Krzysztof Kozlowski --- .../bindings/regulator/fitipower,fp9931.yaml | 110 +++++++++++++++++= ++++ 1 file changed, 110 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/fitipower,fp9931.y= aml b/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml new file mode 100644 index 000000000000..28802e4518c3 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/fitipower,fp9931.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: FitiPower FP9931/JD9930 Power Management Integrated Circuit + +maintainers: + - Andreas Kemnade + +description: + FP9931 is a Power Management IC to provide Power for EPDs with one 3.3V + switch, 2 symmetric LDOs behind 2 DC/DC converters, and one unsymmetric + regulator for a compensation voltage. + JD9930 has in addition some kind of night mode. + +properties: + compatible: + oneOf: + - const: fitipower,fp9931 + + - items: + - const: fitipower,jd9930 + - const: fitipower,fp9931 + + reg: + maxItems: 1 + + enable-gpios: + maxItems: 1 + + pg-gpios: + maxItems: 1 + + en-ts-gpios: + maxItems: 1 + + xon-gpios: + maxItems: 1 + + vin-supply: + description: + Supply for the whole chip. Some vendor kernels and devicetrees + declare this as a non-existing GPIO named "pwrall". + + fitipower,tdly-ms: + description: + Power up soft start delay settings tDLY1-4 bitfields in the + POWERON_DELAY register + items: + - enum: [0, 1, 2, 4] + - enum: [0, 1, 2, 4] + - enum: [0, 1, 2, 4] + - enum: [0, 1, 2, 4] + + regulators: + type: object + additionalProperties: false + patternProperties: + "^(vcom|vposneg|v3p3)$": + unevaluatedProperties: false + type: object + $ref: /schemas/regulator/regulator.yaml + +required: + - compatible + - reg + - pg-gpios + - enable-gpios + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + pmic@18 { + compatible =3D "fitipower,fp9931"; + reg =3D <0x18>; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&pinctrl_fp9931_gpio>; + vin-supply =3D <&epd_pmic_supply>; + pg-gpios =3D <&gpio2 7 GPIO_ACTIVE_HIGH>; + en-ts-gpios =3D <&gpio2 9 GPIO_ACTIVE_HIGH>; + enable-gpios =3D <&gpio2 8 GPIO_ACTIVE_HIGH>; + fitipower,tdly-ms =3D <2 2 4 4>; + + regulators { + vcom { + regulator-name =3D "vcom"; + regulator-min-microvolt =3D <2352840>; + regulator-max-microvolt =3D <2352840>; + }; + + vposneg { + regulator-name =3D "vposneg"; + regulator-min-microvolt =3D <15060000>; + regulator-max-microvolt =3D <15060000>; + }; + + v3p3 { + regulator-name =3D "v3p3"; + }; + }; + }; + }; --=20 2.47.3 From nobody Sun Feb 8 11:21:47 2026 Received: from mail.andi.de1.cc (mail.andi.de1.cc [178.238.236.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 13ACF288C96; Fri, 14 Nov 2025 04:26:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.238.236.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763094368; cv=none; b=U40/5c+4d5hPEPqV5RTeCpVYU9LLaYDNH7OJiMwoMPfhlMSaleWL21GULu8a/VHqS1ti9B/uDCbmFQQ421IfCcA+IzkTKsKS18QfnjqdpGDZwugIMEVXnAXtCn8wt1wVtWwrkUAvNvzah/CFx6EblxV22BN+EQAFwE966rFjumA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763094368; c=relaxed/simple; bh=XASNlsUAFwFUx48/C8pu96IaEIun5G3EzBwKqqoUl3Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hvHnMRh4/e33E4hezYoOAmO1msvXurdy3nKQc27ro+GFMvK+uY8VHADK35I/PWN5ngpBzkpSoK6FGW7y6R8NPQGytjba1eT5vChqFxrlxNDcTtkrfFau97dJkV06wWmWnB87X9+MJqBRBrjhw5RfZoMrPlV2elcbHq3E8YeeWAA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=kemnade.info; spf=pass smtp.mailfrom=kemnade.info; dkim=pass (2048-bit key) header.d=kemnade.info header.i=@kemnade.info header.b=FLPctx9O; arc=none smtp.client-ip=178.238.236.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=kemnade.info Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=kemnade.info Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kemnade.info header.i=@kemnade.info header.b="FLPctx9O" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=kemnade.info; s=20220719; h=Cc:In-Reply-To:References:From:Sender:Reply-To: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID; bh=cv715zj/ybd/4A90QXPKJM+Mx48mcc2pZQQP+skiNXY=; b=FLPctx9OWasOJfE4A5c6SeP4Do MJHtzVCUOKUUZcL4DStRAvdBNqkzhFAvwnTLLNJl//rJS1j/Sozam2lT3b/Rkq97hn/mK5dDK19F5 kAD5EccShFPCojd9gLNkOTPrWxlODSJ/a9L+D6+YrfExkrxnJ7yhxcnMMCTmwkqSe/GxuIMUOu7gB 926Q0iEX9bK2iVQNOSUtjJ0cSNw7F7GYRyKLis5+LmB88sGeNJxZxrYnm2kVBZeWSXOUOtNFblOLh ywkVezBXeRkEb4xzGbd1f9w1XbXwgcQf+ZthuOKJWm8cmd9+kY9IayXZNdqlrO3zUuDYsq2u+GmAT NKQ6saYw==; From: Andreas Kemnade Date: Fri, 14 Nov 2025 00:06:43 +0100 Subject: [PATCH v2 3/3] regulator: Add FP9931/JD9930 driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251114-fp9931-submit-v2-3-cd6998932c4c@kemnade.info> References: <20251114-fp9931-submit-v2-0-cd6998932c4c@kemnade.info> In-Reply-To: <20251114-fp9931-submit-v2-0-cd6998932c4c@kemnade.info> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Guenter Roeck Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, Andreas Kemnade X-Mailer: b4 0.15-dev-a6db3 X-Developer-Signature: v=1; a=openpgp-sha256; l=17016; i=andreas@kemnade.info; h=from:subject:message-id; bh=XASNlsUAFwFUx48/C8pu96IaEIun5G3EzBwKqqoUl3Y=; b=owGbwMvMwCUm/rzkS6lq2x3G02pJDJliKWcvGbxaP7PujbLdw6vtpwO2pIZ/d9R1XMNi0Kp5J 31NSGN2RykLgxgXg6yYIssvawW3TyrPcoOnRtjDzGFlAhnCwMUpABPxZGNkmPhhTY14LFvpcfY3 yyIKT3d0OooaRV0Keptz5Uf5qw21uxgZjv7tOZy99WSx6zqLVrdnB6Tb7rCXHDmzv6dtkv5uC98 gPgA= X-Developer-Key: i=andreas@kemnade.info; a=openpgp; fpr=EEC0DB858E66C0DA70620AC07DBD6AC74DE29324 Add a driver for the FP9931/JD9930 regulator. Implement handling of the PG (power good), TS_EN (temperature sensor enable), and EN (enable regulators) pins. Implement the pair of symmetric LDOs as a single regulator because they share a single voltage set register. For simplicity, just add the temperature sensor (depending on external NTC) directly. Limitations: - As these regulators are controlled together with the VCOM regulator via the EN pin, some kind of management must be in place. As the enable op is not called when the regulator is already enabled, simple refcounting seems not to work to avoid clearing EN when one regulator is still enabled. As these regulators are typically used together, this limitation should not hurt hard, just provide the is_enabled op. - As the VCOM step is quite odd (5V/255 steps), rounding is needed. Due to some limitations in the regulator core, the max/min voltages in the devicetree must match the idea of the driver how to round things exactly. - Night mode is not implemented, so only the FP9931 compatible is needed in the driver, there is no REGULATOR_MODE_NIGHT and no clear definition in the datasheet what it does, also the XON pin which seems to be an input related to that night mode is not used. Signed-off-by: Andreas Kemnade --- drivers/regulator/Kconfig | 10 + drivers/regulator/Makefile | 1 + drivers/regulator/fp9931.c | 564 +++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 575 insertions(+) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index d84f3d054c59..c817a4cc00c8 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -500,6 +500,16 @@ config REGULATOR_ISL6271A help This driver supports ISL6271A voltage regulator chip. =20 +config REGULATOR_FP9931 + tristate "FitiPower FP9931/JD9930 EPD regulator" + depends on I2C + select REGMAP_I2C + help + This driver supports the FP9931/JD9930 voltage regulator chip + which is used to provide power to Electronic Paper Displays + so it is found in E-Book readers. + If HWWON is enabled, it also provides temperature measurement. + config REGULATOR_LM363X tristate "TI LM363X voltage regulators" depends on MFD_TI_LMU diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b3101376029d..98a02c854044 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_REGULATOR_HI6421V600) +=3D hi6421v600-regula= tor.o obj-$(CONFIG_REGULATOR_HI655X) +=3D hi655x-regulator.o obj-$(CONFIG_REGULATOR_ISL6271A) +=3D isl6271a-regulator.o obj-$(CONFIG_REGULATOR_ISL9305) +=3D isl9305.o +obj-$(CONFIG_REGULATOR_FP9931) +=3D fp9931.o obj-$(CONFIG_REGULATOR_LM363X) +=3D lm363x-regulator.o obj-$(CONFIG_REGULATOR_LOCHNAGAR) +=3D lochnagar-regulator.o obj-$(CONFIG_REGULATOR_LP3971) +=3D lp3971.o diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c new file mode 100644 index 000000000000..7e3df5f2ccb9 --- /dev/null +++ b/drivers/regulator/fp9931.c @@ -0,0 +1,564 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2025 Andreas Kemnade + +/* Datasheet: https://www.fitipower.com/dl/file/flXa6hIchVeu0W3K */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FP9931_REG_TMST_VALUE 0 +#define FP9931_REG_VCOM_SETTING 1 +#define FP9931_REG_VPOSNEG_SETTING 2 +#define FP9931_REG_PWRON_DELAY 3 +#define FP9931_REG_CONTROL_REG1 11 + +#define PGOOD_TIMEOUT_MSECS 200 + +struct fp9931_data { + struct device *dev; + struct regmap *regmap; + struct regulator *vin_reg; + struct gpio_desc *pgood_gpio; + struct gpio_desc *en_gpio; + struct gpio_desc *en_ts_gpio; + struct completion pgood_completion; + int pgood_irq; +}; + +static const unsigned int VPOSNEG_table[] =3D { + 7040000, + 7040000, + 7040000, + 7040000, + 7040000, + 7040000, + 7260000, + 7490000, + 7710000, + 7930000, + 8150000, + 8380000, + 8600000, + 8820000, + 9040000, + 9270000, + 9490000, + 9710000, + 9940000, + 10160000, + 10380000, + 10600000, + 10830000, + 11050000, + 11270000, + 11490000, + 11720000, + 11940000, + 12160000, + 12380000, + 12610000, + 12830000, + 13050000, + 13280000, + 13500000, + 13720000, + 13940000, + 14170000, + 14390000, + 14610000, + 14830000, + 15060000, +}; + +static const struct hwmon_channel_info *fp9931_info[] =3D { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), + NULL +}; + +static int setup_timings(struct fp9931_data *data) +{ + u32 tdly[4]; + u8 tdlys =3D 0; + int i; + int ret; + + ret =3D device_property_count_u32(data->dev, "fitipower,tdly-ms"); + if (ret =3D=3D -EINVAL) /* property is optional */ + return 0; + + if (ret < 0) + return ret; + + if (ret !=3D ARRAY_SIZE(tdly)) { + dev_err(data->dev, "invalid delay specification"); + return -EINVAL; + } + + ret =3D device_property_read_u32_array(data->dev, "fitipower,tdly-ms", + tdly, ARRAY_SIZE(tdly)); + if (ret) + return ret; + + for (i =3D ARRAY_SIZE(tdly) - 1; i >=3D 0; i--) { + if (tdly[i] > 4 || tdly[i] =3D=3D 3) + return -EINVAL; + + if (tdly[i] =3D=3D 4) /* convert from ms */ + tdly[i] =3D 3; + + tdlys <<=3D 2; + tdlys |=3D tdly[i]; + } + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + + ret =3D regmap_write(data->regmap, FP9931_REG_PWRON_DELAY, tdlys); + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + +static int fp9931_hwmon_read(struct device *dev, enum hwmon_sensor_types t= ype, + u32 attr, int channel, long *temp) +{ + struct fp9931_data *data =3D dev_get_drvdata(dev); + unsigned int val; + s8 signed_val; + int ret; + + if (attr !=3D hwmon_temp_input) + return -EOPNOTSUPP; + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + + ret =3D regmap_read(data->regmap, FP9931_REG_TMST_VALUE, &val); + if (ret) + return ret; + + pm_runtime_put_autosuspend(data->dev); + signed_val =3D (s8)val; + + *temp =3D signed_val; + *temp =3D *temp * 1000; + + return 0; +} + +static umode_t fp9931_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type !=3D hwmon_temp) + return 0; + + if (attr !=3D hwmon_temp_input) + return 0; + + return 0444; +} + +static const struct hwmon_ops fp9931_hwmon_ops =3D { + .is_visible =3D fp9931_hwmon_is_visible, + .read =3D fp9931_hwmon_read, +}; + +static const struct hwmon_chip_info fp9931_chip_info =3D { + .ops =3D &fp9931_hwmon_ops, + .info =3D fp9931_info, +}; + +static int fp9931_runtime_suspend(struct device *dev) +{ + int ret =3D 0; + struct fp9931_data *data =3D dev_get_drvdata(dev); + + if (data->en_ts_gpio) + gpiod_set_value_cansleep(data->en_ts_gpio, 0); + + if (data->vin_reg) { + ret =3D regulator_disable(data->vin_reg); + regcache_mark_dirty(data->regmap); + } + + return ret; +} + +static int fp9931_runtime_resume(struct device *dev) +{ + int ret =3D 0; + struct fp9931_data *data =3D dev_get_drvdata(dev); + + if (data->vin_reg) + ret =3D regulator_enable(data->vin_reg); + + if (ret) + return ret; + + if (data->en_ts_gpio) { + gpiod_set_value_cansleep(data->en_ts_gpio, 1); + /* wait for one ADC conversion to have sane temperature */ + usleep_range(10000, 15000); + } + + ret =3D regcache_sync(data->regmap); + + return ret; +} + +static bool fp9931_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg =3D=3D FP9931_REG_TMST_VALUE; +} + +static const struct reg_default fp9931_reg_default =3D { + .reg =3D FP9931_REG_VCOM_SETTING, + .def =3D 0x80, +}; + +static const struct regmap_config regmap_config =3D { + .reg_bits =3D 8, + .val_bits =3D 8, + .max_register =3D 12, + .cache_type =3D REGCACHE_FLAT, + .volatile_reg =3D fp9931_volatile_reg, + .reg_defaults =3D &fp9931_reg_default, + .num_reg_defaults =3D 1, +}; + +static void disable_nopm(void *d) +{ + struct fp9931_data *data =3D d; + + fp9931_runtime_suspend(data->dev); +} + +static int fp9931_v3p3_enable(struct regulator_dev *rdev) +{ + struct fp9931_data *data =3D rdev_get_drvdata(rdev); + int ret; + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + + ret =3D regulator_enable_regmap(rdev); + if (ret < 0) + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + +static int fp9931_v3p3_disable(struct regulator_dev *rdev) +{ + struct fp9931_data *data =3D rdev_get_drvdata(rdev); + int ret; + + ret =3D regulator_disable_regmap(rdev); + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + +static int fp9931_v3p3_is_enabled(struct regulator_dev *rdev) +{ + struct fp9931_data *data =3D rdev_get_drvdata(rdev); + int ret; + + if (pm_runtime_status_suspended(data->dev)) + return 0; + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return 0; + + ret =3D regulator_is_enabled_regmap(rdev); + + pm_runtime_put_autosuspend(data->dev); + return ret; +} + +static const struct regulator_ops fp9931_v3p3ops =3D { + .list_voltage =3D regulator_list_voltage_linear, + .enable =3D fp9931_v3p3_enable, + .disable =3D fp9931_v3p3_disable, + .is_enabled =3D fp9931_v3p3_is_enabled, +}; + +static int fp9931_check_powergood(struct regulator_dev *rdev) +{ + struct fp9931_data *data =3D rdev_get_drvdata(rdev); + + if (pm_runtime_status_suspended(data->dev)) + return 0; + + return gpiod_get_value_cansleep(data->pgood_gpio); +} + +static int fp9931_get_voltage_sel(struct regulator_dev *rdev) +{ + struct fp9931_data *data =3D rdev_get_drvdata(rdev); + int ret; + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + + ret =3D regulator_get_voltage_sel_regmap(rdev); + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + +static int fp9931_set_voltage_sel(struct regulator_dev *rdev, unsigned int= selector) +{ + struct fp9931_data *data =3D rdev_get_drvdata(rdev); + int ret; + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + + ret =3D regulator_set_voltage_sel_regmap(rdev, selector); + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + +static irqreturn_t pgood_handler(int irq, void *dev_id) +{ + struct fp9931_data *data =3D dev_id; + + complete(&data->pgood_completion); + + return IRQ_HANDLED; +} + +static int fp9931_set_enable(struct regulator_dev *rdev) +{ + struct fp9931_data *data =3D rdev_get_drvdata(rdev); + int ret; + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + + reinit_completion(&data->pgood_completion); + gpiod_set_value_cansleep(data->en_gpio, 1); + dev_dbg(data->dev, "turning on..."); + wait_for_completion_timeout(&data->pgood_completion, + msecs_to_jiffies(PGOOD_TIMEOUT_MSECS)); + dev_dbg(data->dev, "turned on"); + if (gpiod_get_value_cansleep(data->pgood_gpio) !=3D 1) { + pm_runtime_put_autosuspend(data->dev); + return -ETIMEDOUT; + } + + return 0; +} + +static int fp9931_clear_enable(struct regulator_dev *rdev) +{ + struct fp9931_data *data =3D rdev_get_drvdata(rdev); + + gpiod_set_value_cansleep(data->en_gpio, 0); + pm_runtime_put_autosuspend(data->dev); + return 0; +} + +static const struct regulator_ops fp9931_vcom_ops =3D { + .list_voltage =3D regulator_list_voltage_linear, + .map_voltage =3D regulator_map_voltage_linear, + .enable =3D fp9931_set_enable, + .disable =3D fp9931_clear_enable, + .is_enabled =3D fp9931_check_powergood, + .set_voltage_sel =3D fp9931_set_voltage_sel, + .get_voltage_sel =3D fp9931_get_voltage_sel, +}; + +static const struct regulator_ops fp9931_vposneg_ops =3D { + .list_voltage =3D regulator_list_voltage_table, + .map_voltage =3D regulator_map_voltage_ascend, + /* gets enabled by enabling vcom, too */ + .is_enabled =3D fp9931_check_powergood, + .set_voltage_sel =3D fp9931_set_voltage_sel, + .get_voltage_sel =3D fp9931_get_voltage_sel, +}; + +static const struct regulator_desc regulators[] =3D { + { + .name =3D "v3p3", + .of_match =3D of_match_ptr("v3p3"), + .id =3D 0, + .ops =3D &fp9931_v3p3ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, + .enable_reg =3D FP9931_REG_CONTROL_REG1, + .enable_mask =3D BIT(1), + .n_voltages =3D 1, + .min_uV =3D 3300000 + }, + { + .name =3D "vposneg", + .of_match =3D of_match_ptr("vposneg"), + .id =3D 1, + .ops =3D &fp9931_vposneg_ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, + .n_voltages =3D ARRAY_SIZE(VPOSNEG_table), + .vsel_reg =3D FP9931_REG_VPOSNEG_SETTING, + .vsel_mask =3D 0x3F, + .volt_table =3D VPOSNEG_table, + }, + { + .name =3D "vcom", + .of_match =3D of_match_ptr("vcom"), + .id =3D 2, + .ops =3D &fp9931_vcom_ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, + .n_voltages =3D 255, + .min_uV =3D 0, + .uV_step =3D 5000000 / 255, + .vsel_reg =3D FP9931_REG_VCOM_SETTING, + .vsel_mask =3D 0xFF + }, +}; + +static int fp9931_probe(struct i2c_client *client) +{ + struct fp9931_data *data; + struct regulator_config config =3D { }; + struct regulator_dev *rdev; + int ret =3D 0; + int i; + + data =3D devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + data->regmap =3D devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(&client->dev, PTR_ERR(data->regmap), + "failed to allocate regmap!\n"); + + data->vin_reg =3D devm_regulator_get_optional(&client->dev, "vin"); + if (IS_ERR(data->vin_reg)) + return dev_err_probe(&client->dev, PTR_ERR(data->vin_reg), + "failid to get vin regulator\n"); + + data->pgood_gpio =3D devm_gpiod_get(&client->dev, "pg", GPIOD_IN); + if (IS_ERR(data->pgood_gpio)) + return dev_err_probe(&client->dev, + PTR_ERR(data->pgood_gpio), + "failed to get power good gpio\n"); + + data->pgood_irq =3D gpiod_to_irq(data->pgood_gpio); + if (data->pgood_irq < 0) + return data->pgood_irq; + + data->en_gpio =3D devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(data->en_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(data->en_gpio), + "failed to get en gpio\n"); + + data->en_ts_gpio =3D devm_gpiod_get_optional(&client->dev, "en-ts", GPIOD= _OUT_LOW); + if (IS_ERR(data->en_ts_gpio)) + return dev_err_probe(&client->dev, + PTR_ERR(data->en_ts_gpio), + "failed to get en gpio\n"); + + data->dev =3D &client->dev; + i2c_set_clientdata(client, data); + + init_completion(&data->pgood_completion); + + ret =3D devm_request_threaded_irq(&client->dev, data->pgood_irq, NULL, + pgood_handler, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "PGOOD", data); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to request irq\n"); + + if (IS_ENABLED(CONFIG_PM)) { + devm_pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, 4000); + pm_runtime_use_autosuspend(&client->dev); + } else { + ret =3D fp9931_runtime_resume(&client->dev); + if (ret < 0) + return ret; + + devm_add_action_or_reset(&client->dev, disable_nopm, data); + } + + ret =3D setup_timings(data); + if (ret) + return dev_err_probe(&client->dev, ret, "failed to setup timings\n"); + + config.driver_data =3D data; + config.dev =3D &client->dev; + config.regmap =3D data->regmap; + + for (i =3D 0; i < ARRAY_SIZE(regulators); i++) { + rdev =3D devm_regulator_register(&client->dev, ®ulators[i], + &config); + if (IS_ERR(rdev)) + return dev_err_probe(&client->dev, PTR_ERR(rdev), + "failed to register %s regulator\n", + regulators[i].name); + } + + if (IS_REACHABLE(CONFIG_HWMON)) { + struct device *hwmon_dev; + + hwmon_dev =3D devm_hwmon_device_register_with_info(&client->dev, "fp9931= ", data, + &fp9931_chip_info, NULL); + if (IS_ERR(hwmon_dev)) + dev_err(&client->dev, "failed to register hwmon\n"); + } + + return 0; +} + +static const struct dev_pm_ops fp9931_pm_ops =3D { + SET_RUNTIME_PM_OPS(fp9931_runtime_suspend, fp9931_runtime_resume, NULL) +}; + +static const struct of_device_id fp9931_dt_ids[] =3D { + { + .compatible =3D "fitipower,fp9931", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, fp9931_dt_ids); + +static struct i2c_driver fp9931_i2c_driver =3D { + .driver =3D { + .name =3D "fp9931", + .of_match_table =3D fp9931_dt_ids, + .pm =3D &fp9931_pm_ops, + }, + .probe =3D fp9931_probe, +}; + +module_i2c_driver(fp9931_i2c_driver); + +/* Module information */ +MODULE_DESCRIPTION("FP9931 regulator driver"); +MODULE_LICENSE("GPL"); + --=20 2.47.3