* Re: [PATCH v1 07/14] dt-bindings: display: mediatek,ufoe: Add mediatek,gce-client-reg property
From: Krzysztof Kozlowski @ 2025-08-21 6:50 UTC (permalink / raw)
To: Ariel D'Alessandro
Cc: airlied, amergnat, andrew+netdev, andrew-ct.chen,
angelogioacchino.delregno, broonie, chunkuang.hu, ck.hu, conor+dt,
davem, dmitry.torokhov, edumazet, flora.fu, houlong.wei, jeesw,
jmassot, kernel, krzk+dt, kuba, kyrie.wu, lgirdwood,
linus.walleij, louisalexis.eyraud, maarten.lankhorst,
matthias.bgg, mchehab, minghsiu.tsai, mripard, p.zabel, pabeni,
robh, sean.wang, simona, support.opensource, tiffany.lin,
tzimmermann, yunfei.dong, devicetree, dri-devel, linux-arm-kernel,
linux-clk, linux-gpio, linux-input, linux-kernel, linux-media,
linux-mediatek, linux-sound, netdev
In-Reply-To: <20250820171302.324142-8-ariel.dalessandro@collabora.com>
On Wed, Aug 20, 2025 at 02:12:55PM -0300, Ariel D'Alessandro wrote:
> Current, the DT bindings for Mediatek UFOe (Unified Frame Optimization
> engine) is missing the mediatek,gce-client-reg property. Add it and
Why is it missing? If the binding is complete, it cannot be missing...
> update the example as well.
>
> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
> ---
> .../bindings/display/mediatek/mediatek,ufoe.yaml | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ufoe.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ufoe.yaml
> index 61a5e22effbf2..ecb4c0359fec3 100644
> --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,ufoe.yaml
> +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ufoe.yaml
> @@ -64,6 +64,14 @@ properties:
> - port@0
> - port@1
>
> + mediatek,gce-client-reg:
> + description: The register of client driver can be configured by gce with
> + 4 arguments defined in this property, such as phandle of gce, subsys id,
> + register offset and size. Each GCE subsys id is mapping to a client
Don't explain what DT syntax is. We all know, so that's completely
redundant description. Explain the purpose. Explain Arguments with sechema - items.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v1 02/14] media: dt-bindings: Convert MediaTek mt8173-vpu bindings to YAML
From: Krzysztof Kozlowski @ 2025-08-21 6:47 UTC (permalink / raw)
To: Ariel D'Alessandro
Cc: airlied, amergnat, andrew+netdev, andrew-ct.chen,
angelogioacchino.delregno, broonie, chunkuang.hu, ck.hu, conor+dt,
davem, dmitry.torokhov, edumazet, flora.fu, houlong.wei, jeesw,
jmassot, kernel, krzk+dt, kuba, kyrie.wu, lgirdwood,
linus.walleij, louisalexis.eyraud, maarten.lankhorst,
matthias.bgg, mchehab, minghsiu.tsai, mripard, p.zabel, pabeni,
robh, sean.wang, simona, support.opensource, tiffany.lin,
tzimmermann, yunfei.dong, devicetree, dri-devel, linux-arm-kernel,
linux-clk, linux-gpio, linux-input, linux-kernel, linux-media,
linux-mediatek, linux-sound, netdev
In-Reply-To: <20250820171302.324142-3-ariel.dalessandro@collabora.com>
On Wed, Aug 20, 2025 at 02:12:50PM -0300, Ariel D'Alessandro wrote:
> Convert the existing text-based DT bindings for Mediatek MT8173 Video Processor
> Unit to a YAML schema.
DT schema, not YAML. Don't say YAML at all, neither here nor in subject.
Also looks not wrapped...
>
> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
> ---
> .../bindings/media/mediatek,mt8173-vpu.yaml | 76 +++++++++++++++++++
> .../bindings/media/mediatek-vpu.txt | 31 --------
> 2 files changed, 76 insertions(+), 31 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/media/mediatek,mt8173-vpu.yaml
> delete mode 100644 Documentation/devicetree/bindings/media/mediatek-vpu.txt
>
> diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8173-vpu.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8173-vpu.yaml
> new file mode 100644
> index 0000000000000..44f5d7cc44042
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/mediatek,mt8173-vpu.yaml
> @@ -0,0 +1,76 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/mediatek,mt8173-vpu.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Mediatek MT8173 Video Processor Unit
> +
> +maintainers:
> + - Ariel D'Alessandro <ariel.dalessandro@collabora.com>
> +
> +description:
> + Video Processor Unit is a HW video controller. It controls HW Codec including
> + H.264/VP8/VP9 Decode, H.264/VP8 Encode and Image Processor (scale/rotate/color convert).
Please wrap code according to the preferred limit expressed in Kernel
coding style (checkpatch is not a coding style description, but only a
tool). However don't wrap blindly (see Kernel coding style).
> +
> +properties:
> + compatible:
> + const: mediatek,mt8173-vpu
> +
> + reg:
> + minItems: 2
No, from where do you get such syntax?
> +
> + reg-names:
> + items:
> + - const: tcm
> + - const: cfg_reg
> +
> + interrupts:
> + maxItems: 1
> +
> + clocks:
> + maxItems: 1
> +
> + clock-names:
> + items:
> + - const: main
> +
> + memory-region:
> + description:
> + phandle to a node describing reserved memory used by VPU
> + (see bindings/reserved-memory/reserved-memory.txt)
Drop, redundant description.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v1 01/14] media: dt-bindings: Convert MediaTek mt8173-mdp bindings to YAML
From: Krzysztof Kozlowski @ 2025-08-21 6:46 UTC (permalink / raw)
To: Ariel D'Alessandro
Cc: airlied, amergnat, andrew+netdev, andrew-ct.chen,
angelogioacchino.delregno, broonie, chunkuang.hu, ck.hu, conor+dt,
davem, dmitry.torokhov, edumazet, flora.fu, houlong.wei, jeesw,
jmassot, kernel, krzk+dt, kuba, kyrie.wu, lgirdwood,
linus.walleij, louisalexis.eyraud, maarten.lankhorst,
matthias.bgg, mchehab, minghsiu.tsai, mripard, p.zabel, pabeni,
robh, sean.wang, simona, support.opensource, tiffany.lin,
tzimmermann, yunfei.dong, devicetree, dri-devel, linux-arm-kernel,
linux-clk, linux-gpio, linux-input, linux-kernel, linux-media,
linux-mediatek, linux-sound, netdev
In-Reply-To: <20250820171302.324142-2-ariel.dalessandro@collabora.com>
On Wed, Aug 20, 2025 at 02:12:49PM -0300, Ariel D'Alessandro wrote:
> Convert the existing text-based DT bindings for MediaTek MT8173 Media Data Path
> to a YAML schema.
Please wrap commit message according to Linux coding style / submission
process (neither too early nor over the limit):
https://elixir.bootlin.com/linux/v6.4-rc1/source/Documentation/process/submitting-patches.rst#L597
>
> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
> ---
> .../bindings/media/mediatek,mt8173-mdp.yaml | 174 ++++++++++++++++++
> .../bindings/media/mediatek-mdp.txt | 95 ----------
> 2 files changed, 174 insertions(+), 95 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/media/mediatek,mt8173-mdp.yaml
> delete mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt
>
> diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8173-mdp.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8173-mdp.yaml
> new file mode 100644
> index 0000000000000..f3a08afc305b1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/mediatek,mt8173-mdp.yaml
> @@ -0,0 +1,174 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/mediatek,mt8173-mdp.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT8173 Media Data Path
> +
> +maintainers:
> + - Ariel D'Alessandro <ariel.dalessandro@collabora.com>
> +
> +description:
> + Media Data Path is used for scaling and color space conversion.
> +
> +properties:
> + compatible:
> + oneOf:
> + - items:
Just enum, no items here
> + - enum:
> + - mediatek,mt8173-mdp-rdma
> + - mediatek,mt8173-mdp-rsz
> + - mediatek,mt8173-mdp-wdma
> + - mediatek,mt8173-mdp-wrot
> + - items:
> + - enum:
> + - mediatek,mt8173-mdp-rdma
> + - mediatek,mt8173-mdp-rsz
> + - mediatek,mt8173-mdp-wdma
> + - mediatek,mt8173-mdp-wrot
> + - const: mediatek,mt8173-mdp
This makes no sense. How devices can be compatible and can not be
compatible.
> +
> + reg:
> + maxItems: 1
> +
> + clocks: true
No, there's no such syntax. Look at other bindings.
> +
> + power-domains:
> + maxItems: 1
> +
> + iommus:
> + description: |
Drop |
> + This property should point to the respective IOMMU block with master port as argument,
> + see Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details.
Drop entire description, completely redundant. I don't know why my patch
fixing this was not applied, so you keep repeating same mistakes...
> + maxItems: 1
> +
> + mediatek,vpu:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description:
> + Describes point to vpu.
Useless description. We see that from the property name. Explain the
purpose in the hardware.
> +
> +required:
> + - compatible
> + - reg
> + - clocks
> + - power-domains
> +
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: mediatek,mt8173-mdp-rdma
> + then:
> + properties:
> + clocks:
> + items:
> + - description: Main clock
> + - description: Mutex clock
> + else:
> + properties:
> + clocks:
> + items:
> + - description: Main clock
> +
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - mediatek,mt8173-mdp-rdma
> + - mediatek,mt8173-mdp-wdma
> + - mediatek,mt8173-mdp-wrot
> + then:
> + required:
> + - iommus
> +
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: mediatek,mt8173-mdp
This makes no sense either.
> + then:
> + required:
> + - mediatek,vpu
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/mt8173-clk.h>
> + #include <dt-bindings/memory/mt8173-larb-port.h>
> + #include <dt-bindings/power/mt8173-power.h>
> +
> + soc {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + mdp_rdma0: rdma@14001000 {
One example is enough. Two could be fine if they differ significantly.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v1 03/14] dt-bindings: arm: mediatek: mmsys: Add assigned-clocks/rates properties
From: Krzysztof Kozlowski @ 2025-08-21 6:43 UTC (permalink / raw)
To: Ariel D'Alessandro
Cc: airlied, amergnat, andrew+netdev, andrew-ct.chen,
angelogioacchino.delregno, broonie, chunkuang.hu, ck.hu, conor+dt,
davem, dmitry.torokhov, edumazet, flora.fu, houlong.wei, jeesw,
jmassot, kernel, krzk+dt, kuba, kyrie.wu, lgirdwood,
linus.walleij, louisalexis.eyraud, maarten.lankhorst,
matthias.bgg, mchehab, minghsiu.tsai, mripard, p.zabel, pabeni,
robh, sean.wang, simona, support.opensource, tiffany.lin,
tzimmermann, yunfei.dong, devicetree, dri-devel, linux-arm-kernel,
linux-clk, linux-gpio, linux-input, linux-kernel, linux-media,
linux-mediatek, linux-sound, netdev
In-Reply-To: <20250820171302.324142-4-ariel.dalessandro@collabora.com>
On Wed, Aug 20, 2025 at 02:12:51PM -0300, Ariel D'Alessandro wrote:
> Current, the DT bindings for MediaTek mmsys controller is missing the
> assigned-clocks and assigned-clocks-rates properties. Add these and
No, they do not miss them. I don't understand why you are adding these.
> update the example as well.
>
> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
> ---
> .../devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml
> index 3f4262e93c789..d045d366eb8e2 100644
> --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml
> +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml
> @@ -68,6 +68,12 @@ properties:
> of the power controller specified by phandle. See
> Documentation/devicetree/bindings/power/power-domain.yaml for details.
>
> + assigned-clocks:
> + maxItems: 1
> +
> + assigned-clock-rates:
> + maxItems: 1
> +
Drop both, completely redundant and not actually in the scope of the binding.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v2 0/2] Add tc3408 bindings and timing
From: Langyan Ye @ 2025-08-21 3:44 UTC (permalink / raw)
To: dmitry.torokhov, robh, krzk+dt, conor+dt, jikos, bentiss
Cc: dianders, linux-input, devicetree, linux-kernel
In-Reply-To: <20250821031514.49497-1-yelangyan@huaqin.corp-partner.google.com>
Langyan Ye <yelangyan@huaqin.corp-partner.google.com> 于2025年8月21日周四 11:15写道:
>
> The tc3408 touch screen chip same as Elan eKTH6915 controller
> has a reset gpio. The difference is that they have different
> post_power_delay_ms.
>
> According to the Parade TC3408 datasheet, the reset pin requires a
> pull-down duration longer than 10 ms, therefore post_power_delay_ms
> is set to 10. In addition, the chipset requires an initialization
> time greater than 300 ms after reset, so post_gpio_reset_on_delay_ms
> is configured as 300.
>
> Changes in v3:
> - PATCH 2/2: Corrected post_gpio_reset_on_delay_ms: 100 -> 300
> - PATCH 2/2: Dropped Reviewed-by tag from Douglas Anderson since code changed
> - Link to v2: https://lore.kernel.org/all/20250820122520.3356738-1-yelangyan@huaqin.corp-partner.google.com/
>
> Changes in v2:
> - PATCH 1/2: Drop redundant "bindings for" from subject
> - PATCH 1/2: Improve description (describe hardware instead of bindings)
> - PATCH 1/2: Drop "panel: true" property
> - PATCH 1/2: Drop redundant description for reset-gpios
> - PATCH 1/2: Use unevaluatedProperties: false instead of additionalProperties
> - Link to v1: https://lore.kernel.org/all/20250819034852.1230264-1-yelangyan@huaqin.corp-partner.google.com/
>
> Langyan Ye (2):
> dt-bindings: input: Add Parade TC3408 touchscreen controller
> HID: i2c-hid: elan: Add parade-tc3408 timing
>
> .../bindings/input/parade,tc3408.yaml | 68 +++++++++++++++++++
> drivers/hid/i2c-hid/i2c-hid-of-elan.c | 8 +++
> 2 files changed, 76 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/input/parade,tc3408.yaml
>
> --
> 2.34.1
>
Hi all,
Apologies for the confusion. The last series I sent was labeled as
"[PATCH v2 0/2]" in the subject, but it should have been "[PATCH v3 0/2]".
Please consider that series as v3.
Thanks,
Langyan
^ permalink raw reply
* [PATCH v2 2/2] HID: i2c-hid: elan: Add parade-tc3408 timing
From: Langyan Ye @ 2025-08-21 3:15 UTC (permalink / raw)
To: dmitry.torokhov, robh, krzk+dt, conor+dt, jikos, bentiss
Cc: dianders, linux-input, devicetree, linux-kernel, Langyan Ye
In-Reply-To: <20250821031514.49497-1-yelangyan@huaqin.corp-partner.google.com>
Parade-tc3408 requires reset to pull down time greater than 10ms,
so the configuration post_power_delay_ms is 10, and the chipset
initial time is required to be greater than 300ms,
so the post_gpio_reset_on_delay_ms is set to 300.
Signed-off-by: Langyan Ye <yelangyan@huaqin.corp-partner.google.com>
---
drivers/hid/i2c-hid/i2c-hid-of-elan.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/hid/i2c-hid/i2c-hid-of-elan.c b/drivers/hid/i2c-hid/i2c-hid-of-elan.c
index 3fcff6daa0d3..875f5e214c7b 100644
--- a/drivers/hid/i2c-hid/i2c-hid-of-elan.c
+++ b/drivers/hid/i2c-hid/i2c-hid-of-elan.c
@@ -179,11 +179,19 @@ static const struct elan_i2c_hid_chip_data ilitek_ili2901_chip_data = {
.main_supply_name = "vcc33",
};
+static const struct elan_i2c_hid_chip_data parade_tc3408_chip_data = {
+ .post_power_delay_ms = 10,
+ .post_gpio_reset_on_delay_ms = 300,
+ .hid_descriptor_address = 0x0001,
+ .main_supply_name = "vcc33",
+};
+
static const struct of_device_id elan_i2c_hid_of_match[] = {
{ .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data },
{ .compatible = "elan,ekth6a12nay", .data = &elan_ekth6a12nay_chip_data },
{ .compatible = "ilitek,ili9882t", .data = &ilitek_ili9882t_chip_data },
{ .compatible = "ilitek,ili2901", .data = &ilitek_ili2901_chip_data },
+ { .compatible = "parade,tc3408", .data = ¶de_tc3408_chip_data },
{ }
};
MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/2] dt-bindings: input: Add Parade TC3408 touchscreen controller
From: Langyan Ye @ 2025-08-21 3:15 UTC (permalink / raw)
To: dmitry.torokhov, robh, krzk+dt, conor+dt, jikos, bentiss
Cc: dianders, linux-input, devicetree, linux-kernel, Langyan Ye,
Conor Dooley
In-Reply-To: <20250821031514.49497-1-yelangyan@huaqin.corp-partner.google.com>
The tc3408 touch screen chip same as Elan eKTH6915 controller
has a reset gpio. The difference is that they have different
post_power_delay_ms.
Signed-off-by: Langyan Ye <yelangyan@huaqin.corp-partner.google.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/input/parade,tc3408.yaml | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/parade,tc3408.yaml
diff --git a/Documentation/devicetree/bindings/input/parade,tc3408.yaml b/Documentation/devicetree/bindings/input/parade,tc3408.yaml
new file mode 100644
index 000000000000..30ffefb96c68
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/parade,tc3408.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/parade,tc3408.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Parade TC3408 touchscreen controller
+
+maintainers:
+ - Langyan Ye <yelangyan@huaqin.corp-partner.google.com>
+
+description: |
+ Parade TC3408 is a touchscreen controller supporting the I2C-HID protocol.
+ It requires a reset GPIO and two power supplies (3.3V and 1.8V).
+
+allOf:
+ - $ref: /schemas/input/touchscreen/touchscreen.yaml#
+
+properties:
+ compatible:
+ const: parade,tc3408
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+ vcc33-supply:
+ description: The 3.3V supply to the touchscreen.
+
+ vccio-supply:
+ description: The 1.8V supply to the touchscreen.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - reset-gpios
+ - vcc33-supply
+ - vccio-supply
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ touchscreen: touchscreen@24 {
+ compatible = "parade,tc3408";
+ reg = <0x24>;
+
+ interrupt-parent = <&pio>;
+ interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
+
+ reset-gpios = <&pio 126 GPIO_ACTIVE_LOW>;
+ vcc33-supply = <&pp3300_tchscr_x>;
+ vccio-supply = <&pp1800_tchscr_report_disable>;
+ };
+ };
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/2] Add tc3408 bindings and timing
From: Langyan Ye @ 2025-08-21 3:15 UTC (permalink / raw)
To: dmitry.torokhov, robh, krzk+dt, conor+dt, jikos, bentiss
Cc: dianders, linux-input, devicetree, linux-kernel, Langyan Ye
The tc3408 touch screen chip same as Elan eKTH6915 controller
has a reset gpio. The difference is that they have different
post_power_delay_ms.
According to the Parade TC3408 datasheet, the reset pin requires a
pull-down duration longer than 10 ms, therefore post_power_delay_ms
is set to 10. In addition, the chipset requires an initialization
time greater than 300 ms after reset, so post_gpio_reset_on_delay_ms
is configured as 300.
Changes in v3:
- PATCH 2/2: Corrected post_gpio_reset_on_delay_ms: 100 -> 300
- PATCH 2/2: Dropped Reviewed-by tag from Douglas Anderson since code changed
- Link to v2: https://lore.kernel.org/all/20250820122520.3356738-1-yelangyan@huaqin.corp-partner.google.com/
Changes in v2:
- PATCH 1/2: Drop redundant "bindings for" from subject
- PATCH 1/2: Improve description (describe hardware instead of bindings)
- PATCH 1/2: Drop "panel: true" property
- PATCH 1/2: Drop redundant description for reset-gpios
- PATCH 1/2: Use unevaluatedProperties: false instead of additionalProperties
- Link to v1: https://lore.kernel.org/all/20250819034852.1230264-1-yelangyan@huaqin.corp-partner.google.com/
Langyan Ye (2):
dt-bindings: input: Add Parade TC3408 touchscreen controller
HID: i2c-hid: elan: Add parade-tc3408 timing
.../bindings/input/parade,tc3408.yaml | 68 +++++++++++++++++++
drivers/hid/i2c-hid/i2c-hid-of-elan.c | 8 +++
2 files changed, 76 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/parade,tc3408.yaml
--
2.34.1
^ permalink raw reply
* [PATCH] HID: intel-ish-ipc: Remove redundant ready check after timeout function
From: Zhang Lixu @ 2025-08-21 2:06 UTC (permalink / raw)
To: linux-input, srinivas.pandruvada, jikos, benjamin.tissoires; +Cc: lixu.zhang
timed_wait_for_timeout() internally checks for ish_is_input_ready() and
ishtp_fw_is_ready() based on the provided parameters. If
timed_wait_for_timeout() returns 0, it indicates the status is ready. In
rare cases, another thread may send a message immediately after
timed_wait_for_timeout() returns, causing a subsequent ish_is_input_ready()
check to fail. Since the return value of timed_wait_for_timeout() is
sufficient to determine readiness, the additional ready check is
unnecessary and may introduce issues.
This patch removes the redundant check and relies solely on the return
value of timed_wait_for_timeout().
Fixes: ae02e5d40d5f ("HID: intel-ish-hid: ipc layer")
Signed-off-by: Zhang Lixu <lixu.zhang@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
drivers/hid/intel-ish-hid/ipc/ipc.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c
index 4c861119e97a..3ddaa2cd39d5 100644
--- a/drivers/hid/intel-ish-hid/ipc/ipc.c
+++ b/drivers/hid/intel-ish-hid/ipc/ipc.c
@@ -498,6 +498,7 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
{
uint32_t reset_id;
unsigned long flags;
+ int ret;
/* Read reset ID */
reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;
@@ -510,12 +511,11 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
/* ISHTP notification in IPC_RESET */
ishtp_reset_handler(dev);
- if (!ish_is_input_ready(dev))
- timed_wait_for_timeout(dev, WAIT_FOR_INPUT_RDY,
- TIME_SLICE_FOR_INPUT_RDY_MS, TIMEOUT_FOR_INPUT_RDY_MS);
-
+ ret = timed_wait_for_timeout(dev, WAIT_FOR_INPUT_RDY,
+ TIME_SLICE_FOR_INPUT_RDY_MS,
+ TIMEOUT_FOR_INPUT_RDY_MS);
/* ISH FW is dead */
- if (!ish_is_input_ready(dev))
+ if (ret)
return -EPIPE;
/* Send clock sync at once after reset */
@@ -531,9 +531,10 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
sizeof(uint32_t));
/* Wait for ISH FW'es ILUP and ISHTP_READY */
- timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY,
- TIME_SLICE_FOR_FW_RDY_MS, TIMEOUT_FOR_FW_RDY_MS);
- if (!ishtp_fw_is_ready(dev)) {
+ ret = timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY,
+ TIME_SLICE_FOR_FW_RDY_MS,
+ TIMEOUT_FOR_FW_RDY_MS);
+ if (ret) {
/* ISH FW is dead */
uint32_t ish_status;
base-commit: 3ac864c2d9bb8608ee236e89bf561811613abfce
--
2.43.0
^ permalink raw reply related
* Re: [RESEND v2 1/1] dt-bindings: input: convert lpc32xx-key.txt to yaml format
From: Rob Herring (Arm) @ 2025-08-21 0:08 UTC (permalink / raw)
To: Frank Li
Cc: linux-kernel, Dmitry Torokhov, Vladimir Zapolskiy, linux-input,
devicetree, linux-arm-kernel, imx, Piotr Wojtaszczyk,
Conor Dooley, Krzysztof Kozlowski
In-Reply-To: <20250818183814.3603308-1-Frank.Li@nxp.com>
On Mon, 18 Aug 2025 14:38:13 -0400, Frank Li wrote:
> Convert lpc32xx-key.txt to yaml format.
>
> Additional changes:
> - set maximum of key-row(column) to 4.
> - add ref to matrix-keymap.yaml.
>
> Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> change in v2
> - add ref to matrix-keymap.yaml.
> - remove properties, which already defined in matrix-keymap.yaml.
> - Add Vladimir Zapolskiy review tag
> ---
> .../devicetree/bindings/input/lpc32xx-key.txt | 34 -----------
> .../bindings/input/nxp,lpc3220-key.yaml | 61 +++++++++++++++++++
> 2 files changed, 61 insertions(+), 34 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/input/lpc32xx-key.txt
> create mode 100644 Documentation/devicetree/bindings/input/nxp,lpc3220-key.yaml
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [RESEND v2 1/1] dt-bindings: input: convert lpc32xx-key.txt to yaml format
From: Rob Herring @ 2025-08-21 0:07 UTC (permalink / raw)
To: Vladimir Zapolskiy
Cc: Frank Li, Dmitry Torokhov, Krzysztof Kozlowski, Conor Dooley,
Piotr Wojtaszczyk,
open list:INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN)...,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
moderated list:ARM/LPC32XX SOC SUPPORT, open list, imx
In-Reply-To: <ddcd3af2-534d-4708-9f7d-e301a91373ab@mleia.com>
On Mon, Aug 18, 2025 at 11:02:58PM +0300, Vladimir Zapolskiy wrote:
> On 8/18/25 21:38, Frank Li wrote:
> > Convert lpc32xx-key.txt to yaml format.
> >
> > Additional changes:
> > - set maximum of key-row(column) to 4.
> > - add ref to matrix-keymap.yaml.
> >
> > Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
>
> FWIW I'm fine, if this change enters over linux-input, otherwise I'll send it
> in a PR to linux-arm-kernel/for-next.
The input subsystem is the default.
Rob
^ permalink raw reply
* [PATCH v10 6/6] MAINTAINERS: add an entry for pf1550 mfd driver
From: Samuel Kayode via B4 Relay @ 2025-08-20 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Frank Li, Krzysztof Kozlowski
In-Reply-To: <20250820-pf1550-v10-0-4c0b6e4445e3@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add MAINTAINERS entry for pf1550 PMIC.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v9:
- Pick up Frank's `Reviewed-by` tag
v6:
- Add imx mailing list
---
MAINTAINERS | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 60bba48f5479a025f9da3eaf9dbacb67a194df07..ffc834aace4272e663f9717bcffd67100eb546c7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17996,6 +17996,17 @@ F: Documentation/devicetree/bindings/clock/imx*
F: drivers/clk/imx/
F: include/dt-bindings/clock/imx*
+NXP PF1550 PMIC MFD DRIVER
+M: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+L: imx@lists.linux.dev
+S: Maintained
+F: Documentation/devicetree/bindings/mfd/nxp,pf1550.yaml
+F: drivers/input/misc/pf1550-onkey.c
+F: drivers/mfd/pf1550.c
+F: drivers/power/supply/pf1550-charger.c
+F: drivers/regulator/pf1550-regulator.c
+F: include/linux/mfd/pfd1550.h
+
NXP PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER
M: Jagan Teki <jagan@amarulasolutions.com>
S: Maintained
--
2.50.1
^ permalink raw reply related
* [PATCH v10 4/6] input: pf1550: add onkey support
From: Samuel Kayode via B4 Relay @ 2025-08-20 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Frank Li
In-Reply-To: <20250820-pf1550-v10-0-4c0b6e4445e3@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add support for the onkey of the pf1550 PMIC.
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v10:
- Use regmap_clear_bits instead of regmap_write
v9:
- Requested by Sean:
- Add support for disabling power down of system by onkey
v8:
- Pick up `Acked-by` tag from Dmitry
- Use C++ for SPDX license header comment and C type for rest of license
comment
v7:
- Use reverese christmas tree style
- Drop unecessary 0 in id table's driver data
v4:
- Address Dmitry's feedback
- Drop irq variable in onkey_drv_data
- Drop keycode variable in onkey_drv_data
- Define wakeup as type bool
- Use platform_get_irq
- Use type const for struct pf1550_dev in onkey_drv_data
- Replace (error < 0) with (error) in if statement when applicable
- No need to define driver_data in table id
- Define driver.pm with pm_sleep_ptr
v3:
- Address Dmitry's feedback
- Drop compatible string
- Remove dependency on OF
- Use generic device properties
- Drop unnecessary includes
- Drop unnecessary initializations in probe
- Always use the KEY_POWER property for onkey->keycode
- Do mapping of irqs in MFD driver
- Define onkey->input before interrupts are active
- Drop unnecessary input_free_device since devm
- Manage onkey irqs instead of the main interrupt line.
- Fix integer overflow when unmasking onkey irqs in onkey_resume.
v2:
- Add driver for onkey
---
drivers/input/misc/Kconfig | 11 +++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/pf1550-onkey.c | 197 ++++++++++++++++++++++++++++++++++++++
3 files changed, 209 insertions(+)
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index f5496ca0c0d2bfcb7968503ccd1844ff43bbc1c0..47b3c43ff0550f14d61990997976366436411adc 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -179,6 +179,17 @@ config INPUT_PCSPKR
To compile this driver as a module, choose M here: the
module will be called pcspkr.
+config INPUT_PF1550_ONKEY
+ tristate "NXP PF1550 Onkey support"
+ depends on MFD_PF1550
+ help
+ Say Y here if you want support for PF1550 PMIC. Onkey can trigger
+ release and 1s(push hold), 2s, 3s, 4s, 8s interrupt for long press
+ detect.
+
+ To compile this driver as a module, choose M here. The module will be
+ called pf1550-onkey.
+
config INPUT_PM8941_PWRKEY
tristate "Qualcomm PM8941 power key support"
depends on MFD_SPMI_PMIC
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 6d91804d0a6f761a094e6c380f878f74c3054d63..c652337de464c1eeaf1515d0bc84d10de0cb3a74 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
+obj-$(CONFIG_INPUT_PF1550_ONKEY) += pf1550-onkey.o
obj-$(CONFIG_INPUT_PM8941_PWRKEY) += pm8941-pwrkey.o
obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
diff --git a/drivers/input/misc/pf1550-onkey.c b/drivers/input/misc/pf1550-onkey.c
new file mode 100644
index 0000000000000000000000000000000000000000..9be6377151cb3be824ab34ff37f983196b909324
--- /dev/null
+++ b/drivers/input/misc/pf1550-onkey.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the PF1550 ONKEY
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#include <linux/err.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/platform_device.h>
+
+#define PF1550_ONKEY_IRQ_NR 6
+
+struct onkey_drv_data {
+ struct device *dev;
+ const struct pf1550_ddata *pf1550;
+ bool wakeup;
+ struct input_dev *input;
+};
+
+static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data)
+{
+ struct onkey_drv_data *onkey = data;
+ struct platform_device *pdev = to_platform_device(onkey->dev);
+ int i, state, irq_type = -1;
+
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++)
+ if (irq == platform_get_irq(pdev, i))
+ irq_type = i;
+
+ switch (irq_type) {
+ case PF1550_ONKEY_IRQ_PUSHI:
+ state = 0;
+ break;
+ case PF1550_ONKEY_IRQ_1SI:
+ case PF1550_ONKEY_IRQ_2SI:
+ case PF1550_ONKEY_IRQ_3SI:
+ case PF1550_ONKEY_IRQ_4SI:
+ case PF1550_ONKEY_IRQ_8SI:
+ state = 1;
+ break;
+ default:
+ dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n",
+ irq_type);
+ return IRQ_HANDLED;
+ }
+
+ input_event(onkey->input, EV_KEY, KEY_POWER, state);
+ input_sync(onkey->input);
+
+ return IRQ_HANDLED;
+}
+
+static int pf1550_onkey_probe(struct platform_device *pdev)
+{
+ struct onkey_drv_data *onkey;
+ struct input_dev *input;
+ bool key_power = false;
+ int i, irq, error;
+
+ onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
+ if (!onkey)
+ return -ENOMEM;
+
+ onkey->dev = &pdev->dev;
+
+ onkey->pf1550 = dev_get_drvdata(pdev->dev.parent);
+ if (!onkey->pf1550->regmap)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "failed to get regmap\n");
+
+ onkey->wakeup = device_property_read_bool(pdev->dev.parent,
+ "wakeup-source");
+
+ if (device_property_read_bool(pdev->dev.parent,
+ "nxp,disable-key-power")) {
+ error = regmap_clear_bits(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_PWRCTRL1,
+ PF1550_ONKEY_RST_EN);
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "failed: disable turn system off");
+ } else {
+ key_power = true;
+ }
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input)
+ return dev_err_probe(&pdev->dev, -ENOMEM,
+ "failed to allocate the input device\n");
+
+ input->name = pdev->name;
+ input->phys = "pf1550-onkey/input0";
+ input->id.bustype = BUS_HOST;
+
+ if (key_power)
+ input_set_capability(input, EV_KEY, KEY_POWER);
+
+ onkey->input = input;
+ platform_set_drvdata(pdev, onkey);
+
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ error = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ pf1550_onkey_irq_handler,
+ IRQF_NO_SUSPEND,
+ "pf1550-onkey", onkey);
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "failed: irq request (IRQ: %d)\n",
+ i);
+ }
+
+ error = input_register_device(input);
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "failed to register input device\n");
+
+ device_init_wakeup(&pdev->dev, onkey->wakeup);
+
+ return 0;
+}
+
+static int pf1550_onkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
+ int i, irq;
+
+ if (!device_may_wakeup(&pdev->dev))
+ regmap_write(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI |
+ ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI);
+ else
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq > 0)
+ enable_irq_wake(irq);
+ }
+
+ return 0;
+}
+
+static int pf1550_onkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
+ int i, irq;
+
+ if (!device_may_wakeup(&pdev->dev))
+ regmap_write(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ ~((u8)(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI |
+ ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI |
+ ONKEY_IRQ_8SI)));
+ else
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq > 0)
+ disable_irq_wake(irq);
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend,
+ pf1550_onkey_resume);
+
+static const struct platform_device_id pf1550_onkey_id[] = {
+ { "pf1550-onkey", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, pf1550_onkey_id);
+
+static struct platform_driver pf1550_onkey_driver = {
+ .driver = {
+ .name = "pf1550-onkey",
+ .pm = pm_sleep_ptr(&pf1550_onkey_pm_ops),
+ },
+ .probe = pf1550_onkey_probe,
+ .id_table = pf1550_onkey_id,
+};
+module_platform_driver(pf1550_onkey_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("PF1550 onkey Driver");
+MODULE_LICENSE("GPL");
--
2.50.1
^ permalink raw reply related
* [PATCH v10 5/6] power: supply: pf1550: add battery charger support
From: Samuel Kayode via B4 Relay @ 2025-08-20 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Frank Li
In-Reply-To: <20250820-pf1550-v10-0-4c0b6e4445e3@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add support for the battery charger for pf1550 PMIC.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v9:
- Fix thermal regulation temperature ranges
- Fix default thermal regulation temperature
- Drop unused `data` variable in reg_init
- Select charger operation mode based on application - suggested by Sean
v8:
- Drop PF1550_CHARGER_NAME
- Drop unnecessary POWER_SUPPLY_STATUS_CHARGING s
- Replace POWER_SUPPLY_HEALTH_DEAD with POWER_SUPPLY_HEALTH_NO_BATTERY
- Drop check for charger in delayed_work s
- Use dev_warn when battery is over-voltage
- Define two power supplies: charger and battery
- Use devm_delayed_work_autocancel to automate cleanup and fix race
condition
v7:
- Use reverse christmas tree order
- Drop unecessary 0 in id table's driver data field
- Store virqs to avoid reinvoking platform_get_irq in the interrupt
service routine
- Drop manufacturer and model global variables
v6:
- Drop lock entirely
- Reverse christmas tree order for variables defined in probe as
suggested by Frank
- return pf1550_reg_init
v5:
- Drop lock for battery and charger delayed_work
- More conservative locking in vbus delayed_work
- Apply lock when setting power supply type during register initialization
v4:
- Finish handling of some interrupts in threaded irq handler
- Use platform_get_irq
v3:
- Use struct power_supply_get_battery_info to get constant charge
voltage if specified
- Use virqs mapped in MFD driver
v2:
- Address feedback from Enric Balletbo Serra
---
drivers/power/supply/Kconfig | 11 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/pf1550-charger.c | 636 ++++++++++++++++++++++++++++++++++
3 files changed, 648 insertions(+)
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 79ddb006e2dad6bf96b71ed570a37c006b5f9433..6d0c872edac1f45da314632e671af1aeda4c87b8 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -471,6 +471,17 @@ config CHARGER_88PM860X
help
Say Y here to enable charger for Marvell 88PM860x chip.
+config CHARGER_PF1550
+ tristate "NXP PF1550 battery charger driver"
+ depends on MFD_PF1550
+ help
+ Say Y to enable support for the NXP PF1550 battery charger.
+ The device is a single cell Li-Ion/Li-Polymer battery charger for
+ portable application.
+
+ This driver can also be built as a module. If so, the module will be
+ called pf1550-charger.
+
config BATTERY_RX51
tristate "Nokia RX-51 (N900) battery driver"
depends on TWL4030_MADC
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 4f5f8e3507f80da02812f0d08c2d81ddff0a272f..7f68380099c59dab71b73120150612a23e16a745 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_CHARGER_RT9467) += rt9467-charger.o
obj-$(CONFIG_CHARGER_RT9471) += rt9471.o
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
+obj-$(CONFIG_CHARGER_PF1550) += pf1550-charger.o
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o ab8500_chargalg.o
obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o
diff --git a/drivers/power/supply/pf1550-charger.c b/drivers/power/supply/pf1550-charger.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c43cc086a18239b46c73553d73a85a60ba7c41e
--- /dev/null
+++ b/drivers/power/supply/pf1550-charger.c
@@ -0,0 +1,636 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * charger driver for the PF1550
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#include <linux/devm-helpers.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#define PF1550_DEFAULT_CONSTANT_VOLT 4200000
+#define PF1550_DEFAULT_MIN_SYSTEM_VOLT 3500000
+#define PF1550_DEFAULT_THERMAL_TEMP 95
+#define PF1550_CHARGER_IRQ_NR 5
+
+struct pf1550_charger {
+ struct device *dev;
+ const struct pf1550_ddata *pf1550;
+ struct power_supply *charger;
+ struct power_supply *battery;
+ struct delayed_work vbus_sense_work;
+ struct delayed_work chg_sense_work;
+ struct delayed_work bat_sense_work;
+ int virqs[PF1550_CHARGER_IRQ_NR];
+
+ u32 constant_volt;
+ u32 min_system_volt;
+ u32 thermal_regulation_temp;
+};
+
+static int pf1550_get_charger_state(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_CHG_SNS_MASK;
+
+ switch (data) {
+ case PF1550_CHG_PRECHARGE:
+ case PF1550_CHG_CONSTANT_CURRENT:
+ case PF1550_CHG_CONSTANT_VOL:
+ case PF1550_CHG_EOC:
+ *val = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case PF1550_CHG_DONE:
+ *val = POWER_SUPPLY_STATUS_FULL;
+ break;
+ case PF1550_CHG_TIMER_FAULT:
+ case PF1550_CHG_SUSPEND:
+ *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case PF1550_CHG_OFF_INV:
+ case PF1550_CHG_OFF_TEMP:
+ case PF1550_CHG_LINEAR_ONLY:
+ *val = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ default:
+ *val = POWER_SUPPLY_STATUS_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static int pf1550_get_charge_type(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_CHG_SNS_MASK;
+
+ switch (data) {
+ case PF1550_CHG_SNS_MASK:
+ *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case PF1550_CHG_CONSTANT_CURRENT:
+ case PF1550_CHG_CONSTANT_VOL:
+ case PF1550_CHG_EOC:
+ *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case PF1550_CHG_DONE:
+ case PF1550_CHG_TIMER_FAULT:
+ case PF1550_CHG_SUSPEND:
+ case PF1550_CHG_OFF_INV:
+ case PF1550_CHG_BAT_OVER:
+ case PF1550_CHG_OFF_TEMP:
+ case PF1550_CHG_LINEAR_ONLY:
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ default:
+ *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ }
+
+ return 0;
+}
+
+/*
+ * Supported health statuses:
+ * - POWER_SUPPLY_HEALTH_DEAD
+ * - POWER_SUPPLY_HEALTH_GOOD
+ * - POWER_SUPPLY_HEALTH_OVERVOLTAGE
+ * - POWER_SUPPLY_HEALTH_UNKNOWN
+ */
+static int pf1550_get_battery_health(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_BAT_SNS_MASK;
+
+ switch (data) {
+ case PF1550_BAT_NO_DETECT:
+ *val = POWER_SUPPLY_HEALTH_NO_BATTERY;
+ break;
+ case PF1550_BAT_NO_VBUS:
+ case PF1550_BAT_LOW_THAN_PRECHARG:
+ case PF1550_BAT_CHARG_FAIL:
+ case PF1550_BAT_HIGH_THAN_PRECHARG:
+ *val = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case PF1550_BAT_OVER_VOL:
+ *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ break;
+ default:
+ *val = POWER_SUPPLY_HEALTH_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static int pf1550_get_present(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_BAT_SNS_MASK;
+ *val = (data == PF1550_BAT_NO_DETECT) ? 0 : 1;
+
+ return 0;
+}
+
+static int pf1550_get_online(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_VBUS_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ *val = (data & PF1550_VBUS_VALID) ? 1 : 0;
+
+ return 0;
+}
+
+static void pf1550_chg_bat_work(struct work_struct *work)
+{
+ struct pf1550_charger *chg = container_of(to_delayed_work(work),
+ struct pf1550_charger,
+ bat_sense_work);
+ unsigned int data;
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_BATT_SNS, &data)) {
+ dev_err(chg->dev, "Read BATT_SNS error.\n");
+ return;
+ }
+
+ switch (data & PF1550_BAT_SNS_MASK) {
+ case PF1550_BAT_NO_VBUS:
+ dev_dbg(chg->dev, "No valid VBUS input.\n");
+ break;
+ case PF1550_BAT_LOW_THAN_PRECHARG:
+ dev_dbg(chg->dev, "VBAT < VPRECHG.LB.\n");
+ break;
+ case PF1550_BAT_CHARG_FAIL:
+ dev_dbg(chg->dev, "Battery charging failed.\n");
+ break;
+ case PF1550_BAT_HIGH_THAN_PRECHARG:
+ dev_dbg(chg->dev, "VBAT > VPRECHG.LB.\n");
+ break;
+ case PF1550_BAT_OVER_VOL:
+ dev_dbg(chg->dev, "VBAT > VBATOV.\n");
+ break;
+ case PF1550_BAT_NO_DETECT:
+ dev_dbg(chg->dev, "Battery not detected.\n");
+ break;
+ default:
+ dev_err(chg->dev, "Unknown value read:%x\n",
+ data & PF1550_CHG_SNS_MASK);
+ }
+}
+
+static void pf1550_chg_chg_work(struct work_struct *work)
+{
+ struct pf1550_charger *chg = container_of(to_delayed_work(work),
+ struct pf1550_charger,
+ chg_sense_work);
+ unsigned int data;
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_SNS, &data)) {
+ dev_err(chg->dev, "Read CHG_SNS error.\n");
+ return;
+ }
+
+ switch (data & PF1550_CHG_SNS_MASK) {
+ case PF1550_CHG_PRECHARGE:
+ dev_dbg(chg->dev, "In pre-charger mode.\n");
+ break;
+ case PF1550_CHG_CONSTANT_CURRENT:
+ dev_dbg(chg->dev, "In fast-charge constant current mode.\n");
+ break;
+ case PF1550_CHG_CONSTANT_VOL:
+ dev_dbg(chg->dev, "In fast-charge constant voltage mode.\n");
+ break;
+ case PF1550_CHG_EOC:
+ dev_dbg(chg->dev, "In EOC mode.\n");
+ break;
+ case PF1550_CHG_DONE:
+ dev_dbg(chg->dev, "In DONE mode.\n");
+ break;
+ case PF1550_CHG_TIMER_FAULT:
+ dev_info(chg->dev, "In timer fault mode.\n");
+ break;
+ case PF1550_CHG_SUSPEND:
+ dev_info(chg->dev, "In thermistor suspend mode.\n");
+ break;
+ case PF1550_CHG_OFF_INV:
+ dev_info(chg->dev, "Input invalid, charger off.\n");
+ break;
+ case PF1550_CHG_BAT_OVER:
+ dev_warn(chg->dev, "Battery over-voltage.\n");
+ break;
+ case PF1550_CHG_OFF_TEMP:
+ dev_info(chg->dev, "Temp high, charger off.\n");
+ break;
+ case PF1550_CHG_LINEAR_ONLY:
+ dev_dbg(chg->dev, "In Linear mode, not charging.\n");
+ break;
+ default:
+ dev_err(chg->dev, "Unknown value read:%x\n",
+ data & PF1550_CHG_SNS_MASK);
+ }
+}
+
+static void pf1550_chg_vbus_work(struct work_struct *work)
+{
+ struct pf1550_charger *chg = container_of(to_delayed_work(work),
+ struct pf1550_charger,
+ vbus_sense_work);
+ unsigned int data;
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_VBUS_SNS, &data)) {
+ dev_err(chg->dev, "Read VBUS_SNS error.\n");
+ return;
+ }
+
+ if (data & PF1550_VBUS_UVLO) {
+ dev_dbg(chg->dev, "VBUS detached.\n");
+ power_supply_changed(chg->battery);
+ }
+ if (data & PF1550_VBUS_IN2SYS)
+ dev_dbg(chg->dev, "VBUS_IN2SYS_SNS.\n");
+ if (data & PF1550_VBUS_OVLO)
+ dev_dbg(chg->dev, "VBUS_OVLO_SNS.\n");
+ if (data & PF1550_VBUS_VALID) {
+ dev_dbg(chg->dev, "VBUS attached.\n");
+ power_supply_changed(chg->charger);
+ }
+}
+
+static irqreturn_t pf1550_charger_irq_handler(int irq, void *data)
+{
+ struct pf1550_charger *chg = data;
+ struct device *dev = chg->dev;
+ int i, irq_type = -1;
+
+ for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++)
+ if (irq == chg->virqs[i])
+ irq_type = i;
+
+ switch (irq_type) {
+ case PF1550_CHARG_IRQ_BAT2SOCI:
+ dev_info(dev, "BAT to SYS Overcurrent interrupt.\n");
+ break;
+ case PF1550_CHARG_IRQ_BATI:
+ schedule_delayed_work(&chg->bat_sense_work,
+ msecs_to_jiffies(10));
+ break;
+ case PF1550_CHARG_IRQ_CHGI:
+ schedule_delayed_work(&chg->chg_sense_work,
+ msecs_to_jiffies(10));
+ break;
+ case PF1550_CHARG_IRQ_VBUSI:
+ schedule_delayed_work(&chg->vbus_sense_work,
+ msecs_to_jiffies(10));
+ break;
+ case PF1550_CHARG_IRQ_THMI:
+ dev_info(dev, "Thermal interrupt.\n");
+ break;
+ default:
+ dev_err(dev, "unknown interrupt occurred.\n");
+ }
+
+ return IRQ_HANDLED;
+}
+
+static enum power_supply_property pf1550_charger_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static int pf1550_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pf1550_charger *chg = power_supply_get_drvdata(psy);
+ struct regmap *regmap = chg->pf1550->regmap;
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = pf1550_get_charger_state(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ ret = pf1550_get_charge_type(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = pf1550_get_battery_health(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ ret = pf1550_get_present(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = pf1550_get_online(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = "PF1550";
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = "NXP";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct power_supply_desc pf1550_charger_desc = {
+ .name = "pf1550-charger",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = pf1550_charger_props,
+ .num_properties = ARRAY_SIZE(pf1550_charger_props),
+ .get_property = pf1550_charger_get_property,
+};
+
+static const struct power_supply_desc pf1550_battery_desc = {
+ .name = "pf1550-battery",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = pf1550_charger_props,
+ .num_properties = ARRAY_SIZE(pf1550_charger_props),
+ .get_property = pf1550_charger_get_property,
+};
+
+static int pf1550_set_constant_volt(struct pf1550_charger *chg,
+ unsigned int uvolt)
+{
+ unsigned int data;
+
+ if (uvolt >= 3500000 && uvolt <= 4440000)
+ data = 8 + (uvolt - 3500000) / 20000;
+ else
+ return dev_err_probe(chg->dev, -EINVAL,
+ "Wrong value for constant voltage\n");
+
+ dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt,
+ data);
+
+ return regmap_update_bits(chg->pf1550->regmap,
+ PF1550_CHARG_REG_BATT_REG,
+ PF1550_CHARG_REG_BATT_REG_CHGCV_MASK, data);
+}
+
+static int pf1550_set_min_system_volt(struct pf1550_charger *chg,
+ unsigned int uvolt)
+{
+ unsigned int data;
+
+ switch (uvolt) {
+ case 3500000:
+ data = 0x0;
+ break;
+ case 3700000:
+ data = 0x1;
+ break;
+ case 4300000:
+ data = 0x2;
+ break;
+ default:
+ return dev_err_probe(chg->dev, -EINVAL,
+ "Wrong value for minimum system voltage\n");
+ }
+
+ data <<= PF1550_CHARG_REG_BATT_REG_VMINSYS_SHIFT;
+
+ dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n",
+ uvolt, data);
+
+ return regmap_update_bits(chg->pf1550->regmap,
+ PF1550_CHARG_REG_BATT_REG,
+ PF1550_CHARG_REG_BATT_REG_VMINSYS_MASK, data);
+}
+
+static int pf1550_set_thermal_regulation_temp(struct pf1550_charger *chg,
+ unsigned int cells)
+{
+ unsigned int data;
+
+ switch (cells) {
+ case 80:
+ data = 0x0;
+ break;
+ case 95:
+ data = 0x1;
+ break;
+ case 110:
+ data = 0x2;
+ break;
+ case 125:
+ data = 0x3;
+ break;
+ default:
+ return dev_err_probe(chg->dev, -EINVAL,
+ "Wrong value for thermal temperature\n");
+ }
+
+ data <<= PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_SHIFT;
+
+ dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n",
+ cells, data);
+
+ return regmap_update_bits(chg->pf1550->regmap,
+ PF1550_CHARG_REG_THM_REG_CNFG,
+ PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_MASK,
+ data);
+}
+
+/*
+ * Sets charger registers to proper and safe default values.
+ */
+static int pf1550_reg_init(struct pf1550_charger *chg)
+{
+ struct power_supply_battery_info *info;
+ struct device *dev = chg->dev;
+ int ret;
+
+ /* Unmask charger interrupt, mask DPMI and reserved bit */
+ ret = regmap_write(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT_MASK,
+ PF1550_CHG_INT_MASK);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Error unmask charger interrupt\n");
+
+ ret = pf1550_set_constant_volt(chg, chg->constant_volt);
+ if (ret)
+ return ret;
+
+ ret = pf1550_set_min_system_volt(chg, chg->min_system_volt);
+ if (ret)
+ return ret;
+
+ ret = pf1550_set_thermal_regulation_temp(chg,
+ chg->thermal_regulation_temp);
+ if (ret)
+ return ret;
+
+ /*
+ * The PF1550 charger has 3 modes of operation. By default, the charger
+ * is in mode 1; it remains off. Appropriate for applications not using
+ * a battery. The other supported mode is mode 2, the charger is turned
+ * on to charge a battery when present.
+ */
+ if (power_supply_get_battery_info(chg->charger, &info)) {
+ ret = regmap_write(chg->pf1550->regmap,
+ PF1550_CHARG_REG_CHG_OPER,
+ PF1550_CHG_BAT_ON);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Error turn on charger\n");
+ }
+
+ return 0;
+}
+
+static void pf1550_dt_parse_dev_info(struct pf1550_charger *chg)
+{
+ struct power_supply_battery_info *info;
+ struct device *dev = chg->dev;
+
+ if (device_property_read_u32(dev->parent, "nxp,min-system-microvolt",
+ &chg->min_system_volt))
+ chg->min_system_volt = PF1550_DEFAULT_MIN_SYSTEM_VOLT;
+
+ if (device_property_read_u32(dev->parent,
+ "nxp,thermal-regulation-celsius",
+ &chg->thermal_regulation_temp))
+ chg->thermal_regulation_temp = PF1550_DEFAULT_THERMAL_TEMP;
+
+ if (power_supply_get_battery_info(chg->charger, &info))
+ chg->constant_volt = PF1550_DEFAULT_CONSTANT_VOLT;
+ else
+ chg->constant_volt = info->constant_charge_voltage_max_uv;
+}
+
+static int pf1550_charger_probe(struct platform_device *pdev)
+{
+ const struct pf1550_ddata *pf1550 = dev_get_drvdata(pdev->dev.parent);
+ struct power_supply_config psy_cfg = {};
+ struct pf1550_charger *chg;
+ int i, irq, ret;
+
+ chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
+ if (!chg)
+ return -ENOMEM;
+
+ chg->dev = &pdev->dev;
+ chg->pf1550 = pf1550;
+
+ if (!chg->pf1550->regmap)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "failed to get regmap\n");
+
+ platform_set_drvdata(pdev, chg);
+
+ ret = devm_delayed_work_autocancel(chg->dev, &chg->vbus_sense_work,
+ pf1550_chg_vbus_work);
+ if (ret)
+ return dev_err_probe(chg->dev, ret,
+ "failed to add vbus sense work\n");
+
+ ret = devm_delayed_work_autocancel(chg->dev, &chg->chg_sense_work,
+ pf1550_chg_chg_work);
+ if (ret)
+ return dev_err_probe(chg->dev, ret,
+ "failed to add charger sense work\n");
+
+ ret = devm_delayed_work_autocancel(chg->dev, &chg->bat_sense_work,
+ pf1550_chg_bat_work);
+ if (ret)
+ return dev_err_probe(chg->dev, ret,
+ "failed to add battery sense work\n");
+
+ for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ chg->virqs[i] = irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ pf1550_charger_irq_handler,
+ IRQF_NO_SUSPEND,
+ "pf1550-charger", chg);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed irq request\n");
+ }
+
+ psy_cfg.drv_data = chg;
+
+ chg->charger = devm_power_supply_register(&pdev->dev,
+ &pf1550_charger_desc,
+ &psy_cfg);
+ if (IS_ERR(chg->charger))
+ return dev_err_probe(&pdev->dev, PTR_ERR(chg->charger),
+ "failed: power supply register\n");
+
+ chg->battery = devm_power_supply_register(&pdev->dev,
+ &pf1550_battery_desc,
+ &psy_cfg);
+ if (IS_ERR(chg->battery))
+ return dev_err_probe(&pdev->dev, PTR_ERR(chg->battery),
+ "failed: power supply register\n");
+
+ pf1550_dt_parse_dev_info(chg);
+
+ return pf1550_reg_init(chg);
+}
+
+static const struct platform_device_id pf1550_charger_id[] = {
+ { "pf1550-charger", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, pf1550_charger_id);
+
+static struct platform_driver pf1550_charger_driver = {
+ .driver = {
+ .name = "pf1550-charger",
+ },
+ .probe = pf1550_charger_probe,
+ .id_table = pf1550_charger_id,
+};
+module_platform_driver(pf1550_charger_driver);
+
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_DESCRIPTION("PF1550 charger driver");
+MODULE_LICENSE("GPL");
--
2.50.1
^ permalink raw reply related
* [PATCH v10 2/6] mfd: pf1550: add core driver
From: Samuel Kayode via B4 Relay @ 2025-08-20 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Frank Li
In-Reply-To: <20250820-pf1550-v10-0-4c0b6e4445e3@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add the core driver for pf1550 PMIC. There are 3 subdevices for which the
drivers will be added in subsequent patches.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v10:
- Address Lee's feedback:
- Change dvsX_enb to dvsX_enable
- Add new line where necessary
- Can use 100 chars in a line
- Begin comments with uppercase
- Rearrange members of struct pf1550_ddata
- Add support for disabling onkey shutting down system
v9:
- Requested by Sean:
- Add support for SW1 DVS enable/disable
- Use consistent whitespace
- Adjust commenting and log messages of the read_otp function
v8:
- Address Lee's feedback:
- Drop `mfd` from driver description and comments
- Add module name in Kconfig
- Fix license commenting
- Drop filenames from comments
- Drop unnecessary tabbing
- Alphabetical ordering of includes
- Remove magic numbers
- Add comments for pf1550_read_otp function
- Fix log error message in pf1550_read_otp
- Drop pf1550_add_child_device function
- Start comments with upper case
- Rename pf1550_dev to pf1550_ddata
- Drop i2c member in struct pf1550_ddata/pf1550_dev
- Use more helpful log message when device id not recognized
- Fix dvs_enb: when bit is set the DVS is disabled and when bit is clear the
DVS is enabled
- Verified the PM_OPS suspend and resume do act as expected
v7:
- Address Frank's feedback:
- Ensure reverse christmas tree order for local variable definitions
- Drop unnecessary driver data definition in id table
v6:
- Address Frank's feedback:
- Ensure lowercase when defining register addresses
- Use GENMASK macro for masking
- Hardcode IRQ flags in pf1550_add_child_device
- Add dvs_enb variable for SW2 regulator
- Drop chip type variable
v5:
- Use top level interrupt to manage interrupts for the sub-drivers as
recommended by Mark Brown. The regmap_irq_sub_irq_map would have been used
if not for the irregular charger irq address. For all children, the mask
register is directly after the irq register (i.e., 0x08, 0x09) except
for the charger: 0x80, 0x82. Meaning .mask_base would be applicable
for all but the charger
- Fix bad offset for temperature interrupts of regulator
v4:
- Use struct resource to define irq so platform_get_irq can be used in
children as suggested by Dmitry
- Let mfd_add_devices create the mappings for the interrupts
- ack_base and init_ack_masked defined for charger and regulator irq
chips
- No need to define driver_data in table id
v3:
- Address Dmitry's feedback:
- Place Table IDs next to each other
- Drop of_match_ptr
- Replace dev_err with dev_err_probe in probe method
- Drop useless log in probe
- Map all irqs instead of doing it in the sub-devices as recommended by
Dmitry.
v2:
- Address feedback from Enric Balletbo Serra
---
drivers/mfd/Kconfig | 16 ++
drivers/mfd/Makefile | 2 +
drivers/mfd/pf1550.c | 367 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/pf1550.h | 273 +++++++++++++++++++++++++++++++++
4 files changed, 658 insertions(+)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6fb3768e3d71cbb5c81f63de36cdb2d27a0a7726..14e21f0e239b4a609b01c59435f39abaa41dce14 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -558,6 +558,22 @@ config MFD_MX25_TSADC
i.MX25 processors. They consist of a conversion queue for general
purpose ADC and a queue for Touchscreens.
+config MFD_PF1550
+ tristate "NXP PF1550 PMIC Support"
+ depends on I2C=y && OF
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ help
+ Say yes here to add support for NXP PF1550. This is a companion Power
+ Management IC with regulators, onkey, and charger control on chip.
+ This driver provides common support for accessing the device;
+ additional drivers must be enabled in order to use the functionality
+ of the device.
+
+ This driver can also be built as a module and if so will be called
+ pf1550.
+
config MFD_HI6421_PMIC
tristate "HiSilicon Hi6421 PMU/Codec IC"
depends on OF
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 79495f9f3457b8a666646ec9671861c64d7939e1..8bf712081deaafa554940c1aac0c317a2dcbbfeb 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -120,6 +120,8 @@ obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o
obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
+obj-$(CONFIG_MFD_PF1550) += pf1550.o
+
obj-$(CONFIG_MFD_CORE) += mfd-core.o
ocelot-soc-objs := ocelot-core.o ocelot-spi.o
diff --git a/drivers/mfd/pf1550.c b/drivers/mfd/pf1550.c
new file mode 100644
index 0000000000000000000000000000000000000000..c4f567c055640662cc2db742917cc87cf9cabb5f
--- /dev/null
+++ b/drivers/mfd/pf1550.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Core driver for the PF1550
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+static const struct regmap_config pf1550_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PF1550_PMIC_REG_END,
+};
+
+static const struct regmap_irq pf1550_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_IRQ_CHG, 0, IRQ_CHG),
+ REGMAP_IRQ_REG(PF1550_IRQ_REGULATOR, 0, IRQ_REGULATOR),
+ REGMAP_IRQ_REG(PF1550_IRQ_ONKEY, 0, IRQ_ONKEY),
+};
+
+static const struct regmap_irq_chip pf1550_irq_chip = {
+ .name = "pf1550",
+ .status_base = PF1550_PMIC_REG_INT_CATEGORY,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_irqs),
+};
+
+static const struct regmap_irq pf1550_regulator_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_LS, 0, PMIC_IRQ_SW1_LS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_LS, 0, PMIC_IRQ_SW2_LS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_LS, 0, PMIC_IRQ_SW3_LS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_HS, 3, PMIC_IRQ_SW1_HS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_HS, 3, PMIC_IRQ_SW2_HS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_HS, 3, PMIC_IRQ_SW3_HS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO1_FAULT, 16, PMIC_IRQ_LDO1_FAULT),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO2_FAULT, 16, PMIC_IRQ_LDO2_FAULT),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO3_FAULT, 16, PMIC_IRQ_LDO3_FAULT),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_110, 24, PMIC_IRQ_TEMP_110),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_125, 24, PMIC_IRQ_TEMP_125),
+};
+
+static const struct regmap_irq_chip pf1550_regulator_irq_chip = {
+ .name = "pf1550-regulator",
+ .status_base = PF1550_PMIC_REG_SW_INT_STAT0,
+ .ack_base = PF1550_PMIC_REG_SW_INT_STAT0,
+ .mask_base = PF1550_PMIC_REG_SW_INT_MASK0,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 25,
+ .irqs = pf1550_regulator_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_regulator_irqs),
+};
+
+static const struct resource regulator_resources[] = {
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW1_LS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW2_LS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW3_LS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW1_HS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW2_HS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW3_HS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO1_FAULT),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO2_FAULT),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO3_FAULT),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_TEMP_110),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_TEMP_125),
+};
+
+static const struct regmap_irq pf1550_onkey_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_PUSHI, 0, ONKEY_IRQ_PUSHI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_1SI, 0, ONKEY_IRQ_1SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_2SI, 0, ONKEY_IRQ_2SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_3SI, 0, ONKEY_IRQ_3SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_4SI, 0, ONKEY_IRQ_4SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_8SI, 0, ONKEY_IRQ_8SI),
+};
+
+static const struct regmap_irq_chip pf1550_onkey_irq_chip = {
+ .name = "pf1550-onkey",
+ .status_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
+ .ack_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
+ .mask_base = PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_onkey_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_onkey_irqs),
+};
+
+static const struct resource onkey_resources[] = {
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_PUSHI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_1SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_2SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_3SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_4SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_8SI),
+};
+
+static const struct regmap_irq pf1550_charger_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BAT2SOCI, 0, CHARG_IRQ_BAT2SOCI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BATI, 0, CHARG_IRQ_BATI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_CHGI, 0, CHARG_IRQ_CHGI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_VBUSI, 0, CHARG_IRQ_VBUSI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_THMI, 0, CHARG_IRQ_THMI),
+};
+
+static const struct regmap_irq_chip pf1550_charger_irq_chip = {
+ .name = "pf1550-charger",
+ .status_base = PF1550_CHARG_REG_CHG_INT,
+ .ack_base = PF1550_CHARG_REG_CHG_INT,
+ .mask_base = PF1550_CHARG_REG_CHG_INT_MASK,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_charger_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_charger_irqs),
+};
+
+static const struct resource charger_resources[] = {
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_BAT2SOCI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_BATI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_CHGI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_VBUSI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_THMI),
+};
+
+static const struct mfd_cell pf1550_regulator_cell = {
+ .name = "pf1550-regulator",
+ .num_resources = ARRAY_SIZE(regulator_resources),
+ .resources = regulator_resources,
+};
+
+static const struct mfd_cell pf1550_onkey_cell = {
+ .name = "pf1550-onkey",
+ .num_resources = ARRAY_SIZE(onkey_resources),
+ .resources = onkey_resources,
+};
+
+static const struct mfd_cell pf1550_charger_cell = {
+ .name = "pf1550-charger",
+ .num_resources = ARRAY_SIZE(charger_resources),
+ .resources = charger_resources,
+};
+
+/*
+ * The PF1550 is shipped in variants of A0, A1,...A9. Each variant defines a
+ * configuration of the PMIC in a One-Time Programmable (OTP) memory.
+ * This memory is accessed indirectly by writing valid keys to specific
+ * registers of the PMIC. To read the OTP memory after writing the valid keys,
+ * the OTP register address to be read is written to pf1550 register 0xc4 and
+ * its value read from pf1550 register 0xc5.
+ */
+static int pf1550_read_otp(const struct pf1550_ddata *pf1550, unsigned int index,
+ unsigned int *val)
+{
+ int ret = 0;
+
+ ret = regmap_write(pf1550->regmap, PF1550_PMIC_REG_KEY, PF1550_OTP_PMIC_KEY);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_write(pf1550->regmap, PF1550_CHARG_REG_CHGR_KEY2, PF1550_OTP_CHGR_KEY);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_KEY3, PF1550_OTP_TEST_KEY);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_FMRADDR, index);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_read(pf1550->regmap, PF1550_TEST_REG_FMRDATA, val);
+ if (ret)
+ goto read_err;
+
+ return 0;
+
+read_err:
+ return dev_err_probe(pf1550->dev, ret, "OTP reg %x not found!\n", index);
+}
+
+static int pf1550_i2c_probe(struct i2c_client *i2c)
+{
+ const struct mfd_cell *regulator = &pf1550_regulator_cell;
+ const struct mfd_cell *charger = &pf1550_charger_cell;
+ const struct mfd_cell *onkey = &pf1550_onkey_cell;
+ unsigned int reg_data = 0, otp_data = 0;
+ struct pf1550_ddata *pf1550;
+ struct irq_domain *domain;
+ int irq, ret = 0;
+
+ pf1550 = devm_kzalloc(&i2c->dev, sizeof(*pf1550), GFP_KERNEL);
+ if (!pf1550)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, pf1550);
+ pf1550->dev = &i2c->dev;
+ pf1550->irq = i2c->irq;
+
+ pf1550->regmap = devm_regmap_init_i2c(i2c, &pf1550_regmap_config);
+ if (IS_ERR(pf1550->regmap))
+ return dev_err_probe(pf1550->dev, PTR_ERR(pf1550->regmap),
+ "failed to allocate register map\n");
+
+ ret = regmap_read(pf1550->regmap, PF1550_PMIC_REG_DEVICE_ID, ®_data);
+ if (ret < 0)
+ return dev_err_probe(pf1550->dev, ret, "cannot read chip ID\n");
+ if (reg_data != PF1550_DEVICE_ID)
+ return dev_err_probe(pf1550->dev, -ENODEV, "invalid device ID: 0x%02x\n", reg_data);
+
+ /* Regulator DVS for SW2 */
+ ret = pf1550_read_otp(pf1550, PF1550_OTP_SW2_SW3, &otp_data);
+ if (ret)
+ return ret;
+
+ /* When clear, DVS should be enabled */
+ if (!(otp_data & OTP_SW2_DVS_ENB))
+ pf1550->dvs2_enable = true;
+
+ /* Regulator DVS for SW1 */
+ ret = pf1550_read_otp(pf1550, PF1550_OTP_SW1_SW2, &otp_data);
+ if (ret)
+ return ret;
+
+ if (!(otp_data & OTP_SW1_DVS_ENB))
+ pf1550->dvs1_enable = true;
+
+ /* Add top level interrupts */
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, pf1550->irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING,
+ 0, &pf1550_irq_chip,
+ &pf1550->irq_data);
+ if (ret)
+ return ret;
+
+ /* Add regulator */
+ irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_REGULATOR);
+ if (irq < 0)
+ return dev_err_probe(pf1550->dev, irq,
+ "Failed to get parent vIRQ(%d) for chip %s\n",
+ PF1550_IRQ_REGULATOR, pf1550_irq_chip.name);
+
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_regulator_irq_chip,
+ &pf1550->irq_data_regulator);
+ if (ret)
+ return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
+ pf1550_regulator_irq_chip.name);
+
+ domain = regmap_irq_get_domain(pf1550->irq_data_regulator);
+
+ ret = devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, regulator, 1, NULL, 0, domain);
+ if (ret)
+ return ret;
+
+ /* Add onkey */
+ irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_ONKEY);
+ if (irq < 0)
+ return dev_err_probe(pf1550->dev, irq,
+ "Failed to get parent vIRQ(%d) for chip %s\n",
+ PF1550_IRQ_ONKEY, pf1550_irq_chip.name);
+
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_onkey_irq_chip,
+ &pf1550->irq_data_onkey);
+ if (ret)
+ return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
+ pf1550_onkey_irq_chip.name);
+
+ domain = regmap_irq_get_domain(pf1550->irq_data_onkey);
+
+ ret = devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, onkey, 1, NULL, 0, domain);
+ if (ret)
+ return ret;
+
+ /* Add battery charger */
+ irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_CHG);
+ if (irq < 0)
+ return dev_err_probe(pf1550->dev, irq,
+ "Failed to get parent vIRQ(%d) for chip %s\n",
+ PF1550_IRQ_CHG, pf1550_irq_chip.name);
+
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_charger_irq_chip,
+ &pf1550->irq_data_charger);
+ if (ret)
+ return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
+ pf1550_charger_irq_chip.name);
+
+ domain = regmap_irq_get_domain(pf1550->irq_data_charger);
+
+ return devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, charger, 1, NULL, 0, domain);
+}
+
+static int pf1550_suspend(struct device *dev)
+{
+ struct pf1550_ddata *pf1550 = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ enable_irq_wake(pf1550->irq);
+ disable_irq(pf1550->irq);
+ }
+
+ return 0;
+}
+
+static int pf1550_resume(struct device *dev)
+{
+ struct pf1550_ddata *pf1550 = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ disable_irq_wake(pf1550->irq);
+ enable_irq(pf1550->irq);
+ }
+
+ return 0;
+}
+static DEFINE_SIMPLE_DEV_PM_OPS(pf1550_pm, pf1550_suspend, pf1550_resume);
+
+static const struct i2c_device_id pf1550_i2c_id[] = {
+ { "pf1550" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, pf1550_i2c_id);
+
+static const struct of_device_id pf1550_dt_match[] = {
+ { .compatible = "nxp,pf1550" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pf1550_dt_match);
+
+static struct i2c_driver pf1550_i2c_driver = {
+ .driver = {
+ .name = "pf1550",
+ .pm = pm_sleep_ptr(&pf1550_pm),
+ .of_match_table = pf1550_dt_match,
+ },
+ .probe = pf1550_i2c_probe,
+ .id_table = pf1550_i2c_id,
+};
+module_i2c_driver(pf1550_i2c_driver);
+
+MODULE_DESCRIPTION("NXP PF1550 core driver");
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/pf1550.h b/include/linux/mfd/pf1550.h
new file mode 100644
index 0000000000000000000000000000000000000000..7cb2340ff2bd92883a709806da58601daaf98a88
--- /dev/null
+++ b/include/linux/mfd/pf1550.h
@@ -0,0 +1,273 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Declarations for the PF1550 PMIC
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#ifndef __LINUX_MFD_PF1550_H
+#define __LINUX_MFD_PF1550_H
+
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+enum pf1550_pmic_reg {
+ /* PMIC regulator part */
+ PF1550_PMIC_REG_DEVICE_ID = 0x00,
+ PF1550_PMIC_REG_OTP_FLAVOR = 0x01,
+ PF1550_PMIC_REG_SILICON_REV = 0x02,
+
+ PF1550_PMIC_REG_INT_CATEGORY = 0x06,
+ PF1550_PMIC_REG_SW_INT_STAT0 = 0x08,
+ PF1550_PMIC_REG_SW_INT_MASK0 = 0x09,
+ PF1550_PMIC_REG_SW_INT_SENSE0 = 0x0a,
+ PF1550_PMIC_REG_SW_INT_STAT1 = 0x0b,
+ PF1550_PMIC_REG_SW_INT_MASK1 = 0x0c,
+ PF1550_PMIC_REG_SW_INT_SENSE1 = 0x0d,
+ PF1550_PMIC_REG_SW_INT_STAT2 = 0x0e,
+ PF1550_PMIC_REG_SW_INT_MASK2 = 0x0f,
+ PF1550_PMIC_REG_SW_INT_SENSE2 = 0x10,
+ PF1550_PMIC_REG_LDO_INT_STAT0 = 0x18,
+ PF1550_PMIC_REG_LDO_INT_MASK0 = 0x19,
+ PF1550_PMIC_REG_LDO_INT_SENSE0 = 0x1a,
+ PF1550_PMIC_REG_TEMP_INT_STAT0 = 0x20,
+ PF1550_PMIC_REG_TEMP_INT_MASK0 = 0x21,
+ PF1550_PMIC_REG_TEMP_INT_SENSE0 = 0x22,
+ PF1550_PMIC_REG_ONKEY_INT_STAT0 = 0x24,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0 = 0x25,
+ PF1550_PMIC_REG_ONKEY_INT_SENSE0 = 0x26,
+ PF1550_PMIC_REG_MISC_INT_STAT0 = 0x28,
+ PF1550_PMIC_REG_MISC_INT_MASK0 = 0x29,
+ PF1550_PMIC_REG_MISC_INT_SENSE0 = 0x2a,
+
+ PF1550_PMIC_REG_COINCELL_CONTROL = 0x30,
+
+ PF1550_PMIC_REG_SW1_VOLT = 0x32,
+ PF1550_PMIC_REG_SW1_STBY_VOLT = 0x33,
+ PF1550_PMIC_REG_SW1_SLP_VOLT = 0x34,
+ PF1550_PMIC_REG_SW1_CTRL = 0x35,
+ PF1550_PMIC_REG_SW1_CTRL1 = 0x36,
+ PF1550_PMIC_REG_SW2_VOLT = 0x38,
+ PF1550_PMIC_REG_SW2_STBY_VOLT = 0x39,
+ PF1550_PMIC_REG_SW2_SLP_VOLT = 0x3a,
+ PF1550_PMIC_REG_SW2_CTRL = 0x3b,
+ PF1550_PMIC_REG_SW2_CTRL1 = 0x3c,
+ PF1550_PMIC_REG_SW3_VOLT = 0x3e,
+ PF1550_PMIC_REG_SW3_STBY_VOLT = 0x3f,
+ PF1550_PMIC_REG_SW3_SLP_VOLT = 0x40,
+ PF1550_PMIC_REG_SW3_CTRL = 0x41,
+ PF1550_PMIC_REG_SW3_CTRL1 = 0x42,
+ PF1550_PMIC_REG_VSNVS_CTRL = 0x48,
+ PF1550_PMIC_REG_VREFDDR_CTRL = 0x4a,
+ PF1550_PMIC_REG_LDO1_VOLT = 0x4c,
+ PF1550_PMIC_REG_LDO1_CTRL = 0x4d,
+ PF1550_PMIC_REG_LDO2_VOLT = 0x4f,
+ PF1550_PMIC_REG_LDO2_CTRL = 0x50,
+ PF1550_PMIC_REG_LDO3_VOLT = 0x52,
+ PF1550_PMIC_REG_LDO3_CTRL = 0x53,
+ PF1550_PMIC_REG_PWRCTRL0 = 0x58,
+ PF1550_PMIC_REG_PWRCTRL1 = 0x59,
+ PF1550_PMIC_REG_PWRCTRL2 = 0x5a,
+ PF1550_PMIC_REG_PWRCTRL3 = 0x5b,
+ PF1550_PMIC_REG_SW1_PWRDN_SEQ = 0x5f,
+ PF1550_PMIC_REG_SW2_PWRDN_SEQ = 0x60,
+ PF1550_PMIC_REG_SW3_PWRDN_SEQ = 0x61,
+ PF1550_PMIC_REG_LDO1_PWRDN_SEQ = 0x62,
+ PF1550_PMIC_REG_LDO2_PWRDN_SEQ = 0x63,
+ PF1550_PMIC_REG_LDO3_PWRDN_SEQ = 0x64,
+ PF1550_PMIC_REG_VREFDDR_PWRDN_SEQ = 0x65,
+
+ PF1550_PMIC_REG_STATE_INFO = 0x67,
+ PF1550_PMIC_REG_I2C_ADDR = 0x68,
+ PF1550_PMIC_REG_IO_DRV0 = 0x69,
+ PF1550_PMIC_REG_IO_DRV1 = 0x6a,
+ PF1550_PMIC_REG_RC_16MHZ = 0x6b,
+ PF1550_PMIC_REG_KEY = 0x6f,
+
+ /* Charger part */
+ PF1550_CHARG_REG_CHG_INT = 0x80,
+ PF1550_CHARG_REG_CHG_INT_MASK = 0x82,
+ PF1550_CHARG_REG_CHG_INT_OK = 0x84,
+ PF1550_CHARG_REG_VBUS_SNS = 0x86,
+ PF1550_CHARG_REG_CHG_SNS = 0x87,
+ PF1550_CHARG_REG_BATT_SNS = 0x88,
+ PF1550_CHARG_REG_CHG_OPER = 0x89,
+ PF1550_CHARG_REG_CHG_TMR = 0x8a,
+ PF1550_CHARG_REG_CHG_EOC_CNFG = 0x8d,
+ PF1550_CHARG_REG_CHG_CURR_CNFG = 0x8e,
+ PF1550_CHARG_REG_BATT_REG = 0x8f,
+ PF1550_CHARG_REG_BATFET_CNFG = 0x91,
+ PF1550_CHARG_REG_THM_REG_CNFG = 0x92,
+ PF1550_CHARG_REG_VBUS_INLIM_CNFG = 0x94,
+ PF1550_CHARG_REG_VBUS_LIN_DPM = 0x95,
+ PF1550_CHARG_REG_USB_PHY_LDO_CNFG = 0x96,
+ PF1550_CHARG_REG_DBNC_DELAY_TIME = 0x98,
+ PF1550_CHARG_REG_CHG_INT_CNFG = 0x99,
+ PF1550_CHARG_REG_THM_ADJ_SETTING = 0x9a,
+ PF1550_CHARG_REG_VBUS2SYS_CNFG = 0x9b,
+ PF1550_CHARG_REG_LED_PWM = 0x9c,
+ PF1550_CHARG_REG_FAULT_BATFET_CNFG = 0x9d,
+ PF1550_CHARG_REG_LED_CNFG = 0x9e,
+ PF1550_CHARG_REG_CHGR_KEY2 = 0x9f,
+
+ PF1550_TEST_REG_FMRADDR = 0xc4,
+ PF1550_TEST_REG_FMRDATA = 0xc5,
+ PF1550_TEST_REG_KEY3 = 0xdf,
+
+ PF1550_PMIC_REG_END = 0xff,
+};
+
+/* One-Time Programmable(OTP) memory */
+enum pf1550_otp_reg {
+ PF1550_OTP_SW1_SW2 = 0x1e,
+ PF1550_OTP_SW2_SW3 = 0x1f,
+};
+
+#define PF1550_DEVICE_ID 0x7c
+
+/* Keys for reading OTP */
+#define PF1550_OTP_PMIC_KEY 0x15
+#define PF1550_OTP_CHGR_KEY 0x50
+#define PF1550_OTP_TEST_KEY 0xab
+
+/* Supported charger modes */
+#define PF1550_CHG_BAT_OFF 1
+#define PF1550_CHG_BAT_ON 2
+
+#define PF1550_CHG_PRECHARGE 0
+#define PF1550_CHG_CONSTANT_CURRENT 1
+#define PF1550_CHG_CONSTANT_VOL 2
+#define PF1550_CHG_EOC 3
+#define PF1550_CHG_DONE 4
+#define PF1550_CHG_TIMER_FAULT 6
+#define PF1550_CHG_SUSPEND 7
+#define PF1550_CHG_OFF_INV 8
+#define PF1550_CHG_BAT_OVER 9
+#define PF1550_CHG_OFF_TEMP 10
+#define PF1550_CHG_LINEAR_ONLY 12
+#define PF1550_CHG_SNS_MASK 0xf
+#define PF1550_CHG_INT_MASK 0x51
+
+#define PF1550_BAT_NO_VBUS 0
+#define PF1550_BAT_LOW_THAN_PRECHARG 1
+#define PF1550_BAT_CHARG_FAIL 2
+#define PF1550_BAT_HIGH_THAN_PRECHARG 4
+#define PF1550_BAT_OVER_VOL 5
+#define PF1550_BAT_NO_DETECT 6
+#define PF1550_BAT_SNS_MASK 0x7
+
+#define PF1550_VBUS_UVLO BIT(2)
+#define PF1550_VBUS_IN2SYS BIT(3)
+#define PF1550_VBUS_OVLO BIT(4)
+#define PF1550_VBUS_VALID BIT(5)
+
+#define PF1550_CHARG_REG_BATT_REG_CHGCV_MASK 0x3f
+#define PF1550_CHARG_REG_BATT_REG_VMINSYS_SHIFT 6
+#define PF1550_CHARG_REG_BATT_REG_VMINSYS_MASK GENMASK(7, 6)
+#define PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_SHIFT 2
+#define PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_MASK GENMASK(3, 2)
+
+#define PF1550_ONKEY_RST_EN BIT(7)
+
+/* DVS enable masks */
+#define OTP_SW1_DVS_ENB BIT(1)
+#define OTP_SW2_DVS_ENB BIT(3)
+
+/* Top level interrupt masks */
+#define IRQ_REGULATOR (BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(6))
+#define IRQ_ONKEY BIT(5)
+#define IRQ_CHG BIT(0)
+
+/* Regulator interrupt masks */
+#define PMIC_IRQ_SW1_LS BIT(0)
+#define PMIC_IRQ_SW2_LS BIT(1)
+#define PMIC_IRQ_SW3_LS BIT(2)
+#define PMIC_IRQ_SW1_HS BIT(0)
+#define PMIC_IRQ_SW2_HS BIT(1)
+#define PMIC_IRQ_SW3_HS BIT(2)
+#define PMIC_IRQ_LDO1_FAULT BIT(0)
+#define PMIC_IRQ_LDO2_FAULT BIT(1)
+#define PMIC_IRQ_LDO3_FAULT BIT(2)
+#define PMIC_IRQ_TEMP_110 BIT(0)
+#define PMIC_IRQ_TEMP_125 BIT(1)
+
+/* Onkey interrupt masks */
+#define ONKEY_IRQ_PUSHI BIT(0)
+#define ONKEY_IRQ_1SI BIT(1)
+#define ONKEY_IRQ_2SI BIT(2)
+#define ONKEY_IRQ_3SI BIT(3)
+#define ONKEY_IRQ_4SI BIT(4)
+#define ONKEY_IRQ_8SI BIT(5)
+
+/* Charger interrupt masks */
+#define CHARG_IRQ_BAT2SOCI BIT(1)
+#define CHARG_IRQ_BATI BIT(2)
+#define CHARG_IRQ_CHGI BIT(3)
+#define CHARG_IRQ_VBUSI BIT(5)
+#define CHARG_IRQ_DPMI BIT(6)
+#define CHARG_IRQ_THMI BIT(7)
+
+enum pf1550_irq {
+ PF1550_IRQ_CHG,
+ PF1550_IRQ_REGULATOR,
+ PF1550_IRQ_ONKEY,
+};
+
+enum pf1550_pmic_irq {
+ PF1550_PMIC_IRQ_SW1_LS,
+ PF1550_PMIC_IRQ_SW2_LS,
+ PF1550_PMIC_IRQ_SW3_LS,
+ PF1550_PMIC_IRQ_SW1_HS,
+ PF1550_PMIC_IRQ_SW2_HS,
+ PF1550_PMIC_IRQ_SW3_HS,
+ PF1550_PMIC_IRQ_LDO1_FAULT,
+ PF1550_PMIC_IRQ_LDO2_FAULT,
+ PF1550_PMIC_IRQ_LDO3_FAULT,
+ PF1550_PMIC_IRQ_TEMP_110,
+ PF1550_PMIC_IRQ_TEMP_125,
+};
+
+enum pf1550_onkey_irq {
+ PF1550_ONKEY_IRQ_PUSHI,
+ PF1550_ONKEY_IRQ_1SI,
+ PF1550_ONKEY_IRQ_2SI,
+ PF1550_ONKEY_IRQ_3SI,
+ PF1550_ONKEY_IRQ_4SI,
+ PF1550_ONKEY_IRQ_8SI,
+};
+
+enum pf1550_charg_irq {
+ PF1550_CHARG_IRQ_BAT2SOCI,
+ PF1550_CHARG_IRQ_BATI,
+ PF1550_CHARG_IRQ_CHGI,
+ PF1550_CHARG_IRQ_VBUSI,
+ PF1550_CHARG_IRQ_THMI,
+};
+
+enum pf1550_regulators {
+ PF1550_SW1,
+ PF1550_SW2,
+ PF1550_SW3,
+ PF1550_VREFDDR,
+ PF1550_LDO1,
+ PF1550_LDO2,
+ PF1550_LDO3,
+};
+
+struct pf1550_ddata {
+ struct regmap_irq_chip_data *irq_data_regulator;
+ struct regmap_irq_chip_data *irq_data_charger;
+ struct regmap_irq_chip_data *irq_data_onkey;
+ struct regmap_irq_chip_data *irq_data;
+ struct regmap *regmap;
+ struct device *dev;
+ bool dvs1_enable;
+ bool dvs2_enable;
+ int irq;
+};
+
+#endif /* __LINUX_MFD_PF1550_H */
--
2.50.1
^ permalink raw reply related
* [PATCH v10 1/6] dt-bindings: mfd: add pf1550
From: Samuel Kayode via B4 Relay @ 2025-08-20 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Krzysztof Kozlowski
In-Reply-To: <20250820-pf1550-v10-0-4c0b6e4445e3@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add a DT binding document for pf1550 PMIC. This describes the core mfd
device along with its children: regulators, charger and onkey.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v10:
- Add regulator-state-mem to examples
v9:
- Add regulator suspend bindings in example
- Add binding for disabling onkey power down
- Fix thermal regulation temperature range
v5:
- Address Krzystof's feedback:
- Drop monitored battery ref already included in power supply schema
- Move `additionalProperties` close to `type` for regulator
- Drop unneccessary |
- Change `additionalProperties` to `unevaluatedProperties` for the
PMIC
v4:
- Address Krzystof's feedback:
- Filename changed to nxp,pf1550.yaml
- Replace Freescale with NXP
- Define include before battery-cell
- Drop operating-range-celsius in example since
nxp,thermal-regulation-celsisus already exists
- Not sure if there is similar binding to thermal-regulation...
for regulating temperature on thermal-zones? @Sebastian and @Krzysztof
v3:
- Address Krzysztof's feedback:
- Fold charger and onkey objects
- Drop compatible for sub-devices: onkey, charger and regulator.
- Drop constant voltage property already included in
monitored-battery
- Fix whitespace warnings
- Fix license
v2:
- Add yamls for the PMIC and the sub-devices
---
.../devicetree/bindings/mfd/nxp,pf1550.yaml | 161 +++++++++++++++++++++
1 file changed, 161 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/nxp,pf1550.yaml b/Documentation/devicetree/bindings/mfd/nxp,pf1550.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e50dc44252c60063463295c5ec3e3c90d1592ec2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/nxp,pf1550.yaml
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/nxp,pf1550.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP PF1550 Power Management IC
+
+maintainers:
+ - Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+
+description:
+ PF1550 PMIC provides battery charging and power supply for low power IoT and
+ wearable applications. This device consists of an i2c controlled MFD that
+ includes regulators, battery charging and an onkey/power button.
+
+$ref: /schemas/power/supply/power-supply.yaml
+
+properties:
+ compatible:
+ const: nxp,pf1550
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ wakeup-source: true
+
+ regulators:
+ type: object
+ additionalProperties: false
+
+ patternProperties:
+ "^(ldo[1-3]|sw[1-3]|vrefddr)$":
+ type: object
+ $ref: /schemas/regulator/regulator.yaml
+ description:
+ regulator configuration for ldo1-3, buck converters(sw1-3)
+ and DDR termination reference voltage (vrefddr)
+ unevaluatedProperties: false
+
+ monitored-battery:
+ description: |
+ A phandle to a monitored battery node that contains a valid value
+ for:
+ constant-charge-voltage-max-microvolt.
+
+ nxp,thermal-regulation-celsius:
+ description:
+ Temperature threshold for thermal regulation of charger in celsius.
+ enum: [ 80, 95, 110, 125 ]
+
+ nxp,min-system-microvolt:
+ description:
+ System specific lower limit voltage.
+ enum: [ 3500000, 3700000, 4300000 ]
+
+ nxp,disable-key-power:
+ type: boolean
+ description:
+ Disable power-down using a long key-press. The onkey driver will remove
+ support for the KEY_POWER key press when triggered using a long press of
+ the onkey.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/input/linux-event-codes.h>
+
+ battery: battery-cell {
+ compatible = "simple-battery";
+ constant-charge-voltage-max-microvolt = <4400000>;
+ };
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmic@8 {
+ compatible = "nxp,pf1550";
+ reg = <0x8>;
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+ wakeup-source;
+ monitored-battery = <&battery>;
+ nxp,min-system-microvolt = <4300000>;
+ nxp,thermal-regulation-celsius = <80>;
+
+ regulators {
+ sw1_reg: sw1 {
+ regulator-name = "sw1";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <1387500>;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-min-microvolt = <1270000>;
+ };
+ };
+
+ sw2_reg: sw2 {
+ regulator-name = "sw2";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <1387500>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ sw3_reg: sw3 {
+ regulator-name = "sw3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vldo1_reg: ldo1 {
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vldo2_reg: ldo2 {
+ regulator-name = "ldo2";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vldo3_reg: ldo3 {
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
+ };
--
2.50.1
^ permalink raw reply related
* [PATCH v10 0/6] add support for pf1550 PMIC MFD-based drivers
From: Samuel Kayode via B4 Relay @ 2025-08-20 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Krzysztof Kozlowski, Frank Li
This series adds support for pf1550 PMIC. It provides the core driver and
sub-drivers for the regulator, power supply and input subsystems.
Patch 1 adds the DT binding document for the PMIC. Patches 2-5 adds the
pertinent drivers. Last patch adds a MAINTAINERS entry for the drivers.
The patches 3-5 depend on the core driver provided in patch 2.
Changes since v1:
- DT bindings for all devices included
- Add onkey driver
- Add driver for the regulators
- Ensure charger is activated as some variants have it off by default
- Update mfd and charger driver per feedback from eballetbo@gmail.com
- Add myself as maintainer for these drivers
- Link to v1: https://lore.kernel.org/1523974819-8711-1-git-send-email-abel.vesa@nxp.com/
Changes since v2:
- Rebase on recent mainline kernel v6.15
- Single yaml file containing dt bindings for all pf1550 devices
- irq mapping done in MFD driver as suggested by Dmitry Torokhov
- Drop unnecessary includes in drivers
- Replace dev_err with dev_err_probe in probe method of drivers
- Drop compatible string from drivers of the sub-devices
- Remove dependency on OF from drivers of the sub-devices
- onkey: move driver from input/keyboard into input/misc
- onkey: remove dependency on OF
- onkey: use onkey virqs instead of central irq
- onkey: fix integer overflow for regmap_write when unmasking
interrupts during pf1550_onkey_resume
- charger: add support for monitored-battery which is used in setting
a constant voltage for the charger.
- Address other feedback from Dmitry Torokhov and Krzysztof Kozlowski
- Link to v2: https://lore.kernel.org/cover.1747409892.git.samuel.kayode@savoirfairelinux.com/
Changes since v3:
- Update manufacturer from Freescale to NXP in compatible,
dt-binding and Kconfigs
- Use C++ style comments for SPDX license in .c code
- Add portions copyright to source code
- irqs are defined as struct resource in mfd cell such that
platform_get_irq is used in the sub-devices
- Make struct pf1550_dev of type const in sub-device driver
- irq variable dropped from sub-device driver struct
- EXPORT_SYMBOL of global pf1550_read_otp function for use in
regulator driver
- Drop unneeded info in driver_data when defining device table id
- regulator: validate ramp_delay
- regulator: report overcurrent and over temperature events
- onkey: drop unnecessary keycode variable
- onkey: change wakeup variable to type bool
- onkey: replace (error < 0) with error in if statement when possible
- onkey: use pm_sleep_ptr when defining driver.pm
- charger: finish handling of some interrupts in threaded irq handler
- Link to v3: https://lore.kernel.org/20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com/
Changes since v4:
- Use top level interrupt to minimize number of registers checked on
each interrupt
- Fix bad offset for temperature interrupts of regulator irq chip
- Address Krzysztof's comments for dt-binding
- regulator: add comments to clarify difference in its interrupts
- regulator: issue warn event for _LS interrupt and error event for
_HS interrupt
- regulator: validate maximum and minimum ramp_delay
- charger: drop lock in battery and charger delayed_work
- charger: more conservative locking for vbus delayed_work
- charger: apply lock when setting power_supply type during register
intialization
- Link to v4: https://lore.kernel.org/r/20250603-pf1550-v4-0-bfdf51ee59cc@savoirfairelinux.com
Changes since v5:
- Ensure lowercase when assigning hex values
- Add imx@lists.linux.dev to relevant mailing list in MAINTAINERS file
- Use GENMASK macro
- Drop unused chips variable
- Read the OTP in the mfd driver probe for new dvs_enb variable
- Hardcode IRQ flags in pf1550_add_child function
- charger: drop the mutex entirely
- charger: reverse christmas tree style local variable definition in
probe
- Link to v5: https://lore.kernel.org/r/20250610-pf1550-v5-0-ed0d9e3aaac7@savoirfairelinux.com
Changes since v6:
- Use reverse christmas tree order
- Drop 0 in table id's driver data
- charger: store virq to avoid reinvoking platform_get_irq in ISR
- Link to v6: https://lore.kernel.org/r/20250611-pf1550-v6-0-34f2ddfe045e@savoirfairelinux.com
Changes since v7:
- Thanks everyone for the reviews
- Use C++ comment only for SPDX license header in core, charger and
onkey drivers
- Drop filenames from comments
- Rename pf1550_dev to pf1550_ddata
- Define OTP register for accessing status of DVS
- core: rename from `mfd driver` to `core driver`
- core: add child devices in a cleaner manner
- charger: define two power supplies: battery and external power
- charger: use devm_delayed_work_autocancel
- Link to v7: https://lore.kernel.org/r/20250612-pf1550-v7-0-0e393b0f45d7@savoirfairelinux.com
Changes since v8:
- Collect Frank's `Reviewed-by` tags
- core: use consistent whitespace
- regulator: add standby support for regulators requested by Sean Nyekjaer
- regulator: add support for SW1 DVS enable/disable
- regulator: fix improper DVS activation
- regulator: add map_voltage for regulators
- regulator: add enable/disable for regulators
- charger: use datasheet thermal regulation temperature ranges
- charger: select charger operation mode based on the application
- onkey: add support for disabling system power down via onkey
- dt-bindings: changed temperature ranges
- dt-bindings: added `disable-key-power`
- Link to v8: https://lore.kernel.org/r/20250707-pf1550-v8-0-6b6eb67c03a0@savoirfairelinux.com
Changes since v9:
- add Sean's Tested-by tag
- core: style changes
- dt-bindings: add regulator-state-mem to examples
- onkey: use regmap_clear_bits to avoid overwriting all bits of the
PWRCTRL register
- Link to v9: https://lore.kernel.org/r/20250716-pf1550-v9-0-502a647f04ef@savoirfairelinux.com
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
Samuel Kayode (6):
dt-bindings: mfd: add pf1550
mfd: pf1550: add core driver
regulator: pf1550: add support for regulator
input: pf1550: add onkey support
power: supply: pf1550: add battery charger support
MAINTAINERS: add an entry for pf1550 mfd driver
.../devicetree/bindings/mfd/nxp,pf1550.yaml | 161 ++++++
MAINTAINERS | 11 +
drivers/input/misc/Kconfig | 11 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/pf1550-onkey.c | 197 +++++++
drivers/mfd/Kconfig | 16 +
drivers/mfd/Makefile | 2 +
drivers/mfd/pf1550.c | 367 ++++++++++++
drivers/power/supply/Kconfig | 11 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/pf1550-charger.c | 636 +++++++++++++++++++++
drivers/regulator/Kconfig | 9 +
drivers/regulator/Makefile | 1 +
drivers/regulator/pf1550-regulator.c | 429 ++++++++++++++
include/linux/mfd/pf1550.h | 273 +++++++++
15 files changed, 2126 insertions(+)
---
base-commit: 0a4b866d08c6adaea2f4592d31edac6deeb4dcbd
change-id: 20250527-pf1550-d401f0d07b80
Best regards,
--
Samuel Kayode <samuel.kayode@savoirfairelinux.com>
^ permalink raw reply
* [PATCH v10 3/6] regulator: pf1550: add support for regulator
From: Samuel Kayode via B4 Relay @ 2025-08-20 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, Dmitry Torokhov, Sebastian Reichel,
Frank Li
Cc: imx, devicetree, linux-kernel, linux-input, linux-pm, Abel Vesa,
Abel Vesa, Robin Gong, Robin Gong, Enric Balletbo i Serra,
Sean Nyekjaer, Christophe JAILLET, Samuel Kayode, Abel Vesa,
Frank Li
In-Reply-To: <20250820-pf1550-v10-0-4c0b6e4445e3@savoirfairelinux.com>
From: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Add regulator support for the pf1550 PMIC.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
---
v10:
- Change dvsX_enb to dvsX_enable
v9:
- Requested by Sean:
- Add support for SW1 DVS enable/disable
- Add support for standby voltages
- Add map_voltage for all configurable regulators
- Add regulator enable/disable for all regulators
- Fix for DVS activation when meant to be disabled
v7:
- Use reverese christmas tree style
- Drop unecessary 0 in id table's driver data
v6:
- Use dvs_enb variable in pf1550_dev as suggested by Frank Li
v5:
- Address Mark's feedback:
- Add comments to clarify difference in interrupts
- Issue warn event for _LS(low side) interrupt
- Validate maximum ramp_delay
v4:
- Address Mark's feedback:
- Use C++ comments for SPDX license
- Add portions copyright to reflect my update
- Validate ramp_delay
- Report overcurrent and temperature events
- Use platform_get_irq
v3:
- Drop duplicate include
- Drop unnecessary includes
- Accept lower case regulator names from devicetree
- Use virqs mapped in core MFD driver
v2:
- Add driver for regulator
---
drivers/regulator/Kconfig | 9 +
drivers/regulator/Makefile | 1 +
drivers/regulator/pf1550-regulator.c | 429 +++++++++++++++++++++++++++++++++++
3 files changed, 439 insertions(+)
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6d8988387da4599633ca9bde2698b9711e34a245..de455887f9aeeada5546e44b8dc9d7ed041618a6 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1049,6 +1049,15 @@ config REGULATOR_PV88090
Say y here to support the voltage regulators and convertors
on PV88090
+config REGULATOR_PF1550
+ tristate "NXP PF1550 regulator"
+ depends on MFD_PF1550
+ help
+ Say y here to select this option to enable the regulators on
+ the PF1550 PMICs.
+ This driver controls the PF1550 regulators via I2C bus.
+ The regulators include three bucks and three ldos.
+
config REGULATOR_PWM
tristate "PWM voltage regulator"
depends on PWM
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index c0bc7a0f4e67098c50ac3cf887ae95f46b2eac44..891174b511fc0653bac662c71659498122e8441f 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -125,6 +125,7 @@ obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o
obj-$(CONFIG_REGULATOR_PF9453) += pf9453-regulator.o
+obj-$(CONFIG_REGULATOR_PF1550) += pf1550-regulator.o
obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
diff --git a/drivers/regulator/pf1550-regulator.c b/drivers/regulator/pf1550-regulator.c
new file mode 100644
index 0000000000000000000000000000000000000000..90492609773886343151c2ba40d2d4bf84c37c5e
--- /dev/null
+++ b/drivers/regulator/pf1550-regulator.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// regulator driver for the PF1550
+//
+// Copyright (C) 2016 Freescale Semiconductor, Inc.
+// Robin Gong <yibin.gong@freescale.com>
+//
+// Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+// Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+//
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define PF1550_REGULATOR_IRQ_NR 11
+#define PF1550_MAX_REGULATOR 7
+
+struct pf1550_desc {
+ struct regulator_desc desc;
+ unsigned char stby_reg;
+ unsigned char stby_mask;
+ unsigned char stby_enable_reg;
+ unsigned char stby_enable_mask;
+};
+
+struct pf1550_regulator_info {
+ struct device *dev;
+ const struct pf1550_ddata *pf1550;
+ struct pf1550_desc regulator_descs[PF1550_MAX_REGULATOR];
+ struct regulator_dev *rdevs[PF1550_MAX_REGULATOR];
+};
+
+static const int pf1550_sw12_volts[] = {
+ 1100000, 1200000, 1350000, 1500000, 1800000, 2500000, 3000000, 3300000,
+};
+
+static const int pf1550_ldo13_volts[] = {
+ 750000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
+ 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+ 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+ 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
+};
+
+static int pf1550_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ int id = rdev_get_id(rdev);
+ unsigned int ramp_bits = 0;
+ int ret;
+
+ if (id > PF1550_VREFDDR)
+ return -EACCES;
+
+ if (ramp_delay < 0 || ramp_delay > 6250)
+ return -EINVAL;
+
+ ramp_delay = 6250 / ramp_delay;
+ ramp_bits = ramp_delay >> 1;
+
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg + 4, 0x10,
+ ramp_bits << 4);
+ if (ret < 0)
+ dev_err(&rdev->dev, "ramp failed, err %d\n", ret);
+
+ return ret;
+}
+
+static int pf1550_set_suspend_enable(struct regulator_dev *rdev)
+{
+ const struct pf1550_desc *desc = container_of(rdev->desc,
+ struct pf1550_desc,
+ desc);
+ unsigned int val = desc->stby_enable_mask;
+
+ return regmap_update_bits(rdev->regmap, desc->stby_enable_reg,
+ desc->stby_enable_mask, val);
+}
+
+static int pf1550_set_suspend_disable(struct regulator_dev *rdev)
+{
+ const struct pf1550_desc *desc = container_of(rdev->desc,
+ struct pf1550_desc,
+ desc);
+
+ return regmap_update_bits(rdev->regmap, desc->stby_enable_reg,
+ desc->stby_enable_mask, 0);
+}
+
+static int pf1550_buck_set_table_suspend_voltage(struct regulator_dev *rdev,
+ int uV)
+{
+ const struct pf1550_desc *desc = container_of(rdev->desc,
+ struct pf1550_desc,
+ desc);
+ int ret;
+
+ ret = regulator_map_voltage_ascend(rdev, uV, uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
+ return ret;
+ }
+
+ return regmap_update_bits(rdev->regmap, desc->stby_reg,
+ desc->stby_mask, ret);
+}
+
+static int pf1550_buck_set_linear_suspend_voltage(struct regulator_dev *rdev,
+ int uV)
+{
+ const struct pf1550_desc *desc = container_of(rdev->desc,
+ struct pf1550_desc,
+ desc);
+ int ret;
+
+ ret = regulator_map_voltage_linear(rdev, uV, uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
+ return ret;
+ }
+
+ return regmap_update_bits(rdev->regmap, desc->stby_reg,
+ desc->stby_mask, ret);
+}
+
+static const struct regulator_ops pf1550_sw1_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_voltage = pf1550_buck_set_table_suspend_voltage,
+ .map_voltage = regulator_map_voltage_ascend,
+ .set_ramp_delay = pf1550_set_ramp_delay,
+};
+
+static const struct regulator_ops pf1550_sw2_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_voltage = pf1550_buck_set_linear_suspend_voltage,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_ramp_delay = pf1550_set_ramp_delay,
+};
+
+static const struct regulator_ops pf1550_ldo1_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static const struct regulator_ops pf1550_ldo2_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .map_voltage = regulator_map_voltage_linear,
+};
+
+static const struct regulator_ops pf1550_fixed_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_suspend_enable = pf1550_set_suspend_enable,
+ .set_suspend_disable = pf1550_set_suspend_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+#define PF_VREF(_chip, match, _name, voltage) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = 1, \
+ .ops = &pf1550_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (voltage), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+#define PF_SW(_chip, match, _name, min, max, mask, step) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pf1550_sw2_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .linear_min_sel = 0, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_reg = _chip ## _PMIC_REG_ ## _name ## _STBY_VOLT, \
+ .stby_mask = (mask), \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+#define PF_LDO1(_chip, match, _name, mask, voltages) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ARRAY_SIZE(voltages), \
+ .ops = &pf1550_ldo1_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .volt_table = voltages, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+#define PF_LDO2(_chip, match, _name, mask, min, max, step) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pf1550_ldo2_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .linear_min_sel = 0, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_enable_mask = 0x2, \
+}
+
+static struct pf1550_desc pf1550_regulators[] = {
+ PF_SW(PF1550, "sw1", SW1, 600000, 1387500, 0x3f, 12500),
+ PF_SW(PF1550, "sw2", SW2, 600000, 1387500, 0x3f, 12500),
+ PF_SW(PF1550, "sw3", SW3, 1800000, 3300000, 0xf, 100000),
+ PF_VREF(PF1550, "vrefddr", VREFDDR, 1200000),
+ PF_LDO1(PF1550, "ldo1", LDO1, 0x1f, pf1550_ldo13_volts),
+ PF_LDO2(PF1550, "ldo2", LDO2, 0xf, 1800000, 3300000, 100000),
+ PF_LDO1(PF1550, "ldo3", LDO3, 0x1f, pf1550_ldo13_volts),
+};
+
+static irqreturn_t pf1550_regulator_irq_handler(int irq, void *data)
+{
+ struct pf1550_regulator_info *info = data;
+ struct device *dev = info->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ int i, irq_type = -1;
+ unsigned int event;
+
+ for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++)
+ if (irq == platform_get_irq(pdev, i))
+ irq_type = i;
+
+ switch (irq_type) {
+ /* The _LS interrupts indicate over-current event. The _HS interrupts
+ * which are more accurate and can detect catastrophic faults, issue
+ * an error event. The current limit FAULT interrupt is similar to the
+ * _HS'
+ */
+ case PF1550_PMIC_IRQ_SW1_LS:
+ case PF1550_PMIC_IRQ_SW2_LS:
+ case PF1550_PMIC_IRQ_SW3_LS:
+ event = REGULATOR_EVENT_OVER_CURRENT_WARN;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ if (!strcmp(rdev_get_name(info->rdevs[i]), "SW3"))
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ case PF1550_PMIC_IRQ_SW1_HS:
+ case PF1550_PMIC_IRQ_SW2_HS:
+ case PF1550_PMIC_IRQ_SW3_HS:
+ event = REGULATOR_EVENT_OVER_CURRENT;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ if (!strcmp(rdev_get_name(info->rdevs[i]), "SW3"))
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ case PF1550_PMIC_IRQ_LDO1_FAULT:
+ case PF1550_PMIC_IRQ_LDO2_FAULT:
+ case PF1550_PMIC_IRQ_LDO3_FAULT:
+ event = REGULATOR_EVENT_OVER_CURRENT;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ if (!strcmp(rdev_get_name(info->rdevs[i]), "LDO3"))
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ case PF1550_PMIC_IRQ_TEMP_110:
+ case PF1550_PMIC_IRQ_TEMP_125:
+ event = REGULATOR_EVENT_OVER_TEMP;
+ for (i = 0; i < PF1550_MAX_REGULATOR; i++)
+ regulator_notifier_call_chain(info->rdevs[i],
+ event, NULL);
+ break;
+ default:
+ dev_err(dev, "regulator interrupt: irq %d occurred\n",
+ irq_type);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pf1550_regulator_probe(struct platform_device *pdev)
+{
+ const struct pf1550_ddata *pf1550 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct pf1550_regulator_info *info;
+ int i, irq = -1, ret = 0;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ config.regmap = dev_get_regmap(pf1550->dev, NULL);
+ if (!config.regmap)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "failed to get parent regmap\n");
+
+ config.dev = pf1550->dev;
+ config.regmap = pf1550->regmap;
+ info->dev = &pdev->dev;
+ info->pf1550 = pf1550;
+
+ memcpy(info->regulator_descs, pf1550_regulators,
+ sizeof(info->regulator_descs));
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_regulators); i++) {
+ struct regulator_desc *desc;
+
+ desc = &info->regulator_descs[i].desc;
+
+ if ((desc->id == PF1550_SW2 && !pf1550->dvs2_enable) ||
+ (desc->id == PF1550_SW1 && !pf1550->dvs1_enable)) {
+ /* OTP_SW2_DVS_ENB == 1? or OTP_SW1_DVS_ENB == 1? */
+ desc->volt_table = pf1550_sw12_volts;
+ desc->n_voltages = ARRAY_SIZE(pf1550_sw12_volts);
+ desc->ops = &pf1550_sw1_ops;
+ }
+
+ info->rdevs[i] = devm_regulator_register(&pdev->dev, desc,
+ &config);
+ if (IS_ERR(info->rdevs[i]))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(info->rdevs[i]),
+ "failed to initialize regulator-%d\n",
+ i);
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ pf1550_regulator_irq_handler,
+ IRQF_NO_SUSPEND,
+ "pf1550-regulator", info);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed: irq request (IRQ: %d)\n",
+ i);
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id pf1550_regulator_id[] = {
+ { "pf1550-regulator", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, pf1550_regulator_id);
+
+static struct platform_driver pf1550_regulator_driver = {
+ .driver = {
+ .name = "pf1550-regulator",
+ },
+ .probe = pf1550_regulator_probe,
+ .id_table = pf1550_regulator_id,
+};
+module_platform_driver(pf1550_regulator_driver);
+
+MODULE_DESCRIPTION("NXP PF1550 regulator driver");
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_LICENSE("GPL");
--
2.50.1
^ permalink raw reply related
* Re: [PATCH v2 1/2] dt-bindings: input: Add Parade TC3408 touchscreen controller
From: Conor Dooley @ 2025-08-20 19:36 UTC (permalink / raw)
To: Langyan Ye
Cc: dmitry.torokhov, robh, krzk+dt, conor+dt, jikos, bentiss,
dianders, linux-input, devicetree, linux-kernel
In-Reply-To: <20250820122520.3356738-2-yelangyan@huaqin.corp-partner.google.com>
[-- Attachment #1: Type: text/plain, Size: 348 bytes --]
On Wed, Aug 20, 2025 at 08:25:19PM +0800, Langyan Ye wrote:
> The tc3408 touch screen chip same as Elan eKTH6915 controller
> has a reset gpio. The difference is that they have different
> post_power_delay_ms.
>
> Signed-off-by: Langyan Ye <yelangyan@huaqin.corp-partner.google.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v1 00/14] MediaTek dt-bindings sanitization (MT8173)
From: Rob Herring (Arm) @ 2025-08-20 18:57 UTC (permalink / raw)
To: Ariel D'Alessandro
Cc: linux-kernel, netdev, jmassot, amergnat, chunkuang.hu, mchehab,
conor+dt, support.opensource, maarten.lankhorst,
angelogioacchino.delregno, linux-arm-kernel, kernel, airlied,
davem, mripard, andrew+netdev, krzk+dt, linus.walleij,
tiffany.lin, linux-media, linux-input, yunfei.dong, kuba,
kyrie.wu, sean.wang, dri-devel, edumazet, flora.fu, minghsiu.tsai,
dmitry.torokhov, jeesw, linux-clk, louisalexis.eyraud,
andrew-ct.chen, p.zabel, devicetree, matthias.bgg, ck.hu, broonie,
linux-gpio, pabeni, lgirdwood, simona, linux-mediatek,
houlong.wei, linux-sound, tzimmermann
In-Reply-To: <20250820171302.324142-1-ariel.dalessandro@collabora.com>
On Wed, 20 Aug 2025 14:12:48 -0300, Ariel D'Alessandro wrote:
> This patch series continues the effort to address Device Tree validation
> warnings for MediaTek platforms, with a focus on MT8173. It follows the initial
> cleanup series by Angelo (https://www.spinics.net/lists/kernel/msg5780177.html)
>
> Similarly to the ongoing MT8183 work done by Julien Massot, this patchset
> eliminates several of the remaining warnings by improving or converting DT
> bindings to YAML, adding missing properties, and updating device tree files
> accordingly.
>
> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
>
> Ariel D'Alessandro (14):
> media: dt-bindings: Convert MediaTek mt8173-mdp bindings to YAML
> media: dt-bindings: Convert MediaTek mt8173-vpu bindings to YAML
> dt-bindings: arm: mediatek: mmsys: Add assigned-clocks/rates
> properties
> net: dt-bindings: Convert Marvell 8897/8997 bindings to YAML
> sound: dt-bindings: Convert MediaTek RT5650 codecs bindings to YAML
> dt-bindings: display: mediatek,od: Add mediatek,gce-client-reg
> property
> dt-bindings: display: mediatek,ufoe: Add mediatek,gce-client-reg
> property
> arm64: dts: mediatek: mt8173: Fix mt8173-pinctrl node names
> dt-bindings: pinctrl: mediatek,mt65xx-pinctrl: Allow gpio-line-names
> regulator: dt-bindings: Convert Dialog Semiconductor DA9211 Regulators
> to YAML
> arm64: dts: mediatek: mt8173-elm: Drop unused bank supply
> dt-bindings: soc: mediatek: pwrap: Add power-domains property
> dt-bindings: input/touchscreen: Convert MELFAS MIP4 Touchscreen to
> YAML
> dt-bindings: media: mediatek,jpeg: Fix jpeg encoder/decoder ranges
>
> .../bindings/arm/mediatek/mediatek,mmsys.yaml | 9 +
> .../display/mediatek/mediatek,od.yaml | 10 +
> .../display/mediatek/mediatek,ufoe.yaml | 11 +
> .../input/touchscreen/melfas,mip4_ts.yaml | 55 +++++
> .../input/touchscreen/melfas_mip4.txt | 20 --
> .../bindings/media/mediatek,mt8173-mdp.yaml | 174 +++++++++++++++
> .../bindings/media/mediatek,mt8173-vpu.yaml | 76 +++++++
> .../media/mediatek,mt8195-jpegdec.yaml | 31 +--
> .../media/mediatek,mt8195-jpegenc.yaml | 15 +-
> .../bindings/media/mediatek-mdp.txt | 95 --------
> .../bindings/media/mediatek-vpu.txt | 31 ---
> .../bindings/net/marvell,sd8897-bt.yaml | 91 ++++++++
> .../bindings/net/marvell-bt-8xxx.txt | 83 -------
> .../pinctrl/mediatek,mt65xx-pinctrl.yaml | 2 +
> .../devicetree/bindings/regulator/da9211.txt | 205 ------------------
> .../bindings/regulator/dlg,da9211.yaml | 104 +++++++++
> .../bindings/soc/mediatek/mediatek,pwrap.yaml | 15 ++
> .../sound/mediatek,mt8173-rt5650.yaml | 73 +++++++
> .../bindings/sound/mt8173-rt5650.txt | 31 ---
> .../boot/dts/mediatek/mt8173-elm-hana.dtsi | 2 +-
> arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi | 31 ++-
> arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 14 +-
> arch/arm64/boot/dts/mediatek/mt8173.dtsi | 14 +-
> 23 files changed, 672 insertions(+), 520 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml
> delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
> create mode 100644 Documentation/devicetree/bindings/media/mediatek,mt8173-mdp.yaml
> create mode 100644 Documentation/devicetree/bindings/media/mediatek,mt8173-vpu.yaml
> delete mode 100644 Documentation/devicetree/bindings/media/mediatek-mdp.txt
> delete mode 100644 Documentation/devicetree/bindings/media/mediatek-vpu.txt
> create mode 100644 Documentation/devicetree/bindings/net/marvell,sd8897-bt.yaml
> delete mode 100644 Documentation/devicetree/bindings/net/marvell-bt-8xxx.txt
> delete mode 100644 Documentation/devicetree/bindings/regulator/da9211.txt
> create mode 100644 Documentation/devicetree/bindings/regulator/dlg,da9211.yaml
> create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt8173-rt5650.yaml
> delete mode 100644 Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
>
> --
> 2.50.1
>
>
>
My bot found new DTB warnings on the .dts files added or changed in this
series.
Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.
If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:
pip3 install dtschema --upgrade
This patch series was applied (using b4) to base:
Base: attempting to guess base-commit...
Base: tags/next-20250820 (exact match)
If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)
New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/mediatek/' for 20250820171302.324142-1-ariel.dalessandro@collabora.com:
arch/arm64/boot/dts/mediatek/mt8173-evb.dtb: da9211@68 (dlg,da9211): 'oneOf' conditional failed, one must be fixed:
'interrupts' is a required property
'interrupts-extended' is a required property
from schema $id: http://devicetree.org/schemas/regulator/dlg,da9211.yaml#
arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dtb: jpgdec-master (mediatek,mt8195-jpgdec): 'jpgdec@1a040000', 'jpgdec@1a050000', 'jpgdec@1b040000' do not match any of the regexes: '^jpgdec@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dtb: jpgenc-master (mediatek,mt8195-jpgenc): 'jpgenc@1a030000', 'jpgenc@1b030000' do not match any of the regexes: '^jpgenc@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dtb: jpgdec-master (mediatek,mt8195-jpgdec): 'jpgdec@1a040000', 'jpgdec@1a050000', 'jpgdec@1b040000' do not match any of the regexes: '^jpgdec@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dtb: jpgenc-master (mediatek,mt8195-jpgenc): 'jpgenc@1a030000', 'jpgenc@1b030000' do not match any of the regexes: '^jpgenc@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
arch/arm64/boot/dts/mediatek/mt8395-kontron-3-5-sbc-i1200.dtb: jpgdec-master (mediatek,mt8195-jpgdec): 'jpgdec@1a040000', 'jpgdec@1a050000', 'jpgdec@1b040000' do not match any of the regexes: '^jpgdec@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
arch/arm64/boot/dts/mediatek/mt8395-kontron-3-5-sbc-i1200.dtb: jpgenc-master (mediatek,mt8195-jpgenc): 'jpgenc@1a030000', 'jpgenc@1b030000' do not match any of the regexes: '^jpgenc@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
arch/arm64/boot/dts/mediatek/mt8195-demo.dtb: jpgdec-master (mediatek,mt8195-jpgdec): 'jpgdec@1a040000', 'jpgdec@1a050000', 'jpgdec@1b040000' do not match any of the regexes: '^jpgdec@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
arch/arm64/boot/dts/mediatek/mt8195-demo.dtb: jpgenc-master (mediatek,mt8195-jpgenc): 'jpgenc@1a030000', 'jpgenc@1b030000' do not match any of the regexes: '^jpgenc@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dtb: jpgdec-master (mediatek,mt8195-jpgdec): 'jpgdec@1a040000', 'jpgdec@1a050000', 'jpgdec@1b040000' do not match any of the regexes: '^jpgdec@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dtb: jpgenc-master (mediatek,mt8195-jpgenc): 'jpgenc@1a030000', 'jpgenc@1b030000' do not match any of the regexes: '^jpgenc@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
arch/arm64/boot/dts/mediatek/mt8195-evb.dtb: jpgdec-master (mediatek,mt8195-jpgdec): 'jpgdec@1a040000', 'jpgdec@1a050000', 'jpgdec@1b040000' do not match any of the regexes: '^jpgdec@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
arch/arm64/boot/dts/mediatek/mt8195-evb.dtb: jpgenc-master (mediatek,mt8195-jpgenc): 'jpgenc@1a030000', 'jpgenc@1b030000' do not match any of the regexes: '^jpgenc@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
arch/arm64/boot/dts/mediatek/mt8195-cherry-dojo-r1.dtb: jpgdec-master (mediatek,mt8195-jpgdec): 'jpgdec@1a040000', 'jpgdec@1a050000', 'jpgdec@1b040000' do not match any of the regexes: '^jpgdec@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
arch/arm64/boot/dts/mediatek/mt8195-cherry-dojo-r1.dtb: jpgenc-master (mediatek,mt8195-jpgenc): 'jpgenc@1a030000', 'jpgenc@1b030000' do not match any of the regexes: '^jpgenc@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku32.dtb: pinctrl@10005000 (mediatek,mt8183-pinctrl): mmc1-pins-uhs:pins-clk:mediatek,pull-down-adv: 10 is not one of [0, 1, 2, 3]
from schema $id: http://devicetree.org/schemas/pinctrl/mediatek,mt8183-pinctrl.yaml#
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dtb: jpgdec-master (mediatek,mt8195-jpgdec): 'jpgdec@1a040000', 'jpgdec@1a050000', 'jpgdec@1b040000' do not match any of the regexes: '^jpgdec@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dtb: jpgenc-master (mediatek,mt8195-jpgenc): 'jpgenc@1a030000', 'jpgenc@1b030000' do not match any of the regexes: '^jpgenc@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dtb: jpgdec-master (mediatek,mt8195-jpgdec): 'jpgdec@1a040000', 'jpgdec@1a050000', 'jpgdec@1b040000' do not match any of the regexes: '^jpgdec@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegdec.yaml#
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dtb: jpgenc-master (mediatek,mt8195-jpgenc): 'jpgenc@1a030000', 'jpgenc@1b030000' do not match any of the regexes: '^jpgenc@[0-9],[0-9a-f]+$', '^pinctrl-[0-9]+$'
from schema $id: http://devicetree.org/schemas/media/mediatek,mt8195-jpegenc.yaml#
^ permalink raw reply
* Re: [PATCH v1 14/14] dt-bindings: media: mediatek,jpeg: Fix jpeg encoder/decoder ranges
From: Rob Herring @ 2025-08-20 18:55 UTC (permalink / raw)
To: Ariel D'Alessandro
Cc: airlied, amergnat, andrew+netdev, andrew-ct.chen,
angelogioacchino.delregno, broonie, chunkuang.hu, ck.hu, conor+dt,
davem, dmitry.torokhov, edumazet, flora.fu, houlong.wei, jeesw,
jmassot, kernel, krzk+dt, kuba, kyrie.wu, lgirdwood,
linus.walleij, louisalexis.eyraud, maarten.lankhorst,
matthias.bgg, mchehab, minghsiu.tsai, mripard, p.zabel, pabeni,
sean.wang, simona, support.opensource, tiffany.lin, tzimmermann,
yunfei.dong, devicetree, dri-devel, linux-arm-kernel, linux-clk,
linux-gpio, linux-input, linux-kernel, linux-media,
linux-mediatek, linux-sound, netdev
In-Reply-To: <20250820171302.324142-15-ariel.dalessandro@collabora.com>
On Wed, Aug 20, 2025 at 02:13:02PM -0300, Ariel D'Alessandro wrote:
> Commit 14176e94bb35d ("arm64: dts: mediatek: mt8195: Fix ranges for jpeg
That commit is not in any upstream tree.
> enc/decoder nodes") redefined jpeg encoder/decoder children node ranges.
> Update the related device tree binding yaml definition to match
> mediatek/mt8195.dtsi, as this is currently the only one using it.
>
> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
> ---
> .../media/mediatek,mt8195-jpegdec.yaml | 31 ++++++++++---------
> .../media/mediatek,mt8195-jpegenc.yaml | 15 ++++-----
> 2 files changed, 24 insertions(+), 22 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml
> index e5448c60e3eb5..b1f3df258dc87 100644
> --- a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml
> +++ b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml
> @@ -36,7 +36,7 @@ properties:
>
> # Required child node:
> patternProperties:
> - "^jpgdec@[0-9a-f]+$":
> + "^jpgdec@[0-9],[0-9a-f]+$":
This is wrong unless 0-9 is a separate, distinct address (like a chip
select #).
Rob
^ permalink raw reply
* Re: [PATCH] HID: logitech: Add ids for G PRO 2 LIGHTSPEED
From: Jiri Kosina @ 2025-08-20 18:13 UTC (permalink / raw)
To: Matt Coffin
Cc: linux-input, Benjamin Tissoires, Filipe Laíns,
Bastien Nocera, linux-kernel
In-Reply-To: <20250820074951.1120397-1-mcoffin13@gmail.com>
On Wed, 20 Aug 2025, Matt Coffin wrote:
> Adds support for the G PRO 2 LIGHTSPEED Wireless via it's nano receiver
> or directly. This nano receiver appears to work identically to the 1_1
> receiver for the case I've verified, which is the battery status through
> lg-hidpp.
>
> The same appears to be the case wired, sharing much with the Pro X
> Superlight 2; differences seemed to lie in userland configuration rather
> than in interfaces used by hid_logitech_hidpp on the kernel side.
>
> I verified the sysfs interface for battery charge/discharge status, and
> capacity read to be working on my 910-007290 device (white).
>
> Signed-off-by: Matt Coffin <mcoffin13@gmail.com>
> ---
> drivers/hid/hid-ids.h | 1 +
> drivers/hid/hid-logitech-dj.c | 4 ++++
> drivers/hid/hid-logitech-hidpp.c | 2 ++
> 3 files changed, 7 insertions(+)
>
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index 5a1096283855..37dc42380373 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -907,6 +907,7 @@
> #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534
> #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539
> #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f
> +#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2 0xc543
> #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
> #define USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER 0xc548
> #define USB_DEVICE_ID_SPACETRAVELLER 0xc623
> diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
> index 34fa71ceec2b..cce54dd9884a 100644
> --- a/drivers/hid/hid-logitech-dj.c
> +++ b/drivers/hid/hid-logitech-dj.c
> @@ -1983,6 +1983,10 @@ static const struct hid_device_id logi_dj_receivers[] = {
> HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
> USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1),
> .driver_data = recvr_type_gaming_hidpp},
> + { /* Logitech lightspeed receiver (0xc543) */
> + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
> + USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2),
> + .driver_data = recvr_type_gaming_hidpp},
>
> { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
> HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> index 10a3bc5f931b..aaef405a717e 100644
> --- a/drivers/hid/hid-logitech-hidpp.c
> +++ b/drivers/hid/hid-logitech-hidpp.c
> @@ -4596,6 +4596,8 @@ static const struct hid_device_id hidpp_devices[] = {
> HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) },
> { /* Logitech G Pro X Superlight 2 Gaming Mouse over USB */
> HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC09b) },
> + { /* Logitech G PRO 2 LIGHTSPEED Wireless Mouse over USB */
> + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xc09a) },
>
> { /* G935 Gaming Headset */
> HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0x0a87),
Applied to hid.git#for-6.17/upstream-fixes, thanks.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH v5] platform/x86: Add WMI driver for Redmibook keyboard.
From: Gladyshev Ilya @ 2025-08-20 18:10 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: Armin Wolf, linux-input, Hans de Goede, LKML, platform-driver-x86
In-Reply-To: <0ed8cf19-09cc-52cd-bc55-bf3f5d9e0c33@linux.intel.com>
[resend because I forgot to Cc mailing list... sorry]
On 8/19/25 13:22, Ilpo Järvinen wrote:
>> +
>> + payload = get_unaligned_le32(obj->buffer.pointer);
>> + struct key_entry *entry =
sparse_keymap_entry_from_scancode(data->input_dev, payload);
>
> Please only define variables at the beginning of some block (in this
case,
> at the beginning of the function).
>
> The only exception to this rule are cleanup.h related variables which may
> have to be defined mid-function to ensure the correct teardown order of
> the auto variables.
Oh, sorry, was blinded by a same mistake on another line in a hurry...
Fixed in v6 [1].
By the way, shouldn't it be some checkpatch.pl warning in the ideal
world? Just sounds like a "why not" task to do in my spare time, so I'd
like to clarify in advance)
[1] --
https://lore.kernel.org/platform-driver-x86/20250820174140.41410-1-foxido@foxido.dev/
--
Gladyshev Ilya
^ permalink raw reply
* Re: [PATCH v3 1/2] HID: input: rename hidinput_set_battery_charge_status()
From: Jiri Kosina @ 2025-08-20 18:04 UTC (permalink / raw)
To: José Expósito; +Cc: bentiss, luguohong, linux-input, linux-kernel
In-Reply-To: <20250814103947.116139-1-jose.exposito89@gmail.com>
José,
both patches now queued in hid.git#for-6.17/upstream-fixes. Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* [PATCH v6] platform/x86: Add WMI driver for Redmibook keyboard.
From: Gladyshev Ilya @ 2025-08-20 17:41 UTC (permalink / raw)
To: foxido
Cc: w_armin, linux-input, nikita.nikita.krasnov, Armin Wolf,
Hans de Goede, Ilpo Järvinen, linux-kernel,
platform-driver-x86
This driver implements support for various Fn keys (like Cut) and Xiaomi
specific AI button.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Gladyshev Ilya <foxido@foxido.dev>
---
Changes since v5:
- Fix var declaration in the middle of the func
Link to v5: https://lore.kernel.org/platform-driver-x86/20250813153137.18355-1-foxido@foxido.dev/
---
MAINTAINERS | 6 ++
drivers/platform/x86/Kconfig | 12 +++
drivers/platform/x86/Makefile | 1 +
drivers/platform/x86/redmi-wmi.c | 129 +++++++++++++++++++++++++++++++
4 files changed, 148 insertions(+)
create mode 100644 drivers/platform/x86/redmi-wmi.c
diff --git a/MAINTAINERS b/MAINTAINERS
index c0b444e5fd5a..eb25fb10e751 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20965,6 +20965,12 @@ S: Maintained
T: git https://github.com/pkshih/rtw.git
F: drivers/net/wireless/realtek/rtw89/
+REDMIBOOK WMI DRIVERS
+M: Gladyshev Ilya <foxido@foxido.dev>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: drivers/platform/x86/redmi-wmi.c
+
REDPINE WIRELESS DRIVER
L: linux-wireless@vger.kernel.org
S: Orphan
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index e5cbd58a99f3..9f98a7042e43 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -109,6 +109,18 @@ config XIAOMI_WMI
To compile this driver as a module, choose M here: the module will
be called xiaomi-wmi.
+config REDMI_WMI
+ tristate "Redmibook WMI key driver"
+ depends on ACPI_WMI
+ depends on INPUT
+ select INPUT_SPARSEKMAP
+ help
+ Say Y here if you want support for WMI-based hotkey events on
+ Xiaomi Redmibook devices.
+
+ To compile this driver as a module, choose M here: the module will
+ be called redmi-wmi.
+
config GIGABYTE_WMI
tristate "Gigabyte WMI temperature driver"
depends on ACPI_WMI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index bea87a85ae75..406dd0807ba7 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_HUAWEI_WMI) += huawei-wmi.o
obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
obj-$(CONFIG_NVIDIA_WMI_EC_BACKLIGHT) += nvidia-wmi-ec-backlight.o
obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o
+obj-$(CONFIG_REDMI_WMI) += redmi-wmi.o
obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o
# Acer
diff --git a/drivers/platform/x86/redmi-wmi.c b/drivers/platform/x86/redmi-wmi.c
new file mode 100644
index 000000000000..cb9f4e639acd
--- /dev/null
+++ b/drivers/platform/x86/redmi-wmi.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+/* WMI driver for Xiaomi Redmibooks */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/unaligned.h>
+#include <linux/wmi.h>
+
+#include <uapi/linux/input-event-codes.h>
+
+#define WMI_REDMIBOOK_KEYBOARD_EVENT_GUID "46C93E13-EE9B-4262-8488-563BCA757FEF"
+
+#define AI_KEY_VALUE_MASK 0x00000100
+
+static const struct key_entry redmi_wmi_keymap[] = {
+ {KE_KEY, 0x00000201, {KEY_SELECTIVE_SCREENSHOT}},
+ {KE_KEY, 0x00000301, {KEY_ALL_APPLICATIONS}},
+ {KE_KEY, 0x00001b01, {KEY_SETUP}},
+
+ /* AI button has code for each position */
+ {KE_KEY, 0x00011801, {KEY_ASSISTANT}},
+ {KE_KEY, 0x00011901, {KEY_ASSISTANT}},
+
+ /* Keyboard backlight */
+ {KE_IGNORE, 0x00000501, {}},
+ {KE_IGNORE, 0x00800501, {}},
+ {KE_IGNORE, 0x00050501, {}},
+ {KE_IGNORE, 0x000a0501, {}},
+
+ {KE_END}
+};
+
+struct redmi_wmi {
+ struct input_dev *input_dev;
+ /* Protects the key event sequence */
+ struct mutex key_lock;
+};
+
+static int redmi_wmi_probe(struct wmi_device *wdev, const void *context)
+{
+ struct redmi_wmi *data;
+ int err;
+
+ /* Init dev */
+ data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ dev_set_drvdata(&wdev->dev, data);
+
+ err = devm_mutex_init(&wdev->dev, &data->key_lock);
+ if (err)
+ return err;
+
+ data->input_dev = devm_input_allocate_device(&wdev->dev);
+ if (!data->input_dev)
+ return -ENOMEM;
+
+ data->input_dev->name = "Redmibook WMI keys";
+ data->input_dev->phys = "wmi/input0";
+
+ err = sparse_keymap_setup(data->input_dev, redmi_wmi_keymap, NULL);
+ if (err)
+ return err;
+
+ return input_register_device(data->input_dev);
+}
+
+static void redmi_wmi_notify(struct wmi_device *wdev, union acpi_object *obj)
+{
+ struct key_entry *entry;
+ struct redmi_wmi *data = dev_get_drvdata(&wdev->dev);
+ bool autorelease = true;
+ u32 payload;
+ int value = 1;
+
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ dev_err(&wdev->dev, "Bad response type %u\n", obj->type);
+ return;
+ }
+
+ if (obj->buffer.length < 32) {
+ dev_err(&wdev->dev, "Invalid buffer length %u\n", obj->buffer.length);
+ return;
+ }
+
+ payload = get_unaligned_le32(obj->buffer.pointer);
+ entry = sparse_keymap_entry_from_scancode(data->input_dev, payload);
+
+ if (!entry) {
+ dev_dbg(&wdev->dev, "Unknown WMI event with payload %u", payload);
+ return;
+ }
+
+ /* AI key quirk */
+ if (entry->keycode == KEY_ASSISTANT) {
+ value = !(payload & AI_KEY_VALUE_MASK);
+ autorelease = false;
+ }
+
+ guard(mutex)(&data->key_lock);
+ sparse_keymap_report_entry(data->input_dev, entry, value, autorelease);
+}
+
+static const struct wmi_device_id redmi_wmi_id_table[] = {
+ { WMI_REDMIBOOK_KEYBOARD_EVENT_GUID, NULL },
+ { }
+};
+
+static struct wmi_driver redmi_wmi_driver = {
+ .driver = {
+ .name = "redmi-wmi",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .id_table = redmi_wmi_id_table,
+ .probe = redmi_wmi_probe,
+ .notify = redmi_wmi_notify,
+ .no_singleton = true,
+};
+module_wmi_driver(redmi_wmi_driver);
+
+MODULE_DEVICE_TABLE(wmi, redmi_wmi_id_table);
+MODULE_AUTHOR("Gladyshev Ilya <foxido@foxido.dev>");
+MODULE_DESCRIPTION("Redmibook WMI driver");
+MODULE_LICENSE("GPL");
--
2.50.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox