Linux Input/HID development
 help / color / mirror / Atom feed
* Re: [PATCH 1/2] dt-bindings: input: add adi,max16150.yaml
From: Krzysztof Kozlowski @ 2026-02-23 17:01 UTC (permalink / raw)
  To: marcpaolo.sosa, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-input, devicetree, linux-kernel
In-Reply-To: <20260223-max16150-v1-1-38e2a4f0d0f1@analog.com>

On 23/02/2026 12:03, Marc Paolo Sosa via B4 Relay wrote:
> +
> +properties:
> +  compatible:
> +    description:
> +      Specifies the supported device variants. The MAX16150 and MAX16169 are supported.
> +    enum:
> +      - adi,max16150a
> +      - adi,max16150b
> +      - adi,max16169a
> +      - adi,max16169b

Your driver code says 16150 and 16169 are compatible, to express it with
fallback (oneOf). See example-schema.

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: input: add adi,max16150.yaml
From: Rob Herring @ 2026-02-23 16:50 UTC (permalink / raw)
  To: Marc Paolo Sosa
  Cc: Dmitry Torokhov, Krzysztof Kozlowski, Conor Dooley, linux-input,
	devicetree, linux-kernel
In-Reply-To: <20260223-max16150-v1-1-38e2a4f0d0f1@analog.com>

On Mon, Feb 23, 2026 at 07:03:39PM +0800, Marc Paolo Sosa wrote:
> Add documentation for device tree bindings for MAX16150/MAX16169
> 
> Signed-off-by: Marc Paolo Sosa <marcpaolo.sosa@analog.com>
> ---
>  .../devicetree/bindings/input/adi,max16150.yaml    | 57 ++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/input/adi,max16150.yaml b/Documentation/devicetree/bindings/input/adi,max16150.yaml
> new file mode 100644
> index 000000000000..327811e1ebd4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/adi,max16150.yaml
> @@ -0,0 +1,57 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/input/adi,max16150.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Analog Devices MAX16150/MAX16169 nanoPower Pushbutton On/Off Controller
> +
> +maintainers:
> +  - Marc Paolo Sosa <marcpaolo.sosa@analog.com>
> +
> +description:
> +  The MAX16150/MAX16169 is a low-power pushbutton on/off controller with a
> +  switch debouncer and built-in latch. It accepts a noisy input from a
> +  mechanical switch and produces a clean latched output, as well as a one-shot
> +  interrupt output.
> +
> +properties:
> +  compatible:
> +    description:
> +      Specifies the supported device variants. The MAX16150 and MAX16169 are supported.

Drop description.

> +    enum:
> +      - adi,max16150a
> +      - adi,max16150b
> +      - adi,max16169a
> +      - adi,max16169b

What's the diff between a and b? If nothing s/w needs to know about, 
then maybe you don't need to distinguish. 

> +
> +  interrupt-gpio:
> +    maxItems: 1

Use 'interrupts' property.

> +
> +  clr-gpios:
> +    description:
> +      Clear Input. Pulling CLR low deasserts the latched OUT signal. If OUT is
> +      already deasserted when CLR is pulled low, the state of OUT is unchanged.
> +    maxItems: 1
> +
> +  linux,code:
> +    default: KEY_POWER
> +
> +required:
> +  - compatible
> +  - interrupt-gpios
> +  - clr-gpios
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/input/linux-event-codes.h>
> +    #include <dt-bindings/gpio/gpio.h>
> +
> +    power-button {
> +        compatible = "adi,max16150a";
> +        interrupt-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
> +        clr-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
> +        linux,code = <KEY_POWER>;
> +    };
> 
> -- 
> 2.34.1
> 

^ permalink raw reply

* Re: [PATCH v3 5/9] dt-bindings: input: cpcap-pwrbutton: convert to DT schema
From: Rob Herring (Arm) @ 2026-02-23 16:46 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Pavel Machek, Conor Dooley, Dmitry Torokhov, devicetree,
	David Lechner, linux-input, Krzysztof Kozlowski, Lee Jones,
	Mark Brown, Tony Lindgren, linux-kernel, Liam Girdwood,
	linux-leds
In-Reply-To: <20260223063858.12208-6-clamor95@gmail.com>


On Mon, 23 Feb 2026 08:38:54 +0200, Svyatoslav Ryhel wrote:
> Convert power button devicetree bindings for the Motorola CPCAP MFD from
> TXT to YAML format. This patch does not change any functionality; the
> bindings remain the same.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../bindings/input/cpcap-pwrbutton.txt        | 20 ------------
>  .../input/motorola,cpcap-pwrbutton.yaml       | 32 +++++++++++++++++++
>  2 files changed, 32 insertions(+), 20 deletions(-)
>  delete mode 100644 Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
>  create mode 100644 Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml
> 

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>


^ permalink raw reply

* Re: [PATCH 0/37] PCI/MSI: Enforce explicit IRQ vector management by removing devres auto-free
From: Shawn Lin @ 2026-02-23 16:09 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: shawn.lin, Bjorn Helgaas, Vaibhaav Ram T . L,
	Kumaravel Thiagarajan, Even Xu, Xinpeng Sun, Srinivas Pandruvada,
	Jiri Kosina, Alexandre Belloni, Zhou Wang, Longfang Liu,
	Vinod Koul, Lee Jones, Jijie Shao, Jian Shen, Sunil Goutham,
	Andrew Lunn, Heiner Kallweit, David S . Miller, Jeff Hugo,
	Oded Gabbay, Maciej Falkowski, Karol Wachowski, Min Ma, Lizhi Hou,
	Andreas Noever, Mika Westerberg, Tomasz Jeznach, Will Deacon,
	Xinliang Liu, Tian Tao, Davidlohr Bueso, Jonathan Cameron,
	Srujana Challa, Bharat Bhushan, Antoine Tenart, Herbert Xu,
	Raag Jadav, Hans de Goede, Greg Kroah-Hartman, Jiri Slaby,
	Andy Shevchenko, Manivannan Sadhasivam, Mika Westerberg,
	Andi Shyti, Robert Richter, Mark Brown, Nirmal Patel,
	Kurt Schwemmer, Logan Gunthorpe, Linus Walleij,
	Bartosz Golaszewski, Sakari Ailus, Bingbu Cao, Ulf Hansson,
	Arnd Bergmann, Benjamin Tissoires, linux-input, linux-i3c,
	dmaengine, Philipp Stanner, netdev, nic_swsd, linux-arm-msm,
	dri-devel, linux-usb, iommu, linux-riscv, David Airlie,
	Simona Vetter, linux-cxl, linux-crypto, platform-driver-x86,
	linux-serial, mhi, Andy Shevchenko, Jan Dabros, linux-i2c,
	Daniel Mack, Haojian Zhuang, linux-spi, Jonathan Derrick,
	linux-pci, linux-gpio, Mauro Carvalho Chehab, linux-media,
	linux-mmc
In-Reply-To: <CAHp75VeWD5A0r7-Uayyte1ZXXxdhLixd+z_y0xNeki0N+Ro=jQ@mail.gmail.com>

Hi Andy

在 2026/02/23 星期一 23:50, Andy Shevchenko 写道:
> On Mon, Feb 23, 2026 at 5:32 PM Shawn Lin <shawn.lin@rock-chips.com> wrote:
>>
>> This patch series addresses a long-standing design issue in the PCI/MSI
>> subsystem where the implicit, automatic management of IRQ vectors by
>> the devres framework conflicts with explicit driver cleanup, creating
>> ambiguity and potential resource management bugs.
>>
>> ==== The Problem: Implicit vs. Explicit Management ====
>> Historically, `pcim_enable_device()` not only manages standard PCI resources
>> (BARs) via devres but also implicitly triggers automatic IRQ vector management
>> by setting a flag that registers `pcim_msi_release()` as a cleanup action.
>>
>> This creates an ambiguous ownership model. Many drivers follow a pattern of:
>> 1. Calling `pci_alloc_irq_vectors()` to allocate interrupts.
>> 2. Also calling `pci_free_irq_vectors()` in their error paths or remove routines.
>>
>> When such a driver also uses `pcim_enable_device()`, the devres framework may
>> attempt to free the IRQ vectors a second time upon device release, leading to
>> a double-free. Analysis of the tree shows this hazardous pattern exists widely,
>> while 35 other drivers correctly rely solely on the implicit cleanup.
> 
> Is this confirmed? What I read from the cover letter, this series was
> only compile-tested, so how can you prove the problem exists in the
> first place?

Yes, it's confirmed. My debug of a double free issue of a out-of-tree
PCIe wifi driver which uses
pcim_enable_device + pci_alloc_irq_vectors + pci_free_irq_vectors expose
it. And we did have a TODO to cleanup this hybrid usage, targeted in
this cycle[1] suggested by Philipp:

[1] https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/log/?h=msi

> 
>> ==== The Solution: Making Management Explicit ====
>> This series enforces a clear, predictable model:
>> 1.  New Managed API (Patch 1/37): Introduces pcim_alloc_irq_vectors() and
>>      pcim_alloc_irq_vectors_affinity(). Drivers that desire devres-managed IRQ
>>      vectors should use these functions, which set the is_msi_managed flag and
>>      ensure automatic cleanup.
>> 2.  Patches 2 through 36 convert each driver that uses pcim_enable_device() alongside
>>      pci_alloc_irq_vectors() and relies on devres for IRQ vector cleanup to instead
>>      make an explicit call to pcim_alloc_irq_vectors().
>> 3.  Core Change (Patch 37/37): With the former cleanup, now modifies pcim_setup_msi_release()
>>      to check only the is_msi_managed flag. This decouples automatic IRQ cleanup from
>>      pcim_enable_device(). IRQ vectors allocated via pci_alloc_irq_vectors*()
>>      are now solely the driver's responsibility to free with pci_free_irq_vectors().
>>
>> With these changes, we clear ownership model: Explicit resource management eliminates
>> ambiguity and follows the "principle of least surprise." New drivers choose one model and
>> be consistent.
>> - Use `pci_alloc_irq_vectors()` + `pci_free_irq_vectors()` for explicit control.
>> - Use `pcim_alloc_irq_vectors()` for devres-managed, automatic cleanup.
> 
> Have you checked previous attempts? Why is your series better than those?

There seems not previous attempts.

> 
>> ==== Testing And Review ====
>> 1. This series is only compiled test with allmodconfig.
>> 2. Given the substantial size of this patch series, I have structured the mailing
>>     to facilitate efficient review. The cover letter, the first patch and the last one will be sent
>>     to all relevant mailing lists and key maintainers to ensure broad visibility and
>>     initial feedback on the overall approach. The remaining subsystem-specific patches
>>     will be sent only to the respective subsystem maintainers and their associated
>>     mailing lists, reducing noise.
> 

^ permalink raw reply

* [PATCH 34/37] HID: intel-ish-ipc: Replace pci_alloc_irq_vectors() with pcim_alloc_irq_vectors()
From: Shawn Lin @ 2026-02-23 15:59 UTC (permalink / raw)
  To: Srinivas Pandruvada, Jiri Kosina
  Cc: Benjamin Tissoires, linux-input, Bjorn Helgaas, Philipp Stanner,
	linux-pci, Shawn Lin
In-Reply-To: <1771860581-82092-1-git-send-email-shawn.lin@rock-chips.com>

pcim_enable_device() no longer automatically manages IRQ vectors via devres.
Drivers must now manually call pci_free_irq_vectors() for cleanup. Alternatively,
pcim_alloc_irq_vectors() should be used.

To: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
To: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Philipp Stanner <phasta@kernel.org>
Cc: linux-pci@vger.kernel.org
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---

 drivers/hid/intel-ish-hid/ipc/pci-ish.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index 1612e8c..6933986 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -209,7 +209,7 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	ishtp->pdev = pdev;
 
 	/* request and enable interrupt */
-	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+	ret = pcim_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
 	if (ret < 0) {
 		dev_err(dev, "ISH: Failed to allocate IRQ vectors\n");
 		return ret;
-- 
2.7.4


^ permalink raw reply related

* [PATCH 35/37] HID: Intel-thc-hid: Replace pci_alloc_irq_vectors() with pcim_alloc_irq_vectors()
From: Shawn Lin @ 2026-02-23 15:59 UTC (permalink / raw)
  To: Even Xu, Xinpeng Sun
  Cc: Jiri Kosina, Benjamin Tissoires, linux-input, Bjorn Helgaas,
	Philipp Stanner, linux-pci, Shawn Lin
In-Reply-To: <1771860581-82092-1-git-send-email-shawn.lin@rock-chips.com>

pcim_enable_device() no longer automatically manages IRQ vectors via devres.
Drivers must now manually call pci_free_irq_vectors() for cleanup. Alternatively,
pcim_alloc_irq_vectors() should be used.

To: Even Xu <even.xu@intel.com>
To: Xinpeng Sun <xinpeng.sun@intel.com>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Philipp Stanner <phasta@kernel.org>
Cc: linux-pci@vger.kernel.org
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---

 drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
index f178017..2bed335 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
@@ -654,7 +654,7 @@ static int quicki2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		}
 	}
 
-	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+	ret = pcim_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
 	if (ret < 0) {
 		dev_err_once(&pdev->dev,
 			     "Failed to allocate IRQ vectors. ret = %d\n", ret);
-- 
2.7.4


^ permalink raw reply related

* Re: [PATCH 0/37] PCI/MSI: Enforce explicit IRQ vector management by removing devres auto-free
From: Andy Shevchenko @ 2026-02-23 15:50 UTC (permalink / raw)
  To: Shawn Lin
  Cc: Bjorn Helgaas, Vaibhaav Ram T . L, Kumaravel Thiagarajan, Even Xu,
	Xinpeng Sun, Srinivas Pandruvada, Jiri Kosina, Alexandre Belloni,
	Zhou Wang, Longfang Liu, Vinod Koul, Lee Jones, Jijie Shao,
	Jian Shen, Sunil Goutham, Andrew Lunn, Heiner Kallweit,
	David S . Miller, Jeff Hugo, Oded Gabbay, Maciej Falkowski,
	Karol Wachowski, Min Ma, Lizhi Hou, Andreas Noever,
	Mika Westerberg, Tomasz Jeznach, Will Deacon, Xinliang Liu,
	Tian Tao, Davidlohr Bueso, Jonathan Cameron, Srujana Challa,
	Bharat Bhushan, Antoine Tenart, Herbert Xu, Raag Jadav,
	Hans de Goede, Greg Kroah-Hartman, Jiri Slaby, Andy Shevchenko,
	Manivannan Sadhasivam, Mika Westerberg, Andi Shyti,
	Robert Richter, Mark Brown, Nirmal Patel, Kurt Schwemmer,
	Logan Gunthorpe, Linus Walleij, Bartosz Golaszewski, Sakari Ailus,
	Bingbu Cao, Ulf Hansson, Arnd Bergmann, Benjamin Tissoires,
	linux-input, linux-i3c, dmaengine, Philipp Stanner, netdev,
	nic_swsd, linux-arm-msm, dri-devel, linux-usb, iommu, linux-riscv,
	David Airlie, Simona Vetter, linux-cxl, linux-crypto,
	platform-driver-x86, linux-serial, mhi, Andy Shevchenko,
	Jan Dabros, linux-i2c, Daniel Mack, Haojian Zhuang, linux-spi,
	Jonathan Derrick, linux-pci, linux-gpio, Mauro Carvalho Chehab,
	linux-media, linux-mmc
In-Reply-To: <1771860581-82092-1-git-send-email-shawn.lin@rock-chips.com>

On Mon, Feb 23, 2026 at 5:32 PM Shawn Lin <shawn.lin@rock-chips.com> wrote:
>
> This patch series addresses a long-standing design issue in the PCI/MSI
> subsystem where the implicit, automatic management of IRQ vectors by
> the devres framework conflicts with explicit driver cleanup, creating
> ambiguity and potential resource management bugs.
>
> ==== The Problem: Implicit vs. Explicit Management ====
> Historically, `pcim_enable_device()` not only manages standard PCI resources
> (BARs) via devres but also implicitly triggers automatic IRQ vector management
> by setting a flag that registers `pcim_msi_release()` as a cleanup action.
>
> This creates an ambiguous ownership model. Many drivers follow a pattern of:
> 1. Calling `pci_alloc_irq_vectors()` to allocate interrupts.
> 2. Also calling `pci_free_irq_vectors()` in their error paths or remove routines.
>
> When such a driver also uses `pcim_enable_device()`, the devres framework may
> attempt to free the IRQ vectors a second time upon device release, leading to
> a double-free. Analysis of the tree shows this hazardous pattern exists widely,
> while 35 other drivers correctly rely solely on the implicit cleanup.

Is this confirmed? What I read from the cover letter, this series was
only compile-tested, so how can you prove the problem exists in the
first place?

> ==== The Solution: Making Management Explicit ====
> This series enforces a clear, predictable model:
> 1.  New Managed API (Patch 1/37): Introduces pcim_alloc_irq_vectors() and
>     pcim_alloc_irq_vectors_affinity(). Drivers that desire devres-managed IRQ
>     vectors should use these functions, which set the is_msi_managed flag and
>     ensure automatic cleanup.
> 2.  Patches 2 through 36 convert each driver that uses pcim_enable_device() alongside
>     pci_alloc_irq_vectors() and relies on devres for IRQ vector cleanup to instead
>     make an explicit call to pcim_alloc_irq_vectors().
> 3.  Core Change (Patch 37/37): With the former cleanup, now modifies pcim_setup_msi_release()
>     to check only the is_msi_managed flag. This decouples automatic IRQ cleanup from
>     pcim_enable_device(). IRQ vectors allocated via pci_alloc_irq_vectors*()
>     are now solely the driver's responsibility to free with pci_free_irq_vectors().
>
> With these changes, we clear ownership model: Explicit resource management eliminates
> ambiguity and follows the "principle of least surprise." New drivers choose one model and
> be consistent.
> - Use `pci_alloc_irq_vectors()` + `pci_free_irq_vectors()` for explicit control.
> - Use `pcim_alloc_irq_vectors()` for devres-managed, automatic cleanup.

Have you checked previous attempts? Why is your series better than those?

> ==== Testing And Review ====
> 1. This series is only compiled test with allmodconfig.
> 2. Given the substantial size of this patch series, I have structured the mailing
>    to facilitate efficient review. The cover letter, the first patch and the last one will be sent
>    to all relevant mailing lists and key maintainers to ensure broad visibility and
>    initial feedback on the overall approach. The remaining subsystem-specific patches
>    will be sent only to the respective subsystem maintainers and their associated
>    mailing lists, reducing noise.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH v3 1/9] dt-bindings: regulator: cpcap-regulator: convert to DT schema
From: Rob Herring (Arm) @ 2026-02-23 15:50 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: David Lechner, linux-kernel, Pavel Machek, Krzysztof Kozlowski,
	Tony Lindgren, Lee Jones, linux-input, devicetree,
	Dmitry Torokhov, linux-leds, Mark Brown, Liam Girdwood,
	Conor Dooley
In-Reply-To: <20260223063858.12208-2-clamor95@gmail.com>


On Mon, 23 Feb 2026 08:38:50 +0200, Svyatoslav Ryhel wrote:
> Convert devicetree bindings for the Motorola CPCAP MFD regulator subnode
> from TXT to YAML format. Main functionality preserved.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../bindings/regulator/cpcap-regulator.txt    | 35 --------------
>  .../regulator/motorola,cpcap-regulator.yaml   | 46 +++++++++++++++++++
>  2 files changed, 46 insertions(+), 35 deletions(-)
>  delete mode 100644 Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
>  create mode 100644 Documentation/devicetree/bindings/regulator/motorola,cpcap-regulator.yaml
> 

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>


^ permalink raw reply

* [PATCH] Input: i8042 - add TUXEDO InfinityBook Max 16 Gen10 AMD to i8042 quirk table
From: Werner Sembach @ 2026-02-23 14:20 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Christoffer Sandberg, Werner Sembach, linux-input, linux-kernel

From: Christoffer Sandberg <cs@tuxedo.de>

The device occasionally wakes up from suspend with missing input on the
internal keyboard and the following suspend attempt results in an instant
wake-up. The quirks fix both issues for this device.

Signed-off-by: Christoffer Sandberg <cs@tuxedo.de>
Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/input/serio/i8042-acpipnpio.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h
index d2cf940b105a6..8ebdf4fb90308 100644
--- a/drivers/input/serio/i8042-acpipnpio.h
+++ b/drivers/input/serio/i8042-acpipnpio.h
@@ -1187,6 +1187,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
 		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
 					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+	},
 	{
 		.matches = {
 			DMI_MATCH(DMI_BOARD_NAME, "WUJIE Series-X5SP4NAG"),
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH 1/2] dt-bindings: input: add adi,max16150.yaml
From: Rob Herring (Arm) @ 2026-02-23 12:24 UTC (permalink / raw)
  To: Marc Paolo Sosa
  Cc: Dmitry Torokhov, linux-input, Conor Dooley, devicetree,
	linux-kernel, Krzysztof Kozlowski
In-Reply-To: <20260223-max16150-v1-1-38e2a4f0d0f1@analog.com>


On Mon, 23 Feb 2026 19:03:39 +0800, Marc Paolo Sosa wrote:
> Add documentation for device tree bindings for MAX16150/MAX16169
> 
> Signed-off-by: Marc Paolo Sosa <marcpaolo.sosa@analog.com>
> ---
>  .../devicetree/bindings/input/adi,max16150.yaml    | 57 ++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/input/adi,max16150.example.dtb: power-button (adi,max16150a): 'interrupt-gpios' does not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/input/adi,max16150.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20260223-max16150-v1-1-38e2a4f0d0f1@analog.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply

* Re: [PATCH 2/7] Input: cros_ec_keyb - add function key support
From: Fabio Baltieri @ 2026-02-23 12:24 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Benson Leung, Guenter Roeck, Simon Glass, Tzung-Bi Shih,
	linux-input, chrome-platform, linux-kernel
In-Reply-To: <20260222003717.471977-2-dmitry.torokhov@gmail.com>

On Sat, Feb 21, 2026 at 04:37:10PM -0800, Dmitry Torokhov wrote:
> From: Fabio Baltieri <fabiobaltieri@chromium.org>
> 
> Add support for handling an Fn button and sending separate keycodes for
> a subset of keys in the matrix defined in the upper half of the keymap.
> 
> Signed-off-by: Fabio Baltieri <fabiobaltieri@chromium.org>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> Link: https://patch.msgid.link/20260211173421.1206478-3-fabiobaltieri@chromium.org
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

Thanks, happy with the changes, gave it another run on my test setup
with the whole patchset, all looking good.

Thanks,
Fabio

^ permalink raw reply

* [PATCH 2/2] input: misc: add driver for max16150
From: Marc Paolo Sosa via B4 Relay @ 2026-02-23 11:03 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-input, devicetree, linux-kernel, Marc Paolo Sosa
In-Reply-To: <20260223-max16150-v1-0-38e2a4f0d0f1@analog.com>

From: Marc Paolo Sosa <marcpaolo.sosa@analog.com>

MAX16150/MAX16169 nanoPower Pushbutton On/Off Controller

Signed-off-by: Marc Paolo Sosa <marcpaolo.sosa@analog.com>
---
 drivers/input/misc/Kconfig    |   9 +++
 drivers/input/misc/Makefile   |   1 +
 drivers/input/misc/max16150.c | 161 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 171 insertions(+)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 94a753fcb64f..a31d3d2a7fd6 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -178,6 +178,15 @@ config INPUT_E3X0_BUTTON
 	  To compile this driver as a module, choose M here: the
 	  module will be called e3x0_button.
 
+config INPUT_MAX16150_PWRBUTTON
+	tristate "MAX16150/MAX16169 Pushbutton driver"
+	help
+	  Say Y here if you want to enable power key reporting via
+	  MAX16150/MAX16169 nanoPower Pushbutton On/Off Controller.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called max16150.
+
 config INPUT_PCSPKR
 	tristate "PC Speaker support"
 	depends on PCSPKR_PLATFORM
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 415fc4e2918b..c2c1c45f2df6 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_INPUT_IQS7222)		+= iqs7222.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
 obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
 obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
+obj-$(CONFIG_INPUT_MAX16150_PWRBUTTON)	+= max16150.o
 obj-$(CONFIG_INPUT_MAX7360_ROTARY)	+= max7360-rotary.o
 obj-$(CONFIG_INPUT_MAX77650_ONKEY)	+= max77650-onkey.o
 obj-$(CONFIG_INPUT_MAX77693_HAPTIC)	+= max77693-haptic.o
diff --git a/drivers/input/misc/max16150.c b/drivers/input/misc/max16150.c
new file mode 100644
index 000000000000..ae353b926afc
--- /dev/null
+++ b/drivers/input/misc/max16150.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Analog Devices MAX16150/MAX16169 Pushbutton Driver
+ *
+ * Copyright 2025 Analog Devices Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#define MAX16150_LONG_INTERRUPT 120000000
+
+struct max16150_chip_info {
+	bool has_clr_gpio;
+};
+
+struct max16150_device {
+	struct input_dev *input;
+	struct gpio_desc *gpiod;
+	struct gpio_desc *clr_gpiod;
+	const struct max16150_chip_info *chip_info;
+	u64 low, high, duration;
+	unsigned int keycode;
+};
+
+static irqreturn_t max16150_irq_handler(int irq, void *_max16150)
+{
+	struct max16150_device *max16150 = _max16150;
+	int value;
+
+	value = gpiod_get_value(max16150->gpiod);
+
+	if (!value) {
+		max16150->low = ktime_get_ns();
+		return IRQ_HANDLED;
+	}
+
+	max16150->high = ktime_get_ns();
+	if (max16150->low) {
+		max16150->duration = max16150->high - max16150->low;
+
+		if (max16150->duration > MAX16150_LONG_INTERRUPT) {
+			gpiod_set_value(max16150->clr_gpiod, 1);
+			input_report_key(max16150->input, max16150->keycode, 1);
+			input_sync(max16150->input);
+			input_report_key(max16150->input, max16150->keycode, 0);
+			input_sync(max16150->input);
+		}
+
+		max16150->low = 0;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static const struct max16150_chip_info max16150_variant_a = {
+	.has_clr_gpio = true,
+};
+
+static const struct max16150_chip_info max16150_variant_b = {
+	.has_clr_gpio = false,
+};
+
+static int max16150_probe(struct platform_device *pdev)
+{
+	const struct max16150_chip_info *chip_info;
+	struct max16150_device *max16150;
+	struct device *dev = &pdev->dev;
+	int err, irq, ret;
+	u32 keycode;
+
+	chip_info = device_get_match_data(dev);
+	if (!chip_info)
+		return -EINVAL;
+
+	max16150 = devm_kzalloc(dev, sizeof(*max16150), GFP_KERNEL);
+	if (!max16150)
+		return -ENOMEM;
+
+	max16150->chip_info = chip_info;
+
+	max16150->input = devm_input_allocate_device(dev);
+	if (!max16150->input)
+		return -ENOMEM;
+
+	max16150->input->name = "MAX16150 Pushbutton";
+	max16150->input->phys = "max16150/input0";
+	max16150->input->id.bustype = BUS_HOST;
+
+	keycode = KEY_POWER;
+	ret = device_property_read_u32(dev, "linux,code", &keycode);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to get keycode\n");
+
+	max16150->keycode = keycode;
+
+	input_set_capability(max16150->input, EV_KEY, max16150->keycode);
+
+	max16150->gpiod = devm_gpiod_get(dev, "interrupt", GPIOD_IN);
+	if (IS_ERR(max16150->gpiod))
+		return dev_err_probe(dev, PTR_ERR(max16150->gpiod),
+				     "Failed to get interrupt GPIO\n");
+
+	if (chip_info->has_clr_gpio) {
+		max16150->clr_gpiod = devm_gpiod_get(dev, "clr", GPIOD_OUT_HIGH);
+		if (IS_ERR(max16150->clr_gpiod))
+			return dev_err_probe(dev, PTR_ERR(max16150->clr_gpiod),
+					     "Failed to get clr GPIO\n");
+
+		if (!max16150->clr_gpiod)
+			return dev_err_probe(dev, -ENODEV,
+						 "clr GPIO is mandatory\n");
+
+		if (max16150->clr_gpiod) {
+			fsleep(1000);
+			gpiod_set_value(max16150->clr_gpiod, 0);
+		}
+	}
+
+	irq = gpiod_to_irq(max16150->gpiod);
+	if (irq < 0)
+		return dev_err_probe(dev, irq,
+				     "MAX16150: Failed to map GPIO to IRQ");
+
+	err = devm_request_irq(dev, irq, max16150_irq_handler,
+			       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			       "max16150_irq", max16150);
+	if (err)
+		return err;
+
+	return input_register_device(max16150->input);
+}
+
+static const struct of_device_id max16150_of_match[] = {
+	{ .compatible = "adi,max16150a", .data = &max16150_variant_a },
+	{ .compatible = "adi,max16150b", .data = &max16150_variant_b },
+	{ .compatible = "adi,max16169a", .data = &max16150_variant_a },
+	{ .compatible = "adi,max16169b", .data = &max16150_variant_b },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max16150_of_match);
+
+static struct platform_driver max16150_driver = {
+	.probe  = max16150_probe,
+	.driver = {
+		.name = "max16150",
+		.of_match_table = max16150_of_match,
+	},
+};
+module_platform_driver(max16150_driver);
+
+MODULE_AUTHOR("Marc Paolo Sosa <marcpaolo.sosa@analog.com>");
+MODULE_DESCRIPTION("MAX16150/MAX16169 Pushbutton Driver");
+MODULE_LICENSE("GPL");

-- 
2.34.1



^ permalink raw reply related

* [PATCH 0/2] add driver for max16150
From: Marc Paolo Sosa via B4 Relay @ 2026-02-23 11:03 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-input, devicetree, linux-kernel, Marc Paolo Sosa

Introduce pushbutton control and debouncing support for the
MAX16150/MAX16169. The component is a low‑power on/off controller
featuring an integrated switch debouncer and internal latch, designed
to accept a noisy mechanical pushbutton input while providing a clean,
stable latched output. It also includes a one‑shot interrupt output for
event signaling, enabling reliable switch interfacing in low‑power embedded
systems.

Signed-off-by: Marc Paolo Sosa <marcpaolo.sosa@analog.com>
---
Marc Paolo Sosa (2):
      dt-bindings: input: add adi,max16150.yaml
      input: misc: add driver for max16150

 .../devicetree/bindings/input/adi,max16150.yaml    |  57 ++++++++
 drivers/input/misc/Kconfig                         |   9 ++
 drivers/input/misc/Makefile                        |   1 +
 drivers/input/misc/max16150.c                      | 161 +++++++++++++++++++++
 4 files changed, 228 insertions(+)
---
base-commit: e7b53288d9ea899abc6d47a7f20065ab511a810c
change-id: 20260223-max16150-8ef94e643cd0

Best regards,
-- 
Marc Paolo Sosa <marcpaolo.sosa@analog.com>



^ permalink raw reply

* [PATCH 1/2] dt-bindings: input: add adi,max16150.yaml
From: Marc Paolo Sosa via B4 Relay @ 2026-02-23 11:03 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-input, devicetree, linux-kernel, Marc Paolo Sosa
In-Reply-To: <20260223-max16150-v1-0-38e2a4f0d0f1@analog.com>

From: Marc Paolo Sosa <marcpaolo.sosa@analog.com>

Add documentation for device tree bindings for MAX16150/MAX16169

Signed-off-by: Marc Paolo Sosa <marcpaolo.sosa@analog.com>
---
 .../devicetree/bindings/input/adi,max16150.yaml    | 57 ++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/Documentation/devicetree/bindings/input/adi,max16150.yaml b/Documentation/devicetree/bindings/input/adi,max16150.yaml
new file mode 100644
index 000000000000..327811e1ebd4
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/adi,max16150.yaml
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/adi,max16150.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices MAX16150/MAX16169 nanoPower Pushbutton On/Off Controller
+
+maintainers:
+  - Marc Paolo Sosa <marcpaolo.sosa@analog.com>
+
+description:
+  The MAX16150/MAX16169 is a low-power pushbutton on/off controller with a
+  switch debouncer and built-in latch. It accepts a noisy input from a
+  mechanical switch and produces a clean latched output, as well as a one-shot
+  interrupt output.
+
+properties:
+  compatible:
+    description:
+      Specifies the supported device variants. The MAX16150 and MAX16169 are supported.
+    enum:
+      - adi,max16150a
+      - adi,max16150b
+      - adi,max16169a
+      - adi,max16169b
+
+  interrupt-gpio:
+    maxItems: 1
+
+  clr-gpios:
+    description:
+      Clear Input. Pulling CLR low deasserts the latched OUT signal. If OUT is
+      already deasserted when CLR is pulled low, the state of OUT is unchanged.
+    maxItems: 1
+
+  linux,code:
+    default: KEY_POWER
+
+required:
+  - compatible
+  - interrupt-gpios
+  - clr-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/input/linux-event-codes.h>
+    #include <dt-bindings/gpio/gpio.h>
+
+    power-button {
+        compatible = "adi,max16150a";
+        interrupt-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
+        clr-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
+        linux,code = <KEY_POWER>;
+    };

-- 
2.34.1



^ permalink raw reply related

* Re: [PATCH v5 1/4] firmware_loader: expand firmware error codes with up-to-date error
From: Marco Felsch @ 2026-02-23 10:39 UTC (permalink / raw)
  To: Russ Weight
  Cc: Luis Chamberlain, Greg Kroah-Hartman, Rafael J. Wysocki,
	Andrew Morton, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Kamel Bouhara, Marco Felsch, Henrik Rydberg,
	Danilo Krummrich, linux-kernel, devicetree, linux-input
In-Reply-To: <s24u6ojnflb4nvpssgshjmgir77wpoos6qinypqac564fzcjyy@yilnrsy266er>

Hi Russ,

On 26-02-19, Russ Weight wrote:
> On Sun, Jan 11, 2026 at 04:05:44PM +0100, Marco Felsch wrote:
> > Add FW_UPLOAD_ERR_DUPLICATE to allow drivers to inform the firmware_loader
> > framework that the update is not required. This can be the case if the
> > user provided firmware matches the current running firmware.
> > 
> > Sync lib/test_firmware.c accordingly.
> > 
> > Reviewed-by: Russ Weight <russ.weight@linux.dev>
> > Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> >  drivers/base/firmware_loader/sysfs_upload.c | 1 +
> >  include/linux/firmware.h                    | 2 ++
> >  lib/test_firmware.c                         | 1 +
> >  3 files changed, 4 insertions(+)
> > 
> > diff --git a/drivers/base/firmware_loader/sysfs_upload.c b/drivers/base/firmware_loader/sysfs_upload.c
> > index c3797b93c5f5a2ecf2ae34707893c89eb7773154..9e93070b2c24179986b868a24b09cf051776c644 100644
> > --- a/drivers/base/firmware_loader/sysfs_upload.c
> > +++ b/drivers/base/firmware_loader/sysfs_upload.c
> > @@ -28,6 +28,7 @@ static const char * const fw_upload_err_str[] = {
> >  	[FW_UPLOAD_ERR_RW_ERROR]     = "read-write-error",
> >  	[FW_UPLOAD_ERR_WEAROUT]	     = "flash-wearout",
> >  	[FW_UPLOAD_ERR_FW_INVALID]   = "firmware-invalid",
> > +	[FW_UPLOAD_ERR_DUPLICATE]    = "firmware-duplicate",
> >  };
> 
> Hi Marco,
> 
> There is a corresponding change that should be made to
> lib/test_firmware.c. You can look at the recent change for
> FW_UPLOAD_ERR_FW_INVALID as an example.

Can you elaborate a bit more please? I've added the
FW_UPLOAD_ERR_DUPLICATE to lib/test_firmware.c with this patchset and I
don't know what you want me todo.

Regards,
  Marco


> 
> - Russ
> 
> >  
> >  static const char *fw_upload_progress(struct device *dev,
> > diff --git a/include/linux/firmware.h b/include/linux/firmware.h
> > index aae1b85ffc10e20e9c3c9b6009d26b83efd8cb24..fe7797be4c08cd62cdad9617b8f70095d5e0af2f 100644
> > --- a/include/linux/firmware.h
> > +++ b/include/linux/firmware.h
> > @@ -29,6 +29,7 @@ struct firmware {
> >   * @FW_UPLOAD_ERR_RW_ERROR: read or write to HW failed, see kernel log
> >   * @FW_UPLOAD_ERR_WEAROUT: FLASH device is approaching wear-out, wait & retry
> >   * @FW_UPLOAD_ERR_FW_INVALID: invalid firmware file
> > + * @FW_UPLOAD_ERR_DUPLICATE: firmware is already up to date (duplicate)
> >   * @FW_UPLOAD_ERR_MAX: Maximum error code marker
> >   */
> >  enum fw_upload_err {
> > @@ -41,6 +42,7 @@ enum fw_upload_err {
> >  	FW_UPLOAD_ERR_RW_ERROR,
> >  	FW_UPLOAD_ERR_WEAROUT,
> >  	FW_UPLOAD_ERR_FW_INVALID,
> > +	FW_UPLOAD_ERR_DUPLICATE,
> >  	FW_UPLOAD_ERR_MAX
> >  };
> >  
> > diff --git a/lib/test_firmware.c b/lib/test_firmware.c
> > index be4f93124901e5faac41f48a66dabe6da56be0ca..952ec1cb03102911dbea9abd648ab9d9e0112a46 100644
> > --- a/lib/test_firmware.c
> > +++ b/lib/test_firmware.c
> > @@ -1134,6 +1134,7 @@ static const char * const fw_upload_err_str[] = {
> >  	[FW_UPLOAD_ERR_RW_ERROR]     = "read-write-error",
> >  	[FW_UPLOAD_ERR_WEAROUT]	     = "flash-wearout",
> >  	[FW_UPLOAD_ERR_FW_INVALID]   = "firmware-invalid",
> > +	[FW_UPLOAD_ERR_DUPLICATE]    = "firmware-duplicate",
> >  };
> >  
> >  static void upload_err_inject_error(struct test_firmware_upload *tst,
> > 
> > -- 
> > 2.47.3
> > 
> 

-- 
#gernperDu 
#CallMeByMyFirstName

Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-9    |

^ permalink raw reply

* Re: [PATCH v3 5/9] dt-bindings: input: cpcap-pwrbutton: convert to DT schema
From: Rob Herring (Arm) @ 2026-02-23  9:54 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Tony Lindgren, Dmitry Torokhov, devicetree, linux-kernel,
	David Lechner, Conor Dooley, Pavel Machek, Mark Brown, linux-leds,
	Liam Girdwood, Lee Jones, Krzysztof Kozlowski, linux-input
In-Reply-To: <20260223063858.12208-6-clamor95@gmail.com>


On Mon, 23 Feb 2026 08:38:54 +0200, Svyatoslav Ryhel wrote:
> Convert power button devicetree bindings for the Motorola CPCAP MFD from
> TXT to YAML format. This patch does not change any functionality; the
> bindings remain the same.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../bindings/input/cpcap-pwrbutton.txt        | 20 ------------
>  .../input/motorola,cpcap-pwrbutton.yaml       | 32 +++++++++++++++++++
>  2 files changed, 32 insertions(+), 20 deletions(-)
>  delete mode 100644 Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
>  create mode 100644 Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:


doc reference errors (make refcheckdocs):
Warning: Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Documentation/devicetree/bindings/mfd/motorola-cpcap.txt: Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt

See https://patchwork.kernel.org/project/devicetree/patch/20260223063858.12208-6-clamor95@gmail.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply

* Re: [PATCH v3 4/9] dt-bindings: leds: leds-cpcap: convert to DT schema
From: Rob Herring (Arm) @ 2026-02-23  9:54 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: devicetree, linux-input, Tony Lindgren, linux-kernel,
	Pavel Machek, Conor Dooley, linux-leds, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Lee Jones, David Lechner,
	Dmitry Torokhov
In-Reply-To: <20260223063858.12208-5-clamor95@gmail.com>


On Mon, 23 Feb 2026 08:38:53 +0200, Svyatoslav Ryhel wrote:
> Convert LEDs devicetree bindings for the Motorola CPCAP MFD from TXT to
> YAML format. This patch does not change any functionality; the bindings
> remain the same.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> ---
>  .../devicetree/bindings/leds/leds-cpcap.txt   | 29 -------------
>  .../bindings/leds/motorola,cpcap-leds.yaml    | 42 +++++++++++++++++++
>  2 files changed, 42 insertions(+), 29 deletions(-)
>  delete mode 100644 Documentation/devicetree/bindings/leds/leds-cpcap.txt
>  create mode 100644 Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:


doc reference errors (make refcheckdocs):
Warning: Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/leds/leds-cpcap.txt
Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Documentation/devicetree/bindings/mfd/motorola-cpcap.txt: Documentation/devicetree/bindings/leds/leds-cpcap.txt

See https://patchwork.kernel.org/project/devicetree/patch/20260223063858.12208-5-clamor95@gmail.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply

* Re: [PATCH v3 1/9] dt-bindings: regulator: cpcap-regulator: convert to DT schema
From: Rob Herring (Arm) @ 2026-02-23  9:54 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Mark Brown, linux-kernel, David Lechner, Krzysztof Kozlowski,
	Liam Girdwood, devicetree, linux-input, Conor Dooley, Lee Jones,
	linux-leds, Pavel Machek, Dmitry Torokhov, Tony Lindgren
In-Reply-To: <20260223063858.12208-2-clamor95@gmail.com>


On Mon, 23 Feb 2026 08:38:50 +0200, Svyatoslav Ryhel wrote:
> Convert devicetree bindings for the Motorola CPCAP MFD regulator subnode
> from TXT to YAML format. Main functionality preserved.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../bindings/regulator/cpcap-regulator.txt    | 35 --------------
>  .../regulator/motorola,cpcap-regulator.yaml   | 46 +++++++++++++++++++
>  2 files changed, 46 insertions(+), 35 deletions(-)
>  delete mode 100644 Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
>  create mode 100644 Documentation/devicetree/bindings/regulator/motorola,cpcap-regulator.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:


doc reference errors (make refcheckdocs):
Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
Warning: Documentation/devicetree/bindings/regulator/motorola,cpcap-regulator.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
Documentation/devicetree/bindings/mfd/motorola-cpcap.txt: Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
Documentation/devicetree/bindings/regulator/motorola,cpcap-regulator.yaml: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml

See https://patchwork.kernel.org/project/devicetree/patch/20260223063858.12208-2-clamor95@gmail.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply

* [PATCH v4] HID: generic: add LampArray support via hid-lamparray helper
From: Tim Guttzeit @ 2026-02-23  8:39 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: wse, Tim Guttzeit, linux-kernel, linux-input

Add a new hid-lamparray helper module and integrate it with the
hid-generic driver.

The helper provides basic support for devices exposing a
Lighting/LampArray application collection (usage page 0x59) and
registers a single-zone RGB LED representation via the LED
subsystem.

hid-generic now checks for LampArray support after hid_parse() and
optionally registers a lamparray instance. Failures in the helper
do not abort device probe to keep the device functional.

LampArray resources are released on driver remove.

Signed-off-by: Tim Guttzeit <tgu@tuxedocomputers.com>
---
V1 -> V2: Fix Kconfig to avoid build errors when LEDS_CLASS_MULTICOLOR is disabled
V2 -> V3: Squash V1 and V2 into one patch
V3 -> V4: Restrict CONFIG_HID_LAMPARRAY to built-in configurations only
          to fix additional randconfig build errors

 drivers/hid/Kconfig         |  10 +
 drivers/hid/Makefile        |   2 +
 drivers/hid/hid-generic.c   |  41 +-
 drivers/hid/hid-lamparray.c | 855 ++++++++++++++++++++++++++++++++++++
 drivers/hid/hid-lamparray.h |  91 ++++
 5 files changed, 997 insertions(+), 2 deletions(-)
 create mode 100644 drivers/hid/hid-lamparray.c
 create mode 100644 drivers/hid/hid-lamparray.h

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 920a64b66b25..548dc708e5cd 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -92,6 +92,16 @@ config HID_GENERIC
 
 	If unsure, say Y.
 
+config HID_LAMPARRAY
+	bool "HID LampArray helper"
+	depends on HID=y && HID_GENERIC=y && LEDS_CLASS=y && LEDS_CLASS_MULTICOLOR=y
+	default y
+	help
+	Helper for HID devices exposing a Lighting/LampArray collection.
+	Treats LampArray devices as a single-zone device and exposes a sysfs
+	interface for changing color and intensity values. Also exposes a
+	sysfs flag to be disabled e.g. by a userspace driver.
+
 config HID_HAPTIC
 	bool "Haptic touchpad support"
 	default n
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 361a7daedeb8..5a14b4b0970d 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -13,6 +13,8 @@ obj-$(CONFIG_UHID)		+= uhid.o
 
 obj-$(CONFIG_HID_GENERIC)	+= hid-generic.o
 
+obj-$(CONFIG_HID_LAMPARRAY) += hid-lamparray.o
+
 hid-$(CONFIG_HIDRAW)		+= hidraw.o
 
 hid-logitech-y		:= hid-lg.o
diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c
index c2de916747de..57b81c86982c 100644
--- a/drivers/hid/hid-generic.c
+++ b/drivers/hid/hid-generic.c
@@ -20,6 +20,7 @@
 #include <asm/byteorder.h>
 
 #include <linux/hid.h>
+#include "hid-lamparray.h"
 
 static struct hid_driver hid_generic;
 
@@ -31,7 +32,7 @@ static int __check_hid_generic(struct device_driver *drv, void *data)
 	if (hdrv == &hid_generic)
 		return 0;
 
-	return hid_match_device(hdev, hdrv) != NULL;
+	return !!hid_match_device(hdev, hdrv);
 }
 
 static bool hid_generic_match(struct hid_device *hdev,
@@ -60,6 +61,7 @@ static int hid_generic_probe(struct hid_device *hdev,
 			     const struct hid_device_id *id)
 {
 	int ret;
+	struct lamparray *la = NULL;
 
 	hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
 
@@ -67,7 +69,31 @@ static int hid_generic_probe(struct hid_device *hdev,
 	if (ret)
 		return ret;
 
-	return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret)
+		return ret;
+
+	/*
+	 * Optional: attach LampArray support if present.
+	 * Never fail probe on LampArray errors; keep device functional.
+	 */
+	if (IS_ENABLED(CONFIG_HID_LAMPARRAY) && lamparray_is_supported_device(hdev)) {
+		const struct lamparray_init_state init = {
+			.r = 0xff,
+			.g = 0xff,
+			.b = 0xff,
+			.brightness = LED_FULL,
+		};
+
+		la = lamparray_register(hdev, &init);
+		if (IS_ERR(la)) {
+			hid_warn(hdev, "LampArray init failed: %ld\n", PTR_ERR(la));
+			la = NULL;
+		}
+	}
+
+	hid_set_drvdata(hdev, la);
+	return 0;
 }
 
 static int hid_generic_reset_resume(struct hid_device *hdev)
@@ -78,6 +104,16 @@ static int hid_generic_reset_resume(struct hid_device *hdev)
 	return 0;
 }
 
+static void hid_generic_remove(struct hid_device *hdev)
+{
+	struct lamparray *la = hid_get_drvdata(hdev);
+
+	if (IS_ENABLED(CONFIG_HID_LAMPARRAY) && la)
+		lamparray_unregister(la);
+
+	hid_hw_stop(hdev);
+}
+
 static const struct hid_device_id hid_table[] = {
 	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) },
 	{ }
@@ -90,6 +126,7 @@ static struct hid_driver hid_generic = {
 	.match = hid_generic_match,
 	.probe = hid_generic_probe,
 	.reset_resume = hid_generic_reset_resume,
+	.remove = hid_generic_remove,
 };
 module_hid_driver(hid_generic);
 
diff --git a/drivers/hid/hid-lamparray.c b/drivers/hid/hid-lamparray.c
new file mode 100644
index 000000000000..5be46fff0191
--- /dev/null
+++ b/drivers/hid/hid-lamparray.c
@@ -0,0 +1,855 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * hid-lamparray.c - HID LampArray helper module (single-zone RGB)
+ *
+ * Helper module for HID drivers supporting devices that expose a
+ * Lighting and Illumination (LampArray) application collection
+ * (usage page 0x59).
+ *
+ * The module provides a minimal integration with the LED subsystem
+ * and treats the device as a single zone: all lamps share one RGB
+ * value and a global brightness level. It does not implement multi-
+ * zone layouts or hardware effects.
+ *
+ *
+ * If enabled, one multicolor LED class device is registered under
+ * /sys/class/leds/<HID-ID> to expose the single-zone RGB control.
+ *
+ * The use_leds_uapi sysfs attribute is attached directly to the HID device
+ * under /sys/bus/hid/devices/<HID-ID>/use_leds_uapi.Writing 0 to use_leds_uapi
+ * unregisters the LED class device. The last state is kept cached. Writing 1
+ * registers it again and restores the cached state to hardware.
+ *
+ * State is cached as last known RGB + brightness. Setting sends a HID
+ * SET_REPORT. Getting issues a HID GET_REPORT and updates the cache on
+ * mismatch. Since the device is handled as single-zone, readback only queries
+ * lamp 0 when a lamp range is available.
+ *
+ * The module does not bind to devices on its own. Instead, a HID
+ * driver may query support via lamparray_is_supported_device() after
+ * hid_parse() and create an instance using lamparray_register().
+ *
+ * Copyright (C) 2026 Tim Guttzeit <tgu@tuxedocomputers.com>
+ */
+
+#include "hid-lamparray.h"
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/leds.h>
+#include <linux/led-class-multicolor.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/mutex.h>
+#include <linux/bitops.h>
+#include <linux/xarray.h>
+
+/* Constants */
+
+/* HID usages (LampArray, etc.) */
+#define HID_LIGHTING_ILLUMINATION_USAGE_PAGE	0x0059
+
+#define HID_LAIP_LAMP_COUNT			0x0003
+#define HID_LAIP_LAMP_ID			0x0021
+#define HID_LAIP_RED_UPDATE_CHANNEL		0x0051
+#define HID_LAIP_GREEN_UPDATE_CHANNEL		0x0052
+#define HID_LAIP_BLUE_UPDATE_CHANNEL		0x0053
+#define HID_LAIP_INTENSITY_UPDATE_CHANNEL	0x0054
+#define HID_LAIP_LAMP_ID_START			0x0061
+#define HID_LAIP_LAMP_ID_END			0x0062
+#define HID_LAIP_AUTONOMOUS_MODE		0x0071
+
+#define HID_APPLICATION_COLLECTION_USAGE_TYPE	0x0001
+
+/* Device state */
+
+struct lamparray_quirks {
+	unsigned long flags;
+	int fixed_lamp_count;
+};
+
+#define LAMPARRAY_QUIRK_LAMPCOUNT_FIXED BIT(0)
+
+struct lamparray_quirk_entry {
+	u16 vendor;
+	u16 product;
+	unsigned long flags;
+	int fixed_lamp_count;
+};
+
+static const struct lamparray_quirk_entry lamparray_quirk_table[] = {
+	{ 0xcafe, 0x4005, LAMPARRAY_QUIRK_LAMPCOUNT_FIXED, 12 },
+	{}
+};
+
+static const struct lamparray_quirk_entry *
+lamparray_lookup_quirks(struct hid_device *hdev)
+{
+	const struct lamparray_quirk_entry *e;
+
+	for (e = lamparray_quirk_table; e->vendor; e++) {
+		if (hdev->vendor == e->vendor && hdev->product == e->product)
+			return e;
+	}
+	return NULL;
+}
+
+struct lamparray_device {
+	const struct lamparray_quirk_entry *quirks;
+
+	struct hid_device *hdev;
+	struct hid_report *update_report;
+
+	struct hid_field *red_field;
+	int red_index;
+	struct hid_field *green_field;
+	int green_index;
+	struct hid_field *blue_field;
+	int blue_index;
+	struct hid_field *intensity_field;
+	int intensity_index;
+
+	struct hid_report *autonomous_report;
+	struct hid_field *autonomous_field;
+
+	struct hid_field *range_start_field;
+	int range_start_index;
+
+	struct hid_field *range_end_field;
+	int range_end_index;
+
+	struct hid_field *lamp_count_field;
+	int lamp_count;
+	int lamp_count_index;
+
+	struct led_classdev_mc mc_cdev;
+	struct mc_subled subleds[3];
+
+	struct mutex lock; /* protects cached state and HID access */
+
+	u8 last_r;
+	u8 last_g;
+	u8 last_b;
+	enum led_brightness last_brightness;
+
+	bool use_leds_uapi;
+	bool led_registered;
+};
+
+/*
+ * Opaque handle exposed to callers via the header.
+ * Keep the actual state in lamparray_device, but return a stable pointer.
+ */
+struct lamparray {
+	struct lamparray_device ldev;
+};
+
+static DEFINE_XARRAY(lamparray_by_hdev);
+
+/* HID helper functions */
+
+#ifdef DEBUG
+static void lamparray_dump_reports(struct hid_device *hdev)
+{
+	struct hid_report_enum *re;
+	struct hid_report *report;
+	int i, j, report_type;
+
+	for (report_type = 0; report_type < HID_REPORT_TYPES; report_type++) {
+		re = &hdev->report_enum[report_type];
+		hid_dbg(hdev, "Dumping reports for report type %d",
+			report_type);
+		list_for_each_entry(report, &re->report_list, list) {
+			hid_dbg(hdev,
+				"lamparray: report id=%u type=%d maxfield=%u\n",
+				report->id, report->type, report->maxfield);
+
+			for (i = 0; i < report->maxfield; i++) {
+				struct hid_field *field = report->field[i];
+
+				for (j = 0; j < field->maxusage; j++) {
+					u32 usage = field->usage[j].hid;
+					u16 page = usage >> 16;
+					u16 id = usage & 0xFFFF;
+
+					hid_dbg(hdev,
+						"lamparray: report %u field %d usage[%d]: page=0x%04x id=0x%04x\n",
+						report->id, i, j, page, id);
+				}
+			}
+		}
+	}
+}
+#else
+static inline void lamparray_dump_reports(struct hid_device *hdev)
+{}
+#endif
+
+static int lamparray_read_lamp_count(struct lamparray_device *ldev)
+{
+	struct hid_device *hdev = ldev->hdev;
+	struct hid_report *report;
+
+	if (ldev->quirks &&
+	    (ldev->quirks->flags & LAMPARRAY_QUIRK_LAMPCOUNT_FIXED)) {
+		ldev->lamp_count = ldev->quirks->fixed_lamp_count;
+		hid_dbg(hdev, "LampCount from quirk: %d\n", ldev->lamp_count);
+		return 0;
+	}
+	if (!ldev->lamp_count_field) {
+		hid_warn(hdev, "No LampCount field found\n");
+		return -ENODEV;
+	}
+
+	report = ldev->lamp_count_field->report;
+
+	if (!report) {
+		hid_warn(hdev, "LampCount field has no report\n");
+		return -ENODEV;
+	}
+	hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
+	ldev->lamp_count =
+		ldev->lamp_count_field->value[ldev->lamp_count_index];
+
+	hid_dbg(hdev, "LampCount from device: %d\n", ldev->lamp_count);
+
+	if (ldev->lamp_count <= 0) {
+		hid_warn(hdev, "LampCount is %d (invalid)\n", ldev->lamp_count);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int lamparray_parse_update_report(struct lamparray_device *ldev)
+{
+	struct hid_device *hdev = ldev->hdev;
+	struct hid_report_enum *re;
+	struct hid_report *report;
+	struct hid_field *field;
+	int i, j;
+
+	lamparray_dump_reports(hdev);
+
+	re = &hdev->report_enum[HID_FEATURE_REPORT];
+
+	list_for_each_entry(report, &re->report_list, list) {
+		for (i = 0; i < report->maxfield; i++) {
+			field = report->field[i];
+			if (!field)
+				continue;
+
+			if (!field->usage || !field->maxusage)
+				continue;
+
+			for (j = 0; j < field->maxusage; j++) {
+				u32 usage = field->usage[j].hid;
+				u16 page = usage >> 16;
+				u16 id = usage & 0xffff;
+
+				if (page !=
+				    HID_LIGHTING_ILLUMINATION_USAGE_PAGE)
+					continue;
+				switch (id) {
+				case HID_LAIP_LAMP_COUNT:
+					ldev->lamp_count_field = field;
+					ldev->lamp_count_index = j;
+					break;
+				case HID_LAIP_RED_UPDATE_CHANNEL:
+					ldev->update_report = report;
+					ldev->red_field = field;
+					ldev->red_index = j;
+					break;
+				case HID_LAIP_GREEN_UPDATE_CHANNEL:
+					ldev->update_report = report;
+					ldev->green_field = field;
+					ldev->green_index = j;
+					break;
+				case HID_LAIP_BLUE_UPDATE_CHANNEL:
+					ldev->update_report = report;
+					ldev->blue_field = field;
+					ldev->blue_index = j;
+					break;
+				case HID_LAIP_INTENSITY_UPDATE_CHANNEL:
+					ldev->update_report = report;
+					ldev->intensity_field = field;
+					ldev->intensity_index = j;
+					break;
+				case HID_LAIP_LAMP_ID_START:
+					ldev->range_start_field = field;
+					ldev->range_start_index = j;
+					break;
+				case HID_LAIP_LAMP_ID_END:
+					ldev->range_end_field = field;
+					ldev->range_end_index = j;
+					break;
+				case HID_LAIP_AUTONOMOUS_MODE:
+					ldev->autonomous_field = field;
+					ldev->autonomous_report = report;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+	}
+
+	if (!ldev->update_report || !ldev->red_field || !ldev->green_field ||
+	    !ldev->blue_field || !ldev->autonomous_report || !ldev->autonomous_field)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int lamparray_hw_set_autonomous(struct lamparray_device *ldev,
+				       bool enable)
+{
+	struct hid_device *hdev = ldev->hdev;
+	struct hid_field *field = ldev->autonomous_field;
+	struct hid_report *report = ldev->autonomous_report;
+
+	if (!field || !report)
+		return -ENODEV;
+
+	field->value[0] = enable ? 1 : 0;
+
+	hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
+	return 0;
+}
+
+static int lamparray_hw_set_state(struct lamparray_device *ldev, u8 r, u8 g,
+				  u8 b, u8 intensity)
+{
+	struct hid_device *hdev = ldev->hdev;
+	struct hid_report *report = ldev->update_report;
+	int i, j;
+
+	if (!report || !ldev->red_field || !ldev->green_field ||
+	    !ldev->blue_field || !ldev->intensity_field)
+		return -ENODEV;
+
+	if (ldev->range_start_field && ldev->range_end_field) {
+		ldev->range_start_field->value[ldev->range_start_index] = 0;
+		ldev->range_end_field->value[ldev->range_end_index] = ldev->lamp_count - 1;
+	}
+
+	for (i = 0; i < report->maxfield; i++) {
+		struct hid_field *field = report->field[i];
+
+		if (!field || !field->usage || !field->maxusage)
+			continue;
+
+		for (j = 0; j < field->maxusage; j++) {
+			u32 usage = field->usage[j].hid;
+			u16 page = usage >> 16;
+			u16 id = usage & 0xffff;
+
+			if (page != HID_LIGHTING_ILLUMINATION_USAGE_PAGE)
+				continue;
+
+			switch (id) {
+			case HID_LAIP_RED_UPDATE_CHANNEL:
+				field->value[j] = r;
+				break;
+			case HID_LAIP_GREEN_UPDATE_CHANNEL:
+				field->value[j] = g;
+				break;
+			case HID_LAIP_BLUE_UPDATE_CHANNEL:
+				field->value[j] = b;
+				break;
+			case HID_LAIP_INTENSITY_UPDATE_CHANNEL:
+				field->value[j] = intensity;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+	hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
+	return 0;
+}
+
+static int lamparray_hw_get_state(struct lamparray_device *ldev, u8 *r, u8 *g,
+				  u8 *b, enum led_brightness *brightness)
+{
+	struct hid_device *hdev = ldev->hdev;
+	struct hid_report *report = ldev->update_report;
+
+	if (!report || !ldev->red_field || !ldev->green_field ||
+	    !ldev->blue_field || !ldev->intensity_field)
+		return -ENODEV;
+
+	if (!r || !g || !b || !brightness)
+		return -EINVAL;
+
+	/* Single-zone: Reading lamp 0 only suffices */
+	if (ldev->range_start_field && ldev->range_end_field) {
+		ldev->range_start_field->value[ldev->range_start_index] = 0;
+		ldev->range_end_field->value[ldev->range_end_index] = 0;
+	}
+
+	hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
+
+	*r = ldev->red_field->value[ldev->red_index];
+	*g = ldev->green_field->value[ldev->green_index];
+	*b = ldev->blue_field->value[ldev->blue_index];
+	*brightness = ldev->intensity_field->value[ldev->intensity_index];
+
+	return 0;
+}
+
+/* Helper functions */
+
+static int lamparray_restore_state(struct lamparray_device *ldev)
+{
+	u8 r, g, b;
+	int ret;
+	enum led_brightness brightness;
+
+	mutex_lock(&ldev->lock);
+
+	if (!ldev->use_leds_uapi) {
+		mutex_unlock(&ldev->lock);
+		return 0;
+	}
+
+	r = ldev->last_r;
+	g = ldev->last_g;
+	b = ldev->last_b;
+	brightness = ldev->last_brightness;
+
+	ldev->mc_cdev.subled_info[0].brightness = r;
+	ldev->mc_cdev.subled_info[1].brightness = g;
+	ldev->mc_cdev.subled_info[2].brightness = b;
+	ldev->mc_cdev.led_cdev.brightness = brightness;
+
+	mutex_unlock(&ldev->lock);
+
+	ret = lamparray_hw_set_state(ldev, r, g, b, brightness);
+	return ret;
+}
+
+/* LEDs API */
+
+static int lamparray_led_brightness_set(struct led_classdev *cdev,
+					enum led_brightness brightness)
+{
+	struct led_classdev_mc *mc = lcdev_to_mccdev(cdev);
+	struct lamparray_device *ldev =
+		container_of(mc, struct lamparray_device, mc_cdev);
+	struct lamparray *la = container_of(ldev, struct lamparray, ldev);
+	u8 r, g, b;
+	int ret;
+
+	if (!la)
+		return -ENODEV;
+	ldev = &la->ldev;
+
+	ret = led_mc_calc_color_components(mc, brightness);
+	if (ret)
+		return ret;
+
+	r = mc->subled_info[0].brightness;
+	g = mc->subled_info[1].brightness;
+	b = mc->subled_info[2].brightness;
+
+	ret = lamparray_hw_set_state(ldev, r, g, b, brightness);
+	if (ret)
+		hid_err(ldev->hdev, "Failed to send LampArray update: %d\n",
+			ret);
+
+	mutex_lock(&ldev->lock);
+	ldev->last_r = r;
+	ldev->last_g = g;
+	ldev->last_b = b;
+	ldev->last_brightness = brightness;
+	mutex_unlock(&ldev->lock);
+
+	return 0;
+}
+
+static enum led_brightness
+lamparray_led_brightness_get(struct led_classdev *cdev)
+{
+	struct led_classdev_mc *mc = lcdev_to_mccdev(cdev);
+	struct lamparray_device *ldev =
+		container_of(mc, struct lamparray_device, mc_cdev);
+	enum led_brightness brightness;
+	struct lamparray *la = container_of(ldev, struct lamparray, ldev);
+	u8 rr, gg, bb;
+	enum led_brightness br;
+	int ret;
+
+	/* Default: cache (also used while registering LED classdev) */
+	mutex_lock(&ldev->lock);
+	brightness = ldev->last_brightness;
+	mutex_unlock(&ldev->lock);
+
+	/* Only do HID readback after registration completed */
+	if (READ_ONCE(ldev->led_registered)) {
+		if (!la)
+			return brightness;
+		ldev = &la->ldev;
+
+		ret = lamparray_hw_get_state(ldev, &rr, &gg, &bb, &br);
+		if (ret) {
+			hid_warn(ldev->hdev,
+				 "Failed to read LampArray state (%d), using cached brightness %u\n",
+				 ret, brightness);
+			return brightness;
+		}
+
+		mutex_lock(&ldev->lock);
+		if (ldev->last_r != rr || ldev->last_g != gg ||
+		    ldev->last_b != bb || ldev->last_brightness != br) {
+			ldev->last_r = rr;
+			ldev->last_g = gg;
+			ldev->last_b = bb;
+			ldev->last_brightness = br;
+
+			if (ldev->led_registered && ldev->mc_cdev.subled_info) {
+				ldev->mc_cdev.subled_info[0].brightness = rr;
+				ldev->mc_cdev.subled_info[1].brightness = gg;
+				ldev->mc_cdev.subled_info[2].brightness = bb;
+			}
+		}
+		mutex_unlock(&ldev->lock);
+		return br;
+	}
+	return brightness;
+}
+
+static int lamparray_register_led(struct lamparray_device *ldev)
+{
+	struct device *dev = &ldev->hdev->dev;
+	struct led_classdev *cdev = &ldev->mc_cdev.led_cdev;
+	u8 r_i, g_i, b_i;
+	int ret;
+
+	mutex_lock(&ldev->lock);
+
+	if (ldev->led_registered) {
+		mutex_unlock(&ldev->lock);
+		return 0;
+	}
+
+	if (!cdev->name) {
+		cdev->name =
+			devm_kasprintf(dev, GFP_KERNEL, "%s", dev_name(dev));
+		if (!cdev->name) {
+			mutex_unlock(&ldev->lock);
+			return -ENOMEM;
+		}
+	}
+
+	cdev->max_brightness = 255;
+	cdev->brightness_set_blocking = lamparray_led_brightness_set;
+	cdev->brightness_get = lamparray_led_brightness_get;
+	cdev->brightness = ldev->last_brightness;
+
+	ldev->subleds[0].color_index = LED_COLOR_ID_RED;
+	ldev->subleds[1].color_index = LED_COLOR_ID_GREEN;
+	ldev->subleds[2].color_index = LED_COLOR_ID_BLUE;
+
+	/*
+	 * Initialize the color mix (multi_intensity) from the last known HW/init
+	 * state so that writing only /brightness scales the expected default color
+	 * instead of white.
+	 *
+	 * If last_brightness is non-zero, treat last_r/g/b as per-channel
+	 * brightness and normalize back to intensities (0..255).
+	 * If last_brightness is zero, keep last_r/g/b as the intended mix.
+	 */
+	if (ldev->last_brightness) {
+		r_i = (u8)min_t(unsigned int, 255,
+				(ldev->last_r * 255u) / ldev->last_brightness);
+		g_i = (u8)min_t(unsigned int, 255,
+				(ldev->last_g * 255u) / ldev->last_brightness);
+		b_i = (u8)min_t(unsigned int, 255,
+				(ldev->last_b * 255u) / ldev->last_brightness);
+	} else {
+		r_i = ldev->last_r;
+		g_i = ldev->last_g;
+		b_i = ldev->last_b;
+	}
+
+	ldev->subleds[0].intensity = r_i;
+	ldev->subleds[1].intensity = g_i;
+	ldev->subleds[2].intensity = b_i;
+
+	ldev->mc_cdev.subled_info = ldev->subleds;
+	ldev->mc_cdev.num_colors = ARRAY_SIZE(ldev->subleds);
+
+	/* Ensure subled_info[].brightness matches intensity + brightness */
+	led_mc_calc_color_components(&ldev->mc_cdev, cdev->brightness);
+
+	ldev->mc_cdev.subled_info = ldev->subleds;
+	ldev->mc_cdev.num_colors = ARRAY_SIZE(ldev->subleds);
+
+	mutex_unlock(&ldev->lock);
+
+	ret = led_classdev_multicolor_register(dev, &ldev->mc_cdev);
+	if (ret)
+		return ret;
+
+	mutex_lock(&ldev->lock);
+	ldev->led_registered = true;
+	mutex_unlock(&ldev->lock);
+
+	return 0;
+}
+
+static void lamparray_unregister_led(struct lamparray_device *ldev)
+{
+	bool was_registered;
+
+	mutex_lock(&ldev->lock);
+	was_registered = ldev->led_registered;
+	ldev->led_registered = false;
+	mutex_unlock(&ldev->lock);
+
+	if (!was_registered)
+		return;
+
+	led_classdev_multicolor_unregister(&ldev->mc_cdev);
+}
+
+/* Sysfs */
+
+static struct lamparray_device *
+lamparray_ldev_from_sysfs_dev(struct device *dev)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+
+	return xa_load(&lamparray_by_hdev, (unsigned long)hdev);
+}
+
+static ssize_t use_leds_uapi_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct lamparray_device *ldev = lamparray_ldev_from_sysfs_dev(dev);
+
+	if (!ldev)
+		return -ENODEV;
+
+	return sysfs_emit(buf, "%d\n", ldev->use_leds_uapi);
+}
+
+static ssize_t use_leds_uapi_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct lamparray_device *ldev = lamparray_ldev_from_sysfs_dev(dev);
+	int val;
+	int old_val;
+	int ret;
+
+	if (!ldev)
+		return -ENODEV;
+
+	ret = kstrtoint(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	mutex_lock(&ldev->lock);
+	old_val = ldev->use_leds_uapi;
+
+	if (val == old_val) {
+		mutex_unlock(&ldev->lock);
+		return count;
+	}
+
+	ldev->use_leds_uapi = val;
+	mutex_unlock(&ldev->lock);
+
+	if (val == 1) {
+		ret = lamparray_register_led(ldev);
+		if (ret) {
+			mutex_lock(&ldev->lock);
+			ldev->use_leds_uapi = old_val;
+			mutex_unlock(&ldev->lock);
+			return ret;
+		}
+		ret = lamparray_restore_state(ldev);
+		if (ret) {
+			hid_err(ldev->hdev, "Could not restore state: %d", ret);
+			return ret;
+		}
+
+	} else {
+		lamparray_unregister_led(ldev);
+	}
+
+	return count;
+}
+static DEVICE_ATTR_RW(use_leds_uapi);
+
+static struct attribute *lamparray_attrs[] = {
+	&dev_attr_use_leds_uapi.attr,
+	NULL,
+};
+
+static const struct attribute_group lamparray_attr_group = {
+	.attrs = lamparray_attrs,
+};
+
+static int lamparray_register_sysfs(struct lamparray_device *ldev)
+{
+	struct device *dev = &ldev->hdev->dev;
+	int ret;
+
+	ret = sysfs_create_group(&dev->kobj, &lamparray_attr_group);
+	if (ret)
+		hid_err(ldev->hdev,
+			"Failed to create lamparray sysfs group: %d\n", ret);
+
+	return ret;
+}
+
+static void lamparray_remove_sysfs(struct lamparray_device *ldev)
+{
+	sysfs_remove_group(&ldev->hdev->dev.kobj, &lamparray_attr_group);
+}
+
+/* Public API */
+
+bool lamparray_is_supported_device(struct hid_device *hdev)
+{
+	unsigned int i;
+
+	hid_dbg(hdev, "lamparray: walking %u collections\n",
+		hdev->maxcollection);
+
+	for (i = 0; i < hdev->maxcollection; i++) {
+		struct hid_collection *col = &hdev->collection[i];
+		u16 page = (col->usage & HID_USAGE_PAGE) >> 16;
+		u16 code = col->usage & HID_USAGE;
+
+		hid_dbg(hdev,
+			"lamparray:  collection[%u]: type=%u level=%u usage=0x%08x page=0x%04x code=0x%04x\n",
+			i, col->type, col->level, col->usage, page, code);
+
+		if (col->type == HID_COLLECTION_APPLICATION &&
+		    page == HID_LIGHTING_ILLUMINATION_USAGE_PAGE &&
+		    code == HID_APPLICATION_COLLECTION_USAGE_TYPE) {
+			return true;
+		}
+	}
+	return false;
+}
+EXPORT_SYMBOL_GPL(lamparray_is_supported_device);
+
+struct lamparray *
+lamparray_register(struct hid_device *hdev,
+		   const struct lamparray_init_state *led_init_state)
+{
+	int ret;
+	struct lamparray *la;
+	struct lamparray_device *ldev;
+
+	if (!hdev)
+		return ERR_PTR(-ENODEV);
+
+	la = kzalloc(sizeof(*la), GFP_KERNEL);
+	if (!la)
+		return ERR_PTR(-ENOMEM);
+
+	ldev = &la->ldev;
+
+	mutex_init(&ldev->lock);
+	ldev->hdev = hdev;
+	ldev->quirks = lamparray_lookup_quirks(hdev);
+	ldev->use_leds_uapi = 1;
+	ldev->led_registered = false;
+	if (!led_init_state) {
+		ldev->last_r = 255;
+		ldev->last_g = 255;
+		ldev->last_b = 255;
+		ldev->last_brightness = LED_OFF;
+	} else {
+		ldev->last_r = led_init_state->r;
+		ldev->last_g = led_init_state->g;
+		ldev->last_b = led_init_state->b;
+		ldev->last_brightness = led_init_state->brightness;
+	}
+	ret = lamparray_parse_update_report(ldev);
+	if (ret) {
+		hid_err(hdev, "No LampArray update report found: %d\n", ret);
+		goto err_free;
+	}
+
+	ret = lamparray_read_lamp_count(ldev);
+	if (ret) {
+		hid_err(hdev,
+			"Could not determine LampCount. This device needs a quirk for a fixed LampCount: %d\n",
+			ret);
+		goto err_unregister_led;
+	}
+
+	ret = lamparray_register_led(ldev);
+	if (ret) {
+		hid_warn(hdev, "Failed to register LED UAPI: %d\n", ret);
+		mutex_lock(&ldev->lock);
+		ldev->use_leds_uapi = 0;
+		mutex_unlock(&ldev->lock);
+	}
+
+	ret = xa_err(xa_store(&lamparray_by_hdev, (unsigned long)hdev, ldev,
+			      GFP_KERNEL));
+	if (ret)
+		goto err_unregister_led;
+
+	ret = lamparray_register_sysfs(ldev);
+	if (ret)
+		goto err_xa_erase;
+
+	ret = lamparray_hw_set_autonomous(ldev, false);
+	if (ret) {
+		hid_err(hdev, "Could not disable autonomous mode: %d", ret);
+		goto err_remove_sysfs;
+	}
+
+	hid_info(hdev, "LampArray device registered\n");
+
+	ret = lamparray_restore_state(ldev);
+	if (ret) {
+		hid_err(hdev, "Failed to set standard state: %d", ret);
+		goto err_remove_sysfs;
+	}
+	return la;
+
+err_remove_sysfs:
+	lamparray_remove_sysfs(ldev);
+err_xa_erase:
+	xa_erase(&lamparray_by_hdev, (unsigned long)hdev);
+err_unregister_led:
+	lamparray_unregister_led(ldev);
+err_free:
+	kfree(la);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(lamparray_register);
+
+void lamparray_unregister(struct lamparray *la)
+{
+	struct lamparray_device *ldev;
+
+	if (!la)
+		return;
+
+	ldev = &la->ldev;
+
+	lamparray_unregister_led(ldev);
+	lamparray_remove_sysfs(ldev);
+	xa_erase(&lamparray_by_hdev, (unsigned long)ldev->hdev);
+
+	kfree(la);
+}
+EXPORT_SYMBOL_GPL(lamparray_unregister);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HID LampArray helper module (single-zone RGB)");
diff --git a/drivers/hid/hid-lamparray.h b/drivers/hid/hid-lamparray.h
new file mode 100644
index 000000000000..ac3edd366a5b
--- /dev/null
+++ b/drivers/hid/hid-lamparray.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _HID_LAMPARRAY_H
+#define _HID_LAMPARRAY_H
+
+#include <linux/types.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+
+struct hid_device;
+struct lamparray;
+
+/*
+ * Optional initial LED state for lamparray_register().
+ * Used to define the initial state of a LampArray's LEDs.
+ */
+struct lamparray_init_state {
+	u8 r;
+	u8 g;
+	u8 b;
+	enum led_brightness brightness;
+};
+
+#if IS_ENABLED(CONFIG_HID_LAMPARRAY)
+
+/**
+ * lamparray_is_supported_device() - check whether a HID device supports LampArray
+ * @hdev: HID device to inspect
+ *
+ * Check whether the given HID device exposes a Lighting/LampArray application
+ * collection as defined by the HID Lighting specification.
+ *
+ * This helper can be used by HID drivers to determine whether LampArray
+ * functionality should be enabled for a device.
+ *
+ * Return: %true if LampArray support is detected, %false otherwise.
+ */
+bool lamparray_is_supported_device(struct hid_device *hdev);
+
+/**
+ * lamparray_register() - initialize LampArray support for a HID device
+ * @hdev: HID device
+ * @led_init_state: Optional LED state at init specification
+ *
+ * Allocate and initialize internal LampArray state for the given HID device.
+ * The function parses required HID reports and fields and registers the
+ * associated miscdevice and sysfs attributes.
+ *
+ * If enabled, a multicolor LED class device is also registered to expose the
+ * LampArray functionality via the LED subsystem. If specified, the desired
+ * initial LED state is applied. If led_init_state is NULL, a default state is
+ * applied.
+ *
+ * Return: pointer to a LampArray handle on success, or ERR_PTR() on failure.
+ */
+struct lamparray *lamparray_register(struct hid_device *hdev,
+				     const struct lamparray_init_state *led_init_state);
+
+/**
+ * lamparray_unregister() - tear down LampArray support
+ * @la: LampArray handle returned by lamparray_register()
+ *
+ * Remove all resources associated with a LampArray instance.
+ *
+ * This unregisters the LED class device (if present), removes the miscdevice
+ * and sysfs interfaces and frees all internal state associated with @la.
+ */
+void lamparray_unregister(struct lamparray *la);
+
+#else /* !CONFIG_HID_LAMPARRAY */
+
+static inline bool lamparray_is_supported_device(struct hid_device *hdev)
+{
+	return false;
+}
+
+static inline struct lamparray *
+lamparray_register(struct hid_device *hdev,
+		   const struct lamparray_init_state *led_init_state)
+{
+	return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void lamparray_unregister(struct lamparray *la)
+{
+}
+
+#endif /* CONFIG_HID_LAMPARRAY */
+
+#endif /* _HID_LAMPARRAY_H */
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 9/9] mfd: motorola-cpcap: add support for Mot CPCAP composition
From: Svyatoslav Ryhel @ 2026-02-23  6:38 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Lee Jones, Pavel Machek, Liam Girdwood, Mark Brown,
	Svyatoslav Ryhel, David Lechner, Tony Lindgren
  Cc: linux-input, devicetree, linux-kernel, linux-leds
In-Reply-To: <20260223063858.12208-1-clamor95@gmail.com>

Add a MFD subdevice composition used in Tegra20 based Mot board
(Motorola Atrix 4G and Droid X2).

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/mfd/motorola-cpcap.c | 50 ++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index 516d1e33affa..fdec92f5c6b0 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -335,6 +335,54 @@ static const struct cpcap_chip_data cpcap_mapphone_data = {
 	.num_devices = ARRAY_SIZE(cpcap_mapphone_mfd_devices),
 };
 
+/*
+ * The Mot board features a USB-PHY and charger similar to the ones in
+ * Mapphone; however, because Mot is based on Tegra20, it is incompatible
+ * with the existing implementation, which is tightly interconnected with
+ * the OMAP USB PHY.
+ */
+static const struct mfd_cell cpcap_mot_mfd_devices[] = {
+	{
+		.name          = "cpcap_adc",
+		.of_compatible = "motorola,mot-cpcap-adc",
+	}, {
+		.name          = "cpcap_battery",
+		.of_compatible = "motorola,cpcap-battery",
+	}, {
+		.name          = "cpcap-regulator",
+		.of_compatible = "motorola,mot-cpcap-regulator",
+	}, {
+		.name          = "cpcap-rtc",
+		.of_compatible = "motorola,cpcap-rtc",
+	}, {
+		.name          = "cpcap-pwrbutton",
+		.of_compatible = "motorola,cpcap-pwrbutton",
+	}, {
+		.name          = "cpcap-led",
+		.id            = 0,
+		.of_compatible = "motorola,cpcap-led-red",
+	}, {
+		.name          = "cpcap-led",
+		.id            = 1,
+		.of_compatible = "motorola,cpcap-led-green",
+	}, {
+		.name          = "cpcap-led",
+		.id            = 2,
+		.of_compatible = "motorola,cpcap-led-blue",
+	}, {
+		.name          = "cpcap-led",
+		.id            = 3,
+		.of_compatible = "motorola,cpcap-led-adl",
+	}, {
+		.name          = "cpcap-codec",
+	},
+};
+
+static const struct cpcap_chip_data cpcap_mot_data = {
+	.mfd_devices = cpcap_mot_mfd_devices,
+	.num_devices = ARRAY_SIZE(cpcap_mot_mfd_devices),
+};
+
 static int cpcap_probe(struct spi_device *spi)
 {
 	struct cpcap_ddata *cpcap;
@@ -389,6 +437,7 @@ static int cpcap_probe(struct spi_device *spi)
 static const struct of_device_id cpcap_of_match[] = {
 	{ .compatible = "motorola,cpcap", .data = &cpcap_default_data },
 	{ .compatible = "motorola,mapphone-cpcap", .data = &cpcap_mapphone_data	},
+	{ .compatible = "motorola,mot-cpcap", .data = &cpcap_mot_data },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, cpcap_of_match);
@@ -396,6 +445,7 @@ MODULE_DEVICE_TABLE(of, cpcap_of_match);
 static const struct spi_device_id cpcap_spi_ids[] = {
 	{ .name = "cpcap", .driver_data = (kernel_ulong_t)&cpcap_default_data },
 	{ .name = "mapphone-cpcap", .driver_data = (kernel_ulong_t)&cpcap_mapphone_data },
+	{ .name = "mot-cpcap", .driver_data = (kernel_ulong_t)&cpcap_mot_data },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(spi, cpcap_spi_ids);
-- 
2.51.0


^ permalink raw reply related

* [PATCH v3 8/9] mfd: motorola-cpcap: diverge configuration per-board
From: Svyatoslav Ryhel @ 2026-02-23  6:38 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Lee Jones, Pavel Machek, Liam Girdwood, Mark Brown,
	Svyatoslav Ryhel, David Lechner, Tony Lindgren
  Cc: linux-input, devicetree, linux-kernel, linux-leds
In-Reply-To: <20260223063858.12208-1-clamor95@gmail.com>

MFD have rigid subdevice structure which does not allow flexible dynamic
subdevice linking. Address this by diverging CPCAP subdevice composition
to take into account board specific configuration.

Create a common default subdevice composition, rename existing subdevice
composition into cpcap_mapphone_mfd_devices since it targets mainly
Mapphone board.

Removed st,6556002 as it is no longer applicable to all cases and
duplicates motorola,cpcap, which is used as the default composition.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/mfd/motorola-cpcap.c | 101 ++++++++++++++++++++++++++++-------
 1 file changed, 83 insertions(+), 18 deletions(-)

diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index d8243b956f87..516d1e33affa 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
+#include <linux/property.h>
 #include <linux/regmap.h>
 #include <linux/sysfs.h>
 
@@ -24,10 +25,16 @@
 #define CPCAP_REGISTER_SIZE	4
 #define CPCAP_REGISTER_BITS	16
 
+struct cpcap_chip_data {
+	const struct mfd_cell *mfd_devices;
+	unsigned int num_devices;
+};
+
 struct cpcap_ddata {
 	struct spi_device *spi;
 	struct regmap_irq *irqs;
 	struct regmap_irq_chip_data *irqdata[CPCAP_NR_IRQ_CHIPS];
+	const struct cpcap_chip_data *cdata;
 	const struct regmap_config *regmap_conf;
 	struct regmap *regmap;
 };
@@ -195,20 +202,6 @@ static int cpcap_init_irq(struct cpcap_ddata *cpcap)
 	return 0;
 }
 
-static const struct of_device_id cpcap_of_match[] = {
-	{ .compatible = "motorola,cpcap", },
-	{ .compatible = "st,6556002", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, cpcap_of_match);
-
-static const struct spi_device_id cpcap_spi_ids[] = {
-	{ .name = "cpcap", },
-	{ .name = "6556002", },
-	{},
-};
-MODULE_DEVICE_TABLE(spi, cpcap_spi_ids);
-
 static const struct regmap_config cpcap_regmap_config = {
 	.reg_bits = 16,
 	.reg_stride = 4,
@@ -241,7 +234,56 @@ static int cpcap_resume(struct device *dev)
 
 static DEFINE_SIMPLE_DEV_PM_OPS(cpcap_pm, cpcap_suspend, cpcap_resume);
 
-static const struct mfd_cell cpcap_mfd_devices[] = {
+static const struct mfd_cell cpcap_default_mfd_devices[] = {
+	{
+		.name          = "cpcap_adc",
+		.of_compatible = "motorola,cpcap-adc",
+	}, {
+		.name          = "cpcap_battery",
+		.of_compatible = "motorola,cpcap-battery",
+	}, {
+		.name          = "cpcap-regulator",
+		.of_compatible = "motorola,cpcap-regulator",
+	}, {
+		.name          = "cpcap-rtc",
+		.of_compatible = "motorola,cpcap-rtc",
+	}, {
+		.name          = "cpcap-pwrbutton",
+		.of_compatible = "motorola,cpcap-pwrbutton",
+	}, {
+		.name          = "cpcap-usb-phy",
+		.of_compatible = "motorola,cpcap-usb-phy",
+	}, {
+		.name          = "cpcap-led",
+		.id            = 0,
+		.of_compatible = "motorola,cpcap-led-red",
+	}, {
+		.name          = "cpcap-led",
+		.id            = 1,
+		.of_compatible = "motorola,cpcap-led-green",
+	}, {
+		.name          = "cpcap-led",
+		.id            = 2,
+		.of_compatible = "motorola,cpcap-led-blue",
+	}, {
+		.name          = "cpcap-led",
+		.id            = 3,
+		.of_compatible = "motorola,cpcap-led-adl",
+	}, {
+		.name          = "cpcap-led",
+		.id            = 4,
+		.of_compatible = "motorola,cpcap-led-cp",
+	}, {
+		.name          = "cpcap-codec",
+	},
+};
+
+static const struct cpcap_chip_data cpcap_default_data = {
+	.mfd_devices = cpcap_default_mfd_devices,
+	.num_devices = ARRAY_SIZE(cpcap_default_mfd_devices),
+};
+
+static const struct mfd_cell cpcap_mapphone_mfd_devices[] = {
 	{
 		.name          = "cpcap_adc",
 		.of_compatible = "motorola,mapphone-cpcap-adc",
@@ -285,7 +327,12 @@ static const struct mfd_cell cpcap_mfd_devices[] = {
 		.of_compatible = "motorola,cpcap-led-cp",
 	}, {
 		.name          = "cpcap-codec",
-	}
+	},
+};
+
+static const struct cpcap_chip_data cpcap_mapphone_data = {
+	.mfd_devices = cpcap_mapphone_mfd_devices,
+	.num_devices = ARRAY_SIZE(cpcap_mapphone_mfd_devices),
 };
 
 static int cpcap_probe(struct spi_device *spi)
@@ -297,6 +344,10 @@ static int cpcap_probe(struct spi_device *spi)
 	if (!cpcap)
 		return -ENOMEM;
 
+	cpcap->cdata = device_get_match_data(&spi->dev);
+	if (!cpcap->cdata)
+		return -ENODEV;
+
 	cpcap->spi = spi;
 	spi_set_drvdata(spi, cpcap);
 
@@ -331,10 +382,24 @@ static int cpcap_probe(struct spi_device *spi)
 	spi->dev.coherent_dma_mask = 0;
 	spi->dev.dma_mask = &spi->dev.coherent_dma_mask;
 
-	return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
-				    ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
+	return devm_mfd_add_devices(&spi->dev, 0, cpcap->cdata->mfd_devices,
+				    cpcap->cdata->num_devices, NULL, 0, NULL);
 }
 
+static const struct of_device_id cpcap_of_match[] = {
+	{ .compatible = "motorola,cpcap", .data = &cpcap_default_data },
+	{ .compatible = "motorola,mapphone-cpcap", .data = &cpcap_mapphone_data	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cpcap_of_match);
+
+static const struct spi_device_id cpcap_spi_ids[] = {
+	{ .name = "cpcap", .driver_data = (kernel_ulong_t)&cpcap_default_data },
+	{ .name = "mapphone-cpcap", .driver_data = (kernel_ulong_t)&cpcap_mapphone_data },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, cpcap_spi_ids);
+
 static struct spi_driver cpcap_driver = {
 	.driver = {
 		.name = "cpcap-core",
-- 
2.51.0


^ permalink raw reply related

* [PATCH v3 7/9] dt-bindings: mfd: motorola-cpcap: document Mapphone and Mot CPCAP
From: Svyatoslav Ryhel @ 2026-02-23  6:38 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Lee Jones, Pavel Machek, Liam Girdwood, Mark Brown,
	Svyatoslav Ryhel, David Lechner, Tony Lindgren
  Cc: linux-input, devicetree, linux-kernel, linux-leds
In-Reply-To: <20260223063858.12208-1-clamor95@gmail.com>

Add compatibles for Mapphone and Mot CPCAP subdevice compositions. Both
variations cannot use st,6556002 fallback since they may be based on
different controllers.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 .../devicetree/bindings/mfd/motorola,cpcap.yaml       | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml b/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
index eea5b2efa80c..487e5456864b 100644
--- a/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
+++ b/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
@@ -14,9 +14,14 @@ allOf:
 
 properties:
   compatible:
-    items:
-      - const: motorola,cpcap
-      - const: st,6556002
+    oneOf:
+      - enum:
+          - motorola,mapphone-cpcap
+          - motorola,mot-cpcap
+
+      - items:
+          - const: motorola,cpcap
+          - const: st,6556002
 
   reg:
     maxItems: 1
-- 
2.51.0


^ permalink raw reply related

* [PATCH v3 6/9] dt-bindings: mfd: motorola-cpcap: convert to DT schema
From: Svyatoslav Ryhel @ 2026-02-23  6:38 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Lee Jones, Pavel Machek, Liam Girdwood, Mark Brown,
	Svyatoslav Ryhel, David Lechner, Tony Lindgren
  Cc: linux-input, devicetree, linux-kernel, linux-leds
In-Reply-To: <20260223063858.12208-1-clamor95@gmail.com>

Convert devicetree bindings for the Motorola CPCAP MFD from TXT to YAML.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 .../bindings/mfd/motorola,cpcap.yaml          | 411 ++++++++++++++++++
 .../bindings/mfd/motorola-cpcap.txt           |  78 ----
 2 files changed, 411 insertions(+), 78 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
 delete mode 100644 Documentation/devicetree/bindings/mfd/motorola-cpcap.txt

diff --git a/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml b/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
new file mode 100644
index 000000000000..eea5b2efa80c
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
@@ -0,0 +1,411 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/motorola,cpcap.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Motorola CPCAP PMIC MFD
+
+maintainers:
+  - Svyatoslav Ryhel <clamor95@gmail.com>
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+  compatible:
+    items:
+      - const: motorola,cpcap
+      - const: st,6556002
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  spi-max-frequency:
+    maximum: 9600000
+
+  spi-cs-high: true
+  spi-cpol: true
+  spi-cpha: true
+
+  adc:
+    $ref: /schemas/iio/adc/motorola,cpcap-adc.yaml
+
+  audio-codec:
+    type: object
+    additionalProperties: false
+
+    properties:
+      interrupts:
+        items:
+          - description: headset detect interrupt
+          - description: microphone bias 2 detect interrupt
+
+      interrupt-names:
+        items:
+          - const: hs
+          - const: mb2
+
+      "#sound-dai-cells":
+        const: 1
+
+      VAUDIO-supply:
+        description:
+          Codec power supply, usually VAUDIO regulator of CPCAP.
+
+      ports:
+        $ref: /schemas/graph.yaml#/properties/ports
+
+        properties:
+          port@0:
+            $ref: /schemas/graph.yaml#/properties/port
+            description: port connected to the Stereo HiFi DAC
+
+          port@1:
+            $ref: /schemas/graph.yaml#/properties/port
+            description: port connected to the Voice DAC
+
+        required:
+          - port@0
+          - port@1
+
+    required:
+      - interrupts
+      - interrupt-names
+      - "#sound-dai-cells"
+
+  battery:
+    $ref: /schemas/power/supply/cpcap-battery.yaml
+
+  charger:
+    $ref: /schemas/power/supply/cpcap-charger.yaml
+
+  key-power:
+    $ref: /schemas/input/motorola,cpcap-pwrbutton.yaml
+
+  phy:
+    $ref: /schemas/phy/motorola,cpcap-usb-phy.yaml
+
+  regulator:
+    $ref: /schemas/regulator/motorola,cpcap-regulator.yaml
+
+  rtc:
+    $ref: /schemas/rtc/motorola,cpcap-rtc.yaml
+
+patternProperties:
+  "^led(-[a-z]+)?$":
+    $ref: /schemas/leds/motorola,cpcap-leds.yaml
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/input/linux-event-codes.h>
+
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpcap: pmic@0 {
+            compatible = "motorola,cpcap", "st,6556002";
+            reg = <0>; /* cs0 */
+
+            interrupt-parent = <&gpio1>;
+            interrupts = <7 IRQ_TYPE_EDGE_RISING>;
+
+            interrupt-controller;
+            #interrupt-cells = <2>;
+
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            spi-max-frequency = <3000000>;
+            spi-cs-high;
+
+            spi-cpol;
+            spi-cpha;
+
+            cpcap_adc: adc {
+                compatible = "motorola,cpcap-adc";
+
+                interrupt-parent = <&cpcap>;
+                interrupts = <8 IRQ_TYPE_NONE>;
+                interrupt-names = "adcdone";
+
+                #io-channel-cells = <1>;
+            };
+
+            cpcap_audio: audio-codec {
+                interrupt-parent = <&cpcap>;
+                interrupts = <9 IRQ_TYPE_NONE>, <10 IRQ_TYPE_NONE>;
+                interrupt-names = "hs", "mb2";
+
+                VAUDIO-supply = <&vdd_audio>;
+
+                #sound-dai-cells = <1>;
+
+                ports {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+
+                    /* HiFi */
+                    port@0 {
+                        reg = <0>;
+
+                        cpcap_audio_codec0: endpoint {
+                        };
+                    };
+
+                    /* Voice */
+                    port@1 {
+                        reg = <1>;
+
+                        cpcap_audio_codec1: endpoint {
+                        };
+                    };
+                };
+            };
+
+            cpcap_battery: battery {
+                compatible = "motorola,cpcap-battery";
+
+                interrupt-parent = <&cpcap>;
+                interrupts = <6 IRQ_TYPE_NONE>, <5 IRQ_TYPE_NONE>,
+                             <3 IRQ_TYPE_NONE>, <20 IRQ_TYPE_NONE>,
+                             <54 IRQ_TYPE_NONE>, <57 IRQ_TYPE_NONE>;
+                interrupt-names = "eol", "lowbph", "lowbpl",
+                                  "chrgcurr1", "battdetb", "cccal";
+
+                io-channels = <&cpcap_adc 0>, <&cpcap_adc 1>,
+                              <&cpcap_adc 5>, <&cpcap_adc 6>;
+                io-channel-names = "battdetb", "battp",
+                                   "chg_isense", "batti";
+                power-supplies = <&cpcap_charger>;
+            };
+
+            cpcap_charger: charger {
+                compatible = "motorola,mapphone-cpcap-charger";
+
+                interrupt-parent = <&cpcap>;
+                interrupts = <13 IRQ_TYPE_NONE>, <12 IRQ_TYPE_NONE>,
+                             <29 IRQ_TYPE_NONE>, <28 IRQ_TYPE_NONE>,
+                             <22 IRQ_TYPE_NONE>, <21 IRQ_TYPE_NONE>,
+                             <20 IRQ_TYPE_NONE>, <19 IRQ_TYPE_NONE>,
+                             <54 IRQ_TYPE_NONE>;
+                interrupt-names = "chrg_det", "rvrs_chrg", "chrg_se1b",
+                                  "se0conn", "rvrs_mode", "chrgcurr2",
+                                  "chrgcurr1", "vbusvld", "battdetb";
+
+                mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW>,
+                             <&gpio3 23 GPIO_ACTIVE_LOW>;
+
+                io-channels = <&cpcap_adc 0>, <&cpcap_adc 1>,
+                              <&cpcap_adc 2>, <&cpcap_adc 5>,
+                              <&cpcap_adc 6>;
+                io-channel-names = "battdetb", "battp",
+                                   "vbus", "chg_isense",
+                                   "batti";
+            };
+
+            key-power {
+                compatible = "motorola,cpcap-pwrbutton";
+
+                interrupt-parent = <&cpcap>;
+                interrupts = <23 IRQ_TYPE_NONE>;
+            };
+
+            led-red {
+                compatible = "motorola,cpcap-led-red";
+                vdd-supply = <&vdd_led>;
+                label = "status-led::red";
+            };
+
+            led-green {
+                compatible = "motorola,cpcap-led-green";
+                vdd-supply = <&vdd_led>;
+                label = "status-led::green";
+            };
+
+            led-blue {
+                compatible = "motorola,cpcap-led-blue";
+                vdd-supply = <&vdd_led>;
+                label = "status-led::blue";
+            };
+
+            cpcap_usb2_phy: phy {
+                compatible = "motorola,cpcap-usb-phy";
+
+                pinctrl-0 = <&usb_gpio_mux_sel1>, <&usb_gpio_mux_sel2>;
+                pinctrl-1 = <&usb_ulpi_pins>;
+                pinctrl-2 = <&usb_utmi_pins>;
+                pinctrl-3 = <&uart3_pins>;
+                pinctrl-names = "default", "ulpi", "utmi", "uart";
+                #phy-cells = <0>;
+
+                interrupts-extended =
+                    <&cpcap 15 IRQ_TYPE_NONE>, <&cpcap 14 IRQ_TYPE_NONE>,
+                    <&cpcap 28 IRQ_TYPE_NONE>, <&cpcap 19 IRQ_TYPE_NONE>,
+                    <&cpcap 18 IRQ_TYPE_NONE>, <&cpcap 17 IRQ_TYPE_NONE>,
+                    <&cpcap 16 IRQ_TYPE_NONE>, <&cpcap 49 IRQ_TYPE_NONE>,
+                    <&cpcap 48 IRQ_TYPE_NONE>;
+                interrupt-names = "id_ground", "id_float", "se0conn",
+                                  "vbusvld", "sessvld", "sessend",
+                                  "se1", "dm", "dp";
+
+                mode-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,
+                             <&gpio1 0 GPIO_ACTIVE_HIGH>;
+
+                io-channels = <&cpcap_adc 2>, <&cpcap_adc 7>;
+                io-channel-names = "vbus", "id";
+
+                vusb-supply = <&avdd_usb>;
+            };
+
+            regulator {
+                compatible = "motorola,cpcap-regulator";
+
+                regulators {
+                    vdd_cpu: SW1 {
+                        regulator-name = "vdd_cpu";
+                        regulator-min-microvolt = <750000>;
+                        regulator-max-microvolt = <1125000>;
+                        regulator-enable-ramp-delay = <1500>;
+                        regulator-always-on;
+                        regulator-boot-on;
+                    };
+
+                    vdd_core: SW2 {
+                        regulator-name = "vdd_core";
+                        regulator-min-microvolt = <950000>;
+                        regulator-max-microvolt = <1300000>;
+                        regulator-enable-ramp-delay = <1500>;
+                        regulator-always-on;
+                        regulator-boot-on;
+                    };
+
+                    vdd_1v8_vio: SW3 {
+                        regulator-name = "vdd_1v8_vio";
+                        regulator-min-microvolt = <1800000>;
+                        regulator-max-microvolt = <1800000>;
+                        regulator-enable-ramp-delay = <0>;
+                        regulator-always-on;
+                        regulator-boot-on;
+                    };
+
+                    vdd_aon: SW4 {
+                        regulator-name = "vdd_aon";
+                        regulator-min-microvolt = <950000>;
+                        regulator-max-microvolt = <1300000>;
+                        regulator-enable-ramp-delay = <1500>;
+                        regulator-always-on;
+                        regulator-boot-on;
+                    };
+
+                    vdd_led: SW5 {
+                        regulator-name = "vdd_led";
+                        regulator-min-microvolt = <5050000>;
+                        regulator-max-microvolt = <5050000>;
+                        regulator-enable-ramp-delay = <1500>;
+                        regulator-boot-on;
+                    };
+
+                    vdd_hvio: VHVIO {
+                        regulator-name = "vdd_hvio";
+                        regulator-min-microvolt = <2775000>;
+                        regulator-max-microvolt = <2775000>;
+                        regulator-enable-ramp-delay = <1000>;
+                    };
+
+                    vcore_emmc: VSDIO {
+                        regulator-name = "vcore_emmc";
+                        regulator-min-microvolt = <1500000>;
+                        regulator-max-microvolt = <3000000>;
+                        regulator-enable-ramp-delay = <1000>;
+                        regulator-always-on;
+                        regulator-boot-on;
+                    };
+
+                    avdd_dsi_csi: VCSI {
+                        regulator-name = "avdd_dsi_csi";
+                        regulator-min-microvolt = <1200000>;
+                        regulator-max-microvolt = <1200000>;
+                        regulator-enable-ramp-delay = <1000>;
+                        regulator-boot-on;
+                    };
+
+                    avdd_3v3_periph: VWLAN2 {
+                        regulator-name = "avdd_3v3_periph";
+                        regulator-min-microvolt = <2775000>;
+                        regulator-max-microvolt = <3300000>;
+                        regulator-enable-ramp-delay = <1000>;
+                        regulator-boot-on;
+                    };
+
+                    vddio_usd: VSIMCARD {
+                        regulator-name = "vddio_usd";
+                        regulator-min-microvolt = <1800000>;
+                        regulator-max-microvolt = <2900000>;
+                        regulator-enable-ramp-delay = <1000>;
+                        regulator-boot-on;
+                    };
+
+                    vdd_haptic: VVIB {
+                        regulator-name = "vdd_haptic";
+                        regulator-min-microvolt = <1300000>;
+                        regulator-max-microvolt = <3000000>;
+                        regulator-enable-ramp-delay = <1000>;
+                    };
+
+                    avdd_usb: VUSB {
+                        regulator-name = "avdd_usb";
+                        regulator-min-microvolt = <3300000>;
+                        regulator-max-microvolt = <3300000>;
+                        regulator-enable-ramp-delay = <1000>;
+                        regulator-always-on;
+                        regulator-boot-on;
+                    };
+
+                    vdd_audio: VAUDIO {
+                        regulator-name = "vdd_audio";
+                        regulator-min-microvolt = <2775000>;
+                        regulator-max-microvolt = <2775000>;
+                        regulator-enable-ramp-delay = <1000>;
+                        regulator-always-on;
+                        regulator-boot-on;
+                    };
+                };
+            };
+
+            cpcap_rtc: rtc {
+                compatible = "motorola,cpcap-rtc";
+
+                interrupt-parent = <&cpcap>;
+                interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
+            };
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt b/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
deleted file mode 100644
index 18c3fc26ca93..000000000000
--- a/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-Motorola CPCAP PMIC device tree binding
-
-Required properties:
-- compatible		: One or both of "motorola,cpcap" or "ste,6556002"
-- reg			: SPI chip select
-- interrupts		: The interrupt line the device is connected to
-- interrupt-controller	: Marks the device node as an interrupt controller
-- #interrupt-cells	: The number of cells to describe an IRQ, should be 2
-- #address-cells	: Child device offset number of cells, should be 1
-- #size-cells		: Child device size number of cells, should be 0
-- spi-max-frequency	: Typically set to 3000000
-- spi-cs-high		: SPI chip select direction
-
-Optional subnodes:
-
-The sub-functions of CPCAP get their own node with their own compatible values,
-which are described in the following files:
-
-- Documentation/devicetree/bindings/power/supply/cpcap-battery.yaml
-- Documentation/devicetree/bindings/power/supply/cpcap-charger.yaml
-- Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
-- Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
-- Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
-- Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
-- Documentation/devicetree/bindings/leds/leds-cpcap.txt
-- Documentation/devicetree/bindings/iio/adc/motorola,cpcap-adc.yaml
-
-The only exception is the audio codec. Instead of a compatible value its
-node must be named "audio-codec".
-
-Required properties for the audio-codec subnode:
-
-- #sound-dai-cells = <1>;
-- interrupts		: should contain jack detection interrupts, with headset
-			  detect interrupt matching "hs" and microphone bias 2
-			  detect interrupt matching "mb2" in interrupt-names.
-- interrupt-names	: Contains "hs", "mb2"
-
-The audio-codec provides two DAIs. The first one is connected to the
-Stereo HiFi DAC and the second one is connected to the Voice DAC.
-
-Example:
-
-&mcspi1 {
-	cpcap: pmic@0 {
-		compatible = "motorola,cpcap", "ste,6556002";
-		reg = <0>;	/* cs0 */
-		interrupt-parent = <&gpio1>;
-		interrupts = <7 IRQ_TYPE_EDGE_RISING>;
-		interrupt-controller;
-		#interrupt-cells = <2>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		spi-max-frequency = <3000000>;
-		spi-cs-high;
-
-		audio-codec {
-			#sound-dai-cells = <1>;
-			interrupts-extended = <&cpcap 9 0>, <&cpcap 10 0>;
-			interrupt-names = "hs", "mb2";
-
-			/* HiFi */
-			port@0 {
-				endpoint {
-					remote-endpoint = <&cpu_dai1>;
-				};
-			};
-
-			/* Voice */
-			port@1 {
-				endpoint {
-					remote-endpoint = <&cpu_dai2>;
-				};
-			};
-		};
-	};
-};
-
-- 
2.51.0


^ permalink raw reply related

* [PATCH v3 5/9] dt-bindings: input: cpcap-pwrbutton: convert to DT schema
From: Svyatoslav Ryhel @ 2026-02-23  6:38 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Lee Jones, Pavel Machek, Liam Girdwood, Mark Brown,
	Svyatoslav Ryhel, David Lechner, Tony Lindgren
  Cc: linux-input, devicetree, linux-kernel, linux-leds
In-Reply-To: <20260223063858.12208-1-clamor95@gmail.com>

Convert power button devicetree bindings for the Motorola CPCAP MFD from
TXT to YAML format. This patch does not change any functionality; the
bindings remain the same.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 .../bindings/input/cpcap-pwrbutton.txt        | 20 ------------
 .../input/motorola,cpcap-pwrbutton.yaml       | 32 +++++++++++++++++++
 2 files changed, 32 insertions(+), 20 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
 create mode 100644 Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml

diff --git a/Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt b/Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
deleted file mode 100644
index 0dd0076daf71..000000000000
--- a/Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Motorola CPCAP on key
-
-This module is part of the CPCAP. For more details about the whole
-chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt.
-
-This module provides a simple power button event via an Interrupt.
-
-Required properties:
-- compatible: should be one of the following
-   - "motorola,cpcap-pwrbutton"
-- interrupts: irq specifier for CPCAP's ON IRQ
-
-Example:
-
-&cpcap {
-	cpcap_pwrbutton: pwrbutton {
-		compatible = "motorola,cpcap-pwrbutton";
-		interrupts = <23 IRQ_TYPE_NONE>;
-	};
-};
diff --git a/Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml b/Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml
new file mode 100644
index 000000000000..77a3e5a47d1a
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/motorola,cpcap-pwrbutton.yaml
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/motorola,cpcap-pwrbutton.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Motorola CPCAP PMIC power key
+
+maintainers:
+  - Svyatoslav Ryhel <clamor95@gmail.com>
+
+description:
+  This module is part of the Motorola CPCAP MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml. The
+  power key is represented as a sub-node of the PMIC node on the device
+  tree.
+
+properties:
+  compatible:
+    const: motorola,cpcap-pwrbutton
+
+  interrupts:
+    items:
+      - description: CPCAP's ON interrupt
+
+required:
+  - compatible
+  - interrupts
+
+additionalProperties: false
+
+...
-- 
2.51.0


^ permalink raw reply related

* [PATCH v3 4/9] dt-bindings: leds: leds-cpcap: convert to DT schema
From: Svyatoslav Ryhel @ 2026-02-23  6:38 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Lee Jones, Pavel Machek, Liam Girdwood, Mark Brown,
	Svyatoslav Ryhel, David Lechner, Tony Lindgren
  Cc: linux-input, devicetree, linux-kernel, linux-leds
In-Reply-To: <20260223063858.12208-1-clamor95@gmail.com>

Convert LEDs devicetree bindings for the Motorola CPCAP MFD from TXT to
YAML format. This patch does not change any functionality; the bindings
remain the same.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
---
 .../devicetree/bindings/leds/leds-cpcap.txt   | 29 -------------
 .../bindings/leds/motorola,cpcap-leds.yaml    | 42 +++++++++++++++++++
 2 files changed, 42 insertions(+), 29 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/leds/leds-cpcap.txt
 create mode 100644 Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml

diff --git a/Documentation/devicetree/bindings/leds/leds-cpcap.txt b/Documentation/devicetree/bindings/leds/leds-cpcap.txt
deleted file mode 100644
index ebf7cdc7f70c..000000000000
--- a/Documentation/devicetree/bindings/leds/leds-cpcap.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-Motorola CPCAP PMIC LEDs
-------------------------
-
-This module is part of the CPCAP. For more details about the whole
-chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt.
-
-Requires node properties:
-- compatible: should be one of
-   * "motorola,cpcap-led-mdl"		(Main Display Lighting)
-   * "motorola,cpcap-led-kl"		(Keyboard Lighting)
-   * "motorola,cpcap-led-adl"		(Aux Display Lighting)
-   * "motorola,cpcap-led-red"		(Red Triode)
-   * "motorola,cpcap-led-green"		(Green Triode)
-   * "motorola,cpcap-led-blue"		(Blue Triode)
-   * "motorola,cpcap-led-cf"		(Camera Flash)
-   * "motorola,cpcap-led-bt"		(Bluetooth)
-   * "motorola,cpcap-led-cp"		(Camera Privacy LED)
-- label: see Documentation/devicetree/bindings/leds/common.txt
-- vdd-supply: A phandle to the regulator powering the LED
-
-Example:
-
-&cpcap {
-	cpcap_led_red: red-led {
-		compatible = "motorola,cpcap-led-red";
-		label = "cpcap:red";
-		vdd-supply = <&sw5>;
-	};
-};
diff --git a/Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml b/Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml
new file mode 100644
index 000000000000..c8e7b88a05cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/motorola,cpcap-leds.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/motorola,cpcap-leds.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Motorola CPCAP PMIC LEDs
+
+maintainers:
+  - Svyatoslav Ryhel <clamor95@gmail.com>
+
+description:
+  This module is part of the Motorola CPCAP MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml. LEDs are
+  represented as sub-nodes of the PMIC node on the device tree.
+
+allOf:
+  - $ref: /schemas/leds/common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - motorola,cpcap-led-adl # Display Lighting
+      - motorola,cpcap-led-blue # Blue Triode
+      - motorola,cpcap-led-bt # Bluetooth
+      - motorola,cpcap-led-cf # Camera Flash
+      - motorola,cpcap-led-cp # Camera Privacy LED
+      - motorola,cpcap-led-green # Green Triode
+      - motorola,cpcap-led-kl # Keyboard Lighting
+      - motorola,cpcap-led-mdl # Main Display Lighting
+      - motorola,cpcap-led-red # Red Triode
+
+  vdd-supply: true
+
+required:
+  - compatible
+  - label
+  - vdd-supply
+
+unevaluatedProperties: false
+
+...
-- 
2.51.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox