From nobody Fri Dec 19 20:12:16 2025 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 E0E86309EF1; Fri, 7 Nov 2025 20:07: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=1762546027; cv=none; b=UpvP91PlOrxBbXMIicI3F1rhvxvQ4u41UAypu8RkyQAT94DW40N2b7/+pkRl1c1jASGoxIm8GeBdVR+jNqOC1WHLfnLSfJ4nMpPNMtoCAQk8L9MjXl3NV0UtJQQLpDKXUmADvko8etmhqKkBEZsFpnbIzk0HQNBxlNg6FgtEryY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762546027; c=relaxed/simple; bh=xK1MSW7bqEuQTy6tStX5HrpAotQbanzu2XrfeYjg9kg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UpmFvrzdimYw3Jv8rl2PEGnVsRybw52n61Lic0S9vLQE+O/AtwvacyATX8ui5U5KAYWwt7jfAdvktg/W1x01h/LcxsZgHzTk1V2Ij+fkVaIRZk5ZWJZEpLhzAnY85Y8yYpUt3/Ag2VLA0dBkWvOJP5+4Icw6dA+LrRy00YqJPKo= 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=Z3BGhPy2; 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="Z3BGhPy2" 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=Apyt41+4mOwFak7jR/iDHVXoTub+1mEmP42h2q4HU1A=; b=Z3BGhPy2CHpqj8mm9ED1t3DO8B OQm4OOn5CX8gmBsYNnUdfpsXx3TrSaSyYy+L1KsSms0B5cX+81tICQNXdSCMCECIWBMkrl+3dqFS4 lpbRz+MhtAwJrECqqMZxaOsrkjYf3jPv9h8R+Is8cvyQ4oL8sonmjG2U2fpr2jZ7QNcObIialnFQ3 RHRlv51DRHJHsLfpxYR5Xa+RH4vsoJcpTkqmaKEdo6fwvYCURlpeLAiJWDj+9uwOBG1ddFHWDiXcS x+rRySBojKNfUxd/BMMwydudNKjqAAYp/5q5gsdjx8DL7sVzITt5xNHii5EJGPegbXpvNk5/leOHa SiqChChA==; From: Andreas Kemnade Date: Fri, 07 Nov 2025 21:06:44 +0100 Subject: [PATCH 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: <20251107-fp9931-submit-v1-1-aa7b79d9abb6@kemnade.info> References: <20251107-fp9931-submit-v1-0-aa7b79d9abb6@kemnade.info> In-Reply-To: <20251107-fp9931-submit-v1-0-aa7b79d9abb6@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=813; i=andreas@kemnade.info; h=from:subject:message-id; bh=xK1MSW7bqEuQTy6tStX5HrpAotQbanzu2XrfeYjg9kg=; b=owGbwMvMwCUm/rzkS6lq2x3G02pJDJl8gbFpb27udjm39roES2O2TmD0nHmOW5Qe1ezfEHpsw l1RpSObOkpZGMS4GGTFFFl+WSu4fVJ5lhs8NcIeZg4rE8gQBi5OAZjIGkuGv/LHZfOuXm094Lnl 3o78VRLNJ4NUvkznYvyyef2qThXxkOeMDE/CrL5rRGy+Ffz8aalU101rsxcn9cRvx8cs8rB/wr6 Xjx0A 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 --- 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..506b146e9bd0 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 + "^fiti,.*": + description: Fitipower Integrated Technology Inc. "^flipkart,.*": description: Flipkart Inc. "^focaltech,.*": --=20 2.47.3 From nobody Fri Dec 19 20:12:16 2025 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 7A63C302CB2; Fri, 7 Nov 2025 20:07:03 +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=1762546025; cv=none; b=ALZE2r5v2hbNeHuHYytlCOEh+G32FnT8n9OKFcmnYuSf1ras0GqCqy6WtBXageTvfmcNVzI0MPIzo1XRSI2Ydo6Y4ZslxLPCDCX41UHG3J49vbHa9QzCBTtPcLiSi9jIV+uXYT0D9nBgiw1MNfRNvEZYphHj54Z41dfdpodNibI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762546025; c=relaxed/simple; bh=AlyAos5lAGXVNjR2bMAh2pv4DcOio8Uo9RCDmeLoeq4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XodBWxm01aaaTZvn6s/8yJ0BJd9tWp7/GDuXu1jNaZqGQZs7rlz2OQyglt2N/XuGKB2Hm87lfAB/IS6cLOc3zGoxI8PY51ulwP5VDJxlb11CCIg5yZ2jby9zsYDPmQjPiQX0+vV1f9qx34zDTirdSL0hQR2zMc49N/xC5k1aDzM= 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=NyIEhXoc; 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="NyIEhXoc" 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=VxdgB3HocQdpr4EL2JWSmprEcBe6YuGBAKZnIFLa3JY=; b=NyIEhXocz2ovspKIq5RVBW3KBy dQF0uDeOqfv0wn+sqbLmAeSi26535o5Rszo8hcFezSaEgLhW4cWxAEzkTYqBRxsj1XJlLjN/5p9qA tYaIk4SVIRaq4rFQp0C2rrAnyFjdIxv1ycd6TK/MaFpGGTn2v3PTlz3g8+oTp/LAJFExwbHC7q73N oZHkOZkar9GIF11QV2mrqynY5gfs2sRpp6cqofRVk3bizkL9HEs2P9ZcsJm7oy+6jHm1vPNz1hMiN SMBv/cZ8H5TjHPv/T9frhKz8dGfb/Si7u1apR8MQZGepfPSmU0hXOdb7GVicp6WRhiyatF13L5LSW 7NRC/OkQ==; From: Andreas Kemnade Date: Fri, 07 Nov 2025 21:06:45 +0100 Subject: [PATCH 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: <20251107-fp9931-submit-v1-2-aa7b79d9abb6@kemnade.info> References: <20251107-fp9931-submit-v1-0-aa7b79d9abb6@kemnade.info> In-Reply-To: <20251107-fp9931-submit-v1-0-aa7b79d9abb6@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=4044; i=andreas@kemnade.info; h=from:subject:message-id; bh=AlyAos5lAGXVNjR2bMAh2pv4DcOio8Uo9RCDmeLoeq4=; b=owGbwMvMwCUm/rzkS6lq2x3G02pJDJl8gbHrbIRk1O43bDtQ47jHWiiK1fz4visv1aY1NOptW DCpwupIRykLgxgXg6yYIssvawW3TyrPcoOnRtjDzGFlAhnCwMUpABMp4WP4Z/nml3nZbu3Nnz6+ erb2Ya7ZrO6HGdercrxnv0qOUV3jJczwv3rWQVnzJsWW0KKkf80huyols/a5Vj+TShIy+3TLr5m DBwA= 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 --- .../devicetree/bindings/regulator/fiti,fp9931.yaml | 133 +++++++++++++++++= ++++ 1 file changed, 133 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/fiti,fp9931.yaml b= /Documentation/devicetree/bindings/regulator/fiti,fp9931.yaml new file mode 100644 index 000000000000..ce44040a3c02 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/fiti,fp9931.yaml @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/fiti,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: fiti,fp9931 + + - items: + - const: fiti,jd9930 + - const: fiti,fp9931 + + reg: + maxItems: 1 + + '#thermal-sensor-cells': + const: 0 + + enable-gpios: + maxItems: 1 + + pg-gpios: + maxItems: 1 + + ts-en-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". + + fiti,tdly: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Power up soft start delay settings tDLY1-4 bitfields in the + POWERON_DELAY register + + minItems: 4 + maxItems: 4 + + VCOM: + type: object + $ref: /schemas/regulator/regulator.yaml# + unevaluatedProperties: false + description: + The regulator for the compenstation voltage. + properties: + regulator-name: + const: VCOM + + VPOSNEG: + type: object + $ref: /schemas/regulator/regulator.yaml# + unevaluatedProperties: false + description: + The pair of symmetric LDOs + properties: + regulator-name: + const: VPOSNEG + + V3P3: + type: object + $ref: /schemas/regulator/regulator.yaml# + unevaluatedProperties: false + description: + The pair of symmetric LDOs + properties: + regulator-name: + const: V3P3 + +required: + - compatible + - reg + - '#thermal-sensor-cells' + - pg-gpios + - enable-gpios + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + fp9931: pmic@18 { + compatible =3D "fiti,fp9931"; + reg =3D <0x18>; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&pinctrl_fp9931_gpio>; + #thermal-sensor-cells =3D <0>; + vin-supply =3D <&epd_pmic_supply>; + pg-gpios =3D <&gpio2 7 GPIO_ACTIVE_HIGH>; + ts-en-gpios =3D <&gpio2 9 GPIO_ACTIVE_HIGH>; + enable-gpios =3D <&gpio2 8 GPIO_ACTIVE_HIGH>; + fiti,tdly =3D <2 2 3 3>; + + vcom_reg: VCOM { + regulator-name =3D "VCOM"; + regulator-min-microvolt =3D <2352840>; + regulator-max-microvolt =3D <2352840>; + }; + + vposneg_reg: VPOSNEG { + regulator-name =3D "VPOSNEG"; + regulator-min-microvolt =3D <15060000>; + regulator-max-microvolt =3D <15060000>; + }; + + v3p3_reg: V3P3 { + regulator-name =3D "V3P3"; + }; + }; + }; --=20 2.47.3 From nobody Fri Dec 19 20:12:16 2025 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 BA09A309DDB; Fri, 7 Nov 2025 20:07: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=1762546028; cv=none; b=WYJ5MFMf1llOQsKkvegXm5yw1fMT4j3bF2GTLdXMHTnVKnqsjgH+YBRjAkeTKD60MJY21iPTDPpzB9hjgRYF7k3zlwLCIIqhackPSjYWDhjohOhG4J8t+FtSbg6YzITPUemRt7mfNsrvtIVyRfy9yFvKV6uhTudlbywboqsewt0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762546028; c=relaxed/simple; bh=t81QjKKQ7s4IGEzpGGmmyx85FztlfnG3X0NKrW19n9k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rYdw+/PY/pi6IeJTisi971uHsKRh//evVd+f1Y9RfsoCrbNxSvZGLM590iB99U88Sv3TQlVx3B0vgNAaT+egrwBO6aoBUbijA4rYY5TieZVr09AEZGoc4RaDK+Oe6XLdA625ZlczuI2PZ79Id9eqn2gXsPW7ym4PNTQ4xYR9Smw= 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=mNNlMGyR; 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="mNNlMGyR" 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=VwgObd5S5HmYEkuJUCRFlgZQikxIUpHLfGALkiwov+A=; b=mNNlMGyR91WI8Bz5+SqGDSbNSk VvhRAxzmE4uaFjNunrFqVMvUHwGLcCJV1dppd3P2SR1Cluv0kQsH60NNreVk4NdAIS7xa0+q91U5c 3seWjhUnQdgf14SRkh+5odnondNeGsxbJFAQTAt6zXSKtvdTKA8Er7BfMEDWVoUj1mo8xm0Ydac+T 5F+ool83xp+NWVEAxRvnuAx92SyV7Rqy4KOZWnK/1DQrfAhy8TZzeD9YYg1psa4VcJMQYWFK/zKI2 gTJYM0WGKyDjdqNXu+o5LYjGQm+IpyJlAS2d2//OVFJJBxaXlsxqILjO3kFCXaznGbOAzeplNbkPD 8HQbuxKQ==; From: Andreas Kemnade Date: Fri, 07 Nov 2025 21:06:46 +0100 Subject: [PATCH 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: <20251107-fp9931-submit-v1-3-aa7b79d9abb6@kemnade.info> References: <20251107-fp9931-submit-v1-0-aa7b79d9abb6@kemnade.info> In-Reply-To: <20251107-fp9931-submit-v1-0-aa7b79d9abb6@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=17079; i=andreas@kemnade.info; h=from:subject:message-id; bh=t81QjKKQ7s4IGEzpGGmmyx85FztlfnG3X0NKrW19n9k=; b=owGbwMvMwCUm/rzkS6lq2x3G02pJDJl8gbHW/1a0MkZK11UmT9uyi2VSvffj5zsXbl739yO3O luHbV56RykLgxgXg6yYIssvawW3TyrPcoOnRtjDzGFlAhnCwMUpABMxN2NkmDzJlFv5b5eg/uED sqck+8/8P7BgWryQwpaTwQl71yRu3svw39dAcVHzfYHChOTkaQ/zz+j8zan6pT3jfl91sz/r7cn r2QE= 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 | 567 +++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 578 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..3b6341d4944a --- /dev/null +++ b/drivers/regulator/fp9931.c @@ -0,0 +1,567 @@ +// 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 *ts_en_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, "fiti,tdly"); + 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, "fiti,tdly", tdly, ARRA= Y_SIZE(tdly)); + if (ret) + return ret; + + for (i =3D ARRAY_SIZE(tdly) - 1; i >=3D 0; i--) { + if (tdly[i] > 3) + return -EINVAL; + + 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->ts_en_gpio) + gpiod_set_value_cansleep(data->ts_en_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->ts_en_gpio) { + gpiod_set_value_cansleep(data->ts_en_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), + .of_match =3D of_match_ptr("v3p3"), + .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(struct fp9931_data), GFP_KERNE= L); + 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->ts_en_gpio =3D devm_gpiod_get_optional(&client->dev, "ts-en", GPIOD= _OUT_LOW); + if (IS_ERR(data->ts_en_gpio)) + return dev_err_probe(&client->dev, + PTR_ERR(data->ts_en_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 "fiti,fp9931", + }, { + .compatible =3D "fiti,fp9931", /* no night mode */ + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, fp9931_dt_ids); + +static struct i2c_driver fp9931_i2c_driver =3D { + .driver =3D { + .name =3D "fp9931", + .owner =3D THIS_MODULE, + .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