Skip to contentSkip to conversation

auxdisplay: Add TM16xx 7-segment LED matrix display controllers driver

PATCH Superseded Jean-François Lessard 5 participants 30 messages Aug 20, 2025 – Aug 27, 2025

Subsystems (3)

v3 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v3 cover auxdisplay: Add TM16xx 7-segment LED matrix display controllers driver

This series adds mainline kernel support for TM16xx family LED matrix controllers and compatible chips, widely used in auxiliary displays on TV boxes and embedded devices.

Many consumer devices, particularly TV boxes, use auxiliary displays based on TM16xx controllers to show status information such as time, network connectivity and system state. Currently, there is no mainline kernel support for these displays, forcing users to rely on out-of-tree drivers or userspace solutions that access hardware interfaces directly.

This driver provides unified TM16xx support through the LED subsystem with both I2C and SPI communication protocols. It integrates with the LED class framework, enabling control via standard sysfs interfaces and LED triggers, while supporting keypad input when hardware connections are available.

The driver supports multiple controller families from various vendors:
- Titan Micro Electronics: TM1618, TM1620, TM1628, TM1638, TM1650
- Fuda Hisi Microelectronics: FD620, FD628, FD650, FD655, FD6551
- i-Core Electronics: AiP650, AiP1618, AiP1628
- Princeton Technology: PT6964
- Winrise Technology: HBS658

Key features:
- 7-segment display support with flexible digit/segment mapping
- Individual LED icon control through LED class devices
- Optional keypad scanning with configurable key mapping
- Device tree configuration for board-specific wiring layouts
- LED trigger integration for automatic system event indication
- I2C and SPI protocol support depending on controller interface

Device tree bindings describe board-specific display wiring since controllers are layout-agnostic. The bindings use separate 'digits' and 'leds' containers with specific addressing schemes to accommodate the hardware's grid/segment matrix organization.

Note: This driver is placed in drivers/auxdisplay rather than drivers/leds based on previous maintainer guidance. LED maintainer Pavel Machek recommended auxdisplay for TM1628-based display drivers:
https://lore.kernel.org/linux-devicetree/[email protected]/

Tested on multiple ARM TV boxes (H96 Max, Magicsee N5, Tanix TX3 Mini, Tanix TX6, X92, X96 Max) across different SoC platforms (Rockchip, Amlogic, Allwinner) in both I2C and SPI configurations.

Dependencies:
- CONFIG_NEW_LEDS, CONFIG_LEDS_CLASS (required)
- CONFIG_INPUT, CONFIG_INPUT_MATRIXKMAP (for keypad support)
- CONFIG_I2C or CONFIG_SPI (depending on hardware interface)

Optional LED trigger modules for advanced functionality:
- CONFIG_LEDS_TRIGGER_TIMER for blinking elements.
- CONFIG_LEDS_TRIGGER_NETDEV for network activity indication.
- CONFIG_USB_LEDS_TRIGGER_USBPORT for USB activity indication.

User space utilities available at: https://github.com/jefflessard/tm16xx-display

v3:
- Update vendor prefixes with documented rationale, in a single patch, per maintainer feedback
- Refine device tree bindings per maintainer feedback:
* Update compatible string ordering and fallback logic
* Improve YAML descriptions for clarity and maintain 80-column wrapping
* Replace digit-specific properties with clearer digits container node
* Add explicit constraints for reg and segments properties in container nodes
* Clarify addressing schemes for icons (2-cell) and digits (1-cell + mapping)
* Fix conditional SPI properties handling
* Document rationale for spi-3wire property (required for supported SPI chips)
* Expand DT examples to cover typical and transposed display layouts
- Code reformat from clang-format to kernel coding style per maintainer feedback
- Fix conditional CONFIG_I2C/CONFIG_SPI compilation issues per kernel test robot
- Add keypad scanning with configurable keymap (new feature)
- Add support for TM1638 controller extending hardware compatibility
- Add support for default and maximum brightness properties
- Fix multi-instance device handling and add optional label property
- Allocate DMA-safe SPI buffer for hardware compatibility
- Enhance error handling with comprehensive kernel-doc documentation
- Remove sysfs runtime reconfiguration, enforce device tree-only configuration

v2:
- Fix duplicate label in dt-bindings examples
- Rename device tree property prefixes to use titanmec vendor prefix

Jean-François Lessard (4):
dt-bindings: vendor-prefixes: Add fdhisi, titanmec, princeton,
winrise, wxicore
dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx
auxdisplay: Add TM16xx 7-segment LED matrix display controllers driver
MAINTAINERS: Add entry for TM16xx driver

 .../bindings/auxdisplay/titanmec,tm16xx.yaml  |  471 +++++
 .../devicetree/bindings/vendor-prefixes.yaml  |   10 +
 MAINTAINERS                                   |    6 +
 drivers/auxdisplay/Kconfig                    |   20 +
 drivers/auxdisplay/Makefile                   |    1 +
 drivers/auxdisplay/tm16xx.c                   | 1781 +++++++++++++++++
 6 files changed, 2289 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml
 create mode 100644 drivers/auxdisplay/tm16xx.c
Signature · 1 line
2.43.0
#1 lore raw

PATCH v3 1/4 dt-bindings: vendor-prefixes: Add fdhisi, titanmec, princeton, winrise, wxicore

Add vendor prefixes:
- fdhisi: Fuzhou Fuda Hisi Microelectronics Co., Ltd.
- titanmec: Shenzhen Titan Micro Electronics Co., Ltd.
- princeton: Princeton Technology Corp.
- winrise: Shenzhen Winrise Technology Co., Ltd.
- wxicore: Wuxi i-Core Electronics Co., Ltd.

The titanmec prefix is based on the company's domain name titanmec.com. The remaining prefixes are based on company names, as these manufacturers either lack active .com domains or their .com domains are occupied by unrelated businesses.

The fdhisi and titanmec prefixes were originally identified by Andreas Färber.

---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 10 ++++++++++
 1 file changed, 10 insertions(+)
Documentation/devicetree/bindings/vendor-prefixes.yaml +10 -0
index 77160cd47..9fdba2911 100644
@@ -540,6 +540,8 @@ patternProperties:
     description: Fastrax Oy
   "^fcs,.*":
     description: Fairchild Semiconductor
+  "^fdhisi,.*":
+    description: Fuzhou Fuda Hisi Microelectronics Co., Ltd.
   "^feixin,.*":
     description: Shenzhen Feixin Photoelectic Co., Ltd
   "^feiyang,.*":
@@ -1233,6 +1235,8 @@ patternProperties:
     description: Prime View International (PVI)
   "^primux,.*":
     description: Primux Trading, S.L.
+  "^princeton,.*":
+    description: Princeton Technology Corp.
   "^probox2,.*":
     description: PROBOX2 (by W2COMP Co., Ltd.)
   "^pri,.*":
@@ -1567,6 +1571,8 @@ patternProperties:
     description: Texas Instruments
   "^tianma,.*":
     description: Tianma Micro-electronics Co., Ltd.
+  "^titanmec,.*":
+    description: Shenzhen Titan Micro Electronics Co., Ltd.
   "^tlm,.*":
     description: Trusted Logic Mobility
   "^tmt,.*":
@@ -1724,6 +1730,8 @@ patternProperties:
     description: Wingtech Technology Co., Ltd.
   "^winlink,.*":
     description: WinLink Co., Ltd
+  "^winrise,.*":
+    description: Shenzhen Winrise Technology Co., Ltd.
   "^winsen,.*":
     description: Winsen Corp.
   "^winstar,.*":
@@ -1740,6 +1748,8 @@ patternProperties:
     description: Wobo
   "^wolfvision,.*":
     description: WolfVision GmbH
+  "^wxicore,.*":
+    description: Wuxi i-Core Electronics Co., Ltd.
   "^x-powers,.*":
     description: X-Powers
   "^xen,.*":
Signature · 1 line
2.43.0
Acked-by on v3 1/4
#2 lore raw

Re: [PATCH v3 1/4] dt-bindings: vendor-prefixes: Add fdhisi, titanmec, princeton, winrise, wxicore

Quoted 12 lines · Jean-François Lessard

Add vendor prefixes:
- fdhisi: Fuzhou Fuda Hisi Microelectronics Co., Ltd.
- titanmec: Shenzhen Titan Micro Electronics Co., Ltd.
- princeton: Princeton Technology Corp.
- winrise: Shenzhen Winrise Technology Co., Ltd.
- wxicore: Wuxi i-Core Electronics Co., Ltd.

The titanmec prefix is based on the company's domain name titanmec.com. The remaining prefixes are based on company names, as these manufacturers either lack active .com domains or their .com domains are occupied by unrelated businesses.

Quoted 4 lines

The fdhisi and titanmec prefixes were originally identified by Andreas Färber.

but some reason why all these are being added together would be nice.

Quoted 56 lines
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 10 ++++++++++
 1 file changed, 10 insertions(+)
Documentation/devicetree/bindings/vendor-prefixes.yaml +10 -0
index 77160cd47..9fdba2911 100644
@@ -540,6 +540,8 @@ patternProperties:
     description: Fastrax Oy
   "^fcs,.*":
     description: Fairchild Semiconductor
+  "^fdhisi,.*":
+    description: Fuzhou Fuda Hisi Microelectronics Co., Ltd.
   "^feixin,.*":
     description: Shenzhen Feixin Photoelectic Co., Ltd
   "^feiyang,.*":
@@ -1233,6 +1235,8 @@ patternProperties:
     description: Prime View International (PVI)
   "^primux,.*":
     description: Primux Trading, S.L.
+  "^princeton,.*":
+    description: Princeton Technology Corp.
   "^probox2,.*":
     description: PROBOX2 (by W2COMP Co., Ltd.)
   "^pri,.*":
@@ -1567,6 +1571,8 @@ patternProperties:
     description: Texas Instruments
   "^tianma,.*":
     description: Tianma Micro-electronics Co., Ltd.
+  "^titanmec,.*":
+    description: Shenzhen Titan Micro Electronics Co., Ltd.
   "^tlm,.*":
     description: Trusted Logic Mobility
   "^tmt,.*":
@@ -1724,6 +1730,8 @@ patternProperties:
     description: Wingtech Technology Co., Ltd.
   "^winlink,.*":
     description: WinLink Co., Ltd
+  "^winrise,.*":
+    description: Shenzhen Winrise Technology Co., Ltd.
   "^winsen,.*":
     description: Winsen Corp.
   "^winstar,.*":
@@ -1740,6 +1748,8 @@ patternProperties:
     description: Wobo
   "^wolfvision,.*":
     description: WolfVision GmbH
+  "^wxicore,.*":
+    description: Wuxi i-Core Electronics Co., Ltd.
   "^x-powers,.*":
     description: X-Powers
   "^xen,.*":
Signature · 1 line
2.43.0
#3 lore raw

Re: [PATCH v3 1/4] dt-bindings: vendor-prefixes: Add fdhisi, titanmec, princeton, winrise, wxicore

Le 20 août 2025 16 h 08 min 01 s HAE, Conor Dooley <[email protected]> a écrit :

Quoted 13 lines · Jean-François Lessard
Quoted 12 lines

Add vendor prefixes:
- fdhisi: Fuzhou Fuda Hisi Microelectronics Co., Ltd.
- titanmec: Shenzhen Titan Micro Electronics Co., Ltd.
- princeton: Princeton Technology Corp.
- winrise: Shenzhen Winrise Technology Co., Ltd.
- wxicore: Wuxi i-Core Electronics Co., Ltd.

The titanmec prefix is based on the company's domain name titanmec.com. The remaining prefixes are based on company names, as these manufacturers either lack active .com domains or their .com domains are occupied by unrelated businesses.

Quoted 6 lines
Quoted 4 lines

The fdhisi and titanmec prefixes were originally identified by Andreas Färber.

Thanks for your acknowledgement, I will include it in the v4 submission.

Quoted 1 line

but some reason why all these are being added together would be nice.

Do you mean repeating this cover letter v3 changelog note in this patch:

v3:
- Update vendor prefixes with documented rationale, in a single patch, per maintainer feedback

See https://lore.kernel.org/linux-devicetree/[email protected]/#t

Or do you mean the relationship between these vendors being added here, such as replacing the fist line of the commit message to:

Add vendor prefixes of chip manufacturers supported by the TM16xx 7-segment LED matrix display controllers driver:
- fdhisi...

Quoted 2 lines
Quoted 2 lines

---

...

Best regards,
Jean-Francois Lessard

#4 lore raw

Re: [PATCH v3 1/4] dt-bindings: vendor-prefixes: Add fdhisi, titanmec, princeton, winrise, wxicore

Quoted 27 lines · Jean-François Lessard

Le 20 août 2025 16 h 08 min 01 s HAE, Conor Dooley <[email protected]> a écrit :

Quoted 13 lines · Jean-François Lessard
Quoted 12 lines

Add vendor prefixes:
- fdhisi: Fuzhou Fuda Hisi Microelectronics Co., Ltd.
- titanmec: Shenzhen Titan Micro Electronics Co., Ltd.
- princeton: Princeton Technology Corp.
- winrise: Shenzhen Winrise Technology Co., Ltd.
- wxicore: Wuxi i-Core Electronics Co., Ltd.

The titanmec prefix is based on the company's domain name titanmec.com. The remaining prefixes are based on company names, as these manufacturers either lack active .com domains or their .com domains are occupied by unrelated businesses.

Quoted 6 lines
Quoted 4 lines

The fdhisi and titanmec prefixes were originally identified by Andreas Färber.

Thanks for your acknowledgement, I will include it in the v4 submission.

Quoted 1 line

but some reason why all these are being added together would be nice.

Do you mean repeating this cover letter v3 changelog note in this patch:

Quoted 8 lines

v3:
- Update vendor prefixes with documented rationale, in a single patch, per maintainer feedback

See https://lore.kernel.org/linux-devicetree/[email protected]/#t

Or do you mean the relationship between these vendors being added here, such as replacing the fist line of the commit message to:

Ye, this. The relation between the vendors.

Quoted 12 lines

Add vendor prefixes of chip manufacturers supported by the TM16xx 7-segment LED matrix display controllers driver:
- fdhisi...

Quoted 2 lines
Quoted 2 lines

---

...

Best regards,
Jean-Francois Lessard

#5 lore raw

Re: [PATCH v3 1/4] dt-bindings: vendor-prefixes: Add fdhisi, titanmec, princeton, winrise, wxicore

Le 21 août 2025 16 h 13 min 44 s HAE, Conor Dooley <[email protected]> a écrit :

Quoted 32 lines · Jean-François Lessard
Quoted 31 lines

Le 20 août 2025 16 h 08 min 01 s HAE, Conor Dooley <[email protected]> a écrit :

Quoted 13 lines · Jean-François Lessard
Quoted 12 lines

Add vendor prefixes:
- fdhisi: Fuzhou Fuda Hisi Microelectronics Co., Ltd.
- titanmec: Shenzhen Titan Micro Electronics Co., Ltd.
- princeton: Princeton Technology Corp.
- winrise: Shenzhen Winrise Technology Co., Ltd.
- wxicore: Wuxi i-Core Electronics Co., Ltd.

The titanmec prefix is based on the company's domain name titanmec.com. The remaining prefixes are based on company names, as these manufacturers either lack active .com domains or their .com domains are occupied by unrelated businesses.

Quoted 6 lines
Quoted 4 lines

The fdhisi and titanmec prefixes were originally identified by Andreas Färber.

Thanks for your acknowledgement, I will include it in the v4 submission.

Quoted 1 line

but some reason why all these are being added together would be nice.

Do you mean repeating this cover letter v3 changelog note in this patch:

v3:
- Update vendor prefixes with documented rationale, in a single patch, per maintainer feedback

Quoted 7 lines
Quoted 4 lines

See https://lore.kernel.org/linux-devicetree/[email protected]/#t

Or do you mean the relationship between these vendors being added here, such as replacing the fist line of the commit message to:

Ye, this. The relation between the vendors.

Well received. I will update the commit message accordingly in v4.

Quoted 12 lines
Quoted 12 lines

Add vendor prefixes of chip manufacturers supported by the TM16xx 7-segment LED matrix display controllers driver:
- fdhisi...

Quoted 2 lines
Quoted 2 lines

---

...

Best regards,
Jean-Francois Lessard

#6 lore raw

PATCH v3 2/4 dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx

In reply to Jean-François Lessard

Add documentation for TM16xx-compatible 7-segment LED display controllers with keyscan.

---

Note: The 'segments' property is intentionally not vendor-prefixed as it defines a generic hardware description concept applicable to any 7-segment display controller. The property describes the fundamental grid/segment coordinate mapping that is controller-agnostic and could be reused by other LED matrix display bindings. Similar to how 'gpios' describes GPIO connections generically, 'segments' describes segment connections in a standardized way using uint32-matrix format.

 .../bindings/auxdisplay/titanmec,tm16xx.yaml  | 471 ++++++++++++++++++
 1 file changed, 471 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +471 -0
new file mode 100644
index 000000000..b563c6e1e
@@ -0,0 +1,471 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/auxdisplay/titanmec,tm16xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Auxiliary displays based on TM16xx and compatible LED controllers
+
+maintainers:
+  - Jean-François Lessard <[email protected]>
+
+description: |
+  LED matrix controllers used in auxiliary display devices that drive individual
+  LED icons and 7-segment digit groups through a grid/segment addressing scheme.
+  Controllers manage a matrix of LEDs organized as grids (columns/banks in
+  vendor datasheets) and segments (rows/bit positions in vendor datasheets).
+  Maximum grid and segment indices are controller-specific.
+
+  The controller is agnostic of the display layout. Board-specific LED wiring is
+  described through child nodes that specify grid/segment coordinates for
+  individual icons and segment mapping for 7-segment digits.
+
+  The bindings use separate 'leds' and 'digits' containers to accommodate
+  different addressing schemes:
+  - LEDs use 2-cell addressing (grid, segment) for matrix coordinates
+  - Digits use 1-cell addressing with explicit segment mapping
+
+  Optional keypad scanning is supported when both 'linux,keymap' and
+  'poll-interval' properties are specified.
+
+properties:
+  compatible:
+    oneOf:
+      # Controllers with titanmec,tm1628 fallback
+      - items:
+          - enum:
+              - fdhisi,fd628
+              - princeton,pt6964
+              - wxicore,aip1628
+          - const: titanmec,tm1628
+      - const: titanmec,tm1628
+      # Controllers with titanmec,tm1618 fallback
+      - items:
+          - enum:
+              - wxicore,aip1618
+          - const: titanmec,tm1618
+      - const: titanmec,tm1618
+      # Controllers with titanmec,tm1650 fallback
+      - items:
+          - enum:
+              - fdhisi,fd650
+              - wxicore,aip650
+          - const: titanmec,tm1650
+      - const: titanmec,tm1650
+      # Canonical standalone controllers
+      - const: fdhisi,fd620
+      - const: fdhisi,fd655
+      - const: fdhisi,fd6551
+      - const: titanmec,tm1620
+      - const: titanmec,tm1638
+      - const: winrise,hbs658
+
+  reg:
+    maxItems: 1
+
+  label:
+    description: Name of the entire device
+    default: display
+
+  default-brightness:
+    description:
+      Brightness to be set if LED's default state is on. Used only during
+      initialization. If the option is not set then max brightness is used.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  max-brightness:
+    description:
+      Normally the maximum brightness is determined by the hardware and this
+      property is not required. This property is used to put a software limit
+      on the brightness apart from what the driver says, as it could happen
+      that a LED can be made so bright that it gets damaged or causes damage
+      due to restrictions in a specific system, such as mounting conditions.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  linux,keymap:
+    $ref: /schemas/input/matrix-keymap.yaml#/properties/linux,keymap
+
+  poll-interval:
+    $ref: /schemas/input/input.yaml#/properties/poll-interval
+
+  autorepeat:
+    $ref: /schemas/input/input.yaml#/properties/autorepeat
+
+  digits:
+    type: object
+    description: Container for 7-segment digit group definitions
+    properties:
+      "#address-cells":
+        const: 1
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^digit@[0-9]+$":
+        type: object
+        properties:
+          reg:
+            description: Digit position identifier
+            maxItems: 1
+          segments:
+            $ref: /schemas/types.yaml#/definitions/uint32-matrix
+            description: |
+              Array of grid/segment coordinate pairs for each 7-segment position.
+              Each entry is <grid segment> mapping to standard 7-segment positions
+              in order: a, b, c, d, e, f, g
+
+              Standard 7-segment layout:
+                 aaa
+                f   b
+                f   b
+                 ggg
+                e   c
+                e   c
+                 ddd
+            items:
+              items:
+                - description: Grid index
+                - description: Segment index
+            minItems: 7
+            maxItems: 7
+        required:
+          - reg
+          - segments
+        unevaluatedProperties: false
+
+    additionalProperties: false
+
+  leds:
+    type: object
+    description: Container for individual LED icon definitions
+    properties:
+      "#address-cells":
+        const: 2
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^led@[0-9]+,[0-9]+$":
+        type: object
+        $ref: /schemas/leds/common.yaml#
+        properties:
+          reg:
+            description:
+              Grid and segment indices as <grid segment> of this individual LED icon
+        required:
+          - reg
+        unevaluatedProperties: false
+
+    additionalProperties: false
+
+# SPI controllers require 3-wire (combined MISO/MOSI line)
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - fdhisi,fd620
+          - fdhisi,fd628
+          - princeton,pt6964
+          - titanmec,tm1618
+          - titanmec,tm1620
+          - titanmec,tm1628
+          - titanmec,tm1638
+          - wxicore,aip1618
+          - wxicore,aip1628
+then:
+  allOf:
+    - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  properties:
+    spi-3wire: true
+  required:
+    - spi-3wire
+
+dependencies:
+  poll-interval:
+    - linux,keymap
+  linux,keymap:
+    - poll-interval
+  autorepeat:
+    - linux,keymap
+    - poll-interval
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/leds/common.h>
+
+    // I2C example: Magicsee N5 TV box with fd655 controller
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      display-controller@24 {
+        reg = <0x24>;
+        compatible = "fdhisi,fd655";
+
+        digits {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          digit@0 {
+            reg = <0>;
+            segments = <4 3>, <4 4>, <4 5>, <4 0>, <4 1>, <4 2>, <4 6>;
+          };
+
+          digit@1 {
+            reg = <1>;
+            segments = <3 3>, <3 4>, <3 5>, <3 0>, <3 1>, <3 2>, <3 6>;
+          };
+
+          digit@2 {
+            reg = <2>;
+            segments = <2 3>, <2 4>, <2 5>, <2 0>, <2 1>, <2 2>, <2 6>;
+          };
+
+          digit@3 {
+            reg = <3>;
+            segments = <1 3>, <1 4>, <1 5>, <1 0>, <1 1>, <1 2>, <1 6>;
+          };
+        };
+
+        leds {
+          #address-cells = <2>;
+          #size-cells = <0>;
+
+          led@0,0 {
+            reg = <0 0>;
+            function = LED_FUNCTION_ALARM;
+          };
+
+          led@0,1 {
+            reg = <0 1>;
+            function = LED_FUNCTION_USB;
+          };
+
+          led@0,2 {
+            reg = <0 2>;
+            function = "play";
+          };
+
+          led@0,3 {
+            reg = <0 3>;
+            function = "pause";
+          };
+
+          led@0,4 {
+            reg = <0 4>;
+            function = "colon";
+          };
+
+          led@0,5 {
+            reg = <0 5>;
+            function = LED_FUNCTION_LAN;
+          };
+
+          led@0,6 {
+            reg = <0 6>;
+            function = LED_FUNCTION_WLAN;
+          };
+        };
+      };
+    };
+
+  - |
+    #include <dt-bindings/input/input.h>
+
+    // SPI example: TM1638 module with keypad support
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      display-controller@0 {
+        reg = <0>;
+        compatible = "titanmec,tm1638";
+        spi-3wire;
+        spi-lsb-first;
+        spi-max-frequency = <500000>;
+
+        label = "tm1638";
+        default-brightness = <2>;
+        max-brightness = <4>;
+        poll-interval = <100>;
+        linux,keymap = <MATRIX_KEY(2, 0, KEY_F1)
+                        MATRIX_KEY(2, 2, KEY_F2)
+                        MATRIX_KEY(2, 4, KEY_F3)
+                        MATRIX_KEY(2, 6, KEY_F4)
+                        MATRIX_KEY(2, 1, KEY_F5)
+                        MATRIX_KEY(2, 3, KEY_F6)
+                        MATRIX_KEY(2, 5, KEY_F7)
+                        MATRIX_KEY(2, 7, KEY_F8)>;
+
+        digits {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          digit@0 {
+            reg = <0>;
+            segments = <7 0>, <7 1>, <7 2>, <7 3>, <7 4>, <7 5>, <7 6>;
+          };
+
+          digit@1 {
+            reg = <1>;
+            segments = <6 0>, <6 1>, <6 2>, <6 3>, <6 4>, <6 5>, <6 6>;
+          };
+
+          digit@2 {
+            reg = <2>;
+            segments = <5 0>, <5 1>, <5 2>, <5 3>, <5 4>, <5 5>, <5 6>;
+          };
+
+          digit@3 {
+            reg = <3>;
+            segments = <4 0>, <4 1>, <4 2>, <4 3>, <4 4>, <4 5>, <4 6>;
+          };
+
+          digit@4 {
+            reg = <4>;
+            segments = <3 0>, <3 1>, <3 2>, <3 3>, <3 4>, <3 5>, <3 6>;
+          };
+
+          digit@5 {
+            reg = <5>;
+            segments = <2 0>, <2 1>, <2 2>, <2 3>, <2 4>, <2 5>, <2 6>;
+          };
+
+          digit@6 {
+            reg = <6>;
+            segments = <1 0>, <1 1>, <1 2>, <1 3>, <1 4>, <1 5>, <1 6>;
+          };
+
+          digit@7 {
+            reg = <7>;
+            segments = <0 0>, <0 1>, <0 2>, <0 3>, <0 4>, <0 5>, <0 6>;
+          };
+        };
+
+        leds {
+          #address-cells = <2>;
+          #size-cells = <0>;
+
+          led@0,7 {
+            reg = <0 7>;
+          };
+
+          led@1,7 {
+            reg = <1 7>;
+          };
+
+          led@2,7 {
+            reg = <2 7>;
+          };
+
+          led@3,7 {
+            reg = <3 7>;
+          };
+
+          led@4,7 {
+            reg = <4 7>;
+          };
+
+          led@5,7 {
+            reg = <5 7>;
+          };
+
+          led@6,7 {
+            reg = <6 7>;
+          };
+
+          led@7,7 {
+            reg = <7 7>;
+          };
+        };
+      };
+    };
+
+  - |
+    #include <dt-bindings/leds/common.h>
+
+    // SPI example: X96 Max with transposed layout (fd628 with tm1628 fallback)
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      display-controller@0 {
+        reg = <0>;
+        compatible = "fdhisi,fd628", "titanmec,tm1628";
+        spi-3wire;
+        spi-lsb-first;
+        spi-max-frequency = <500000>;
+
+        digits {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          digit@0 {
+            reg = <0>;
+            segments = <0 3>, <1 3>, <2 3>, <3 3>, <4 3>, <5 3>, <6 3>;
+          };
+
+          digit@1 {
+            reg = <1>;
+            segments = <0 2>, <1 2>, <2 2>, <3 2>, <4 2>, <5 2>, <6 2>;
+          };
+
+          digit@2 {
+            reg = <2>;
+            segments = <0 1>, <1 1>, <2 1>, <3 1>, <4 1>, <5 1>, <6 1>;
+          };
+
+          digit@3 {
+            reg = <3>;
+            segments = <0 0>, <1 0>, <2 0>, <3 0>, <4 0>, <5 0>, <6 0>;
+          };
+        };
+
+        leds {
+          #address-cells = <2>;
+          #size-cells = <0>;
+
+          led@0,4 {
+            reg = <0 4>;
+            function = "apps";
+          };
+
+          led@1,4 {
+            reg = <1 4>;
+            function = "setup";
+          };
+
+          led@2,4 {
+            reg = <2 4>;
+            function = LED_FUNCTION_USB;
+          };
+
+          led@3,4 {
+            reg = <3 4>;
+            function = LED_FUNCTION_SD;
+          };
+
+          led@4,4 {
+            reg = <4 4>;
+            function = "colon";
+          };
+
+          led@5,4 {
+            reg = <5 4>;
+            function = "hdmi";
+          };
+
+          led@6,4 {
+            reg = <6 4>;
+            function = "video";
+          };
+        };
+      };
+    };
Signature · 1 line
2.43.0
#7 lore raw

Re: [PATCH v3 2/4] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx

Quoted 2 lines · Jean-François Lessard

Add documentation for TM16xx-compatible 7-segment LED display controllers with keyscan.

Here and other patches - this is not wrapped.

Please wrap commit message according to Linux coding style / submission process (neither too early nor over the limit):
https://elixir.bootlin.com/linux/v6.4-rc1/source/Documentation/process/submitting-patches.rst#L597

Quoted 46 lines

---

Note: The 'segments' property is intentionally not vendor-prefixed as it defines a generic hardware description concept applicable to any 7-segment display controller. The property describes the fundamental grid/segment coordinate mapping that is controller-agnostic and could be reused by other LED matrix display bindings. Similar to how 'gpios' describes GPIO connections generically, 'segments' describes segment connections in a standardized way using uint32-matrix format.

 .../bindings/auxdisplay/titanmec,tm16xx.yaml  | 471 ++++++++++++++++++
 1 file changed, 471 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +24 -0
new file mode 100644
index 000000000..b563c6e1e
@@ -0,0 +1,471 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/auxdisplay/titanmec,tm16xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Auxiliary displays based on TM16xx and compatible LED controllers
+
+maintainers:
+  - Jean-François Lessard <[email protected]>
+
+description: |
+  LED matrix controllers used in auxiliary display devices that drive individual
+  LED icons and 7-segment digit groups through a grid/segment addressing scheme.
+  Controllers manage a matrix of LEDs organized as grids (columns/banks in
+  vendor datasheets) and segments (rows/bit positions in vendor datasheets).
+  Maximum grid and segment indices are controller-specific.
+
+  The controller is agnostic of the display layout. Board-specific LED wiring is
+  described through child nodes that specify grid/segment coordinates for
+  individual icons and segment mapping for 7-segment digits.
+
+  The bindings use separate 'leds' and 'digits' containers to accommodate
+  different addressing schemes:

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 34

Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10 -0
+  - LEDs use 2-cell addressing (grid, segment) for matrix coordinates
+  - Digits use 1-cell addressing with explicit segment mapping
+
+  Optional keypad scanning is supported when both 'linux,keymap' and
+  'poll-interval' properties are specified.
+
+properties:
+  compatible:
+    oneOf:
+      # Controllers with titanmec,tm1628 fallback

Drop comment, obvious. Schema tells that.

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 41

Quoted 7 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +7 -0
+      - items:
+          - enum:
+              - fdhisi,fd628
+              - princeton,pt6964
+              - wxicore,aip1628
+          - const: titanmec,tm1628
+      - const: titanmec,tm1628

This is part of one enum

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 47

Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6 -0
+      # Controllers with titanmec,tm1618 fallback
+      - items:
+          - enum:
+              - wxicore,aip1618
+          - const: titanmec,tm1618
+      - const: titanmec,tm1618

Enum...

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 55

Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +8 -0
+      # Controllers with titanmec,tm1650 fallback
+      - items:
+          - enum:
+              - fdhisi,fd650
+              - wxicore,aip650
+          - const: titanmec,tm1650
+      - const: titanmec,tm1650
+      # Canonical standalone controllers

Drop

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 61

Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6 -0
+      - const: fdhisi,fd620
+      - const: fdhisi,fd655
+      - const: fdhisi,fd6551
+      - const: titanmec,tm1620
+      - const: titanmec,tm1638
+      - const: winrise,hbs658

This is one enum

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 68

Quoted 7 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +7 -0
+
+  reg:
+    maxItems: 1
+
+  label:
+    description: Name of the entire device
+    default: display

Huh? Why do you need label? Are you sure auxdisplays have labels?

Quoted 14 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +14 -0
+
+  default-brightness:
+    description:
+      Brightness to be set if LED's default state is on. Used only during
+      initialization. If the option is not set then max brightness is used.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  max-brightness:
+    description:
+      Normally the maximum brightness is determined by the hardware and this
+      property is not required. This property is used to put a software limit
+      on the brightness apart from what the driver says, as it could happen
+      that a LED can be made so bright that it gets damaged or causes damage
+      due to restrictions in a specific system, such as mounting conditions.

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 92

Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10 -0
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  linux,keymap:
+    $ref: /schemas/input/matrix-keymap.yaml#/properties/linux,keymap
+
+  poll-interval:
+    $ref: /schemas/input/input.yaml#/properties/poll-interval
+
+  autorepeat:
+    $ref: /schemas/input/input.yaml#/properties/autorepeat

You rather miss some reference to input or touchscreen.

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 96

Quoted 4 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +4 -0
+
+  digits:
+    type: object
+    description: Container for 7-segment digit group definitions

additionalProperties go here

and blank line

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 105

Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +9 -0
+    properties:
+      "#address-cells":
+        const: 1
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^digit@[0-9]+$":
+        type: object

unevaluatedProperties

Blank line

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 109

Quoted 4 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +4 -0
+        properties:
+          reg:
+            description: Digit position identifier
+            maxItems: 1

Blank line

Quoted 40 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +40 -0
+          segments:
+            $ref: /schemas/types.yaml#/definitions/uint32-matrix
+            description: |
+              Array of grid/segment coordinate pairs for each 7-segment position.
+              Each entry is <grid segment> mapping to standard 7-segment positions
+              in order: a, b, c, d, e, f, g
+
+              Standard 7-segment layout:
+                 aaa
+                f   b
+                f   b
+                 ggg
+                e   c
+                e   c
+                 ddd
+            items:
+              items:
+                - description: Grid index
+                - description: Segment index
+            minItems: 7
+            maxItems: 7
+        required:
+          - reg
+          - segments
+        unevaluatedProperties: false
+
+    additionalProperties: false
+
+  leds:
+    type: object
+    description: Container for individual LED icon definitions
+    properties:
+      "#address-cells":
+        const: 2
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^led@[0-9]+,[0-9]+$":
+        type: object

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 159

Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10 -0
+        $ref: /schemas/leds/common.yaml#
+        properties:
+          reg:
+            description:
+              Grid and segment indices as <grid segment> of this individual LED icon
+        required:
+          - reg
+        unevaluatedProperties: false
+
+    additionalProperties: false

Best regards,
Krzysztof

#8 lore raw

Re: [PATCH v3 2/4] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx

Le 21 août 2025 03 h 48 min 21 s HAE, Krzysztof Kozlowski <[email protected]> a écrit :

Quoted 10 lines · Jean-François Lessard
Quoted 2 lines

Add documentation for TM16xx-compatible 7-segment LED display controllers with keyscan.

Here and other patches - this is not wrapped.

Please wrap commit message according to Linux coding style / submission process (neither too early nor over the limit):
https://elixir.bootlin.com/linux/v6.4-rc1/source/Documentation/process/submitting-patches.rst#L597

Well received. Will wrap at 75 instead of 80 for commit messages.

Quoted 50 lines
Quoted 50 lines

---

Note: The 'segments' property is intentionally not vendor-prefixed as it defines a generic hardware description concept applicable to any 7-segment display controller. The property describes the fundamental grid/segment coordinate mapping that is controller-agnostic and could be reused by other LED matrix display bindings. Similar to how 'gpios' describes GPIO connections generically, 'segments' describes segment connections in a standardized way using uint32-matrix format.

 .../bindings/auxdisplay/titanmec,tm16xx.yaml  | 471 ++++++++++++++++++
 1 file changed, 471 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +28 -0
new file mode 100644
index 000000000..b563c6e1e
@@ -0,0 +1,471 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/auxdisplay/titanmec,tm16xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Auxiliary displays based on TM16xx and compatible LED controllers
+
+maintainers:
+  - Jean-François Lessard <[email protected]>
+
+description: |
+  LED matrix controllers used in auxiliary display devices that drive individual
+  LED icons and 7-segment digit groups through a grid/segment addressing scheme.
+  Controllers manage a matrix of LEDs organized as grids (columns/banks in
+  vendor datasheets) and segments (rows/bit positions in vendor datasheets).
+  Maximum grid and segment indices are controller-specific.
+
+  The controller is agnostic of the display layout. Board-specific LED wiring is
+  described through child nodes that specify grid/segment coordinates for
+  individual icons and segment mapping for 7-segment digits.
+
+  The bindings use separate 'leds' and 'digits' containers to accommodate
+  different addressing schemes:
+  - LEDs use 2-cell addressing (grid, segment) for matrix coordinates
+  - Digits use 1-cell addressing with explicit segment mapping
+
+  Optional keypad scanning is supported when both 'linux,keymap' and
Quoted 9 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 34

Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6 -0
+  'poll-interval' properties are specified.
+
+properties:
+  compatible:
+    oneOf:
+      # Controllers with titanmec,tm1628 fallback

Drop comment, obvious. Schema tells that.

Well received.

Quoted 30 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 41

Quoted 7 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +7 -0
+      - items:
+          - enum:
+              - fdhisi,fd628
+              - princeton,pt6964
+              - wxicore,aip1628
+          - const: titanmec,tm1628
+      - const: titanmec,tm1628

This is part of one enum

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 47

Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6 -0
+      # Controllers with titanmec,tm1618 fallback
+      - items:
+          - enum:
+              - wxicore,aip1618
+          - const: titanmec,tm1618
+      - const: titanmec,tm1618

Enum...

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 55

Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +8 -0
+      # Controllers with titanmec,tm1650 fallback
+      - items:
+          - enum:
+              - fdhisi,fd650
+              - wxicore,aip650
+          - const: titanmec,tm1650
+      - const: titanmec,tm1650
+      # Canonical standalone controllers

Drop

Quoted 9 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 61

Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6 -0
+      - const: fdhisi,fd620
+      - const: fdhisi,fd655
+      - const: fdhisi,fd6551
+      - const: titanmec,tm1620
+      - const: titanmec,tm1638
+      - const: winrise,hbs658

This is one enum

Well received. I followed the older style and will adopt the modern approach:

properties:
compatible:
items:
- enum:
- fdhisi,fd628
- princeton,pt6964
- wxicore,aip1628
- wxicore,aip1618
- fdhisi,fd650
- wxicore,aip650
- fdhisi,fd620
- fdhisi,fd655
- fdhisi,fd6551
- titanmec,tm1620
- titanmec,tm1638
- winrise,hbs658
- enum:
- titanmec,tm1628
- titanmec,tm1618
- titanmec,tm1650
minItems: 1
maxItems: 2

Fallback relationships will be documented explicitly in the binding’s description.

Quoted 11 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 68

Quoted 7 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +7 -0
+
+  reg:
+    maxItems: 1
+
+  label:
+    description: Name of the entire device
+    default: display

Huh? Why do you need label? Are you sure auxdisplays have labels?

Display integrates with the LED subsystem (/sys/class/leds), where label is a standard property per leds/common.yaml. It ensures predictable LED class device naming when multiple display instances are present, following established LED subsystem conventions rather than general DT naming rules.

If helpful, I can add a $ref to /schemas/leds/common.yaml#/properties/label or include its description explicitly.

Quoted 18 lines
Quoted 18 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +18 -0
+
+  default-brightness:
+    description:
+      Brightness to be set if LED's default state is on. Used only during
+      initialization. If the option is not set then max brightness is used.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  max-brightness:
+    description:
+      Normally the maximum brightness is determined by the hardware and this
+      property is not required. This property is used to put a software limit
+      on the brightness apart from what the driver says, as it could happen
+      that a LED can be made so bright that it gets damaged or causes damage
+      due to restrictions in a specific system, such as mounting conditions.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  linux,keymap:
+    $ref: /schemas/input/matrix-keymap.yaml#/properties/linux,keymap
Quoted 9 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 92

Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6 -0
+
+  poll-interval:
+    $ref: /schemas/input/input.yaml#/properties/poll-interval
+
+  autorepeat:
+    $ref: /schemas/input/input.yaml#/properties/autorepeat

You rather miss some reference to input or touchscreen.

Well received. I will replace the individual references with:

allOf:
- $ref: /schemas/input/input.yaml#
- $ref: /schemas/input/matrix-keymap.yaml#

Quoted 21 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 96

Quoted 4 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +4 -0
+
+  digits:
+    type: object
+    description: Container for 7-segment digit group definitions

additionalProperties go here

and blank line

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 105

Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +9 -0
+    properties:
+      "#address-cells":
+        const: 1
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^digit@[0-9]+$":
+        type: object

unevaluatedProperties

Quoted 9 lines

Blank line

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 109

Quoted 4 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +4 -0
+        properties:
+          reg:
+            description: Digit position identifier
+            maxItems: 1

Blank line

Well received.

Quoted 45 lines
Quoted 45 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +45 -0
+          segments:
+            $ref: /schemas/types.yaml#/definitions/uint32-matrix
+            description: |
+              Array of grid/segment coordinate pairs for each 7-segment position.
+              Each entry is <grid segment> mapping to standard 7-segment positions
+              in order: a, b, c, d, e, f, g
+
+              Standard 7-segment layout:
+                 aaa
+                f   b
+                f   b
+                 ggg
+                e   c
+                e   c
+                 ddd
+            items:
+              items:
+                - description: Grid index
+                - description: Segment index
+            minItems: 7
+            maxItems: 7
+        required:
+          - reg
+          - segments
+        unevaluatedProperties: false
+
+    additionalProperties: false
+
+  leds:
+    type: object
+    description: Container for individual LED icon definitions
+    properties:
+      "#address-cells":
+        const: 2
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^led@[0-9]+,[0-9]+$":
+        type: object
+        $ref: /schemas/leds/common.yaml#
+        properties:
+          reg:
+            description:
+              Grid and segment indices as <grid segment> of this individual LED icon
Quoted 9 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 136

Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5 -0
+        required:
+          - reg
+        unevaluatedProperties: false
+
+    additionalProperties: false

Best regards,
Krzysztof

Thanks for your detailed feedback.

Best regards,
Jean-François Lessard

#9 lore raw

Re: [PATCH v3 2/4] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx

Quoted 47 lines · Jean-François Lessard
Quoted 12 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 55

Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +8 -0
+      # Controllers with titanmec,tm1650 fallback
+      - items:
+          - enum:
+              - fdhisi,fd650
+              - wxicore,aip650
+          - const: titanmec,tm1650
+      - const: titanmec,tm1650
+      # Canonical standalone controllers

Drop

Quoted 9 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 61

Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6 -0
+      - const: fdhisi,fd620
+      - const: fdhisi,fd655
+      - const: fdhisi,fd6551
+      - const: titanmec,tm1620
+      - const: titanmec,tm1638
+      - const: winrise,hbs658

This is one enum

Well received. I followed the older style and will adopt the modern approach:

properties:
compatible:
items:
- enum:
- fdhisi,fd628
- princeton,pt6964
- wxicore,aip1628
- wxicore,aip1618
- fdhisi,fd650
- wxicore,aip650
- fdhisi,fd620
- fdhisi,fd655
- fdhisi,fd6551
- titanmec,tm1620
- titanmec,tm1638
- winrise,hbs658
- enum:
- titanmec,tm1628
- titanmec,tm1618
- titanmec,tm1650
minItems: 1
maxItems: 2

Quoted 1 line

Fallback relationships will be documented explicitly in the binding’s description.

Sorry, but what? I commented under specific lines. Why are you changing other things?

Quoted 13 lines
Quoted 12 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 68

Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +7 -0
+
+  reg:
+    maxItems: 1
+
+  label:
+    description: Name of the entire device
+    default: display

Huh? Why do you need label? Are you sure auxdisplays have labels?

Quoted 4 lines

Display integrates with the LED subsystem (/sys/class/leds), where label is a standard property per leds/common.yaml. It ensures predictable LED class device naming when multiple display instances are present, following established LED subsystem conventions rather than general DT naming rules.

You want to say that top level node is like LED? Then probably it misses common.yaml reference. Although I am still puzzled... you have sub nodes for actual LEDs, no?

Quoted 4 lines

If helpful, I can add a $ref to /schemas/leds/common.yaml#/properties/label or include its description explicitly.

Best regards,
Krzysztof

#10 lore raw

Re: [PATCH v3 2/4] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx

Le 22 août 2025 02 h 44 min 26 s HAE, Krzysztof Kozlowski <[email protected]> a écrit :

Quoted 48 lines · Jean-François Lessard
Quoted 47 lines
Quoted 12 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 55

Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +8 -0
+      # Controllers with titanmec,tm1650 fallback
+      - items:
+          - enum:
+              - fdhisi,fd650
+              - wxicore,aip650
+          - const: titanmec,tm1650
+      - const: titanmec,tm1650
+      # Canonical standalone controllers

Drop

Quoted 9 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 61

Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6 -0
+      - const: fdhisi,fd620
+      - const: fdhisi,fd655
+      - const: fdhisi,fd6551
+      - const: titanmec,tm1620
+      - const: titanmec,tm1638
+      - const: winrise,hbs658

This is one enum

Well received. I followed the older style and will adopt the modern approach:

properties:
compatible:
items:
- enum:
- fdhisi,fd628
- princeton,pt6964
- wxicore,aip1628
- wxicore,aip1618
- fdhisi,fd650
- wxicore,aip650
- fdhisi,fd620
- fdhisi,fd655
- fdhisi,fd6551
- titanmec,tm1620
- titanmec,tm1638
- winrise,hbs658
- enum:
- titanmec,tm1628
- titanmec,tm1618
- titanmec,tm1650
minItems: 1
maxItems: 2

Quoted 6 lines
Quoted 1 line

Fallback relationships will be documented explicitly in the binding’s description.

Sorry, but what? I commented under specific lines. Why are you changing other things?

I apologize for misunderstanding. I hope this fits your specific comments:

properties:
compatible:
oneOf:
- items:
- enum:
- fdhisi,fd628
- princeton,pt6964
- wxicore,aip1628
- const: titanmec,tm1628
- items:
- enum:
- wxicore,aip1618
- const: titanmec,tm1618
- items:
- enum:
- fdhisi,fd650
- wxicore,aip650
- const: titanmec,tm1650
- enum:
- titanmec,tm1628
- titanmec,tm1618
- titanmec,tm1650
- fdhisi,fd620
- fdhisi,fd655
- fdhisi,fd6551
- titanmec,tm1620
- titanmec,tm1638
- winrise,hbs658

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines

Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 68

Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +7 -0
+
+  reg:
+    maxItems: 1
+
+  label:
+    description: Name of the entire device
+    default: display

Huh? Why do you need label? Are you sure auxdisplays have labels?

Quoted 9 lines
Quoted 4 lines

Display integrates with the LED subsystem (/sys/class/leds), where label is a standard property per leds/common.yaml. It ensures predictable LED class device naming when multiple display instances are present, following established LED subsystem conventions rather than general DT naming rules.

You want to say that top level node is like LED? Then probably it misses common.yaml reference. Although I am still puzzled... you have sub nodes for actual LEDs, no?

The top-level device node is registered as a pseudo-LED device to control the entire display (brightness 0-7, digits) via /sys/class/leds/{label}. Individual LED icons are separate LED devices at /sys/class/leds/{label}::{function} with on/off status control (brightness 0-1).

However, the top-level pseudo-LED shouldn't support all LED properties (no color, function, trigger-sources, etc.), so I'll reference specific properties from leds/common.yaml rather than the entire schema:

label:
$ref: /schemas/leds/common.yaml#/properties/label
max-brightness:
$ref: /schemas/leds/common.yaml#/properties/max-brightness

This approach provides LED subsystem consistency while avoiding inappropriate properties for the entire display.

Quoted 4 lines
Quoted 4 lines

If helpful, I can add a $ref to /schemas/leds/common.yaml#/properties/label or include its description explicitly.

Best Regards,
Jean-François Lessard

#11 lore raw

PATCH v3 3/4 auxdisplay: Add TM16xx 7-segment LED matrix display controllers driver

In reply to Jean-François Lessard

Add driver for TM16xx family LED controllers and compatible chips from multiple vendors including Titan Micro, Fuda Hisi, i-Core, Princeton, and Winrise. These controllers drive 7-segment digits and individual LED icons through either I2C or SPI interfaces with optional keypad scanning support.

Successfully tested on various ARM TV boxes including H96 Max, Magicsee N5, Tanix TX3 Mini, Tanix TX6, X92, and X96 Max across different SoC platforms (Rockchip, Amlogic, Allwinner).

---

Note: checkpatch reports several false positives that are intentionally ignored:

- COMPLEX_MACRO/MACRO_ARG_REUSE for for_each_key(): This is a standard iterator pattern following kernel conventions (similar to for_each_* macros throughout the kernel). The nested for loops are the correct implementation for matrix iteration.

- DEVICE_ATTR_FUNCTIONS: Functions are correctly prefixed with driver name (tm16xx_*) following standard kernel practice for device attribute functions to avoid namespace conflicts.

 drivers/auxdisplay/Kconfig  |   20 +
 drivers/auxdisplay/Makefile |    1 +
 drivers/auxdisplay/tm16xx.c | 1781 +++++++++++++++++++++++++++++++++++
 3 files changed, 1802 insertions(+)
 create mode 100644 drivers/auxdisplay/tm16xx.c
drivers/auxdisplay/Kconfig +20 -0
index bedc6133f..54c4c43c0 100644
@@ -526,6 +526,26 @@ config SEG_LED_GPIO
 	  This driver can also be built as a module. If so, the module
 	  will be called seg-led-gpio.
 
+config TM16XX
+	tristate "TM16XX-compatible 7-segment LED controllers with keyscan"
+	depends on SPI || I2C
+	depends on INPUT
+	select NEW_LEDS
+	select LEDS_CLASS
+	select LEDS_TRIGGERS
+	select INPUT_MATRIXKMAP
+	help
+	  This driver supports the following TM16XX compatible
+	  I2C and SPI 7-segment led display chips:
+	  - Titanmec: TM1618, TM1620, TM1628, TM1638, TM1650
+	  - Fuda Hisi: FD620, FD628, FD650, FD655, FD6551
+	  - i-Core: AiP650, AiP1618, AiP1628
+	  - Princeton: PT6964
+	  - Winrise: HBS658
+
+	  This driver can also be built as a module. If so, the module
+	  will be called tm16xx.
+
 #
 # Character LCD with non-conforming interface section
 #
drivers/auxdisplay/Makefile +1 -0
index f5c13ed1c..a2444cfb7 100644
@@ -16,3 +16,4 @@ obj-$(CONFIG_LINEDISP)		+= line-display.o
 obj-$(CONFIG_MAX6959)		+= max6959.o
 obj-$(CONFIG_PARPORT_PANEL)	+= panel.o
 obj-$(CONFIG_SEG_LED_GPIO)	+= seg-led-gpio.o
+obj-$(CONFIG_TM16XX)		+= tm16xx.o
drivers/auxdisplay/tm16xx.c new file +1781 -0

1,781 lines not on this page · raw message

Signature · 1 line
2.43.0
#12 lore raw
Quoted 12 lines · Jean-François Lessard
drivers/auxdisplay/tm16xx.c new file +12 -0
+/**
+ * tm16xx_map_seg7_store() - Sysfs: set 7-segment character map (binary blob)
+ * @dev: pointer to device
+ * @attr: device attribute (unused)
+ * @buf: new mapping (must match size of map_seg7)
+ * @cnt: buffer length
+ *
+ * Return: cnt on success, negative errno on failure
+ */
+static ssize_t tm16xx_map_seg7_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t cnt)

drivers/auxdisplay/tm16xx.c line 726

Quoted 10 lines
drivers/auxdisplay/tm16xx.c new file +10 -0
+{
+	if (cnt != sizeof(map_seg7))
+		return -EINVAL;
+	memcpy(&map_seg7, buf, cnt);
+	return cnt;
+}
+
+static DEVICE_ATTR(value, 0644, tm16xx_value_show, tm16xx_value_store);
+static DEVICE_ATTR(num_digits, 0444, tm16xx_num_digits_show, NULL);
+static DEVICE_ATTR(map_seg7, 0644, tm16xx_map_seg7_show, tm16xx_map_seg7_store);

Where did you document the ABI?

Quoted 9 lines
drivers/auxdisplay/tm16xx.c new file +9 -0
+
+static struct attribute *tm16xx_main_led_attrs[] = {
+	&dev_attr_value.attr,
+	&dev_attr_num_digits.attr,
+	&dev_attr_map_seg7.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(tm16xx_main_led);
+

...

Quoted 27 lines
drivers/auxdisplay/tm16xx.c new file +27 -0
+#if IS_ENABLED(CONFIG_I2C)
+/**
+ * tm16xx_i2c_probe() - Probe callback for I2C-attached controllers
+ * @client: pointer to i2c_client
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int tm16xx_i2c_probe(struct i2c_client *client)
+{
+	const struct tm16xx_controller *controller;
+	struct tm16xx_display *display;
+	int ret;
+
+	controller = i2c_get_match_data(client);
+	if (!controller)
+		return -EINVAL;
+
+	display = devm_kzalloc(&client->dev, sizeof(*display), GFP_KERNEL);
+	if (!display)
+		return -ENOMEM;
+
+	display->client.i2c = client;
+	display->dev = &client->dev;
+	display->controller = controller;
+
+	i2c_set_clientdata(client, display);
+

drivers/auxdisplay/tm16xx.c line 1439

Quoted 10 lines
drivers/auxdisplay/tm16xx.c new file +10 -0
+	ret = tm16xx_probe(display);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/**
+ * tm16xx_i2c_remove() - Remove callback for I2C-attached controllers
+ * @client: pointer to i2c_client

Please don't ever add comments, especially kerneldocs, for such obvious driver API. This function cannot be anything else than what you described. Why? Linux core driver model tells that. You never have to repeat what Linux core driver model is...

Best regards,
Krzysztof

#13 lore raw

Le 21 août 2025 03 h 43 min 51 s HAE, Krzysztof Kozlowski <[email protected]> a écrit :

Quoted 17 lines · Jean-François Lessard
Quoted 16 lines
drivers/auxdisplay/tm16xx.c new file +16 -0
+/**
+ * tm16xx_map_seg7_store() - Sysfs: set 7-segment character map (binary blob)
+ * @dev: pointer to device
+ * @attr: device attribute (unused)
+ * @buf: new mapping (must match size of map_seg7)
+ * @cnt: buffer length
+ *
+ * Return: cnt on success, negative errno on failure
+ */
+static ssize_t tm16xx_map_seg7_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t cnt)
+{
+	if (cnt != sizeof(map_seg7))
+		return -EINVAL;
+	memcpy(&map_seg7, buf, cnt);
Quoted 9 lines

drivers/auxdisplay/tm16xx.c line 726

Quoted 6 lines
drivers/auxdisplay/tm16xx.c new file +6 -0
+	return cnt;
+}
+
+static DEVICE_ATTR(value, 0644, tm16xx_value_show, tm16xx_value_store);
+static DEVICE_ATTR(num_digits, 0444, tm16xx_num_digits_show, NULL);
+static DEVICE_ATTR(map_seg7, 0644, tm16xx_map_seg7_show, tm16xx_map_seg7_store);

Where did you document the ABI?

Currently, there is no formal ABI documentation for the TM16xx sysfs attributes. While map_seg7 follows existing auxdisplay conventions (which lack ABI docs), I plan to add TM16xx-specific ABI documentation under Documentation/ABI/testing/sysfs-class-leds-tm16xx in the v4 submission.

Quoted 46 lines
Quoted 9 lines
drivers/auxdisplay/tm16xx.c new file +9 -0
+
+static struct attribute *tm16xx_main_led_attrs[] = {
+	&dev_attr_value.attr,
+	&dev_attr_num_digits.attr,
+	&dev_attr_map_seg7.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(tm16xx_main_led);
+

...

Quoted 34 lines
drivers/auxdisplay/tm16xx.c new file +34 -0
+#if IS_ENABLED(CONFIG_I2C)
+/**
+ * tm16xx_i2c_probe() - Probe callback for I2C-attached controllers
+ * @client: pointer to i2c_client
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int tm16xx_i2c_probe(struct i2c_client *client)
+{
+	const struct tm16xx_controller *controller;
+	struct tm16xx_display *display;
+	int ret;
+
+	controller = i2c_get_match_data(client);
+	if (!controller)
+		return -EINVAL;
+
+	display = devm_kzalloc(&client->dev, sizeof(*display), GFP_KERNEL);
+	if (!display)
+		return -ENOMEM;
+
+	display->client.i2c = client;
+	display->dev = &client->dev;
+	display->controller = controller;
+
+	i2c_set_clientdata(client, display);
+
+	ret = tm16xx_probe(display);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
Quoted 9 lines
Quoted 3 lines

+/**
+ * tm16xx_i2c_remove() - Remove callback for I2C-attached controllers
+ * @client: pointer to i2c_client

Please don't ever add comments, especially kerneldocs, for such obvious driver API. This function cannot be anything else than what you described. Why? Linux core driver model tells that. You never have to repeat what Linux core driver model is...

Well received, thank you. I will drop these trivial kernel-doc comments.

Quoted 3 lines

Best regards,
Krzysztof

Best regards,

Jean-François Lessard

#14 lore raw
In reply to Jean-François Lessard
Quoted 9 lines · Jean-François Lessard

Add driver for TM16xx family LED controllers and compatible chips from multiple vendors including Titan Micro, Fuda Hisi, i-Core, Princeton, and Winrise. These controllers drive 7-segment digits and individual LED icons through either I2C or SPI interfaces with optional keypad scanning support.

Successfully tested on various ARM TV boxes including H96 Max, Magicsee N5, Tanix TX3 Mini, Tanix TX6, X92, and X96 Max across different SoC platforms (Rockchip, Amlogic, Allwinner).

This patch is ~1800 lines. Can you split it to a few based on main features (like the keyboard may be separated)? 2k is hard to review.

Quoted 2 lines

I dunno what these tags may mean in the current context...

...

drivers/auxdisplay/tm16xx.c line 11

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
 
+#include <linux/bitops.h>

When bitmap,h is included, bitops.h is implied. But it's okay to include both.

drivers/auxdisplay/tm16xx.c line 19

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/leds.h>
+#include <linux/map_to_7segment.h>
+#include <linux/module.h>

Missing mod_devicetable.h for the ID table definitions.

drivers/auxdisplay/tm16xx.c line 21

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+#include <linux/of.h>
+#include <linux/of_device.h>

Cargo-cult? These two should be rarely used in a new code, for this driver I'm pretty sure they need not to be used at all.

Quoted 5 lines
drivers/auxdisplay/tm16xx.c new file +5 -0
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>

...

drivers/auxdisplay/tm16xx.c line 29

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+#define TM16XX_DRIVER_NAME "tm16xx"
+#define TM16XX_DEVICE_NAME "display"

Not sure why we need these two.

...

drivers/auxdisplay/tm16xx.c line 41

Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +6 -0
+/* Command type bits (bits 7-6) */
+#define TM16XX_CMD_MASK                GENMASK(7, 6)
 
+#define TM16XX_CMD_MODE                0
+#define TM16XX_CMD_DATA                BIT(6)
+#define TM16XX_CMD_CTRL                BIT(7)
+#define TM16XX_CMD_ADDR                (BIT(7) | BIT(6))

As far as I can see these are clearly not bits, please use the form of (0 << 6), (1 << 6) and so on.

...

drivers/auxdisplay/tm16xx.c line 50

Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +6 -0
+/* Mode command grid settings (bits 1-0) */
+#define TM16XX_MODE_GRID_MASK  GENMASK(1, 0)
 
+#define TM16XX_MODE_4GRIDS     0
+#define TM16XX_MODE_5GRIDS     BIT(0)
+#define TM16XX_MODE_6GRIDS     BIT(1)
+#define TM16XX_MODE_7GRIDS     (BIT(1) | BIT(0))

Ditto.

...

drivers/auxdisplay/tm16xx.c line 55

Quoted 5 lines
drivers/auxdisplay/tm16xx.c new file +4 -0
+/* Data command settings */
+#define TM16XX_DATA_ADDR_MASK  BIT(2)
 
+#define TM16XX_DATA_ADDR_AUTO  0
+#define TM16XX_DATA_ADDR_FIXED BIT(2)

Not sure why we need a definition for 0. But if it's required, make it
similar to above.

...

drivers/auxdisplay/tm16xx.c line 58

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM16XX_DATA_MODE_MASK  GENMASK(1, 0)
+#define TM16XX_DATA_MODE_WRITE 0
+#define TM16XX_DATA_MODE_READ  BIT(1)

Seems also needs to be converted to plain numbers.

...

drivers/auxdisplay/tm16xx.c line 94

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM1650_CTRL_BR_MASK    GENMASK(6, 4)
+#define TM1650_CTRL_ON         BIT(0)
+#define TM1650_CTRL_SLEEP      BIT(2)

Are they really bits and not an enum in the datasheet?

...

drivers/auxdisplay/tm16xx.c line 97

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM1650_CTRL_SEG_MASK   BIT(3)
 
+#define TM1650_CTRL_SEG8_MODE  0
+#define TM1650_CTRL_SEG7_MODE  BIT(3)

Same Q as per above case.

...

drivers/auxdisplay/tm16xx.c line 116

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM16XX_CTRL_BRIGHTNESS(enabled, value, prefix) \
+       ((enabled) ? (FIELD_PREP(prefix##_CTRL_BR_MASK, (value)) | \
+                     prefix##_CTRL_ON) : 0)

Okay, but can you split it logically, perhaps making it only one line (for the lines 2nd and 3rd)?

...

drivers/auxdisplay/tm16xx.c line 120

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+static char *default_value;
+module_param(default_value, charp, 0444);
+MODULE_PARM_DESC(default_value, "Default display value to initialize");

Do we need this? Why?

...

drivers/auxdisplay/tm16xx.c line 278

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +4 -0
+static inline u16 tm16xx_get_grid(const struct tm16xx_display *display,
+                                 const unsigned int grid)
+{
+       return (u16)bitmap_read(display->state, grid * display->num_segments,

Why casting?

Quoted 2 lines
(quoted diff) +2 -0
+                               display->num_segments);
+}

...

Quoted 1 line

+#define for_each_key(keypad, _r, _c) \

This is too broad a name for the macro. If it's useful not only in this driver, make it in one of the linux/input* headers perhaps.

Quoted 1 line

+ for (unsigned int (_r) = 0; \

Can _r be an expression? Really?

drivers/auxdisplay/tm16xx.c line 337

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+            (_r) < (keypad)->display->controller->max_key_rows; (_r)++) \
+               for (unsigned int (_c) = 0; \

Same about _c.

Quoted 1 line

+ (_c) < (keypad)->display->controller->max_key_cols; (_c)++)

...

Quoted 1 line

+ mutex_lock(&keypad->display->lock);

Perhaps scoped_guard() from cleanup.h?

Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +7 -0
+       ret = keypad->display->controller->keys(keypad);
+       mutex_unlock(&keypad->display->lock);
+
+       if (ret < 0) {
+               dev_err(keypad->display->dev, "Reading failed: %d\n", ret);
+               return;
+       }

...

drivers/auxdisplay/tm16xx.c line 377

Quoted 6 lines
drivers/auxdisplay/tm16xx.c new file +5 -0
+       for_each_set_bit(bit, keypad->changes, nbits) {
+               row = tm16xx_get_key_row(keypad, bit);
+               col = tm16xx_get_key_col(keypad, bit);
+               pressed = _test_bit(bit, keypad->state);
 
+               u16 scancode = MATRIX_SCAN_CODE(row, col, keypad->row_shift);

Don't mix definitions and code. It's only relaxed for iterators and RAII (cleanup.h) variables in Linux kernel.

Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +7 -0
+               dev_dbg(keypad->display->dev,
+                       "key changed: %u, row=%u col=%u down=%d\n", bit, row,
+                       col, pressed);
+
+               input_event(keypad->input, EV_MSC, MSC_SCAN, scancode);
+               input_report_key(keypad->input, keycodes[scancode], pressed);
+       }

...

drivers/auxdisplay/tm16xx.c line 404

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+static int tm16xx_keypad_probe(struct tm16xx_display *display)
+{
+       const u8 rows = display->controller->max_key_rows;
+       const u8 cols = display->controller->max_key_cols;
+       struct tm16xx_keypad *keypad;
+       struct input_dev *input;
+       unsigned int poll_interval, nbits;
+       int ret = 0;

I don't see how this assignment is used.

Quoted 70 lines
drivers/auxdisplay/tm16xx.c new file +69 -0
+       if (!display->controller->keys || !rows || !cols) {
+               dev_dbg(display->dev, "keypad not supported\n");
+               return 0;
+       }
+
+       if (!device_property_present(display->dev, "poll-interval") ||
+           !device_property_present(display->dev, "linux,keymap")) {
+               dev_dbg(display->dev, "keypad disabled\n");
+               return 0;
+       }
+
+       dev_dbg(display->dev, "Configuring keypad\n");
+
+       ret = device_property_read_u32(display->dev, "poll-interval",
+                                      &poll_interval);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to read poll-interval: %d\n", ret);
+               return ret;
+       }
+
+       keypad = devm_kzalloc(display->dev, sizeof(*keypad), GFP_KERNEL);
+       if (!keypad)
+               return -ENOMEM;
+       keypad->display = display;
+
+       nbits = tm16xx_key_nbits(keypad);
+       keypad->state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->last_state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->changes = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       if (!keypad->state || !keypad->last_state || !keypad->changes) {
+               ret = -ENOMEM;
+               goto free_keypad;
+       }
+
+       input = devm_input_allocate_device(display->dev);
+       if (!input) {
 
+               dev_err(display->dev, "Failed to allocate input device\n");
+               ret = -ENOMEM;
+               goto free_bitmaps;
+       }
+       input->name = TM16XX_DRIVER_NAME "-keypad";
+       keypad->input = input;
+       input_set_drvdata(input, keypad);
+
+       keypad->row_shift = get_count_order(cols);
+       ret = matrix_keypad_build_keymap(NULL, "linux,keymap", rows, cols, NULL,
+                                        input);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to build keymap: %d\n", ret);
+               goto free_input;
+       }
+
+       if (device_property_read_bool(display->dev, "autorepeat"))
+               __set_bit(EV_REP, input->evbit);
+
+       input_setup_polling(input, tm16xx_keypad_poll);
+       input_set_poll_interval(input, poll_interval);
+       ret = input_register_device(input);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to register input device: %d\n",
+                       ret);
+               goto free_input;
+       }
+
+       dev_dbg(display->dev, "keypad rows=%u, cols=%u, poll=%u\n", rows, cols,
+               poll_interval);
+
+       return 0;
+

drivers/auxdisplay/tm16xx.c line 484

Quoted 10 lines
drivers/auxdisplay/tm16xx.c new file +10 -0
+free_input:
+       input_free_device(input);
+free_bitmaps:
+       devm_kfree(display->dev, keypad->state);
+       devm_kfree(display->dev, keypad->last_state);
+       devm_kfree(display->dev, keypad->changes);
+free_keypad:
+       devm_kfree(display->dev, keypad);
+       return ret;
+}

...

I stopped here, I believe it's enough for now (and I would wait for the smaller changes per patch, perhaps 2 DT bindings patch + common part (basic functionality) + spi driver + i2c driver + keyboard, something like 6+ patches).
Also, split i2c and spi glue drivers to a separate modules, so you will have 3 files:

$main
$main_i2c
$main_spi

Look at ton of examples under drivers/iio/

--
With Best Regards,
Andy Shevchenko

author Acked-by The Stakeholder
#15 lore raw

Le 21 août 2025 04 h 08 min 51 s HAE, Andy Shevchenko <[email protected]> a écrit :

Quoted 8 lines
Quoted 6 lines · Jean-François Lessard

Add driver for TM16xx family LED controllers and compatible chips from multiple vendors including Titan Micro, Fuda Hisi, i-Core, Princeton, and Winrise. These controllers drive 7-segment digits and individual LED icons through either I2C or SPI interfaces with optional keypad scanning support.

Quoted 8 lines
Quoted 3 lines

Successfully tested on various ARM TV boxes including H96 Max, Magicsee N5, Tanix TX3 Mini, Tanix TX6, X92, and X96 Max across different SoC platforms (Rockchip, Amlogic, Allwinner).

This patch is ~1800 lines. Can you split it to a few based on main features (like the keyboard may be separated)? 2k is hard to review.

I agree that 1800 lines is a lot to review at once. For v4, I plan to split the submission into separate patches and source files for better reviewability and maintainability:
- tm16xx.h / tm16xx.c (core driver)
- tm16xx_keypad.c (keypad support)
- tm16xx_spi.c (SPI glue)
- tm16xx_i2c.c (I2C glue)

I believe this will improve clarity without fragmenting the driver nor its DT bindings.

Quoted 5 lines
Quoted 2 lines

I dunno what these tags may mean in the current context...

These “Acked-by” tags follow kernel submission guidelines to record approval from key users.

Per Documentation/process/submitting-patches.rst:
Acked-by: may also be used by other stakeholders, such as people with domain knowledge (e.g. the original author of the code being modified), userspace-side reviewers for a kernel uAPI patch or key users of a feature. Optionally, in these cases, it can be useful to add a "# Suffix" to clarify its meaning::

Quoted 26 lines

...

drivers/auxdisplay/tm16xx.c line 11

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
 
+#include <linux/bitops.h>

When bitmap,h is included, bitops.h is implied. But it's okay to include both.

drivers/auxdisplay/tm16xx.c line 19

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/leds.h>
+#include <linux/map_to_7segment.h>
+#include <linux/module.h>

Missing mod_devicetable.h for the ID table definitions.

drivers/auxdisplay/tm16xx.c line 21

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+#include <linux/of.h>
+#include <linux/of_device.h>

Cargo-cult? These two should be rarely used in a new code, for this driver I'm pretty sure they need not to be used at all.

Quoted 5 lines

drivers/auxdisplay/tm16xx.c line 26

Quoted 5 lines
drivers/auxdisplay/tm16xx.c new file +5 -0
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>

Thanks for pointing that out. For v4, I will revise includes to:

#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/leds.h>
#include <linux/map_to_7segment.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>

Quoted 8 lines

...

drivers/auxdisplay/tm16xx.c line 29

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+#define TM16XX_DRIVER_NAME "tm16xx"
+#define TM16XX_DEVICE_NAME "display"

Not sure why we need these two.

I will drop TM16XX_DEVICE_NAME since DT node name/label property should be used.

The TM16XX_DRIVER_NAME macro is standard practice for consistent string usage in registration and module macros.
If helpful, I can add a leading /* module name */ header comment.

Quoted 5 lines

...

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+/* Command type bits (bits 7-6) */
+#define TM16XX_CMD_MASK                GENMASK(7, 6)
Quoted 8 lines

drivers/auxdisplay/tm16xx.c line 41

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +4 -0
+#define TM16XX_CMD_MODE                0
+#define TM16XX_CMD_DATA                BIT(6)
+#define TM16XX_CMD_CTRL                BIT(7)
+#define TM16XX_CMD_ADDR                (BIT(7) | BIT(6))

As far as I can see these are clearly not bits, please use the form of (0 << 6), (1 << 6) and so on.

You are correct. Per datasheet, these fields represent enumerated values of a 2-bit field and not independent single bits. I will update definitions accordingly in v4 for clarity and correctness:

#define TM16XX_CMD_MODE  (0 << 6)
#define TM16XX_CMD_DATA  (1 << 6)
#define TM16XX_CMD_CTRL  (2 << 6)
#define TM16XX_CMD_ADDR  (3 << 6)

and similarly for other multi-bit fields.

Quoted 31 lines

...

drivers/auxdisplay/tm16xx.c line 50

Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +6 -0
+/* Mode command grid settings (bits 1-0) */
+#define TM16XX_MODE_GRID_MASK  GENMASK(1, 0)
 
+#define TM16XX_MODE_4GRIDS     0
+#define TM16XX_MODE_5GRIDS     BIT(0)
+#define TM16XX_MODE_6GRIDS     BIT(1)
+#define TM16XX_MODE_7GRIDS     (BIT(1) | BIT(0))

Ditto.

...

drivers/auxdisplay/tm16xx.c line 55

Quoted 5 lines
drivers/auxdisplay/tm16xx.c new file +4 -0
+/* Data command settings */
+#define TM16XX_DATA_ADDR_MASK  BIT(2)
 
+#define TM16XX_DATA_ADDR_AUTO  0
+#define TM16XX_DATA_ADDR_FIXED BIT(2)

Not sure why we need a definition for 0. But if it's required, make it similar to above.

...

drivers/auxdisplay/tm16xx.c line 58

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM16XX_DATA_MODE_MASK  GENMASK(1, 0)
+#define TM16XX_DATA_MODE_WRITE 0
+#define TM16XX_DATA_MODE_READ  BIT(1)

Seems also needs to be converted to plain numbers.

Quoted 8 lines

...

drivers/auxdisplay/tm16xx.c line 94

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM1650_CTRL_BR_MASK    GENMASK(6, 4)
+#define TM1650_CTRL_ON         BIT(0)
+#define TM1650_CTRL_SLEEP      BIT(2)

Are they really bits and not an enum in the datasheet?

These are respectively B0 and B2 according to the TM1650 datasheet:
- B0: Off screen display / Open screen display
- B1: fixed to 0
- B2: Normal operating mode / Standby mode
- B7-B4: brightness enum

Quoted 9 lines

...

drivers/auxdisplay/tm16xx.c line 97

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM1650_CTRL_SEG_MASK   BIT(3)
 
+#define TM1650_CTRL_SEG8_MODE  0
+#define TM1650_CTRL_SEG7_MODE  BIT(3)

Same Q as per above case.

B3 controls 8 vs 7 segment mode. I will make it clearer:
#define TM1650_CTRL_SEG8_MODE (0 << 3)
#define TM1650_CTRL_SEG7_MODE (1 << 3)

Quoted 9 lines

...

drivers/auxdisplay/tm16xx.c line 116

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM16XX_CTRL_BRIGHTNESS(enabled, value, prefix) \
+       ((enabled) ? (FIELD_PREP(prefix##_CTRL_BR_MASK, (value)) | \
+                     prefix##_CTRL_ON) : 0)

Okay, but can you split it logically, perhaps making it only one line (for the lines 2nd and 3rd)?

I currently format it as a multi-line macro respecting 80-column limit, with conditional ternary expression on separate lines for readability. If you prefer a different formatting style or logical grouping, please advise, as I want to keep it consistent with kernel coding style.

Quoted 8 lines

...

drivers/auxdisplay/tm16xx.c line 120

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+static char *default_value;
+module_param(default_value, charp, 0444);
+MODULE_PARM_DESC(default_value, "Default display value to initialize");

Do we need this? Why?

This parameter was requested by community users to allow a boot message (e.g., “boot”) before user space takes control of the display value. I believe a module parameter is appropriate here to maintain separation between driver internals and user content, avoiding hardcoding display content in DT or code.

Quoted 9 lines

...

drivers/auxdisplay/tm16xx.c line 278

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +4 -0
+static inline u16 tm16xx_get_grid(const struct tm16xx_display *display,
+                                 const unsigned int grid)
+{
+       return (u16)bitmap_read(display->state, grid * display->num_segments,

Why casting?

I agree the cast to u16 is redundant and will remove it.

Quoted 10 lines
Quoted 2 lines
(quoted diff) +2 -0
+                               display->num_segments);
+}

...

Quoted 1 line

+#define for_each_key(keypad, _r, _c) \

This is too broad a name for the macro. If it's useful not only in this driver, make it in one of the linux/input* headers perhaps.

Quoted 11 lines
Quoted 1 line

+ for (unsigned int (_r) = 0; \

Can _r be an expression? Really?

drivers/auxdisplay/tm16xx.c line 337

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+            (_r) < (keypad)->display->controller->max_key_rows; (_r)++) \
+               for (unsigned int (_c) = 0; \

Same about _c.

Quoted 1 line

+ (_c) < (keypad)->display->controller->max_key_cols; (_c)++)

I will rename it to tm16xx_for_each_key to avoid overly generic macro names and remove parentheses around arguments to conform with kernel macro conventions.

Quoted 6 lines

...

Quoted 1 line

+ mutex_lock(&keypad->display->lock);

Perhaps scoped_guard() from cleanup.h?

I will replace manual mutex locking with modern scoped guard constructs.

Quoted 15 lines
Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +7 -0
+       ret = keypad->display->controller->keys(keypad);
+       mutex_unlock(&keypad->display->lock);
+
+       if (ret < 0) {
+               dev_err(keypad->display->dev, "Reading failed: %d\n", ret);
+               return;
+       }

...

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +4 -0
+       for_each_set_bit(bit, keypad->changes, nbits) {
+               row = tm16xx_get_key_row(keypad, bit);
+               col = tm16xx_get_key_col(keypad, bit);
+               pressed = _test_bit(bit, keypad->state);
Quoted 5 lines
Quoted 1 line

+ u16 scancode = MATRIX_SCAN_CODE(row, col, keypad->row_shift);

Don't mix definitions and code. It's only relaxed for iterators and RAII (cleanup.h) variables in Linux kernel.

I will move variable declarations to the beginning of blocks.

Quoted 10 lines
Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +7 -0
+               dev_dbg(keypad->display->dev,
+                       "key changed: %u, row=%u col=%u down=%d\n", bit, row,
+                       col, pressed);
+
+               input_event(keypad->input, EV_MSC, MSC_SCAN, scancode);
+               input_report_key(keypad->input, keycodes[scancode], pressed);
+       }

...

Quoted 11 lines

drivers/auxdisplay/tm16xx.c line 404

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+static int tm16xx_keypad_probe(struct tm16xx_display *display)
+{
+       const u8 rows = display->controller->max_key_rows;
+       const u8 cols = display->controller->max_key_cols;
+       struct tm16xx_keypad *keypad;
+       struct input_dev *input;
+       unsigned int poll_interval, nbits;
+       int ret = 0;

I don't see how this assignment is used.

I will remove this unnecessary initialization.

Quoted 90 lines
Quoted 70 lines
drivers/auxdisplay/tm16xx.c new file +69 -0
+       if (!display->controller->keys || !rows || !cols) {
+               dev_dbg(display->dev, "keypad not supported\n");
+               return 0;
+       }
+
+       if (!device_property_present(display->dev, "poll-interval") ||
+           !device_property_present(display->dev, "linux,keymap")) {
+               dev_dbg(display->dev, "keypad disabled\n");
+               return 0;
+       }
+
+       dev_dbg(display->dev, "Configuring keypad\n");
+
+       ret = device_property_read_u32(display->dev, "poll-interval",
+                                      &poll_interval);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to read poll-interval: %d\n", ret);
+               return ret;
+       }
+
+       keypad = devm_kzalloc(display->dev, sizeof(*keypad), GFP_KERNEL);
+       if (!keypad)
+               return -ENOMEM;
+       keypad->display = display;
+
+       nbits = tm16xx_key_nbits(keypad);
+       keypad->state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->last_state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->changes = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       if (!keypad->state || !keypad->last_state || !keypad->changes) {
+               ret = -ENOMEM;
+               goto free_keypad;
+       }
+
+       input = devm_input_allocate_device(display->dev);
+       if (!input) {
 
+               dev_err(display->dev, "Failed to allocate input device\n");
+               ret = -ENOMEM;
+               goto free_bitmaps;
+       }
+       input->name = TM16XX_DRIVER_NAME "-keypad";
+       keypad->input = input;
+       input_set_drvdata(input, keypad);
+
+       keypad->row_shift = get_count_order(cols);
+       ret = matrix_keypad_build_keymap(NULL, "linux,keymap", rows, cols, NULL,
+                                        input);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to build keymap: %d\n", ret);
+               goto free_input;
+       }
+
+       if (device_property_read_bool(display->dev, "autorepeat"))
+               __set_bit(EV_REP, input->evbit);
+
+       input_setup_polling(input, tm16xx_keypad_poll);
+       input_set_poll_interval(input, poll_interval);
+       ret = input_register_device(input);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to register input device: %d\n",
+                       ret);
+               goto free_input;
+       }
+
+       dev_dbg(display->dev, "keypad rows=%u, cols=%u, poll=%u\n", rows, cols,
+               poll_interval);
+
+       return 0;
+

drivers/auxdisplay/tm16xx.c line 484

Quoted 10 lines
drivers/auxdisplay/tm16xx.c new file +10 -0
+free_input:
+       input_free_device(input);
+free_bitmaps:
+       devm_kfree(display->dev, keypad->state);
+       devm_kfree(display->dev, keypad->last_state);
+       devm_kfree(display->dev, keypad->changes);
+free_keypad:
+       devm_kfree(display->dev, keypad);
+       return ret;
+}

...

I stopped here, I believe it's enough for now (and I would wait for the smaller changes per patch, perhaps 2 DT bindings patch + common part (basic functionality) + spi driver + i2c driver + keyboard, something like 6+ patches).
Also, split i2c and spi glue drivers to a separate modules, so you will have 3 files:

Quoted 6 lines

$main
$main_i2c
$main_spi

Look at ton of examples under drivers/iio/

I plan to split source files for review but maintain a single unified kernel module that handles both I2C and SPI buses. This avoids confusion and unnecessary duplication since the hardware and DT bindings are shared. If you intended splitting into separate loadable kernel modules for I2C and SPI, could you please clarify? I believe a single driver module better fits this hardware model.

Quoted 3 lines

--
With Best Regards,
Andy Shevchenko

Thank you for the thorough feedback; I will incorporate these changes in v4 and welcome further guidance.

Best regards,
Jean-François Lessard

#16 lore raw
Quoted 3 lines · Jean-François Lessard
Quoted 2 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:32 PM Jean-François Lessard <[email protected]> wrote:

...

Quoted 11 lines
Quoted 2 lines

This patch is ~1800 lines. Can you split it to a few based on main features (like the keyboard may be separated)? 2k is hard to review.

I agree that 1800 lines is a lot to review at once. For v4, I plan to split the submission into separate patches and source files for better reviewability and maintainability:
- tm16xx.h / tm16xx.c (core driver)
- tm16xx_keypad.c (keypad support)
- tm16xx_spi.c (SPI glue)
- tm16xx_i2c.c (I2C glue)

Quoted 2 lines

I believe this will improve clarity without fragmenting the driver nor its DT bindings.

Sounds good.

...

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

I dunno what these tags may mean in the current context...

These “Acked-by” tags follow kernel submission guidelines to record approval from key users.

Quoted 7 lines

Per Documentation/process/submitting-patches.rst:
Acked-by: may also be used by other stakeholders, such as people with domain knowledge (e.g. the original author of the code being modified), userspace-side reviewers for a kernel uAPI patch or key users of a feature. Optionally, in these cases, it can be useful to add a "# Suffix" to clarify its meaning::

Ah, interesting. TIL.

...

Quoted 32 lines
Quoted 24 lines

drivers/auxdisplay/tm16xx.c line 11

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
 
+#include <linux/bitops.h>

When bitmap,h is included, bitops.h is implied. But it's okay to include both.

drivers/auxdisplay/tm16xx.c line 19

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/leds.h>
+#include <linux/map_to_7segment.h>
+#include <linux/module.h>

Missing mod_devicetable.h for the ID table definitions.

drivers/auxdisplay/tm16xx.c line 21

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+#include <linux/of.h>
+#include <linux/of_device.h>

Cargo-cult? These two should be rarely used in a new code, for this driver I'm pretty sure they need not to be used at all.

Quoted 5 lines

drivers/auxdisplay/tm16xx.c line 26

Quoted 5 lines
drivers/auxdisplay/tm16xx.c new file +5 -0
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>

Thanks for pointing that out. For v4, I will revise includes to:

Quoted 4 lines

#include <linux/bitfield.h>
#include <linux/bitmap.h>

#include <linux/i2c.h>

Probably not this in the core file.

Quoted 8 lines

#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/leds.h>
#include <linux/map_to_7segment.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/spi/spi.h>

Nor this.

Quoted 1 line

#include <linux/workqueue.h>

...

Quoted 10 lines
Quoted 4 lines

drivers/auxdisplay/tm16xx.c line 29

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+#define TM16XX_DRIVER_NAME "tm16xx"
+#define TM16XX_DEVICE_NAME "display"

Not sure why we need these two.

I will drop TM16XX_DEVICE_NAME since DT node name/label property should be used.

The TM16XX_DRIVER_NAME macro is standard practice for consistent string usage in registration and module macros.
If helpful, I can add a leading /* module name */ header comment.

Instead of an unneeded comment it seems better to use explicit string literal in all cases (two?).

...

Quoted 11 lines
Quoted 5 lines

drivers/auxdisplay/tm16xx.c line 94

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM1650_CTRL_BR_MASK    GENMASK(6, 4)
+#define TM1650_CTRL_ON         BIT(0)
+#define TM1650_CTRL_SLEEP      BIT(2)

Are they really bits and not an enum in the datasheet?

These are respectively B0 and B2 according to the TM1650 datasheet:
- B0: Off screen display / Open screen display
- B1: fixed to 0
- B2: Normal operating mode / Standby mode
- B7-B4: brightness enum

I see, I would put a double names then

_OFF_OPEN // is it "open" or "on"? What's the difference? _RUN_STANDBY

(find better names)

...

Quoted 10 lines
Quoted 6 lines

drivers/auxdisplay/tm16xx.c line 97

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM1650_CTRL_SEG_MASK   BIT(3)
 
+#define TM1650_CTRL_SEG8_MODE  0
+#define TM1650_CTRL_SEG7_MODE  BIT(3)

Same Q as per above case.

B3 controls 8 vs 7 segment mode. I will make it clearer:
#define TM1650_CTRL_SEG8_MODE (0 << 3)
#define TM1650_CTRL_SEG7_MODE (1 << 3)

Hmm... Here it's clear and both are probably needed in the code, but maybe it also makes sense to put similar for the above?

CTRL_OFF (0 << ...)
CTRL_OPEN
CTRL_RUN
CTRL_STANDBY

?

...

Quoted 11 lines
Quoted 6 lines

drivers/auxdisplay/tm16xx.c line 116

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM16XX_CTRL_BRIGHTNESS(enabled, value, prefix) \
+       ((enabled) ? (FIELD_PREP(prefix##_CTRL_BR_MASK, (value)) | \
+                     prefix##_CTRL_ON) : 0)

Okay, but can you split it logically, perhaps making it only one line (for the lines 2nd and 3rd)?

I currently format it as a multi-line macro respecting 80-column limit, with conditional ternary expression on separate lines for readability. If you prefer a different formatting style or logical grouping, please advise, as I want to keep it consistent with kernel coding style.

We have a relaxed format and I don't mind that people use it. But the main point here is readability / logical split. Also parameter names can be shortened a bit (like value --> val, enable --> en{a} / on.

...

Quoted 10 lines
Quoted 5 lines

drivers/auxdisplay/tm16xx.c line 120

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+static char *default_value;
+module_param(default_value, charp, 0444);
+MODULE_PARM_DESC(default_value, "Default display value to initialize");

Do we need this? Why?

This parameter was requested by community users to allow a boot message (e.g., “boot”) before user space takes control of the display value. I believe a module parameter is appropriate here to maintain separation between driver internals and user content, avoiding hardcoding display content in DT or code.

Currently we have a compile-time option and I don't think module parameter is what we need. If somebody wants it, please make it a separate patch with much better justification ("a user wants it" doesn't work). DT most likely is also not the best choice as it's about HW and not some policies.

TL;DR: please drop it for now (but if you wish something, use the compile time option we have in Kconfig for that).

...

Quoted 11 lines
Quoted 10 lines

drivers/auxdisplay/tm16xx.c line 404

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+static int tm16xx_keypad_probe(struct tm16xx_display *display)
+{
+       const u8 rows = display->controller->max_key_rows;
+       const u8 cols = display->controller->max_key_cols;
+       struct tm16xx_keypad *keypad;
+       struct input_dev *input;
+       unsigned int poll_interval, nbits;
+       int ret = 0;

I don't see how this assignment is used.

Quoted 35 lines

I will remove this unnecessary initialization.

Quoted 33 lines
Quoted 33 lines
drivers/auxdisplay/tm16xx.c new file +32 -0
+       if (!display->controller->keys || !rows || !cols) {
+               dev_dbg(display->dev, "keypad not supported\n");
+               return 0;
+       }
+
+       if (!device_property_present(display->dev, "poll-interval") ||
+           !device_property_present(display->dev, "linux,keymap")) {
+               dev_dbg(display->dev, "keypad disabled\n");
+               return 0;
+       }
+
+       dev_dbg(display->dev, "Configuring keypad\n");
+
+       ret = device_property_read_u32(display->dev, "poll-interval",
+                                      &poll_interval);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to read poll-interval: %d\n", ret);
+               return ret;
+       }
+
+       keypad = devm_kzalloc(display->dev, sizeof(*keypad), GFP_KERNEL);
+       if (!keypad)
+               return -ENOMEM;
+       keypad->display = display;
+
+       nbits = tm16xx_key_nbits(keypad);
+       keypad->state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->last_state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->changes = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       if (!keypad->state || !keypad->last_state || !keypad->changes) {
+               ret = -ENOMEM;
 
+               goto free_keypad;

(Hit send too early that time...) This goto is bad. It means misunderstanding of the devm concept. See below.

Quoted 7 lines
Quoted 7 lines

drivers/auxdisplay/tm16xx.c line 443

Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +6 -0
+       }
+
+       input = devm_input_allocate_device(display->dev);
+       if (!input) {
 
+               dev_err(display->dev, "Failed to allocate input device\n");
+               ret = -ENOMEM;

No, we do not spill an error message on ENOMEM. This is an agreement in the kernel community for drivers.

Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
drivers/auxdisplay/tm16xx.c new file +15 -0
+               goto free_bitmaps;
+       }
+       input->name = TM16XX_DRIVER_NAME "-keypad";
+       keypad->input = input;
+       input_set_drvdata(input, keypad);
+
+       keypad->row_shift = get_count_order(cols);
+       ret = matrix_keypad_build_keymap(NULL, "linux,keymap", rows, cols, NULL,
+                                        input);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to build keymap: %d\n", ret);
+               goto free_input;
+       }
+
+       if (device_property_read_bool(display->dev, "autorepeat"))
Quoted 8 lines
Quoted 8 lines

drivers/auxdisplay/tm16xx.c line 466

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+               __set_bit(EV_REP, input->evbit);
+
+       input_setup_polling(input, tm16xx_keypad_poll);
+       input_set_poll_interval(input, poll_interval);
+       ret = input_register_device(input);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to register input device: %d\n",
+                       ret);

Use in all cases like this

  return dev_err_probe(...);

pattern.

Quoted 11 lines
Quoted 10 lines
Quoted 10 lines
drivers/auxdisplay/tm16xx.c new file +9 -0
+               goto free_input;
+       }
+
+       dev_dbg(display->dev, "keypad rows=%u, cols=%u, poll=%u\n", rows, cols,
+               poll_interval);
+
+       return 0;
 
+free_input:
+       input_free_device(input);
Quoted 7 lines
Quoted 7 lines

drivers/auxdisplay/tm16xx.c line 483

Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +7 -0
+free_bitmaps:
+       devm_kfree(display->dev, keypad->state);
+       devm_kfree(display->dev, keypad->last_state);
+       devm_kfree(display->dev, keypad->changes);
+free_keypad:
+       devm_kfree(display->dev, keypad);
+       return ret;

No way. We don't do that, If required it signals about exceptional case (0.01% probability) or misunderstanding of devm:
- managed resources are managed by core, no need to call for free
- using managed resources in the contexts when object lifetime is short is incorrect, needs to be switched to the plain alloc (nowadays with __free() from cleanup.h to have RAII enabled)

Choose one of these and fix the code accordingly.

Quoted 1 line
Quoted 1 line
Quoted 1 line

+}

...

Quoted 14 lines
Quoted 7 lines

I stopped here, I believe it's enough for now (and I would wait for the smaller changes per patch, perhaps 2 DT bindings patch + common part (basic functionality) + spi driver + i2c driver + keyboard, something like 6+ patches).
Also, split i2c and spi glue drivers to a separate modules, so you will have 3 files:

Quoted 6 lines

$main
$main_i2c
$main_spi

Look at ton of examples under drivers/iio/

Quoted 6 lines

I plan to split source files for review but maintain a single unified kernel module that handles both I2C and SPI buses. This avoids confusion and unnecessary duplication since the hardware and DT bindings are shared. If you intended splitting into separate loadable kernel modules for I2C and SPI, could you please clarify? I believe a single driver module better fits this hardware model.

Please, make two independent glue drivers. The common approach is error prone. See, for example, this:
https://stackoverflow.com/q/79462895/2511795 (read about kernel autoloading part).

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#17 lore raw

Le 21 août 2025 16 h 19 min 23 s HAE, Andy Shevchenko <[email protected]> a écrit :

Quoted 19 lines
Quoted 3 lines · Jean-François Lessard
Quoted 2 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:32 PM Jean-François Lessard <[email protected]> wrote:

...

Quoted 11 lines
Quoted 2 lines

This patch is ~1800 lines. Can you split it to a few based on main features (like the keyboard may be separated)? 2k is hard to review.

I agree that 1800 lines is a lot to review at once. For v4, I plan to split the submission into separate patches and source files for better reviewability and maintainability:
- tm16xx.h / tm16xx.c (core driver)
- tm16xx_keypad.c (keypad support)
- tm16xx_spi.c (SPI glue)
- tm16xx_i2c.c (I2C glue)

Quoted 5 lines
Quoted 2 lines

I believe this will improve clarity without fragmenting the driver nor its DT bindings.

Sounds good.

Excellent, I'll proceed with this structure for v4.

Quoted 16 lines

...

Quoted 14 lines
Quoted 4 lines
Quoted 2 lines

I dunno what these tags may mean in the current context...

These “Acked-by” tags follow kernel submission guidelines to record approval from key users.

Per Documentation/process/submitting-patches.rst:
Acked-by: may also be used by other stakeholders, such as people with domain knowledge (e.g. the original author of the code being modified), userspace-side reviewers for a kernel uAPI patch or key users of a feature. Optionally, in these cases, it can be useful to add a "# Suffix" to clarify its meaning::

Quoted 4 lines
Quoted 1 line

Ah, interesting. TIL.

Good to clarify - I'll keep these as they follow established process.

Quoted 50 lines

...

Quoted 32 lines
Quoted 24 lines

drivers/auxdisplay/tm16xx.c line 11

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
 
+#include <linux/bitops.h>

When bitmap,h is included, bitops.h is implied. But it's okay to include both.

drivers/auxdisplay/tm16xx.c line 19

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/leds.h>
+#include <linux/map_to_7segment.h>
+#include <linux/module.h>

Missing mod_devicetable.h for the ID table definitions.

drivers/auxdisplay/tm16xx.c line 21

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+#include <linux/of.h>
+#include <linux/of_device.h>

Cargo-cult? These two should be rarely used in a new code, for this driver I'm pretty sure they need not to be used at all.

Quoted 5 lines

drivers/auxdisplay/tm16xx.c line 26

Quoted 5 lines
drivers/auxdisplay/tm16xx.c new file +5 -0
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>

Thanks for pointing that out. For v4, I will revise includes to:

Quoted 4 lines

#include <linux/bitfield.h>
#include <linux/bitmap.h>

#include <linux/i2c.h>

Probably not this in the core file.

Quoted 8 lines

#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/leds.h>
#include <linux/map_to_7segment.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/spi/spi.h>

Quoted 4 lines

Nor this.

Quoted 1 line

#include <linux/workqueue.h>

Agreed. With the split structure, bus-specific headers will only be in their respective glue files. I will need to reintroduce #include <linux/of.h> in the SPI glue for of_match_ptr since it's not included via spi.h (unlike i2c.h).

Quoted 7 lines

...

Quoted 5 lines
Quoted 4 lines

drivers/auxdisplay/tm16xx.c line 29

Quoted 2 lines
drivers/auxdisplay/tm16xx.c new file +2 -0
+#define TM16XX_DRIVER_NAME "tm16xx"
+#define TM16XX_DEVICE_NAME "display"

Not sure why we need these two.

Quoted 9 lines
Quoted 5 lines

I will drop TM16XX_DEVICE_NAME since DT node name/label property should be used.

The TM16XX_DRIVER_NAME macro is standard practice for consistent string usage in registration and module macros.
If helpful, I can add a leading /* module name */ header comment.

Instead of an unneeded comment it seems better to use explicit string literal in all cases (two?).

I'm surprised by this preference since driver name macros are very common practice, but I'll use explicit string literals to align on this preference.

Quoted 37 lines

...

Quoted 11 lines
Quoted 5 lines

drivers/auxdisplay/tm16xx.c line 94

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM1650_CTRL_BR_MASK    GENMASK(6, 4)
+#define TM1650_CTRL_ON         BIT(0)
+#define TM1650_CTRL_SLEEP      BIT(2)

Are they really bits and not an enum in the datasheet?

These are respectively B0 and B2 according to the TM1650 datasheet:
- B0: Off screen display / Open screen display
- B1: fixed to 0
- B2: Normal operating mode / Standby mode
- B7-B4: brightness enum

I see, I would put a double names then

_OFF_OPEN // is it "open" or "on"? What's the difference? _RUN_STANDBY

(find better names)

...

Quoted 10 lines
Quoted 6 lines

drivers/auxdisplay/tm16xx.c line 97

Quoted 4 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM1650_CTRL_SEG_MASK   BIT(3)
 
+#define TM1650_CTRL_SEG8_MODE  0
+#define TM1650_CTRL_SEG7_MODE  BIT(3)

Same Q as per above case.

B3 controls 8 vs 7 segment mode. I will make it clearer:
#define TM1650_CTRL_SEG8_MODE (0 << 3)
#define TM1650_CTRL_SEG7_MODE (1 << 3)

Hmm... Here it's clear and both are probably needed in the code, but maybe it also makes sense to put similar for the above?

Quoted 7 lines

CTRL_OFF (0 << ...)
CTRL_OPEN
CTRL_RUN
CTRL_STANDBY

?

Yes, for consistency I'll use bit shifts for all field values while keeping *_MASK definitions using GENMASK/BIT to clearly describe bit positions. This makes both usage and pattern clear.

Quoted 9 lines

...

Quoted 7 lines
Quoted 6 lines

drivers/auxdisplay/tm16xx.c line 116

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+#define TM16XX_CTRL_BRIGHTNESS(enabled, value, prefix) \
+       ((enabled) ? (FIELD_PREP(prefix##_CTRL_BR_MASK, (value)) | \
+                     prefix##_CTRL_ON) : 0)

Okay, but can you split it logically, perhaps making it only one line (for the lines 2nd and 3rd)?

Quoted 9 lines
Quoted 4 lines

I currently format it as a multi-line macro respecting 80-column limit, with conditional ternary expression on separate lines for readability. If you prefer a different formatting style or logical grouping, please advise, as I want to keep it consistent with kernel coding style.

We have a relaxed format and I don't mind that people use it. But the main point here is readability / logical split. Also parameter names can be shortened a bit (like value --> val, enable --> en{a} / on.

Understood. I'll shorten parameter names and format it on a single line using the relaxed column length for better readability.

Quoted 13 lines

...

Quoted 10 lines
Quoted 5 lines

drivers/auxdisplay/tm16xx.c line 120

Quoted 3 lines
drivers/auxdisplay/tm16xx.c new file +3 -0
+static char *default_value;
+module_param(default_value, charp, 0444);
+MODULE_PARM_DESC(default_value, "Default display value to initialize");

Do we need this? Why?

This parameter was requested by community users to allow a boot message (e.g., “boot”) before user space takes control of the display value. I believe a module parameter is appropriate here to maintain separation between driver internals and user content, avoiding hardcoding display content in DT or code.

Quoted 9 lines

Currently we have a compile-time option and I don't think module parameter is what we need. If somebody wants it, please make it a separate patch with much better justification ("a user wants it" doesn't work). DT most likely is also not the best choice as it's about HW and not some policies.

TL;DR: please drop it for now (but if you wish something, use the compile time option we have in Kconfig for that).

Perfect suggestion! I'll drop the module parameter and replace it with a CONFIG_PANEL_BOOT_MESSAGE Kconfig option. This is a much cleaner approach than a module parameter.

Quoted 47 lines

...

Quoted 44 lines
Quoted 10 lines

drivers/auxdisplay/tm16xx.c line 404

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+static int tm16xx_keypad_probe(struct tm16xx_display *display)
+{
+       const u8 rows = display->controller->max_key_rows;
+       const u8 cols = display->controller->max_key_cols;
+       struct tm16xx_keypad *keypad;
+       struct input_dev *input;
+       unsigned int poll_interval, nbits;
+       int ret = 0;

I don't see how this assignment is used.

I will remove this unnecessary initialization.

Quoted 31 lines
Quoted 31 lines
drivers/auxdisplay/tm16xx.c new file +31 -0
+       if (!display->controller->keys || !rows || !cols) {
+               dev_dbg(display->dev, "keypad not supported\n");
+               return 0;
+       }
+
+       if (!device_property_present(display->dev, "poll-interval") ||
+           !device_property_present(display->dev, "linux,keymap")) {
+               dev_dbg(display->dev, "keypad disabled\n");
+               return 0;
+       }
+
+       dev_dbg(display->dev, "Configuring keypad\n");
+
+       ret = device_property_read_u32(display->dev, "poll-interval",
+                                      &poll_interval);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to read poll-interval: %d\n", ret);
+               return ret;
+       }
+
+       keypad = devm_kzalloc(display->dev, sizeof(*keypad), GFP_KERNEL);
+       if (!keypad)
+               return -ENOMEM;
+       keypad->display = display;
+
+       nbits = tm16xx_key_nbits(keypad);
+       keypad->state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->last_state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->changes = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       if (!keypad->state || !keypad->last_state || !keypad->changes) {
+               ret = -ENOMEM;
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line

+ goto free_keypad;

(Hit send too early that time...) This goto is bad. It means misunderstanding of the devm concept. See below.

I can assure I understand the devm paradigm. The keypad probe is optional, failure doesn't fail the main driver probe but only generates a warning. The cleanup code prevents memory from staying allocated until device removal in this specific optional failure case. However, if you insist, I'll remove the cleanup and let devm handle it normally.

Quoted 11 lines
Quoted 7 lines
Quoted 7 lines

drivers/auxdisplay/tm16xx.c line 443

Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +6 -0
+       }
+
+       input = devm_input_allocate_device(display->dev);
+       if (!input) {
 
+               dev_err(display->dev, "Failed to allocate input device\n");
+               ret = -ENOMEM;

No, we do not spill an error message on ENOMEM. This is an agreement in the kernel community for drivers.

Acknowledged, my fault. I'll ensure there are no ENOMEM error messages.

Quoted 26 lines
Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
drivers/auxdisplay/tm16xx.c new file +15 -0
+               goto free_bitmaps;
+       }
+       input->name = TM16XX_DRIVER_NAME "-keypad";
+       keypad->input = input;
+       input_set_drvdata(input, keypad);
+
+       keypad->row_shift = get_count_order(cols);
+       ret = matrix_keypad_build_keymap(NULL, "linux,keymap", rows, cols, NULL,
+                                        input);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to build keymap: %d\n", ret);
+               goto free_input;
+       }
+
+       if (device_property_read_bool(display->dev, "autorepeat"))
Quoted 8 lines
Quoted 8 lines

drivers/auxdisplay/tm16xx.c line 466

Quoted 8 lines
drivers/auxdisplay/tm16xx.c new file +8 -0
+               __set_bit(EV_REP, input->evbit);
+
+       input_setup_polling(input, tm16xx_keypad_poll);
+       input_set_poll_interval(input, poll_interval);
+       ret = input_register_device(input);
+       if (ret < 0) {
+               dev_err(display->dev, "Failed to register input device: %d\n",
+                       ret);

Use in all cases like this

Quoted 4 lines

return dev_err_probe(...);

pattern.

Thank you for pointing this out. I wasn't familiar with dev_err_probe(). I'll add this to my toolbox and use it consistently.

Quoted 26 lines
Quoted 11 lines
Quoted 10 lines
Quoted 10 lines
drivers/auxdisplay/tm16xx.c new file +9 -0
+               goto free_input;
+       }
+
+       dev_dbg(display->dev, "keypad rows=%u, cols=%u, poll=%u\n", rows, cols,
+               poll_interval);
+
+       return 0;
 
+free_input:
+       input_free_device(input);
Quoted 7 lines
Quoted 7 lines

drivers/auxdisplay/tm16xx.c line 483

Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +7 -0
+free_bitmaps:
+       devm_kfree(display->dev, keypad->state);
+       devm_kfree(display->dev, keypad->last_state);
+       devm_kfree(display->dev, keypad->changes);
+free_keypad:
+       devm_kfree(display->dev, keypad);
+       return ret;

No way. We don't do that, If required it signals about exceptional case (0.01% probability) or misunderstanding of devm:
- managed resources are managed by core, no need to call for free
- using managed resources in the contexts when object lifetime is short is incorrect, needs to be switched to the plain alloc (nowadays with __free() from cleanup.h to have RAII enabled)

Quoted 2 lines

Choose one of these and fix the code accordingly.

Same as above.

Quoted 26 lines
Quoted 2 lines

+}

...

Quoted 14 lines
Quoted 7 lines

I stopped here, I believe it's enough for now (and I would wait for the smaller changes per patch, perhaps 2 DT bindings patch + common part (basic functionality) + spi driver + i2c driver + keyboard, something like 6+ patches).
Also, split i2c and spi glue drivers to a separate modules, so you will have 3 files:

Quoted 6 lines

$main
$main_i2c
$main_spi

Look at ton of examples under drivers/iio/

Quoted 6 lines

I plan to split source files for review but maintain a single unified kernel module that handles both I2C and SPI buses. This avoids confusion and unnecessary duplication since the hardware and DT bindings are shared. If you intended splitting into separate loadable kernel modules for I2C and SPI, could you please clarify? I believe a single driver module better fits this hardware model.

Quoted 5 lines

Please, make two independent glue drivers. The common approach is error prone. See, for example, this:
https://stackoverflow.com/q/79462895/2511795 (read about kernel autoloading part).

Thanks for clarifying and providing the link. I understand now. I'll split into separate modules (tm16xx_i2c.ko, tm16xx_spi.ko) with shared core following IIO-style practice to ensure reliable kernel autoloading and proper module aliasing.

Best regards,
Jean-François Lessard

#18 lore raw
Quoted 6 lines · Jean-François Lessard
Quoted 5 lines · Andy Shevchenko
Quoted 3 lines · Jean-François Lessard
Quoted 2 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:32 PM Jean-François Lessard <[email protected]> wrote:

...

Quoted 11 lines
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line

+#define TM16XX_DRIVER_NAME "tm16xx"

The TM16XX_DRIVER_NAME macro is standard practice for consistent string usage in registration and module macros.
If helpful, I can add a leading /* module name */ header comment.

Instead of an unneeded comment it seems better to use explicit string literal in all cases (two?).

I'm surprised by this preference since driver name macros are very common practice, but I'll use explicit string literals to align on this preference.

Usually we put a macro to something which (theoretically) might change. The driver name is part of an ABI and I prefer it to be explicit as we do not break an ABI. Once introduced it can't be modified or removed. Also it's better to see clearly exactly at the place in use in the code the name as it's easier to (git) grep for something similar. With a macro I would need to grep at least twice to see the users.

...

Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +6 -0
+       keypad->state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->last_state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->changes = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       if (!keypad->state || !keypad->last_state || !keypad->changes) {
+               ret = -ENOMEM;
 
+               goto free_keypad;
Quoted 8 lines
Quoted 2 lines

(Hit send too early that time...) This goto is bad. It means misunderstanding of the devm concept. See below.

I can assure I understand the devm paradigm. The keypad probe is optional, failure doesn't fail the main driver probe but only generates a warning. The cleanup code prevents memory from staying allocated until device removal in this specific optional failure case. However, if you insist, I'll remove the cleanup and let devm handle it normally.

Assume you have a separate feature, let's say keypad driver for some complex HW, like this one, and you have even a separate (library) driver for it. Then you want to introduce some kind of library functions to probe and remove the only keypad part, here are two options:
- follow the library pattern with plain (non-devm) k*alloc() in probe and kfree in remove
- use driver pattern with devm

If you choose the second one, it will be weird to call devm_kfree(). The rule of thumb the devm_$FREE_MY_RESOURSE() *must* be *well* justified. Because it's exceptional. Losing 1kb memory or so is not enough to justify.

Quoted 22 lines
Quoted 19 lines
Quoted 11 lines
Quoted 11 lines

drivers/auxdisplay/tm16xx.c line 483

Quoted 11 lines
drivers/auxdisplay/tm16xx.c new file +10 -0
+       }
+
+       input = devm_input_allocate_device(display->dev);
 
+free_bitmaps:
+       devm_kfree(display->dev, keypad->state);
+       devm_kfree(display->dev, keypad->last_state);
+       devm_kfree(display->dev, keypad->changes);
+free_keypad:
+       devm_kfree(display->dev, keypad);
+       return ret;

No way. We don't do that, If required it signals about exceptional case (0.01% probability) or misunderstanding of devm:
- managed resources are managed by core, no need to call for free
- using managed resources in the contexts when object lifetime is short is incorrect, needs to be switched to the plain alloc (nowadays with __free() from cleanup.h to have RAII enabled)

Quoted 1 line

Choose one of these and fix the code accordingly.

Same as above.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#19 lore raw

Le 22 août 2025 02 h 08 min 42 s HAE, Andy Shevchenko <[email protected]> a écrit :

Quoted 23 lines
Quoted 6 lines · Jean-François Lessard
Quoted 5 lines · Andy Shevchenko
Quoted 3 lines · Jean-François Lessard
Quoted 2 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:32 PM Jean-François Lessard <[email protected]> wrote:

...

Quoted 11 lines
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line

+#define TM16XX_DRIVER_NAME "tm16xx"

The TM16XX_DRIVER_NAME macro is standard practice for consistent string usage in registration and module macros.
If helpful, I can add a leading /* module name */ header comment.

Instead of an unneeded comment it seems better to use explicit string literal in all cases (two?).

I'm surprised by this preference since driver name macros are very common practice, but I'll use explicit string literals to align on this preference.

Quoted 8 lines

Usually we put a macro to something which (theoretically) might change. The driver name is part of an ABI and I prefer it to be explicit as we do not break an ABI. Once introduced it can't be modified or removed. Also it's better to see clearly exactly at the place in use in the code the name as it's easier to (git) grep for something similar. With a macro I would need to grep at least twice to see the users.

Well received. I'll use explicit string literals.

Quoted 28 lines

...

Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
drivers/auxdisplay/tm16xx.c new file +6 -0
+       keypad->state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->last_state = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       keypad->changes = devm_bitmap_zalloc(display->dev, nbits, GFP_KERNEL);
+       if (!keypad->state || !keypad->last_state || !keypad->changes) {
+               ret = -ENOMEM;
 
+               goto free_keypad;
Quoted 8 lines
Quoted 2 lines

(Hit send too early that time...) This goto is bad. It means misunderstanding of the devm concept. See below.

I can assure I understand the devm paradigm. The keypad probe is optional, failure doesn't fail the main driver probe but only generates a warning. The cleanup code prevents memory from staying allocated until device removal in this specific optional failure case. However, if you insist, I'll remove the cleanup and let devm handle it normally.

Assume you have a separate feature, let's say keypad driver for some complex HW, like this one, and you have even a separate (library) driver for it. Then you want to introduce some kind of library functions to probe and remove the only keypad part, here are two options:
- follow the library pattern with plain (non-devm) k*alloc() in probe and kfree in remove
- use driver pattern with devm

Quoted 5 lines

If you choose the second one, it will be weird to call devm_kfree(). The rule of thumb the devm_$FREE_MY_RESOURSE() *must* be *well* justified. Because it's exceptional. Losing 1kb memory or so is not enough to justify.

Understood. I'll remove the cleanup gotos for this scenario given that devm is generally preferred and that losing 1kb memory or so is not enough to justify.

Quoted 23 lines
Quoted 22 lines
Quoted 19 lines
Quoted 11 lines
Quoted 11 lines

drivers/auxdisplay/tm16xx.c line 483

Quoted 11 lines
drivers/auxdisplay/tm16xx.c new file +10 -0
+       }
+
+       input = devm_input_allocate_device(display->dev);
 
+free_bitmaps:
+       devm_kfree(display->dev, keypad->state);
+       devm_kfree(display->dev, keypad->last_state);
+       devm_kfree(display->dev, keypad->changes);
+free_keypad:
+       devm_kfree(display->dev, keypad);
+       return ret;

No way. We don't do that, If required it signals about exceptional case (0.01% probability) or misunderstanding of devm:
- managed resources are managed by core, no need to call for free
- using managed resources in the contexts when object lifetime is short is incorrect, needs to be switched to the plain alloc (nowadays with __free() from cleanup.h to have RAII enabled)

Quoted 1 line

Choose one of these and fix the code accordingly.

Same as above.

...

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

I stopped here, I believe it's enough for now (and I would wait for the smaller changes per patch, perhaps 2 DT bindings patch + common part (basic functionality) + spi driver + i2c driver + keyboard, something like 6+ patches).

I know it's a lot to review ~1800 lines at once and that the split into multiple files will require a review anyway, but feel free to share additional feedback on any other obvious issues you may observe, so I can fix these for v4.

Thanks again for your time and thorough feedback,
Jean-François Lessard

#20 lore raw
In reply to Jean-François Lessard
kernel test robot noticed the following build errors:

Hi Jean-François,

kernel test robot noticed the following build errors:

[auto build test ERROR on robh/for-next]
[also build test ERROR on linus/master v6.17-rc3 next-20250826] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Jean-Fran-ois-Lessard/dt-bindings-vendor-prefixes-Add-fdhisi-titanmec-princeton-winrise-wxicore/20250821-003451
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20250820163120.24997-4-jefflessard3%40gmail.com
patch subject: [PATCH v3 3/4] auxdisplay: Add TM16xx 7-segment LED matrix display controllers driver
config: x86_64-randconfig-r112-20250827 (https://download.01.org/0day-ci/archive/20250827/[email protected]/config)
compiler: gcc-12 (Debian 12.2.0-14+deb12u1) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250827/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

ld: vmlinux.o: in function `tm16xx_i2c_write':

>> drivers/auxdisplay/tm16xx.c:1469: undefined reference to `i2c_transfer'
   ld: vmlinux.o: in function `tm16xx_i2c_read':
   drivers/auxdisplay/tm16xx.c:1497: undefined reference to `i2c_transfer'
   ld: vmlinux.o: in function `tm16xx_i2c_probe':
>> drivers/auxdisplay/tm16xx.c:1416: undefined reference to `i2c_get_match_data'
   ld: vmlinux.o: in function `tm16xx_i2c_register':
>> drivers/auxdisplay/tm16xx.c:1727: undefined reference to `i2c_register_driver'
   ld: vmlinux.o: in function `tm16xx_i2c_unregister':
>> drivers/auxdisplay/tm16xx.c:1732: undefined reference to `i2c_del_driver'

vim +1469 drivers/auxdisplay/tm16xx.c

1401
1402 /* I2C specific code */
1403 #if IS_ENABLED(CONFIG_I2C)
1404 /**
1405 * tm16xx_i2c_probe() - Probe callback for I2C-attached controllers
1406 * @client: pointer to i2c_client
1407 *
1408 * Return: 0 on success, negative error code on failure
1409 */
1410 static int tm16xx_i2c_probe(struct i2c_client *client)
1411 {
1412 const struct tm16xx_controller *controller;
1413 struct tm16xx_display *display;
1414 int ret;
1415

> 1416		controller = i2c_get_match_data(client);
  1417		if (!controller)
  1418			return -EINVAL;
  1419	
  1420		display = devm_kzalloc(&client->dev, sizeof(*display), GFP_KERNEL);
  1421		if (!display)
  1422			return -ENOMEM;
  1423	
  1424		display->client.i2c = client;
  1425		display->dev = &client->dev;
  1426		display->controller = controller;
  1427	
  1428		i2c_set_clientdata(client, display);
  1429	
  1430		ret = tm16xx_probe(display);
  1431		if (ret)
  1432			return ret;
  1433	
  1434		return 0;
  1435	}
  1436	
  1437	/**
  1438	 * tm16xx_i2c_remove() - Remove callback for I2C-attached controllers
  1439	 * @client: pointer to i2c_client
  1440	 */
  1441	static void tm16xx_i2c_remove(struct i2c_client *client)
  1442	{
  1443		struct tm16xx_display *display = i2c_get_clientdata(client);
  1444	
  1445		tm16xx_display_remove(display);
  1446	}
  1447	
  1448	/**
  1449	 * tm16xx_i2c_write() - I2C write helper for controller
  1450	 * @display: pointer to tm16xx_display structure
  1451	 * @data: command and data bytes to send
  1452	 * @len: number of bytes in @data
  1453	 *
  1454	 * Return: 0 on success, negative error code on failure
  1455	 */
  1456	static int tm16xx_i2c_write(struct tm16xx_display *display, u8 *data, size_t len)
  1457	{
  1458		dev_dbg(display->dev, "i2c_write %*ph", (char)len, data);
  1459	
  1460		/* expected sequence: S Command [A] Data [A] P */
  1461		struct i2c_msg msg = {
  1462			.addr = data[0] >> 1,
  1463			.flags = 0,
  1464			.len = len - 1,
  1465			.buf = &data[1],
  1466		};
  1467		int ret;
  1468	
> 1469		ret = i2c_transfer(display->client.i2c->adapter, &msg, 1);

1470 if (ret < 0)
1471 return ret;
1472
1473 return (ret == 1) ? 0 : -EIO;
1474 }
1475

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#21 lore raw

PATCH v3 4/4 MAINTAINERS: Add entry for TM16xx driver

In reply to Jean-François Lessard
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)
MAINTAINERS +6 -0
index daf520a13..55afed22f 100644
@@ -25402,6 +25402,12 @@ W:	http://sourceforge.net/projects/tlan/
 F:	Documentation/networking/device_drivers/ethernet/ti/tlan.rst
 F:	drivers/net/ethernet/ti/tlan.*
 
+TM16XX-COMPATIBLE LED CONTROLLERS DISPLAY DRIVER
+M:	Jean-François Lessard <[email protected]>
+S:	Maintained
+F:	Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml
+F:	drivers/auxdisplay/tm16xx.c
+
 TMIO/SDHI MMC DRIVER
 M:	Wolfram Sang <[email protected]>
 L:	[email protected]
Signature · 1 line
2.43.0
#22 lore raw

Re: [PATCH v3 4/4] MAINTAINERS: Add entry for TM16xx driver

On Wed, Aug 20, 2025 at 7:31 PM Jean-François Lessard <[email protected]> wrote:

Besides the missing commit message, the main part of this patch should be merged with the patch 2 where the YAML file is being added. Otherwise it will be a dangling file. I dunno if DT tooling has its own concept of a maintainer database, though.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#23 lore raw

Re: [PATCH v3 4/4] MAINTAINERS: Add entry for TM16xx driver

Quoted 7 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:31 PM Jean-François Lessard <[email protected]> wrote:

Besides the missing commit message, the main part of this patch should be merged with the patch 2 where the YAML file is being added. Otherwise it will be a dangling file. I dunno if DT tooling has its own concept of a maintainer database, though.

get_maintainer.pl will pull the maintainer out of the file, so it won't be truly dangling without a way to associate Jean-François with this file, if that;s what you mean.

#24 lore raw

Re: [PATCH v3 4/4] MAINTAINERS: Add entry for TM16xx driver

Quoted 5 lines · Conor Dooley
Quoted 3 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:31 PM Jean-François Lessard <[email protected]> wrote:

Quoted 8 lines
Quoted 4 lines

Besides the missing commit message, the main part of this patch should be merged with the patch 2 where the YAML file is being added. Otherwise it will be a dangling file. I dunno if DT tooling has its own concept of a maintainer database, though.

get_maintainer.pl will pull the maintainer out of the file, so it won't be truly dangling without a way to associate Jean-François with this file, if that;s what you mean.

Let's assume patch 2 is applied and patch 4 is not, what will be the result of get_maintainer.pl for the YAML file?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#25 lore raw

Re: [PATCH v3 4/4] MAINTAINERS: Add entry for TM16xx driver

Quoted 11 lines · Andy Shevchenko
Quoted 10 lines · Conor Dooley
Quoted 7 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:31 PM Jean-François Lessard <[email protected]> wrote:

Besides the missing commit message, the main part of this patch should be merged with the patch 2 where the YAML file is being added. Otherwise it will be a dangling file. I dunno if DT tooling has its own concept of a maintainer database, though.

Quoted 6 lines
Quoted 3 lines

get_maintainer.pl will pull the maintainer out of the file, so it won't be truly dangling without a way to associate Jean-François with this file, if that;s what you mean.

Let's assume patch 2 is applied and patch 4 is not, what will be the result of get_maintainer.pl for the YAML file?

Andy Shevchenko <[email protected]> (maintainer:AUXILIARY DISPLAY DRIVERS)
Geert Uytterhoeven <[email protected]> (reviewer:AUXILIARY DISPLAY DRIVERS)
Rob Herring <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Krzysztof Kozlowski <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) Conor Dooley <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) "Jean-François Lessard" <[email protected]> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:471/471=100%,in file)

                                                                                                                    ^^^^^^^

[email protected] (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) [email protected] (open list)
AUXILIARY DISPLAY DRIVERS status: Odd Fixes

#26 lore raw

Re: [PATCH v3 4/4] MAINTAINERS: Add entry for TM16xx driver

Quoted 18 lines · Conor Dooley
Quoted 10 lines · Andy Shevchenko
Quoted 9 lines · Conor Dooley
Quoted 7 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:31 PM Jean-François Lessard <[email protected]> wrote:

Besides the missing commit message, the main part of this patch should be merged with the patch 2 where the YAML file is being added. Otherwise it will be a dangling file. I dunno if DT tooling has its own concept of a maintainer database, though.

Quoted 6 lines
Quoted 3 lines

get_maintainer.pl will pull the maintainer out of the file, so it won't be truly dangling without a way to associate Jean-François with this file, if that;s what you mean.

Let's assume patch 2 is applied and patch 4 is not, what will be the result of get_maintainer.pl for the YAML file?

Quoted 7 lines

Andy Shevchenko <[email protected]> (maintainer:AUXILIARY DISPLAY DRIVERS)
Geert Uytterhoeven <[email protected]> (reviewer:AUXILIARY DISPLAY DRIVERS)
Rob Herring <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Krzysztof Kozlowski <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) Conor Dooley <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) "Jean-François Lessard" <[email protected]> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:471/471=100%,in file)

                                                                                                                    ^^^^^^^

Which is a git lookup heuristics. If you disable that, there is no maintainer for the file. Try with --m and --no-git (IIRC the option name).

Quoted 3 lines

[email protected] (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) [email protected] (open list)
AUXILIARY DISPLAY DRIVERS status: Odd Fixes

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#27 lore raw

Re: [PATCH v3 4/4] MAINTAINERS: Add entry for TM16xx driver

Quoted 27 lines · Andy Shevchenko
Quoted 18 lines · Conor Dooley
Quoted 10 lines · Andy Shevchenko
Quoted 9 lines · Conor Dooley
Quoted 7 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:31 PM Jean-François Lessard <[email protected]> wrote:

Besides the missing commit message, the main part of this patch should be merged with the patch 2 where the YAML file is being added. Otherwise it will be a dangling file. I dunno if DT tooling has its own concept of a maintainer database, though.

Quoted 6 lines
Quoted 3 lines

get_maintainer.pl will pull the maintainer out of the file, so it won't be truly dangling without a way to associate Jean-François with this file, if that;s what you mean.

Let's assume patch 2 is applied and patch 4 is not, what will be the result of get_maintainer.pl for the YAML file?

Quoted 7 lines

Andy Shevchenko <[email protected]> (maintainer:AUXILIARY DISPLAY DRIVERS)
Geert Uytterhoeven <[email protected]> (reviewer:AUXILIARY DISPLAY DRIVERS)
Rob Herring <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Krzysztof Kozlowski <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) Conor Dooley <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) "Jean-François Lessard" <[email protected]> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:471/471=100%,in file)

                                                                                                                    ^^^^^^^
Quoted 3 lines

Which is a git lookup heuristics. If you disable that, there is no maintainer for the file. Try with --m and --no-git (IIRC the option name).

Actually doesn't checkpatch complain in this case?

Quoted 3 lines
Quoted 3 lines

[email protected] (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) [email protected] (open list)
AUXILIARY DISPLAY DRIVERS status: Odd Fixes

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#28 lore raw

Re: [PATCH v3 4/4] MAINTAINERS: Add entry for TM16xx driver

Quoted 29 lines · Andy Shevchenko
Quoted 27 lines · Andy Shevchenko
Quoted 25 lines · Conor Dooley
Quoted 10 lines · Andy Shevchenko
Quoted 9 lines · Conor Dooley
Quoted 7 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:31 PM Jean-François Lessard <[email protected]> wrote:

Besides the missing commit message, the main part of this patch should be merged with the patch 2 where the YAML file is being added. Otherwise it will be a dangling file. I dunno if DT tooling has its own concept of a maintainer database, though.

Quoted 6 lines
Quoted 3 lines

get_maintainer.pl will pull the maintainer out of the file, so it won't be truly dangling without a way to associate Jean-François with this file, if that;s what you mean.

Let's assume patch 2 is applied and patch 4 is not, what will be the result of get_maintainer.pl for the YAML file?

Andy Shevchenko <[email protected]> (maintainer:AUXILIARY DISPLAY DRIVERS)
Geert Uytterhoeven <[email protected]> (reviewer:AUXILIARY DISPLAY DRIVERS)
Rob Herring <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Krzysztof Kozlowski <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) Conor Dooley <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) "Jean-François Lessard" <[email protected]> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:471/471=100%,in file)

                                                                                                                    ^^^^^^^
Quoted 3 lines
Quoted 3 lines

Which is a git lookup heuristics. If you disable that, there is no maintainer for the file. Try with --m and --no-git (IIRC the option name).

Also, I think linewrap might done some fuckery cos it was the
"in file" I was pointing to, pretty sure that's not coming from git.
I tried ./scripts/get_maintainer.pl --nogit --nogit-fallback -f Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml (I think --nogit-fallback is the salient option, --nogit is a default
actually) and I got:
Andy Shevchenko <[email protected]> (maintainer:AUXILIARY DISPLAY DRIVERS)
Geert Uytterhoeven <[email protected]> (reviewer:AUXILIARY DISPLAY DRIVERS)
Rob Herring <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Krzysztof Kozlowski <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Conor Dooley <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) "Jean-François Lessard" <[email protected]> (in file)

                                                  ^^^^^^^

and the in file still appears.
[email protected] (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) [email protected] (open list)
AUXILIARY DISPLAY DRIVERS status: Odd Fixes

Quoted 1 line

Actually doesn't checkpatch complain in this case?

The usual warning about MAINTAINERS appears ye, the one that appears whenever a file is moved, created or deleted. I personally don't care about that, as long as the end result of a series deals with it since the file will produce the correct maintainer list in a bisection etc anyway. Of course, your subsystem your prerogative.

#29 lore raw

Re: [PATCH v3 4/4] MAINTAINERS: Add entry for TM16xx driver

Quoted 45 lines · Conor Dooley
Quoted 29 lines · Andy Shevchenko
Quoted 27 lines · Andy Shevchenko
Quoted 25 lines · Conor Dooley
Quoted 10 lines · Andy Shevchenko
Quoted 9 lines · Conor Dooley
Quoted 7 lines · Andy Shevchenko

On Wed, Aug 20, 2025 at 7:31 PM Jean-François Lessard <[email protected]> wrote:

Besides the missing commit message, the main part of this patch should be merged with the patch 2 where the YAML file is being added. Otherwise it will be a dangling file. I dunno if DT tooling has its own concept of a maintainer database, though.

Quoted 6 lines
Quoted 3 lines

get_maintainer.pl will pull the maintainer out of the file, so it won't be truly dangling without a way to associate Jean-François with this file, if that;s what you mean.

Let's assume patch 2 is applied and patch 4 is not, what will be the result of get_maintainer.pl for the YAML file?

Andy Shevchenko <[email protected]> (maintainer:AUXILIARY DISPLAY DRIVERS)
Geert Uytterhoeven <[email protected]> (reviewer:AUXILIARY DISPLAY DRIVERS)
Rob Herring <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Krzysztof Kozlowski <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) Conor Dooley <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) "Jean-François Lessard" <[email protected]> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:471/471=100%,in file)

                                                                                                                    ^^^^^^^
Quoted 3 lines
Quoted 3 lines

Which is a git lookup heuristics. If you disable that, there is no maintainer for the file. Try with --m and --no-git (IIRC the option name).

Also, I think linewrap might done some fuckery cos it was the
"in file" I was pointing to, pretty sure that's not coming from git.
I tried ./scripts/get_maintainer.pl --nogit --nogit-fallback -f Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml (I think --nogit-fallback is the salient option, --nogit is a default
actually) and I got:
Andy Shevchenko <[email protected]> (maintainer:AUXILIARY DISPLAY DRIVERS)
Geert Uytterhoeven <[email protected]> (reviewer:AUXILIARY DISPLAY DRIVERS)
Rob Herring <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Krzysztof Kozlowski <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Conor Dooley <[email protected]> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) "Jean-François Lessard" <[email protected]> (in file)

Quoted 2 lines
                                                  ^^^^^^^

and the in file still appears.

Cool, thanks for providing this, TIL! Is this documented somewhere? I mean how should I know that YAML files are not orphaned by default (assuming they are correct and have a "maintainer" field inside)?

Quoted 11 lines

[email protected] (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) [email protected] (open list)
AUXILIARY DISPLAY DRIVERS status: Odd Fixes

Quoted 1 line

Actually doesn't checkpatch complain in this case?

The usual warning about MAINTAINERS appears ye, the one that appears whenever a file is moved, created or deleted. I personally don't care about that, as long as the end result of a series deals with it since the file will produce the correct maintainer list in a bisection etc anyway. Of course, your subsystem your prerogative.

Shouldn't checkpatch also be fixed at least for that part as get_maintainer does?

Signature · 2 lines
With Best Regards,
Andy Shevchenko