auxdisplay: Add TM16xx 7-segment LED matrix display controllers driver
Subsystems (3)
v4 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
v4:
- Split MAINTAINERS patch into each specific patch
- Document ABI of sysfs driver attributes
- Remove kernel-doc of obvious Linux core driver model APIs
- dt-bindings: Drop obvious comments that schema tells by itself
- dt-bindings: Gather canonical compatible strings in a single enum
- dt-bindings: Clarify top-level logical led DT node name/label property
- dt:bindings: Replace refs to input properties with allOf
- Split driver patch and code file for better reviewability
- Refactor into separate i2c and spi glue driver modules
- Drop driver name macro constant in favor of explicit string literals
- Revise to use bit shifts for values and GENMASK/BIT for bit positions
- Format TM16XX_CTRL_BRIGHTNESS on one line
- Drop default_value module param in favor of Kconfig compile time option
- Fix for_each_key name and expressions
- Replace manual mutex locking with scoped_guard
- Move scancode declaration to avoid mix with code
- Remove unnecessary ret initialization
- Remove ENOMEM error message
- Replace probe error messages by dev_err_probe
- Remove keypad failed probe cleanup to avoid devm anti-pattern confusion
- Switch to non-devm led registration to avoid anti-pattern confusion
- Replace u16 in favor of unsigned int for controller data
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 80-column wrapping
* Replace digit-specific properties with clearer digits container node
* Add required constraints for properties in container nodes
* Clarify addressing schemes for LED icons and digits
* Fix conditional SPI properties handling
* Document rationale for spi-3wire property
* Expand DT examples to cover typical and transposed display layouts
- Code reformat from clang-format to kernel style per maintainer feedback
- Fix conditional CONFIG_I2C/_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
v2:
- Fix duplicate label in dt-bindings examples
- Rename device tree property prefixes to use titanmec vendor prefix
Jean-François Lessard (6):
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
auxdisplay: TM16xx: Add keypad support for scanning matrix keys
auxdisplay: TM16xx: Add support for I2C-based controllers
auxdisplay: TM16xx: Add support for SPI-based controllers
.../ABI/testing/sysfs-class-leds-tm16xx | 57 ++ .../bindings/auxdisplay/titanmec,tm16xx.yaml | 477 ++++++++++++++ .../devicetree/bindings/vendor-prefixes.yaml | 10 + MAINTAINERS | 11 + drivers/auxdisplay/Kconfig | 43 +- drivers/auxdisplay/Makefile | 5 + drivers/auxdisplay/tm16xx.h | 204 ++++++ drivers/auxdisplay/tm16xx_core.c | 622 ++++++++++++++++++ drivers/auxdisplay/tm16xx_i2c.c | 332 ++++++++++ drivers/auxdisplay/tm16xx_keypad.c | 208 ++++++ drivers/auxdisplay/tm16xx_spi.c | 398 +++++++++++ 11 files changed, 2366 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-class-leds-tm16xx create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml create mode 100644 drivers/auxdisplay/tm16xx.h create mode 100644 drivers/auxdisplay/tm16xx_core.c create mode 100644 drivers/auxdisplay/tm16xx_i2c.c create mode 100644 drivers/auxdisplay/tm16xx_keypad.c create mode 100644 drivers/auxdisplay/tm16xx_spi.c
Signature · 1 line
2.43.0
PATCH v4 1/6 dt-bindings: vendor-prefixes: Add fdhisi, titanmec, princeton, winrise, wxicore
Add vendor prefixes of chip manufacturers supported by the TM16xx 7-segment LED matrix display controllers driver:
- 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
@@ -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
Re: [PATCH v4 1/6] dt-bindings: vendor-prefixes: Add fdhisi, titanmec, princeton, winrise, wxicore
Quoted 15 lines · Jean-François Lessard
Add vendor prefixes of chip manufacturers supported by the TM16xx 7-segment LED matrix display controllers driver:
- 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.
...
Quoted 1 line
CC Andreas Färber <[email protected]>
Not a big issue in _this_ case, but I would suggest to keep the Cc: list after the '---' line. This will have same effect except being removed from the commit messages where it would be an unneeded noise. The actual list will be available via lore archive in emails.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v4 1/6] dt-bindings: vendor-prefixes: Add fdhisi, titanmec, princeton, winrise, wxicore
Le 25 août 2025 09 h 53 min 38 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 17 lines · Jean-François Lessard
Quoted 8 lines
Add vendor prefixes of chip manufacturers supported by the TM16xx 7-segment LED matrix display controllers driver:
- 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.Quoted 7 lines
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.
Quoted 9 lines
...
Quoted 1 line
CC Andreas Färber <[email protected]>Not a big issue in _this_ case, but I would suggest to keep the Cc: list after the '---' line. This will have same effect except being removed from the commit messages where it would be an unneeded noise. The actual list will be available via lore archive in emails.
Acknowledged. Will move to the notes section on the next submission.
PATCH v4 2/6 dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx
In reply to Jean-François LessardAdd documentation for TM16xx-compatible 7-segment LED display controllers with keyscan.
---
Notes:
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 | 477 ++++++++++++++++++ MAINTAINERS | 5 + 2 files changed, 482 insertions(+) create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +477 -0
@@ -0,0 +1,477 @@ +# 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 + + The controller node exposes a logical LED-like control for the aggregate + display brightness. Child nodes describe individual icons and 7-seg digits. + The top-level control supports only label and brightness-related properties + and does not support other common LED properties such as color or function. + Child LED nodes use the standard LED binding. + + Optional keypad scanning is supported when both 'linux,keymap' and + 'poll-interval' properties are specified. + +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: + - fdhisi,fd620 + - fdhisi,fd655 + - fdhisi,fd6551 + - titanmec,tm1618 + - titanmec,tm1620 + - titanmec,tm1628 + - titanmec,tm1638 + - titanmec,tm1650 + - winrise,hbs658 + + reg: + maxItems: 1 + + label: + description: + The label for the top-level LED. If omitted, the label is taken from the + node name (excluding the unit address). It has to uniquely identify a + device, i.e. no other LED class device can be assigned the same label. + $ref: /schemas/leds/common.yaml#/properties/label + + 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/leds/common.yaml#/properties/max-brightness + + 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 + + digits: + type: object + description: Container for 7-segment digit group definitions + additionalProperties: false + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + patternProperties: + "^digit@[0-9]+$": + type: object + unevaluatedProperties: false + + 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 + + leds: + type: object + description: Container for individual LED icon definitions + additionalProperties: false + + properties: + "#address-cells": + const: 2 + "#size-cells": + const: 0 + + patternProperties: + "^led@[0-9]+,[0-9]+$": + type: object + $ref: /schemas/leds/common.yaml# + unevaluatedProperties: false + + properties: + reg: + description: + Grid and segment indices as <grid segment> of this individual LED icon + + required: + - reg + +allOf: + - $ref: /schemas/input/input.yaml# + - $ref: /schemas/input/matrix-keymap.yaml# + +dependencies: + poll-interval: + - linux,keymap + linux,keymap: + - poll-interval + autorepeat: + - linux,keymap + - poll-interval + +# 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 + +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@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@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@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"; + }; + }; + }; + };
MAINTAINERS +5 -0
@@ -25402,6 +25402,11 @@ 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 + TMIO/SDHI MMC DRIVER M: Wolfram Sang <[email protected]> L: [email protected]
Signature · 1 line
2.43.0
Rob Herring
maintainerRe: [PATCH v4 2/6] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx
Quoted 99 lines · Jean-François Lessard
Add documentation for TM16xx-compatible 7-segment LED display controllers with keyscan.
Signed-off-by Jean-François Lessard <[email protected]>---
Notes:
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 | 477 ++++++++++++++++++ MAINTAINERS | 5 + 2 files changed, 482 insertions(+) create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yamlDocumentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +73
-0@@ -0,0 +1,477 @@ +# 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 + + The controller node exposes a logical LED-like control for the aggregate + display brightness. Child nodes describe individual icons and 7-seg digits. + The top-level control supports only label and brightness-related properties + and does not support other common LED properties such as color or function. + Child LED nodes use the standard LED binding. + + Optional keypad scanning is supported when both 'linux,keymap' and + 'poll-interval' properties are specified. + +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: + - fdhisi,fd620 + - fdhisi,fd655 + - fdhisi,fd6551 + - titanmec,tm1618 + - titanmec,tm1620 + - titanmec,tm1628 + - titanmec,tm1638 + - titanmec,tm1650 + - winrise,hbs658 + + reg: + maxItems: 1 + + label: + description: + The label for the top-level LED. If omitted, the label is taken from the + node name (excluding the unit address). It has to uniquely identify a + device, i.e. no other LED class device can be assigned the same label.
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 83
Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10
-0+ $ref: /schemas/leds/common.yaml#/properties/label + + 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/leds/common.yaml#/properties/max-brightness
These 2 $ref's should be at the node level. The clue is you copied-n-pasted the whole description.
What you need here is some constraints. What's the max value?
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 89
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6
-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
This needs to first go into leds/common.yaml.
Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10
-0+ + digits: + type: object + description: Container for 7-segment digit group definitions + additionalProperties: false + + properties: + "#address-cells": + const: 1 + "#size-cells":
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 109
Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10
-0+ const: 0 + + patternProperties: + "^digit@[0-9]+$": + type: object + unevaluatedProperties: false + + properties: + reg: + description: Digit position identifier
Position is right to left (0 on right)? Please clarify.
Quoted 11 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +11
-0+ 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
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 130
Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10
-0+ f b + f b + ggg + e c + e c + ddd + items: + items: + - description: Grid index + - description: Segment index
Can't you do an array instead and make the array index be the grid or segment index?
Quoted 37 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +37
-0+ minItems: 7 + maxItems: 7 + + required: + - reg + - segments + + leds: + type: object + description: Container for individual LED icon definitions + additionalProperties: false + + properties: + "#address-cells": + const: 2 + "#size-cells": + const: 0 + + patternProperties: + "^led@[0-9]+,[0-9]+$": + type: object + $ref: /schemas/leds/common.yaml# + unevaluatedProperties: false + + properties: + reg: + description: + Grid and segment indices as <grid segment> of this individual LED icon + + required: + - reg + +allOf: + - $ref: /schemas/input/input.yaml# + - $ref: /schemas/input/matrix-keymap.yaml# + +dependencies:
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 177
Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10
-0+ poll-interval: + - linux,keymap + linux,keymap: + - poll-interval + autorepeat: + - linux,keymap + - poll-interval + +# SPI controllers require 3-wire (combined MISO/MOSI line) +if:
Move this under the allOf.
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ properties: + compatible: + contains: + enum: + - fdhisi,fd620
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 192
Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10
-0+ - fdhisi,fd628 + - princeton,pt6964 + - titanmec,tm1618 + - titanmec,tm1620 + - titanmec,tm1628 + - titanmec,tm1638 + - wxicore,aip1618 + - wxicore,aip1628 +then: + allOf:
Drop allOf.
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 195
Quoted 3 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +3
-0+ - $ref: /schemas/spi/spi-peripheral-props.yaml# + properties: + spi-3wire: true
Drop 'properties'
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 199
Quoted 4 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +4
-0+ required: + - spi-3wire + +required:
Order should be 'dependencies', 'required', 'allOf'.
Quoted 297 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +278
-0+ - 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@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@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@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"; + }; + }; + }; + };MAINTAINERS +5
-0@@ -25402,6 +25402,11 @@ 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 + TMIO/SDHI MMC DRIVER M: Wolfram Sang <[email protected]> L: [email protected]Signature · 1 line
2.43.0
Re: [PATCH v4 2/6] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx
Le 25 août 2025 14 h 26 min 57 s HAE, Rob Herring <[email protected]> a écrit :
Quoted 36 lines · Jean-François Lessard
Quoted 35 lines
Add documentation for TM16xx-compatible 7-segment LED display controllers with keyscan.
Signed-off-by Jean-François Lessard <[email protected]>---
Notes:
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 | 477 ++++++++++++++++++ MAINTAINERS | 5 + 2 files changed, 482 insertions(+) create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yamlDocumentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +9
-0@@ -0,0 +1,477 @@ +# 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:
Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 17
Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +8
-0+ - 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.
In reference to max-brightness, I'll replace with:
Maximum brightness and grid/segment indices are controller-specific. Controller-specific maximum are validated in the driver.
Quoted 61 lines
Quoted 61 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +61
-0+ + 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 + + The controller node exposes a logical LED-like control for the aggregate + display brightness. Child nodes describe individual icons and 7-seg digits. + The top-level control supports only label and brightness-related properties + and does not support other common LED properties such as color or function. + Child LED nodes use the standard LED binding. + + Optional keypad scanning is supported when both 'linux,keymap' and + 'poll-interval' properties are specified. + +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: + - fdhisi,fd620 + - fdhisi,fd655 + - fdhisi,fd6551 + - titanmec,tm1618 + - titanmec,tm1620 + - titanmec,tm1628 + - titanmec,tm1638 + - titanmec,tm1650 + - winrise,hbs658 + + reg: + maxItems: 1 + + label: + description: + The label for the top-level LED. If omitted, the label is taken from the + node name (excluding the unit address). It has to uniquely identify a + device, i.e. no other LED class device can be assigned the same label. + $ref: /schemas/leds/common.yaml#/properties/label + + max-brightness: + description: + Normally the maximum brightness is determined by the hardware and this
Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 83
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ 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/leds/common.yaml#/properties/max-brightnessThese 2 $ref's should be at the node level. The clue is you copied-n-pasted the whole description.
I'll add:
allOf:
- $ref: /schemas/leds/common.yaml#
at the node level and constrain inapplicable LED properties (color, function) using properties: false since this auxdisplay device integrates with LED subsystem for brightness control.
Quoted 2 lines
What you need here is some constraints. What's the max value?
Maximum brightness varies by controller:
- TM1618/TM1628/TM1638 support levels 0-8
- TM1650 supports levels 0-8
- TM1620 supports levels 0-3
I'll set the schema maximum to 8:
max-brightness:
maximum: 8 # Maximum across all TM16xx controllers
with the top-level description note that actual limits are controller-dependent and are enforced by the driver.
Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 89
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6
-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/uint32This needs to first go into
leds/common.yaml.
Given its specific relevance to this auxdisplay use case rather than general LED behavior, I am not sure it's worth adding default-brightness to LEDs/common.yaml If broader LED subsystem adoption is wanted, I am willing to submit a separate patch to this series to add it.
Otherwise, existing precedent in backlight/common.yaml and leds/leds-pwm.yaml would advocate for defining it locally.
Quoted 14 lines
Quoted 14 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +14
-0+ + digits: + type: object + description: Container for 7-segment digit group definitions + additionalProperties: false + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + patternProperties: + "^digit@[0-9]+$":
Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 109
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6
-0+ type: object + unevaluatedProperties: false + + properties: + reg: + description: Digit position identifierPosition is right to left (0 on right)? Please clarify.
I'll clarify: digit positions are numbered sequentially left-to-right, with reg=0 representing the leftmost digit position as displayed to the user.
Quoted 16 lines
Quoted 16 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +16
-0+ 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
Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 130
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ ddd + items: + items: + - description: Grid index + - description: Segment indexCan't you do an array instead and make the array index be the grid or segment index?
Original design was array-based:
- titanmec,digits: array of grid indices
- titanmec,segment-mapping: array of segment indices for a,b,c,d,e,f,g
- titanmec,transposed: boolean for matrix-transposed cases
The current explicit coordinate approach was adopted based on v2 feedback and handles both standard and transposed wiring patterns effectively, where manufacturers swap grid/segment relationships:
- Standard: digit segments use same grid, different segments
- Transposed: digit segments use same segment, different grids
It also future-proofs potential irregular wiring patterns where individual digits might have different grid/segment relationships.
Unless you have strong objections, I prefer to keep this approach to avoid further churn, as it's proven to handle all the real-world board layouts encountered.
See ttps://lore.kernel.org/linux-devicetree/[email protected]/
Quoted 41 lines
Quoted 41 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +41
-0+ minItems: 7 + maxItems: 7 + + required: + - reg + - segments + + leds: + type: object + description: Container for individual LED icon definitions + additionalProperties: false + + properties: + "#address-cells": + const: 2 + "#size-cells": + const: 0 + + patternProperties: + "^led@[0-9]+,[0-9]+$": + type: object + $ref: /schemas/leds/common.yaml# + unevaluatedProperties: false + + properties: + reg: + description: + Grid and segment indices as <grid segment> of this individual LED icon + + required: + - reg + +allOf: + - $ref: /schemas/input/input.yaml# + - $ref: /schemas/input/matrix-keymap.yaml# + +dependencies: + poll-interval: + - linux,keymap + linux,keymap: + - poll-interval
Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 177
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6
-0+ autorepeat: + - linux,keymap + - poll-interval + +# SPI controllers require 3-wire (combined MISO/MOSI line) +if:Move this under the allOf.
Well received.
Quoted 16 lines
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ properties: + compatible: + contains: + enum: + - fdhisi,fd620Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 192
Quoted 10 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +10
-0+ - fdhisi,fd628 + - princeton,pt6964 + - titanmec,tm1618 + - titanmec,tm1620 + - titanmec,tm1628 + - titanmec,tm1638 + - wxicore,aip1618 + - wxicore,aip1628 +then: + allOf:
Quoted 2 lines
Drop allOf.
Well received.
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 195
Quoted 3 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +3
-0+ - $ref: /schemas/spi/spi-peripheral-props.yaml# + properties: + spi-3wire: trueDrop 'properties'
Well received.
Quoted 7 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 199
Quoted 4 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +4
-0+ required: + - spi-3wire + +required:Order should be 'dependencies', 'required', 'allOf'.
I'll reorder the schema sections accordingly.
Quoted 5 lines
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ - compatible + - reg + +unevaluatedProperties: false +
...
Quoted 3 lines
Quoted 3 lines
Signature · 1 line
2.43.0
Thanks for your time and your feedback,
Best Regards
Jean-François Lessard
Re: [PATCH v4 2/6] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx
Le 25 août 2025 21 h 33 min 58 s HAE, "Jean-François Lessard" <[email protected]> a écrit :
Quoted 8 lines
Le 25 août 2025 14 h 26 min 57 s HAE, Rob Herring <[email protected]> a écrit :
Quoted 7 lines · Jean-François Lessard
Quoted 6 lines
Add documentation for TM16xx-compatible 7-segment LED display controllers with keyscan.
Signed-off-by Jean-François Lessard <[email protected]>---
...
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
.../bindings/auxdisplay/titanmec,tm16xx.yaml | 477 ++++++++++++++++++ MAINTAINERS | 5 + 2 files changed, 482 insertions(+) create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yamlDocumentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +8
-0@@ -0,0 +1,477 @@ +# 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 +
...
Quoted 66 lines
Quoted 14 lines
Quoted 14 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +14
-0+ + digits: + type: object + description: Container for 7-segment digit group definitions + additionalProperties: false + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + patternProperties: + "^digit@[0-9]+$":Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 109
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6
-0+ type: object + unevaluatedProperties: false + + properties: + reg: + description: Digit position identifierPosition is right to left (0 on right)? Please clarify.
I'll clarify: digit positions are numbered sequentially left-to-right, with reg=0 representing the leftmost digit position as displayed to the user.
Quoted 16 lines
Quoted 16 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +16
-0+ 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 cQuoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 130
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ ddd + items: + items: + - description: Grid index + - description: Segment indexCan't you do an array instead and make the array index be the grid or segment index?
Original design was array-based:
- titanmec,digits: array of grid indices
- titanmec,segment-mapping: array of segment indices for a,b,c,d,e,f,g
- titanmec,transposed: boolean for matrix-transposed casesThe current explicit coordinate approach was adopted based on v2 feedback and handles both standard and transposed wiring patterns effectively, where manufacturers swap grid/segment relationships:
- Standard: digit segments use same grid, different segments
- Transposed: digit segments use same segment, different grids
It also future-proofs potential irregular wiring patterns where individual digits might have different grid/segment relationships.
Quoted 7 lines
Unless you have strong objections, I prefer to keep this approach to avoid further churn, as it's proven to handle all the real-world board layouts encountered.
See ttps://lore.kernel.org/linux-devicetree/[email protected]/
Diving deeper on your suggestion of using arrays, would this revised design be acceptable?
properties:
digits:
patternProperties:
"^digit@[0-9]+$":
properties:
reg:
maxItems: 1
grids:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: Grid indices for segments a,b,c,d,e,f,g in order
minItems: 7
maxItems: 7
segments:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: Segment indices for segments a,b,c,d,e,f,g in order
minItems: 7
maxItems: 7
This approach:
- Uses arrays as you suggested, indexed by segment position
- Maintains flexibility for both standard and transpose layouts
- Keeps the semantic clarity that Krzysztof requested
Example usage would be:
digit@0 {
reg = <0>;
grids = <4 4 4 4 4 4 4>; // Standard: all segments use same grid
segments = <3 4 5 0 1 2 6>; // Different segment indices
};
// vs transpose case:
digit@0 {
reg = <0>;
grids = <0 1 2 3 4 5 6>; // Transpose: different grids
segments = <3 3 3 3 3 3 3>; // Same segment index
};Would this better align with your preference for array-based approaches?
If so, the remaining question is if these needs to be vendor prefixed or if they are still generic enough hardware description concept applicable to any 7-segment display controller.
Quoted 7 lines
Quoted 7 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 137
Quoted 7 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +7
-0+ minItems: 7 + maxItems: 7 + + required: + - reg + - segments +
...
Best Regards
Jean-François Lessard
Rob Herring
maintainerRe: [PATCH v4 2/6] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx
In reply to Jean-François LessardQuoted 155 lines · Jean-François Lessard
Le 25 août 2025 14 h 26 min 57 s HAE, Rob Herring <[email protected]> a écrit :
Quoted 36 lines · Jean-François Lessard
Quoted 35 lines
Add documentation for TM16xx-compatible 7-segment LED display controllers with keyscan.
Signed-off-by Jean-François Lessard <[email protected]>---
Notes:
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 | 477 ++++++++++++++++++ MAINTAINERS | 5 + 2 files changed, 482 insertions(+) create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yamlDocumentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +9
-0@@ -0,0 +1,477 @@ +# 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:Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 17
Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +8
-0+ - 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.In reference to max-brightness, I'll replace with:
Maximum brightness and grid/segment indices are controller-specific. Controller-specific maximum are validated in the driver.
Quoted 61 lines
Quoted 61 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +61
-0+ + 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 + + The controller node exposes a logical LED-like control for the aggregate + display brightness. Child nodes describe individual icons and 7-seg digits. + The top-level control supports only label and brightness-related properties + and does not support other common LED properties such as color or function. + Child LED nodes use the standard LED binding. + + Optional keypad scanning is supported when both 'linux,keymap' and + 'poll-interval' properties are specified. + +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: + - fdhisi,fd620 + - fdhisi,fd655 + - fdhisi,fd6551 + - titanmec,tm1618 + - titanmec,tm1620 + - titanmec,tm1628 + - titanmec,tm1638 + - titanmec,tm1650 + - winrise,hbs658 + + reg: + maxItems: 1 + + label: + description: + The label for the top-level LED. If omitted, the label is taken from the + node name (excluding the unit address). It has to uniquely identify a + device, i.e. no other LED class device can be assigned the same label. + $ref: /schemas/leds/common.yaml#/properties/label + + max-brightness: + description: + Normally the maximum brightness is determined by the hardware and thisQuoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 83
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ 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/leds/common.yaml#/properties/max-brightnessThese 2 $ref's should be at the node level. The clue is you copied-n-pasted the whole description.
I'll add:
allOf:
- $ref: /schemas/leds/common.yaml#at the node level and constrain inapplicable LED properties (color, function) using properties: false since this auxdisplay device integrates with LED subsystem for brightness control.
Quoted 2 lines
What you need here is some constraints. What's the max value?
Maximum brightness varies by controller:
- TM1618/TM1628/TM1638 support levels 0-8
- TM1650 supports levels 0-8
- TM1620 supports levels 0-3
I'll set the schema maximum to 8:max-brightness:
maximum: 8 # Maximum across all TM16xx controllerswith the top-level description note that actual limits are controller-dependent and are enforced by the driver.
Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 89
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6
-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/uint32This needs to first go into
leds/common.yaml.
Quoted 7 lines
Given its specific relevance to this auxdisplay use case rather than general LED behavior, I am not sure it's worth adding default-brightness to
LEDs/common.yamlIf broader LED subsystem adoption is wanted, I am willing to submit a separate patch to this series to add it.Otherwise, existing precedent in
backlight/common.yamlandleds/leds-pwm.yamlwould advocate for defining it locally.
The type for a property should really only be set in 1 place. Otherwise, it is easy to define different types for the same property (which we have and have to deal with some).
Given we now have 2 cases for LEDs, it should at least be in leds/common.yaml. Should there be 1 definition for both backlight and LEDs, yes. But I can live with 2 definitions in common bindings for now.
Quoted 66 lines
Quoted 14 lines
Quoted 14 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +14
-0+ + digits: + type: object + description: Container for 7-segment digit group definitions + additionalProperties: false + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + patternProperties: + "^digit@[0-9]+$":Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 109
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6
-0+ type: object + unevaluatedProperties: false + + properties: + reg: + description: Digit position identifierPosition is right to left (0 on right)? Please clarify.
I'll clarify: digit positions are numbered sequentially left-to-right, with reg=0 representing the leftmost digit position as displayed to the user.
Quoted 16 lines
Quoted 16 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +16
-0+ 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 cQuoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 130
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ ddd + items: + items: + - description: Grid index + - description: Segment indexCan't you do an array instead and make the array index be the grid or segment index?
Original design was array-based:
- titanmec,digits: array of grid indices
- titanmec,segment-mapping: array of segment indices for a,b,c,d,e,f,g
- titanmec,transposed: boolean for matrix-transposed casesThe current explicit coordinate approach was adopted based on v2 feedback and handles both standard and transposed wiring patterns effectively, where manufacturers swap grid/segment relationships:
- Standard: digit segments use same grid, different segments
- Transposed: digit segments use same segment, different grids
It also future-proofs potential irregular wiring patterns where individual digits might have different grid/segment relationships.
Quoted 3 lines
Unless you have strong objections, I prefer to keep this approach to avoid further churn, as it's proven to handle all the real-world board layouts encountered.
2 arrays would not be an improvement. So leave it as you have it.
Rob
Re: [PATCH v4 2/6] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx
Le 29 août 2025 11 h 26 min 13 s HAE, Rob Herring <[email protected]> a écrit :
Quoted 164 lines · Jean-François Lessard
Quoted 155 lines
Le 25 août 2025 14 h 26 min 57 s HAE, Rob Herring <[email protected]> a écrit :
Quoted 36 lines · Jean-François Lessard
Quoted 35 lines
Add documentation for TM16xx-compatible 7-segment LED display controllers with keyscan.
Signed-off-by Jean-François Lessard <[email protected]>---
Notes:
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 | 477 ++++++++++++++++++ MAINTAINERS | 5 + 2 files changed, 482 insertions(+) create mode 100644 Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yamlDocumentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +9
-0@@ -0,0 +1,477 @@ +# 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:Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 17
Quoted 8 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +8
-0+ - 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.In reference to max-brightness, I'll replace with:
Maximum brightness and grid/segment indices are controller-specific. Controller-specific maximum are validated in the driver.
Quoted 61 lines
Quoted 61 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +61
-0+ + 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 + + The controller node exposes a logical LED-like control for the aggregate + display brightness. Child nodes describe individual icons and 7-seg digits. + The top-level control supports only label and brightness-related properties + and does not support other common LED properties such as color or function. + Child LED nodes use the standard LED binding. + + Optional keypad scanning is supported when both 'linux,keymap' and + 'poll-interval' properties are specified. + +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: + - fdhisi,fd620 + - fdhisi,fd655 + - fdhisi,fd6551 + - titanmec,tm1618 + - titanmec,tm1620 + - titanmec,tm1628 + - titanmec,tm1638 + - titanmec,tm1650 + - winrise,hbs658 + + reg: + maxItems: 1 + + label: + description: + The label for the top-level LED. If omitted, the label is taken from the + node name (excluding the unit address). It has to uniquely identify a + device, i.e. no other LED class device can be assigned the same label. + $ref: /schemas/leds/common.yaml#/properties/label + + max-brightness: + description: + Normally the maximum brightness is determined by the hardware and thisQuoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 83
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ 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/leds/common.yaml#/properties/max-brightnessThese 2 $ref's should be at the node level. The clue is you copied-n-pasted the whole description.
I'll add:
allOf:
- $ref: /schemas/leds/common.yaml#at the node level and constrain inapplicable LED properties (color, function) using properties: false since this auxdisplay device integrates with LED subsystem for brightness control.
Quoted 2 lines
What you need here is some constraints. What's the max value?
Maximum brightness varies by controller:
- TM1618/TM1628/TM1638 support levels 0-8
- TM1650 supports levels 0-8
- TM1620 supports levels 0-3
I'll set the schema maximum to 8:max-brightness:
maximum: 8 # Maximum across all TM16xx controllerswith the top-level description note that actual limits are controller-dependent and are enforced by the driver.
Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 89
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6
-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/uint32This needs to first go into
leds/common.yaml.Quoted 7 lines
Given its specific relevance to this auxdisplay use case rather than general LED behavior, I am not sure it's worth adding default-brightness to
LEDs/common.yamlIf broader LED subsystem adoption is wanted, I am willing to submit a separate patch to this series to add it.Otherwise, existing precedent in
backlight/common.yamlandleds/leds-pwm.yamlwould advocate for defining it locally.
Quoted 8 lines
The type for a property should really only be set in 1 place. Otherwise, it is easy to define different types for the same property (which we have and have to deal with some).
Given we now have 2 cases for LEDs, it should at least be in
leds/common.yaml. Should there be 1 definition for both backlight and LEDs, yes. But I can live with 2 definitions in common bindings for now.
Understood. I'll add default-brightness definition to leds/common.yaml.
Quoted 66 lines
Quoted 66 lines
Quoted 14 lines
Quoted 14 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +14
-0+ + digits: + type: object + description: Container for 7-segment digit group definitions + additionalProperties: false + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + patternProperties: + "^digit@[0-9]+$":Quoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 109
Quoted 6 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +6
-0+ type: object + unevaluatedProperties: false + + properties: + reg: + description: Digit position identifierPosition is right to left (0 on right)? Please clarify.
I'll clarify: digit positions are numbered sequentially left-to-right, with reg=0 representing the leftmost digit position as displayed to the user.
Quoted 16 lines
Quoted 16 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +16
-0+ 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 cQuoted 9 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml line 130
Quoted 5 lines
Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml new file +5
-0+ ddd + items: + items: + - description: Grid index + - description: Segment indexCan't you do an array instead and make the array index be the grid or segment index?
Original design was array-based:
- titanmec,digits: array of grid indices
- titanmec,segment-mapping: array of segment indices for a,b,c,d,e,f,g
- titanmec,transposed: boolean for matrix-transposed casesThe current explicit coordinate approach was adopted based on v2 feedback and handles both standard and transposed wiring patterns effectively, where manufacturers swap grid/segment relationships:
- Standard: digit segments use same grid, different segments
- Transposed: digit segments use same segment, different grids
It also future-proofs potential irregular wiring patterns where individual digits might have different grid/segment relationships.
Quoted 6 lines
Quoted 3 lines
Unless you have strong objections, I prefer to keep this approach to avoid further churn, as it's proven to handle all the real-world board layouts encountered.
2 arrays would not be an improvement. So leave it as you have it.
Acknowledged. I'll keep segments as uint32-matrix.
Thank you,
Jean-François Lessard
Re: [PATCH v4 2/6] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx
In reply to Jean-François LessardQuoted 1 line · On Sun, 24 Aug 2025 23:32:28 -0400 Jean-François Lessard…
+ - Digits use 1-cell addressing with explicit segment mapping
This new digits layout introduced in v3 implies that a different segment mapping can be used per digit by a single display/controller. Is that really a thing?
Regards
Per Larsson
Re: [PATCH v4 2/6] dt-bindings: auxdisplay: add Titan Micro Electronics TM16xx
Le 25 août 2025 15 h 08 min 36 s HAE, Per Larsson <[email protected]> a écrit :
Quoted 9 lines
Quoted 1 line · On Sun, 24 Aug 2025 23:32:28 -0400 Jean-François Lessard…
+ - Digits use 1-cell addressing with explicit segment mapping
This new digits layout introduced in v3 implies that a different segment mapping can be used per digit by a single display/controller. Is that really a thing?
Board manufacturers typically use consistent patterns across digits, but some use matrix-transposed layouts where grid/segment relationships are swapped system-wide. The explicit coordinate mapping handles both standard and transposed configurations.
Bottom line: I am not aware of different per digit 7-segment mappings on a single display board.
Best Regards
Jean-François Lessard
PATCH v4 3/6 auxdisplay: Add TM16xx 7-segment LED matrix display controllers driver
In reply to Jean-François LessardAdd 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 buses.
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).
---
Notes:
checkpatch reports false positives that are intentionally ignored:
DEVICE_ATTR_FUNCTIONS: Functions are correctly prefixed with driver name (tm16xx_*) following standard kernel practice for device attribute functions to avoid namespace conflicts.
BIT_MACRO: bit shifts are used for field values while GENMASK/BIT are used for bit positions per semantic convention
include <linux/of.h> is required for the default name of the main led device, excluding the unit address, as implemented in drivers/leds/led-core.c which relies on of_node->name
LED registration uses non-devm variant on-purpose to allow explicit unregistration on device removal, ensuring LED triggers are immediately stopped. This prevents stale LED trigger activity from continuing after the hardware is gone, avoiding the need for complex state tracking in brightness callbacks.
.../ABI/testing/sysfs-class-leds-tm16xx | 57 ++ MAINTAINERS | 3 + drivers/auxdisplay/Kconfig | 20 +- drivers/auxdisplay/Makefile | 2 + drivers/auxdisplay/tm16xx.h | 177 +++++ drivers/auxdisplay/tm16xx_core.c | 618 ++++++++++++++++++ 6 files changed, 876 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-class-leds-tm16xx create mode 100644 drivers/auxdisplay/tm16xx.h create mode 100644 drivers/auxdisplay/tm16xx_core.c
Documentation/ABI/testing/sysfs-class-leds-tm16xx new file +57 -0
@@ -0,0 +1,57 @@ +What: /sys/class/leds/<led>/value +Date: August 2025 +KernelVersion: 6.17 +Contact: Jean-François Lessard <[email protected]> +Description: + Controls the text displayed on the TM16xx 7-segment display. + + Reading returns the current display content as ASCII characters, + one character per digit position, followed by a newline. + + Writing sets new display content. Input characters are mapped + to 7-segment patterns using the configured character map. The + string length should not exceed the number of available digits + (see num_digits). Shorter strings will clear remaining digits. + + Example: + echo "1234" > value # Display "1234" + cat value # Returns "1234\n" + +What: /sys/class/leds/<led>/num_digits +Date: August 2025 +KernelVersion: 6.17 +Contact: Jean-François Lessard <[email protected]> +Description: + Read-only attribute showing the number of 7-segment digit + positions available on this TM16xx display controller. + + The value is determined by the device tree configuration + and represents the maximum length for the 'value' attribute. + + Example: + cat num_digits # Returns "4\n" for 4-digit display + +What: /sys/class/leds/<led>/map_seg7 +Date: August 2025 +KernelVersion: 6.17 +Contact: Jean-François Lessard <[email protected]> +Description: + Read/write binary blob representing the ASCII-to-7-segment + display conversion table used by the TM16xx driver, as defined + by struct seg7_conversion_map in <linux/map_to_7segment.h>. + + This attribute is not human-readable. Writes must match the + struct size exactly, else -EINVAL is returned; reads return the + entire mapping as a binary blob. + + This interface and its implementation match existing conventions + used in auxdisplay and segment-mapped display drivers since 2005. + + ABI note: This style of binary sysfs attribute *is an exception* + to current "one value per file, text only" sysfs rules, for + historical compatibility and driver uniformity. New drivers are + discouraged from introducing additional binary sysfs ABIs. + + Reference interface guidance: + - include/uapi/linux/map_to_7segment.h +Users: Display configuration utilities and embedded system scripts/tools.
MAINTAINERS +3 -0
@@ -25405,7 +25405,10 @@ F: drivers/net/ethernet/ti/tlan.* TM16XX-COMPATIBLE LED CONTROLLERS DISPLAY DRIVER M: Jean-François Lessard <[email protected]> S: Maintained +F: Documentation/ABI/testing/sysfs-class-leds-tm16xx F: Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml +F: drivers/auxdisplay/tm16xx.h +F: drivers/auxdisplay/tm16xx_core.c TMIO/SDHI MMC DRIVER M: Wolfram Sang <[email protected]>
drivers/auxdisplay/Kconfig +19 -1
@@ -316,7 +316,7 @@ endif # PARPORT_PANEL config PANEL_CHANGE_MESSAGE bool "Change LCD initialization message ?" - depends on CHARLCD || LINEDISP + depends on CHARLCD || LINEDISP || TM16XX help This allows you to replace the boot message indicating the kernel version and the driver version with a custom message. This is useful on appliances
@@ -526,6 +526,24 @@ 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" + depends on SPI || I2C + select NEW_LEDS + select LEDS_CLASS + select LEDS_TRIGGERS + 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 +2 -0
@@ -16,3 +16,5 @@ 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 +tm16xx-y += tm16xx_core.o
drivers/auxdisplay/tm16xx.h new file +177 -0
177 lines not on this page · raw message
drivers/auxdisplay/tm16xx_core.c new file +618 -0
618 lines not on this page · raw message
Signature · 1 line
2.43.0
Quoted 8 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 buses.
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).
...
Quoted 11 lines
Notes:
checkpatch reports false positives that are intentionally ignored:
DEVICE_ATTR_FUNCTIONS: Functions are correctly prefixed with driver name (tm16xx_*) following standard kernel practice for device attribute functions to avoid namespace conflicts.
BIT_MACRO: bit shifts are used for field values while GENMASK/BIT are used for bit positions per semantic conventioninclude <
linux/of.h> is required for the default name of the main led device, excluding the unit address, as implemented indrivers/leds/led-core.cwhich relies onof_node->name
Sorry, but I do not see how of.h is related to all this... Please, drop it.
Quoted 5 lines
LED registration uses non-devm variant on-purpose to allow explicit unregistration on device removal, ensuring LED triggers are immediately stopped. This prevents stale LED trigger activity from continuing after the hardware is gone, avoiding the need for complex state tracking in brightness callbacks.
...
Documentation/ABI/testing/sysfs-class-leds-tm16xx line 3
Quoted 4 lines
Documentation/ABI/testing/sysfs-class-leds-tm16xx new file +3
-0+What: /sys/class/leds/<led>/value +Date: August 2025 +KernelVersion: 6.17
The Date should be approximate date of the kernel release (alternatively, -rc1 of that). The version is estimated version where ABI can be found first.
Both of these need to be changed.
Quoted 43 lines
Documentation/ABI/testing/sysfs-class-leds-tm16xx new file +43
-0+Contact: Jean-François Lessard <[email protected]> +Description: + Controls the text displayed on the TM16xx 7-segment display. + + Reading returns the current display content as ASCII characters, + one character per digit position, followed by a newline. + + Writing sets new display content. Input characters are mapped + to 7-segment patterns using the configured character map. The + string length should not exceed the number of available digits + (see num_digits). Shorter strings will clear remaining digits. + + Example: + echo "1234" > value # Display "1234" + cat value # Returns "1234\n" + +What: /sys/class/leds/<led>/num_digits +Date: August 2025 +KernelVersion: 6.17 +Contact: Jean-François Lessard <[email protected]> +Description: + Read-only attribute showing the number of 7-segment digit + positions available on this TM16xx display controller. + + The value is determined by the device tree configuration + and represents the maximum length for the 'value' attribute. + + Example: + cat num_digits # Returns "4\n" for 4-digit display + +What: /sys/class/leds/<led>/map_seg7 +Date: August 2025 +KernelVersion: 6.17 +Contact: Jean-François Lessard <[email protected]> +Description: + Read/write binary blob representing the ASCII-to-7-segment + display conversion table used by the TM16xx driver, as defined + by struct seg7_conversion_map in <linux/map_to_7segment.h>. + + This attribute is not human-readable. Writes must match the + struct size exactly, else -EINVAL is returned; reads return the + entire mapping as a binary blob. +
Documentation/ABI/testing/sysfs-class-leds-tm16xx line 56
Quoted 10 lines
Documentation/ABI/testing/sysfs-class-leds-tm16xx new file +10
-0+ This interface and its implementation match existing conventions + used in auxdisplay and segment-mapped display drivers since 2005. + + ABI note: This style of binary sysfs attribute *is an exception* + to current "one value per file, text only" sysfs rules, for + historical compatibility and driver uniformity. New drivers are + discouraged from introducing additional binary sysfs ABIs. + + Reference interface guidance: + - include/uapi/linux/map_to_7segment.h
So, the driver is under auxdisplay, but at the same time it completely relies on LED subsystem... What's going on here?
Btw, have you seen
https://lore.kernel.org/linux-leds/[email protected]/
? And if so, what're your takeaways? (Yes, I know that's about different HW)
Quoted 1 line
+Users: Display configuration utilities and embedded system
scripts/tools.
...
Quoted 1 line
+ * Copyright (C) 2024 Jean-François Lessard
My calendar shows something different.
drivers/auxdisplay/tm16xx.h line 13
Quoted 3 lines
drivers/auxdisplay/tm16xx.h new file +2
-0+#include <linux/bitfield.h> +#include <linux/bitmap.h>
Is this used?
Quoted 2 lines
drivers/auxdisplay/tm16xx.h new file +2
-0+#include <linux/leds.h> +#include <linux/workqueue.h>
...
Quoted 1 line
+#define
TM16XX_DIGIT_SEGMENTS7
Why do we even need this?
...
drivers/auxdisplay/tm16xx.h line 101
Quoted 2 lines
drivers/auxdisplay/tm16xx.h new file +2
-0+#define TM16XX_CTRL_BRIGHTNESS (on, val, prfx) \ + ((on) ? (FIELD_PREP(prfx##_CTRL_BR_MASK, (val)) | prfx##_CTRL_ON) : 0)
prefix can be spelled fully, going slightly over 80 is not a crime.
...
drivers/auxdisplay/tm16xx.h line 158
Quoted 8 lines
drivers/auxdisplay/tm16xx.h new file +7
-0+struct tm16xx_display { +struct device *dev; +const struct tm16xx_controller *controller; +union { +struct i2c_client *i2c; +struct spi_device *spi; + } client;
Why? Just drop it. struct device *dev is enough and I can't see the need in this at all.
Quoted 14 lines
drivers/auxdisplay/tm16xx.h new file +14
-0+u8 *spi_buffer; +u8 num_grids; +u8 num_segments; +struct led_classdev main_led; +struct tm16xx_led *leds; +u8 num_leds; +struct tm16xx_digit *digits; +u8 num_digits; +struct work_struct flush_init; +struct work_struct flush_display; +int flush_status; +struct mutex lock;/* prevents concurrent work operations */ +unsigned long *state; +};
...
Quoted 1 line
+ * Copyright (C) 2024 Jean-François Lessard
Year?
...
drivers/auxdisplay/tm16xx_core.c line 12
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c new file +4
-0+#include <linux/map_to_7segment.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/property.h>
Please, follow IWYU principle.
...
drivers/auxdisplay/tm16xx_core.c line 267
Quoted 7 lines
drivers/auxdisplay/tm16xx_core.c new file +7
-0+static ssize_t tm16xx_num_digits_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +struct tm16xx_display *display =dev_get_drvdata (led_cdev->dev->parent); + +return sprintf (buf,"%u\n" , display->num_digits);
Should be sysfs_emit().
Quoted 1 line
+}
...
drivers/auxdisplay/tm16xx_core.c line 283
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+static ssize_t tm16xx_map_seg7_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +memcpy (buf, &map_seg7,sizeof (map_seg7)); +return sizeof (map_seg7); +}
Can we use LINEDISP library?
...
drivers/auxdisplay/tm16xx_core.c line 312
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+static struct attribute *tm16xx_main_led_attrs[] = { + &dev_attr_value.attr, + &dev_attr_num_digits.attr, + &dev_attr_map_seg7.attr, +NULL ,
No comma in the terminator entry.
Quoted 2 lines
drivers/auxdisplay/tm16xx_core.c new file +2
-0+}; +ATTRIBUTE_GROUPS (tm16xx_main_led);
...
drivers/auxdisplay/tm16xx_core.c line 326
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c new file +4
-0+static int tm16xx_display_init (struct tm16xx_display *display) +{ +unsigned int nbits =tm16xx_led_nbits (display); +dev_dbg (display->dev,"Initializing display\n" );
Please, drop all these dev_dbg() over the code as they are close to useless, use tracers and other mechanisms to debug if required.
Also drop unneeded kernel-doc for the (esp. static) functions that have well established meaning (e.g., no need a kernel-doc for device attributes as they should be documented in the ABI).
Quoted 22 lines
drivers/auxdisplay/tm16xx_core.c new file +22
-0+schedule_work (&display->flush_init); +flush_work (&display->flush_init); +if (display->flush_status <0 ) +return display->flush_status; + +if (tm16xx_init_value) { +tm16xx_value_store (display->main_led.dev,NULL , + tm16xx_init_value, +strlen (tm16xx_init_value)); + }else { +bitmap_fill (display->state, nbits); +schedule_work (&display->flush_display); +flush_work (&display->flush_display); +bitmap_zero (display->state, nbits); +if (display->flush_status <0 ) +return display->flush_status; + } + +dev_info (display->dev,"Display turned on\n" ); + +return 0 ; +}
...
Quoted 1 line
+static int
tm16xx_parse_dt(struct device *dev, struct tm16xx_display *display)
Why DT only? No support for other platforms? Why? I think this is just matter of naming the function properly.
drivers/auxdisplay/tm16xx_core.c line 362
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+{ +struct fwnode_handle *leds_node, *digits_node, *child; +struct tm16xx_led *led; +struct tm16xx_digit *digit; +int max_grid =0 , max_segment =0 ;
Why signed?
drivers/auxdisplay/tm16xx_core.c line 363
Quoted 1 line
drivers/auxdisplay/tm16xx_core.c new file +1
-0+int ret, i, j;
Why are i and j signed?
drivers/auxdisplay/tm16xx_core.c line 372
Quoted 10 lines
drivers/auxdisplay/tm16xx_core.c new file +9
-0+u32 segments[TM16XX_DIGIT_SEGMENTS *2 ]; +u32 reg[2 ]; + +/* parse digits */ + digits_node =device_get_named_child_node (dev,"digits" ); +if (digits_node) { + display->num_digits =0 ; +fwnode_for_each_child_node (digits_node, child) + display->num_digits++;
Don't we have a _count API for this?
drivers/auxdisplay/tm16xx_core.c line 381
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c new file +8
-0+dev_dbg (dev,"Number of digits: %u\n" , display->num_digits); + +if (display->num_digits) { + display->digits =devm_kcalloc (dev, display->num_digits, +sizeof (*display->digits), +GFP_KERNEL ); +if (!display->digits) { +fwnode_handle_put (digits_node);
Use RAII instead, we have defined __free() method for this.
drivers/auxdisplay/tm16xx_core.c line 386
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+return -ENOMEM ; + } + + i =0 ; +fwnode_for_each_child_node (digits_node, child) {
Ditto. Use _scoped variant.
drivers/auxdisplay/tm16xx_core.c line 390
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c new file +3
-0+ digit = &display->digits[i]; + ret =fwnode_property_read_u32 (child,"reg" , + reg);
One line.
Review
Quoted 1 line
(quoted diff) +1
-0+ if (ret < 0) {
Can it be positive? Here and everywhere else, if there is no positive return, use 'if (ret)'.
Quoted 10 lines
drivers/auxdisplay/tm16xx_core.c new file +10
-0+fwnode_handle_put (child); +fwnode_handle_put (digits_node); +return ret; + } + + ret =fwnode_property_read_u32_array (child, +"segments" , + segments, +TM16XX_DIGIT_SEGMENTS *2 ); +if (ret <0 ) {
drivers/auxdisplay/tm16xx_core.c line 410
Quoted 10 lines
drivers/auxdisplay/tm16xx_core.c new file +9
-0+fwnode_handle_put (child); +fwnode_handle_put (digits_node); +return ret; + } + +for (j =0 ; j <TM16XX_DIGIT_SEGMENTS ; ++j) { + digit->segments[j].grid = segments[2 * j]; + digit->segments[j].segment = segments[2 * j +1 ]; + max_grid = umax(max_grid,
Firstly, the variables made signed and then specifically force them to be unsigned in the macro. Weird. Can we make them to be a proper type and use max()?
drivers/auxdisplay/tm16xx_core.c line 411
Quoted 1 line
drivers/auxdisplay/tm16xx_core.c new file +1
-0+ digit->segments[j].grid);
One line
drivers/auxdisplay/tm16xx_core.c line 413
Quoted 2 lines
drivers/auxdisplay/tm16xx_core.c new file +2
-0+ max_segment =umax (max_segment, + digit->segments[j].segment);
As per above comments.
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+ } + digit->value =0 ; + i++; + } +
drivers/auxdisplay/tm16xx_core.c line 428
Quoted 10 lines
drivers/auxdisplay/tm16xx_core.c new file +10
-0+fwnode_handle_put (digits_node); + } + } + +/* parse leds */ + leds_node =device_get_named_child_node (dev,"leds" ); +if (leds_node) { + display->num_leds =0 ; +fwnode_for_each_child_node (leds_node, child) + display->num_leds++;
As per above.
Quoted 8 lines
drivers/auxdisplay/tm16xx_core.c new file +8
-0+dev_dbg (dev,"Number of LEDs: %u\n" , display->num_leds); + +if (display->num_leds) { + display->leds =devm_kcalloc (dev, display->num_leds, +sizeof (*display->leds), +GFP_KERNEL ); +if (!display->leds) { +fwnode_handle_put (leds_node);
drivers/auxdisplay/tm16xx_core.c line 446
Quoted 10 lines
drivers/auxdisplay/tm16xx_core.c new file +9
-0+return -ENOMEM ; + } + + i =0 ; +fwnode_for_each_child_node (leds_node, child) { + led = &display->leds[i]; + ret =fwnode_property_read_u32_array (child, +"reg" , reg, +2 );
Make it one line.
Quoted 24 lines
drivers/auxdisplay/tm16xx_core.c new file +24
-0+if (ret <0 ) { +fwnode_handle_put (child); +fwnode_handle_put (leds_node); +return ret; + } + + led->grid = reg[0 ]; + led->segment = reg[1 ]; + max_grid =umax (max_grid, led->grid); + max_segment =umax (max_segment, led->segment); + i++; + } + } + +fwnode_handle_put (leds_node); + } + +if (max_grid >= display->controller->max_grids) { +dev_err (dev,"grid %u exceeds controller max_grids %u\n" , + max_grid, display->controller->max_grids); +return -EINVAL ; + } + +if (max_segment >= display->controller->max_segments) {
drivers/auxdisplay/tm16xx_core.c line 480
Quoted 10 lines
drivers/auxdisplay/tm16xx_core.c new file +9
-0+dev_err (dev,"segment %u exceeds controller max_segments %u\n" , + max_segment, display->controller->max_segments); +return -EINVAL ; + } + + display->num_grids = max_grid +1 ; + display->num_segments = max_segment +1 ; +dev_dbg (dev,"Number of grids: %u\n" , display->num_grids); +dev_dbg (dev,"Number of segments: %u\n" , display->num_segments);
I didn't get this. You mean that they are not strictly 7-segment ones?
Quoted 3 lines
drivers/auxdisplay/tm16xx_core.c new file +3
-0+ +return 0 ; +}
...
drivers/auxdisplay/tm16xx_core.c line 497
Quoted 7 lines
drivers/auxdisplay/tm16xx_core.c new file +7
-0+int tm16xx_probe (struct tm16xx_display *display) +{ +struct device *dev = display->dev; +struct led_classdev *main = &display->main_led; +struct fwnode_handle *leds_node, *child; +unsigned int nbits; +int ret, i;
Why is i signed?
drivers/auxdisplay/tm16xx_core.c line 509
Quoted 11 lines
drivers/auxdisplay/tm16xx_core.c new file +10
-0+dev_dbg (dev,"Probing device\n" ); + ret =tm16xx_parse_dt (dev, display); +if (ret <0 ) +return dev_err_probe (dev, ret,"Failed to parse device tree\n" ); + + nbits =tm16xx_led_nbits (display); + display->state =devm_bitmap_zalloc (dev, nbits,GFP_KERNEL ); +if (!display->state) +return -ENOMEM ; +mutex_init (&display->lock);
devm_mutex_init()
drivers/auxdisplay/tm16xx_core.c line 518
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c new file +8
-0+INIT_WORK (&display->flush_init, tm16xx_display_flush_init); +INIT_WORK (&display->flush_display, tm16xx_display_flush_data); +/* Initialize main LED properties */ +if (dev->of_node) + main->name = dev->of_node->name; +if (!main->name) + main->name ="display" ; +device_property_read_string (dev,"label" , &main->name);
My gosh. This is done in the LED core if we even need this...
Quoted 58 lines
drivers/auxdisplay/tm16xx_core.c new file +57
-0+ main->max_brightness = display->controller->max_brightness; +device_property_read_u32 (dev,"max-brightness" , &main->max_brightness); + main->max_brightness =umin (main->max_brightness, + display->controller->max_brightness); + + main->brightness = main->max_brightness; +device_property_read_u32 (dev,"default-brightness" , &main->brightness); + main->brightness =umin (main->brightness, main->max_brightness); + + main->brightness_set = tm16xx_brightness_set; + main->groups = tm16xx_main_led_groups; + main->flags =LED_RETAIN_AT_SHUTDOWN |LED_CORE_SUSPENDRESUME ; + + ret =led_classdev_register (dev, main); +if (ret <0 ) +return dev_err_probe (dev, ret,"Failed to register main LED\n" ); + i =0 ; + leds_node =device_get_named_child_node (dev,"leds" ); +fwnode_for_each_child_node (leds_node, child) { +struct tm16xx_led *led = &display->leds[i]; +struct led_init_data led_init = { + .fwnode = child, + .devicename =dev_name (main->dev), + .devname_mandatory = true, + .default_label ="led" , + }; + led->cdev.max_brightness =1 ; + led->cdev.brightness_set = tm16xx_led_set; + led->cdev.flags =LED_RETAIN_AT_SHUTDOWN | +LED_CORE_SUSPENDRESUME ; + + ret =led_classdev_register_ext (dev, &led->cdev, &led_init); +if (ret <0 ) { +fwnode_handle_put (child); +dev_err_probe (dev, ret,"Failed to register LED %s\n" , + led->cdev.name); + goto unregister_leds; + } + + i++; + } + + ret =tm16xx_display_init (display); +if (ret <0 ) { +dev_err_probe (dev, ret,"Failed to initialize display\n" ); + goto unregister_leds; + } + +return 0 ; + +unregister_leds: +while (i--) +led_classdev_unregister (&display->leds[i].cdev); + +led_classdev_unregister (main); +return ret; +}
...
drivers/auxdisplay/tm16xx_core.c line 589
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+void tm16xx_remove (struct tm16xx_display *display) +{ +unsigned int nbits =tm16xx_led_nbits (display); +struct tm16xx_led *led; +dev_dbg (display->dev,"Removing display\n" );
Unneeded noise.
drivers/auxdisplay/tm16xx_core.c line 596
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+/* +* Unregister LEDs first to immediately stop trigger activity. +* This prevents LED triggers from attempting to access hardware +* after it's been disconnected or driver unloaded. +*/ +for (int i =0 ; i < display->num_leds; i++) {
Why iterator is signed?
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+ led = &display->leds[i]; +led_classdev_unregister (&led->cdev); + } +led_classdev_unregister (&display->main_led); + +/* Clear display state */
drivers/auxdisplay/tm16xx_core.c line 612
Quoted 10 lines
drivers/auxdisplay/tm16xx_core.c new file +9
-0+bitmap_zero (display->state, nbits); +schedule_work (&display->flush_display); +flush_work (&display->flush_display); + +/* Turn off display */ + display->main_led.brightness =LED_OFF ; +schedule_work (&display->flush_init); +flush_work (&display->flush_init); +dev_info (display->dev,"Display turned off\n" );
Unneeded noise.
Quoted 1 line
+}
Signature · 2 lines
With Best Regards, Andy Shevchenko
Le 25 août 2025 11 h 14 min 21 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 20 lines · Jean-François Lessard
Quoted 8 lines
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 buses.
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).
...
Quoted 7 lines
Notes:
checkpatch reports false positives that are intentionally ignored:
DEVICE_ATTR_FUNCTIONS: Functions are correctly prefixed with driver name (tm16xx_*) following standard kernel practice for device attribute functions to avoid namespace conflicts.
BIT_MACRO: bit shifts are used for field values while GENMASK/BIT are used for bit positions per semantic convention
Quoted 6 lines
Quoted 3 lines
include <
linux/of.h> is required for the default name of the main led device, excluding the unit address, as implemented indrivers/leds/led-core.cwhich relies onof_node->nameSorry, but I do not see how
of.his related to all this... Please, drop it.
This relates to the LED subsystem integration question below. I'll address both together and remove the include if not needed.
Quoted 10 lines
Quoted 5 lines
LED registration uses non-devm variant on-purpose to allow explicit unregistration on device removal, ensuring LED triggers are immediately stopped. This prevents stale LED trigger activity from continuing after the hardware is gone, avoiding the need for complex state tracking in brightness callbacks.
...
Quoted 1 line
+What: /sys/class/leds/<led>/value
Quoted 9 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+Date: August 2025 +KernelVersion: 6.17The Date should be approximate date of the kernel release (alternatively, -rc1 of that). The version is estimated version where ABI can be found first.
Both of these need to be changed.
Given that 6.17-rc3 was just released, should I target 6.18 for the kernel version and use a March 2025 date for the estimated release timeframe?
Quoted 48 lines
Quoted 48 lines
Documentation/ABI/testing/sysfs-class-leds-tm16xx new file +48
-0+Contact: Jean-François Lessard <[email protected]> +Description: + Controls the text displayed on the TM16xx 7-segment display. + + Reading returns the current display content as ASCII characters, + one character per digit position, followed by a newline. + + Writing sets new display content. Input characters are mapped + to 7-segment patterns using the configured character map. The + string length should not exceed the number of available digits + (see num_digits). Shorter strings will clear remaining digits. + + Example: + echo "1234" > value # Display "1234" + cat value # Returns "1234\n" + +What: /sys/class/leds/<led>/num_digits +Date: August 2025 +KernelVersion: 6.17 +Contact: Jean-François Lessard <[email protected]> +Description: + Read-only attribute showing the number of 7-segment digit + positions available on this TM16xx display controller. + + The value is determined by the device tree configuration + and represents the maximum length for the 'value' attribute. + + Example: + cat num_digits # Returns "4\n" for 4-digit display + +What: /sys/class/leds/<led>/map_seg7 +Date: August 2025 +KernelVersion: 6.17 +Contact: Jean-François Lessard <[email protected]> +Description: + Read/write binary blob representing the ASCII-to-7-segment + display conversion table used by the TM16xx driver, as defined + by struct seg7_conversion_map in <linux/map_to_7segment.h>. + + This attribute is not human-readable. Writes must match the + struct size exactly, else -EINVAL is returned; reads return the + entire mapping as a binary blob. + + This interface and its implementation match existing conventions + used in auxdisplay and segment-mapped display drivers since 2005. + + ABI note: This style of binary sysfs attribute *is an exception* + to current "one value per file, text only" sysfs rules, for
Quoted 9 lines
Documentation/ABI/testing/sysfs-class-leds-tm16xx line 56
Quoted 5 lines
Documentation/ABI/testing/sysfs-class-leds-tm16xx new file +5
-0+ historical compatibility and driver uniformity. New drivers are + discouraged from introducing additional binary sysfs ABIs. + + Reference interface guidance: + - include/uapi/linux/map_to_7segment.hSo, the driver is under auxdisplay, but at the same time it completely relies on LED subsystem... What's going on here?
The design integrates with the LED subsystem for two main reasons:
1. Brightness control:
The entire display brightness is controlled at the display level (individual LED icons can only be on/off via their brightness attributes). The LED subsystem provides established mechanisms for this.
2. Coherent sysfs interface:
This provides consistent /sys/class/leds/display for display-level controls and /sys/class/leds/display::{function} for individual icons.
I'm seeking your guidance on the best design for the auxdisplay subsystem.
Quoted 4 lines
Btw, have you seen
https://lore.kernel.org/linux-leds/[email protected]/
? And if so, what're your takeaways? (Yes, I know that's about different HW)
I've read the thread but I'm not clear on the specific point you're making. Could you clarify what aspect I should focus on?
(Though, my personal opinion is that using auxdisplay for keyboard LEDs doesn't really make sense. I think it would be better to properly implement it the required mechanism into input subsystem, with maybe some integration with the leds subsystem. Just a quick opinion, I do not master all aspects of this question at all.)
Quoted 9 lines
Quoted 1 line
+Users: Display configuration utilities and embedded system
scripts/tools....
Quoted 1 line
+ * Copyright (C) 2024 Jean-François Lessard
My calendar shows something different.
The original code was developed in 2024, though it's being submitted in 2025.
Quoted 6 lines
drivers/auxdisplay/tm16xx.h line 13
Quoted 3 lines
drivers/auxdisplay/tm16xx.h new file +2
-0+#include <linux/bitfield.h> +#include <linux/bitmap.h> Is this used?
Yes, display->state is a bitmap. I'll move this include to tm16xx_core.c since it's not used in the header itself.
Quoted 9 lines
Quoted 2 lines
drivers/auxdisplay/tm16xx.h new file +2
-0+#include <linux/leds.h> +#include <linux/workqueue.h> ...
Quoted 1 line
+#define
TM16XX_DIGIT_SEGMENTS7Why do we even need this?
You're right. I'll move it to tm16xx_core.c.
Quoted 7 lines
...
drivers/auxdisplay/tm16xx.h line 101
Quoted 2 lines
drivers/auxdisplay/tm16xx.h new file +2
-0+#define TM16XX_CTRL_BRIGHTNESS (on, val, prfx) \ + ((on) ? (FIELD_PREP(prfx##_CTRL_BR_MASK, (val)) | prfx##_CTRL_ON) : 0)prefix can be spelled fully, going slightly over 80 is not a crime.
Acknowledged, I'll use the full prefix name.
Quoted 6 lines
...
Quoted 3 lines
drivers/auxdisplay/tm16xx.h new file +3
-0+struct tm16xx_display { +struct device *dev; +const struct tm16xx_controller *controller;
Quoted 8 lines
drivers/auxdisplay/tm16xx.h line 158
Quoted 4 lines
drivers/auxdisplay/tm16xx.h new file +4
-0+union { +struct i2c_client *i2c; +struct spi_device *spi; + } client;Why? Just drop it. struct device *dev is enough and I can't see the need in this at all.
I'll remove this union and use container_of(dev, struct i2c_client, dev) or container_of(dev, struct spi_device, dev) where the specific client type is needed.
Quoted 17 lines
Quoted 14 lines
drivers/auxdisplay/tm16xx.h new file +14
-0+u8 *spi_buffer; +u8 num_grids; +u8 num_segments; +struct led_classdev main_led; +struct tm16xx_led *leds; +u8 num_leds; +struct tm16xx_digit *digits; +u8 num_digits; +struct work_struct flush_init; +struct work_struct flush_display; +int flush_status; +struct mutex lock;/* prevents concurrent work operations */ +unsigned long *state; +};...
Quoted 4 lines
Quoted 1 line
+ * Copyright (C) 2024 Jean-François Lessard
Year?
Same as above.
Quoted 9 lines
...
drivers/auxdisplay/tm16xx_core.c line 12
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c new file +4
-0+#include <linux/map_to_7segment.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/property.h> Please, follow IWYU principle.
I'll explicitly include all required headers in each source file instead of relying on transitive includes from the header.
Quoted 12 lines
...
drivers/auxdisplay/tm16xx_core.c line 267
Quoted 7 lines
drivers/auxdisplay/tm16xx_core.c new file +7
-0+static ssize_t tm16xx_num_digits_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +struct tm16xx_display *display =dev_get_drvdata (led_cdev->dev->parent); + +return sprintf (buf,"%u\n" , display->num_digits);Should be
sysfs_emit().
Well received.
Quoted 4 lines
Quoted 1 line
+}
...
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c line 283
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+static ssize_t tm16xx_map_seg7_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +memcpy (buf, &map_seg7,sizeof (map_seg7)); +return sizeof (map_seg7); +}Can we use LINEDISP library?
I considered this but have two concerns:
1. It creates attributes under a virtual "linedisp.{n}" device, which conflicts with the coherent LED sysfs design
2. Messages scroll indefinitely. There should be control for single-pass scrolling
I'm willing to contribute improvements to line-display if needed, but this depends on resolving the main LED design question above.
Quoted 11 lines
...
drivers/auxdisplay/tm16xx_core.c line 312
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+static struct attribute *tm16xx_main_led_attrs[] = { + &dev_attr_value.attr, + &dev_attr_num_digits.attr, + &dev_attr_map_seg7.attr, +NULL ,No comma in the terminator entry.
Well received.
Quoted 5 lines
Quoted 2 lines
drivers/auxdisplay/tm16xx_core.c new file +2
-0+}; +ATTRIBUTE_GROUPS (tm16xx_main_led);...
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c line 326
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c new file +4
-0+static int tm16xx_display_init (struct tm16xx_display *display) +{ +unsigned int nbits =tm16xx_led_nbits (display); +dev_dbg (display->dev,"Initializing display\n" );Please, drop all these
dev_dbg()over the code as they are close to useless, use tracers and other mechanisms to debug if required.
Understood, I'll remove the debug noise.
Quoted 4 lines
Also drop unneeded kernel-doc for the (esp. static) functions that have well established meaning (e.g., no need a kernel-doc for device attributes as they should be documented in the ABI).
Understood, I'll remove these kernel-doc.
Quoted 25 lines
Quoted 22 lines
drivers/auxdisplay/tm16xx_core.c new file +22
-0+schedule_work (&display->flush_init); +flush_work (&display->flush_init); +if (display->flush_status <0 ) +return display->flush_status; + +if (tm16xx_init_value) { +tm16xx_value_store (display->main_led.dev,NULL , + tm16xx_init_value, +strlen (tm16xx_init_value)); + }else { +bitmap_fill (display->state, nbits); +schedule_work (&display->flush_display); +flush_work (&display->flush_display); +bitmap_zero (display->state, nbits); +if (display->flush_status <0 ) +return display->flush_status; + } + +dev_info (display->dev,"Display turned on\n" ); + +return 0 ; +}...
Quoted 5 lines
Quoted 1 line
+static int
tm16xx_parse_dt(struct device *dev, struct tm16xx_display *display)Why DT only? No support for other platforms? Why? I think this is just matter of naming the function properly.
You're right, I'll rename it to tm16xx_parse_fwnode since it uses fwnode APIs.
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c line 362
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+{ +struct fwnode_handle *leds_node, *digits_node, *child; +struct tm16xx_led *led; +struct tm16xx_digit *digit; +int max_grid =0 , max_segment =0 ;Why signed?
My oversight - I'll change these to appropriate unsigned types.
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c line 363
Quoted 1 line
drivers/auxdisplay/tm16xx_core.c new file +1
-0+int ret, i, j;Why are i and j signed?
Standard kernel practice uses int for simple loop counters. But I will change to unsigned types for consistency.
Quoted 7 lines
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+u32 segments[TM16XX_DIGIT_SEGMENTS *2 ]; +u32 reg[2 ]; + +/* parse digits */ + digits_node =device_get_named_child_node (dev,"digits" ); +if (digits_node) {
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c line 372
Quoted 3 lines
drivers/auxdisplay/tm16xx_core.c new file +3
-0+ display->num_digits =0 ; +fwnode_for_each_child_node (digits_node, child) + display->num_digits++;Don't we have a
_countAPI for this?
I'll use device_get_child_node_count() instead of manual counting loops.
Quoted 12 lines
drivers/auxdisplay/tm16xx_core.c line 381
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c new file +8
-0+dev_dbg (dev,"Number of digits: %u\n" , display->num_digits); + +if (display->num_digits) { + display->digits =devm_kcalloc (dev, display->num_digits, +sizeof (*display->digits), +GFP_KERNEL ); +if (!display->digits) { +fwnode_handle_put (digits_node);Use RAII instead, we have defined
__free()method for this.
Quoted 8 lines
drivers/auxdisplay/tm16xx_core.c line 386
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+return -ENOMEM ; + } + + i =0 ; +fwnode_for_each_child_node (digits_node, child) {Ditto. Use
_scopedvariant.
Well received.
Quoted 7 lines
drivers/auxdisplay/tm16xx_core.c line 390
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c new file +3
-0+ digit = &display->digits[i]; + ret =fwnode_property_read_u32 (child,"reg" , + reg);One line.
Well received.
Quoted 5 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ if (ret < 0) {Can it be positive? Here and everywhere else, if there is no positive return, use 'if (ret)'.
I'll change error checks to if (ret) where functions only return 0 on success or negative on error.
Quoted 19 lines
Quoted 18 lines
drivers/auxdisplay/tm16xx_core.c new file +18
-0+fwnode_handle_put (child); +fwnode_handle_put (digits_node); +return ret; + } + + ret =fwnode_property_read_u32_array (child, +"segments" , + segments, +TM16XX_DIGIT_SEGMENTS *2 ); +if (ret <0 ) { +fwnode_handle_put (child); +fwnode_handle_put (digits_node); +return ret; + } + +for (j =0 ; j <TM16XX_DIGIT_SEGMENTS ; ++j) { + digit->segments[j].grid = segments[2 * j]; + digit->segments[j].segment = segments[2 * j +1 ];
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c line 410
Quoted 1 line
drivers/auxdisplay/tm16xx_core.c new file +1
-0+ max_grid = umax(max_grid,Firstly, the variables made signed and then specifically force them to be unsigned in the macro. Weird. Can we make them to be a proper type and use
max()?
Will change to unsigned types per above.
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c line 411
Quoted 1 line
drivers/auxdisplay/tm16xx_core.c new file +1
-0+ digit->segments[j].grid);One line
Well received.
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c line 413
Quoted 2 lines
drivers/auxdisplay/tm16xx_core.c new file +2
-0+ max_segment =umax (max_segment, + digit->segments[j].segment);As per above comments.
Will change to unsigned types per above.
Quoted 9 lines
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c new file +9
-0+ } + digit->value =0 ; + i++; + } + +fwnode_handle_put (digits_node); + } + } +
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c line 428
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+/* parse leds */ + leds_node =device_get_named_child_node (dev,"leds" ); +if (leds_node) { + display->num_leds =0 ; +fwnode_for_each_child_node (leds_node, child) + display->num_leds++;As per above.
I'll use device_get_child_node_count() instead of manual counting loops.
Quoted 15 lines
Quoted 14 lines
drivers/auxdisplay/tm16xx_core.c new file +14
-0+dev_dbg (dev,"Number of LEDs: %u\n" , display->num_leds); + +if (display->num_leds) { + display->leds =devm_kcalloc (dev, display->num_leds, +sizeof (*display->leds), +GFP_KERNEL ); +if (!display->leds) { +fwnode_handle_put (leds_node); +return -ENOMEM ; + } + + i =0 ; +fwnode_for_each_child_node (leds_node, child) { + led = &display->leds[i];
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c line 446
Quoted 3 lines
drivers/auxdisplay/tm16xx_core.c new file +3
-0+ ret =fwnode_property_read_u32_array (child, +"reg" , reg, +2 );Make it one line.
Well received.
Quoted 32 lines
Quoted 31 lines
drivers/auxdisplay/tm16xx_core.c new file +31
-0+if (ret <0 ) { +fwnode_handle_put (child); +fwnode_handle_put (leds_node); +return ret; + } + + led->grid = reg[0 ]; + led->segment = reg[1 ]; + max_grid =umax (max_grid, led->grid); + max_segment =umax (max_segment, led->segment); + i++; + } + } + +fwnode_handle_put (leds_node); + } + +if (max_grid >= display->controller->max_grids) { +dev_err (dev,"grid %u exceeds controller max_grids %u\n" , + max_grid, display->controller->max_grids); +return -EINVAL ; + } + +if (max_segment >= display->controller->max_segments) { +dev_err (dev,"segment %u exceeds controller max_segments %u\n" , + max_segment, display->controller->max_segments); +return -EINVAL ; + } + + display->num_grids = max_grid +1 ; + display->num_segments = max_segment +1 ;
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c line 480
Quoted 2 lines
drivers/auxdisplay/tm16xx_core.c new file +2
-0+dev_dbg (dev,"Number of grids: %u\n" , display->num_grids); +dev_dbg (dev,"Number of segments: %u\n" , display->num_segments);I didn't get this. You mean that they are not strictly 7-segment ones?
The terminology is confusing - "segment" is used both for 7-segment digits (which are indeed 7-segment) and for controller matrix coordinates (grid,segment) from datasheets. Controllers support varying numbers of segments For individual LED icons, not necessarily related to 7-segment displays. I'll add a comment to clarify this distinction.
Quoted 6 lines
Quoted 3 lines
drivers/auxdisplay/tm16xx_core.c new file +3
-0+ +return 0 ; +}...
Quoted 10 lines
drivers/auxdisplay/tm16xx_core.c line 497
Quoted 7 lines
drivers/auxdisplay/tm16xx_core.c new file +7
-0+int tm16xx_probe (struct tm16xx_display *display) +{ +struct device *dev = display->dev; +struct led_classdev *main = &display->main_led; +struct fwnode_handle *leds_node, *child; +unsigned int nbits; +int ret, i;Why is i signed?
Will change to unsigned types per above.
Quoted 10 lines
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c new file +9
-0+dev_dbg (dev,"Probing device\n" ); + ret =tm16xx_parse_dt (dev, display); +if (ret <0 ) +return dev_err_probe (dev, ret,"Failed to parse device tree\n" ); + + nbits =tm16xx_led_nbits (display); + display->state =devm_bitmap_zalloc (dev, nbits,GFP_KERNEL ); +if (!display->state) +return -ENOMEM ;
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c line 509
Quoted 1 line
drivers/auxdisplay/tm16xx_core.c new file +1
-0+mutex_init (&display->lock);
devm_mutex_init()
Well received.
Quoted 12 lines
drivers/auxdisplay/tm16xx_core.c line 518
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c new file +8
-0+INIT_WORK (&display->flush_init, tm16xx_display_flush_init); +INIT_WORK (&display->flush_display, tm16xx_display_flush_data); +/* Initialize main LED properties */ +if (dev->of_node) + main->name = dev->of_node->name; +if (!main->name) + main->name ="display" ; +device_property_read_string (dev,"label" , &main->name);My gosh. This is done in the LED core if we even need this...
This relates to the LED subsystem integration question. If my design approach is acceptable, I'll review the LED core implementation to avoid duplicating this logic if possible.
Quoted 61 lines
Quoted 58 lines
drivers/auxdisplay/tm16xx_core.c new file +57
-0+ main->max_brightness = display->controller->max_brightness; +device_property_read_u32 (dev,"max-brightness" , &main->max_brightness); + main->max_brightness =umin (main->max_brightness, + display->controller->max_brightness); + + main->brightness = main->max_brightness; +device_property_read_u32 (dev,"default-brightness" , &main->brightness); + main->brightness =umin (main->brightness, main->max_brightness); + + main->brightness_set = tm16xx_brightness_set; + main->groups = tm16xx_main_led_groups; + main->flags =LED_RETAIN_AT_SHUTDOWN |LED_CORE_SUSPENDRESUME ; + + ret =led_classdev_register (dev, main); +if (ret <0 ) +return dev_err_probe (dev, ret,"Failed to register main LED\n" ); + i =0 ; + leds_node =device_get_named_child_node (dev,"leds" ); +fwnode_for_each_child_node (leds_node, child) { +struct tm16xx_led *led = &display->leds[i]; +struct led_init_data led_init = { + .fwnode = child, + .devicename =dev_name (main->dev), + .devname_mandatory = true, + .default_label ="led" , + }; + led->cdev.max_brightness =1 ; + led->cdev.brightness_set = tm16xx_led_set; + led->cdev.flags =LED_RETAIN_AT_SHUTDOWN | +LED_CORE_SUSPENDRESUME ; + + ret =led_classdev_register_ext (dev, &led->cdev, &led_init); +if (ret <0 ) { +fwnode_handle_put (child); +dev_err_probe (dev, ret,"Failed to register LED %s\n" , + led->cdev.name); + goto unregister_leds; + } + + i++; + } + + ret =tm16xx_display_init (display); +if (ret <0 ) { +dev_err_probe (dev, ret,"Failed to initialize display\n" ); + goto unregister_leds; + } + +return 0 ; + +unregister_leds: +while (i--) +led_classdev_unregister (&display->leds[i].cdev); + +led_classdev_unregister (main); +return ret; +}...
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c line 589
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+void tm16xx_remove (struct tm16xx_display *display) +{ +unsigned int nbits =tm16xx_led_nbits (display); +struct tm16xx_led *led; +dev_dbg (display->dev,"Removing display\n" );Unneeded noise.
Well received.
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c line 596
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+/* +* Unregister LEDs first to immediately stop trigger activity. +* This prevents LED triggers from attempting to access hardware +* after it's been disconnected or driver unloaded. +*/ +for (int i =0 ; i < display->num_leds; i++) {Why iterator is signed?
Will change to unsigned types per above.
Quoted 15 lines
Quoted 14 lines
drivers/auxdisplay/tm16xx_core.c new file +14
-0+ led = &display->leds[i]; +led_classdev_unregister (&led->cdev); + } +led_classdev_unregister (&display->main_led); + +/* Clear display state */ +bitmap_zero (display->state, nbits); +schedule_work (&display->flush_display); +flush_work (&display->flush_display); + +/* Turn off display */ + display->main_led.brightness =LED_OFF ; +schedule_work (&display->flush_init); +flush_work (&display->flush_init);
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c line 612
Quoted 1 line
drivers/auxdisplay/tm16xx_core.c new file +1
-0+dev_info (display->dev,"Display turned off\n" );Unneeded noise.
Well received.
Quoted 2 lines
Quoted 1 line
+}
Thank you for the detailed review. The main question remains about the LED subsystem integration approach. I'd appreciate your guidance on the best design direction.
Quoted 2 lines · Jean-François Lessard
Le 25 août 2025 11 h 14 min 21 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 1 line · Jean-François Lessard
...
Quoted 10 lines
Quoted 7 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+Date: August 2025 +KernelVersion: 6.17The Date should be approximate date of the kernel release (alternatively, -rc1 of that). The version is estimated version where ABI can be found first.
Both of these need to be changed.
Given that 6.17-rc3 was just released, should I target 6.18 for the kernel version and use a March 2025 date for the estimated release timeframe?
6.18
The date is not in the past, obviously. You can consult with this site:
https://hansen.beer/~dave/phb/
...
Quoted 14 lines
Quoted 2 lines
So, the driver is under auxdisplay, but at the same time it completely relies on LED subsystem... What's going on here?
The design integrates with the LED subsystem for two main reasons:
1. Brightness control:
The entire display brightness is controlled at the display level (individual LED icons can only be on/off via their brightness attributes). The LED subsystem provides established mechanisms for this.2. Coherent sysfs interface:
This provides consistent/sys/class/leds/displayfor display-level controls and /sys/class/leds/display::{function} for individual icons.
Quoted 8 lines
I'm seeking your guidance on the best design for the auxdisplay subsystem.
Quoted 3 lines
Btw, have you seen
https://lore.kernel.org/linux-leds/[email protected]/
? And if so, what're your takeaways? (Yes, I know that's about different HW)I've read the thread but I'm not clear on the specific point you're making. Could you clarify what aspect I should focus on?
If you have a LED matrix, perhaps we can consider different approaches as well. (It's all about the current HW, is it a 7-segment or arbitrary display, if the
former, that discussion is unrelated)
Quoted 5 lines
(Though, my personal opinion is that using auxdisplay for keyboard LEDs doesn't really make sense. I think it would be better to properly implement it the required mechanism into input subsystem, with maybe some integration with the leds subsystem. Just a quick opinion, I do not master all aspects of this question at all.)
...
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
+ * Copyright (C) 2024 Jean-François Lessard
My calendar shows something different.
The original code was developed in 2024, though it's being submitted in 2025.
But haven't you changed it in 2025?
...
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
+#include <
linux/bitmap.h>Is this used?
Yes,
display->stateis a bitmap. I'll move this include totm16xx_core.csince it's not used in the header itself.
Yes, that's what I meant "used by this header file".
...
Quoted 11 lines
Quoted 7 lines
drivers/auxdisplay/tm16xx.h line 158
Quoted 4 lines
drivers/auxdisplay/tm16xx.h new file +4
-0+union { +struct i2c_client *i2c; +struct spi_device *spi; + } client;Why? Just drop it. struct device *dev is enough and I can't see the need in this at all.
I'll remove this union and use
container_of(dev, struct i2c_client, dev)orcontainer_of(dev, struct spi_device, dev)where the specific client type is needed.
This is in correlation with the regmap proposal.
...
Quoted 9 lines
Quoted 8 lines
drivers/auxdisplay/tm16xx_core.c line 283
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+static ssize_t tm16xx_map_seg7_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +memcpy (buf, &map_seg7,sizeof (map_seg7)); +return sizeof (map_seg7); +}Can we use LINEDISP library?
Quoted 4 lines
I considered this but have two concerns:
1. It creates attributes under a virtual "linedisp.{n}" device, which conflicts with the coherent LED sysfs design
It creates the specific attributes for the 7-segment HW, So look at it from this angle. We have well established library and we expect 7-seg drivers will use it to make sure that user space may be written in uniform way.
Quoted 1 line
2. Messages scroll indefinitely. There should be control for single-pass scrolling
If we miss that, add it to linedisp. I wouldn't mind, actually I will be in favour of the development of that library.
Quoted 2 lines
I'm willing to contribute improvements to line-display if needed, but this depends on resolving the main LED design question above.
...
Quoted 7 lines
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c line 372
Quoted 3 lines
drivers/auxdisplay/tm16xx_core.c new file +3
-0+ display->num_digits =0 ; +fwnode_for_each_child_node (digits_node, child) + display->num_digits++;Don't we have a
_countAPI for this?I'll use
device_get_child_node_count()instead of manual counting loops.
fwnode_get_child_node_count() I assume you meant.
...
Quoted 10 lines
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c line 480
Quoted 2 lines
drivers/auxdisplay/tm16xx_core.c new file +2
-0+dev_dbg (dev,"Number of grids: %u\n" , display->num_grids); +dev_dbg (dev,"Number of segments: %u\n" , display->num_segments);I didn't get this. You mean that they are not strictly 7-segment ones?
The terminology is confusing - "segment" is used both for 7-segment digits (which are indeed 7-segment) and for controller matrix coordinates (grid,segment) from datasheets. Controllers support varying numbers of segments For individual LED icons, not necessarily related to 7-segment displays. I'll add a comment to clarify this distinction.
Hmm... Maybe try to rename these 'segments' to something else, like 'hwseg' (find a better name).
...
Quoted 9 lines
Quoted 8 lines
drivers/auxdisplay/tm16xx_core.c line 518
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+/* Initialize main LED properties */ +if (dev->of_node) + main->name = dev->of_node->name; +if (!main->name) + main->name ="display" ; +device_property_read_string (dev,"label" , &main->name);My gosh. This is done in the LED core if we even need this...
Quoted 3 lines
This relates to the LED subsystem integration question. If my design approach is acceptable, I'll review the LED core implementation to avoid duplicating this logic if possible.
I think if you integrate LED for special LED icons and linedisp for 7-segment into a single driver, it's fine. I just can't speak about LED icons case. The 7-seg LGTM (assuming linedisp and other existing APIs/ABIs to use, if required).
Signature · 2 lines
With Best Regards, Andy Shevchenko
Le 26 août 2025 11 h 22 min 56 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 12 lines · Jean-François Lessard
Quoted 2 lines
Le 25 août 2025 11 h 14 min 21 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 1 line · Jean-François Lessard
...
Quoted 5 lines
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+Date: August 2025 +KernelVersion: 6.17The Date should be approximate date of the kernel release (alternatively, -rc1 of that). The version is estimated version where ABI can be found first.
Quoted 9 lines
Quoted 4 lines
Quoted 1 line
Both of these need to be changed.
Given that 6.17-rc3 was just released, should I target 6.18 for the kernel version and use a March 2025 date for the estimated release timeframe?
6.18
The date is not in the past, obviously. You can consult with this site:
https://hansen.beer/~dave/phb/
Thanks for the correction and link. I'll update to 6.18 with appropriate future date.
Quoted 22 lines
...
Quoted 20 lines
Quoted 2 lines
So, the driver is under auxdisplay, but at the same time it completely relies on LED subsystem... What's going on here?
The design integrates with the LED subsystem for two main reasons:
1. Brightness control:
The entire display brightness is controlled at the display level (individual LED icons can only be on/off via their brightness attributes). The LED subsystem provides established mechanisms for this.2. Coherent sysfs interface:
This provides consistent/sys/class/leds/displayfor display-level controls and /sys/class/leds/display::{function} for individual icons.I'm seeking your guidance on the best design for the auxdisplay subsystem.
Quoted 3 lines
Btw, have you seen
https://lore.kernel.org/linux-leds/[email protected]/
? And if so, what're your takeaways? (Yes, I know that's about different HW)
Quoted 7 lines
Quoted 2 lines
I've read the thread but I'm not clear on the specific point you're making. Could you clarify what aspect I should focus on?
If you have a LED matrix, perhaps we can consider different approaches as well. (It's all about the current HW, is it a 7-segment or arbitrary display, if the former, that discussion is unrelated)
TM16xx devices are primarily 7-segment displays with additional LED icon and key scanning capabilities.
Quoted 8 lines
Quoted 5 lines
(Though, my personal opinion is that using auxdisplay for keyboard LEDs doesn't really make sense. I think it would be better to properly implement it the required mechanism into input subsystem, with maybe some integration with the leds subsystem. Just a quick opinion, I do not master all aspects of this question at all.)
...
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
+ * Copyright (C) 2024 Jean-François Lessard
My calendar shows something different.
The original code was developed in 2024, though it's being submitted in 2025.
But haven't you changed it in 2025?
You're right, I'll update the copyright to 2025.
Quoted 11 lines
...
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
+#include <
linux/bitmap.h>Is this used?
Yes,
display->stateis a bitmap. I'll move this include totm16xx_core.csince it's not used in the header itself.Yes, that's what I meant "used by this header file".
I'll move bitmap.h to the source file.
Quoted 10 lines
...
Quoted 8 lines
Quoted 7 lines
drivers/auxdisplay/tm16xx.h line 158
Quoted 4 lines
drivers/auxdisplay/tm16xx.h new file +4
-0+union { +struct i2c_client *i2c; +struct spi_device *spi; + } client;Why? Just drop it. struct device *dev is enough and I can't see the need in this at all.
Quoted 6 lines
Quoted 3 lines
I'll remove this union and use
container_of(dev, struct i2c_client, dev)orcontainer_of(dev, struct spi_device, dev)where the specific client type is needed.This is in correlation with the regmap proposal.
I'll address the regmap evaluation in the cover letter of the next submission as you requested.
The union removal will be addressed too.
Quoted 13 lines
...
Quoted 11 lines
Quoted 8 lines
drivers/auxdisplay/tm16xx_core.c line 283
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+static ssize_t tm16xx_map_seg7_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +memcpy (buf, &map_seg7,sizeof (map_seg7)); +return sizeof (map_seg7); +}Can we use LINEDISP library?
I considered this but have two concerns:
Quoted 8 lines
Quoted 2 lines
1. It creates attributes under a virtual "linedisp.{n}" device, which conflicts with the coherent LED sysfs design
It creates the specific attributes for the 7-segment HW, So look at it from this angle. We have well established library and we expect 7-seg drivers will use it to make sure that user space may be written in uniform way.
To provide a coherent user interface, I'd like to propose extending linedisp to optionally attach attributes to an existing device rather than always creating virtual devices. This would create a unified /sys/class/leds/{label}/ interface for content, brightness, and icons while maintaining linedisp's established APIs.
If device attachment isn't feasible, could linedisp at minimum accept a device name parameter to create /sys/virtual/linedisp-{label} instead of generic linedisp.{n}?
I'm happy to implement these linedisp enhancements as part of the TM16xx integration if you find the approach acceptable.
Quoted 5 lines
Quoted 1 line
2. Messages scroll indefinitely. There should be control for single-pass scrolling
If we miss that, add it to linedisp. I wouldn't mind, actually I will be in favour of the development of that library.
I'll submit patches to extend linedisp with missing functionality (like single-pass scrolling control) as part of this integration.
Quoted 11 lines
Quoted 2 lines
I'm willing to contribute improvements to line-display if needed, but this depends on resolving the main LED design question above.
...
Quoted 6 lines
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c line 372
Quoted 3 lines
drivers/auxdisplay/tm16xx_core.c new file +3
-0+ display->num_digits =0 ; +fwnode_for_each_child_node (digits_node, child) + display->num_digits++;Don't we have a
_countAPI for this?
Quoted 4 lines
Quoted 1 line
I'll use
device_get_child_node_count()instead of manual counting loops.
fwnode_get_child_node_count()I assume you meant.
Correct, my oversight. I'll use the fwnode variant.
Quoted 7 lines
...
Quoted 5 lines
Quoted 4 lines
drivers/auxdisplay/tm16xx_core.c line 480
Quoted 2 lines
drivers/auxdisplay/tm16xx_core.c new file +2
-0+dev_dbg (dev,"Number of grids: %u\n" , display->num_grids); +dev_dbg (dev,"Number of segments: %u\n" , display->num_segments);I didn't get this. You mean that they are not strictly 7-segment ones?
Quoted 9 lines
Quoted 5 lines
The terminology is confusing - "segment" is used both for 7-segment digits (which are indeed 7-segment) and for controller matrix coordinates (grid,segment) from datasheets. Controllers support varying numbers of segments For individual LED icons, not necessarily related to 7-segment displays. I'll add a comment to clarify this distinction.
Hmm... Maybe try to rename these 'segments' to something else, like 'hwseg' (find a better name).
Good point. I'll use a different name to distinguish from 7-segment terminology.
Quoted 11 lines
...
Quoted 9 lines
Quoted 8 lines
drivers/auxdisplay/tm16xx_core.c line 518
Quoted 6 lines
drivers/auxdisplay/tm16xx_core.c new file +6
-0+/* Initialize main LED properties */ +if (dev->of_node) + main->name = dev->of_node->name; +if (!main->name) + main->name ="display" ; +device_property_read_string (dev,"label" , &main->name);My gosh. This is done in the LED core if we even need this...
Quoted 8 lines
Quoted 3 lines
This relates to the LED subsystem integration question. If my design approach is acceptable, I'll review the LED core implementation to avoid duplicating this logic if possible.
I think if you integrate LED for special LED icons and linedisp for 7-segment into a single driver, it's fine. I just can't speak about LED icons case. The 7-seg LGTM (assuming linedisp and other existing APIs/ABIs to use, if required).
I think linedisp is the way to go if we can provide a consistent user space API.
Le 25 août 2025 13 h 48 min 45 s HAE, "Jean-François Lessard" <[email protected]> a écrit :
Quoted 2 lines
Le 25 août 2025 11 h 14 min 21 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 1 line · Jean-François Lessard
...
Quoted 29 lines
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c line 372
Quoted 2 lines
drivers/auxdisplay/tm16xx_core.c new file +2
-0+fwnode_for_each_child_node (digits_node, child) + display->num_digits++;Don't we have a
_countAPI for this?I'll use
device_get_child_node_count()instead of manual counting loops.Quoted 12 lines
drivers/auxdisplay/tm16xx_core.c line 381
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c new file +8
-0+dev_dbg (dev,"Number of digits: %u\n" , display->num_digits); + +if (display->num_digits) { + display->digits =devm_kcalloc (dev, display->num_digits, +sizeof (*display->digits), +GFP_KERNEL ); +if (!display->digits) { +fwnode_handle_put (digits_node);Use RAII instead, we have defined
__free()method for this.Quoted 8 lines
drivers/auxdisplay/tm16xx_core.c line 386
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+return -ENOMEM ; + } + + i =0 ; +fwnode_for_each_child_node (digits_node, child) {Ditto. Use
_scopedvariant.
Quoted 2 lines
Well received.
After further investigation, _scoped variant exists for device_for_each_child_node_scoped() but not for fwnode_for_each_child_node().
I suggest to include an additional patch in next submission to add to include/linux/property.h:
#define fwnode_for_each_child_node_scoped(fwnode, child) \ for (struct fwnode_handle *child __free(fwnode_handle) = \ fwnode_get_next_child_node(fwnode, NULL); \ child; child = fwnode_get_next_child_node(fwnode, child))
#define fwnode_for_each_named_child_node_scoped(fwnode, child, name) \ fwnode_for_each_child_node_scoped(fwnode, child) \ for_each_if(fwnode_name_eq(child, name))
#define fwnode_for_each_available_child_node_scoped(fwnode, child) \ for (struct fwnode_handle *child __free(fwnode_handle) = \ fwnode_get_next_available_child_node(fwnode, NULL); \ child; child = fwnode_get_next_available_child_node(fwnode, child))
...
Quoted 3 lines · Jean-François Lessard
Le 25 août 2025 13 h 48 min 45 s HAE, "Jean-François Lessard" <[email protected]> a écrit :
Quoted 2 lines
Le 25 août 2025 11 h 14 min 21 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 1 line · Jean-François Lessard
...
Quoted 41 lines
Quoted 28 lines
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c line 372
Quoted 2 lines
drivers/auxdisplay/tm16xx_core.c new file +2
-0+fwnode_for_each_child_node (digits_node, child) + display->num_digits++;Don't we have a
_countAPI for this?I'll use
device_get_child_node_count()instead of manual counting loops.Quoted 12 lines
drivers/auxdisplay/tm16xx_core.c line 381
Quoted 9 lines
drivers/auxdisplay/tm16xx_core.c new file +8
-0+dev_dbg (dev,"Number of digits: %u\n" , display->num_digits); + +if (display->num_digits) { + display->digits =devm_kcalloc (dev, display->num_digits, +sizeof (*display->digits), +GFP_KERNEL ); +if (!display->digits) { +fwnode_handle_put (digits_node);Use RAII instead, we have defined
__free()method for this.Quoted 7 lines
drivers/auxdisplay/tm16xx_core.c line 386
Quoted 5 lines
drivers/auxdisplay/tm16xx_core.c new file +5
-0+return -ENOMEM ; + } + + i =0 ; +fwnode_for_each_child_node (digits_node, child) {Ditto. Use
_scopedvariant.Quoted 1 line
Well received.
After further investigation,
_scopedvariant exists fordevice_for_each_child_node_scoped()but not forfwnode_for_each_child_node().I suggest to include an additional patch in next submission to add to
include/linux/property.h:#define fwnode_for_each_child_node_scoped(fwnode, child) \ for (struct fwnode_handle *child __free(fwnode_handle) = \ fwnode_get_next_child_node(fwnode, NULL); \ child; child = fwnode_get_next_child_node(fwnode, child))
Quoted 8 lines
#define fwnode_for_each_named_child_node_scoped(fwnode, child, name) \ fwnode_for_each_child_node_scoped(fwnode, child) \ for_each_if(fwnode_name_eq(child, name))#define fwnode_for_each_available_child_node_scoped(fwnode, child) \ for (struct fwnode_handle *child __free(fwnode_handle) = \ fwnode_get_next_available_child_node(fwnode, NULL); \ child; child = fwnode_get_next_available_child_node(fwnode, child))
LGTM!
Signature · 2 lines
With Best Regards, Andy Shevchenko
PATCH v4 4/6 auxdisplay: TM16xx: Add keypad support for scanning matrix keys
In reply to Jean-François LessardAdd support for keypad scanning on TM16xx-compatible auxiliary display controllers. It handles keypad initialization, scanning, and input reporting for matrix keys managed by the TM16xx devices.
Key features include:
- Input device registration configured by device properties (poll-interval, linux,keymap, autorepeat)
- Key state tracking using managed bitmaps
- Matrix scanning and event reporting integrated with Linux input subsystem
This code is separated from main core driver to improve maintainability and reviewability.
---
Notes:
checkpatch reports false positives that are intentionally ignored:
COMPLEX_MACRO/MACRO_ARG_REUSE for tm16xx_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.
MAINTAINERS | 1 + drivers/auxdisplay/Kconfig | 11 +- drivers/auxdisplay/Makefile | 1 + drivers/auxdisplay/tm16xx.h | 27 ++++ drivers/auxdisplay/tm16xx_core.c | 4 + drivers/auxdisplay/tm16xx_keypad.c | 208 +++++++++++++++++++++++++++++ 6 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 drivers/auxdisplay/tm16xx_keypad.c
MAINTAINERS +1 -0
@@ -25409,6 +25409,7 @@ F: Documentation/ABI/testing/sysfs-class-leds-tm16xx F: Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml F: drivers/auxdisplay/tm16xx.h F: drivers/auxdisplay/tm16xx_core.c +F: drivers/auxdisplay/tm16xx_keypad.c TMIO/SDHI MMC DRIVER M: Wolfram Sang <[email protected]>
drivers/auxdisplay/Kconfig +10 -1
@@ -527,11 +527,14 @@ config SEG_LED_GPIO will be called seg-led-gpio. config TM16XX - tristate "TM16XX-compatible 7-segment LED controllers" + 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 + select TM16XX_KEYPAD if (INPUT) help This driver supports the following TM16XX compatible I2C and SPI 7-segment led display chips:
@@ -544,6 +547,12 @@ config TM16XX This driver can also be built as a module. If so, the module will be called tm16xx. +config TM16XX_KEYPAD + bool + depends on TM16XX + help + Enable keyscan support for TM16XX driver. + # # Character LCD with non-conforming interface section #
drivers/auxdisplay/Makefile +1 -0
@@ -18,3 +18,4 @@ obj-$(CONFIG_PARPORT_PANEL) += panel.o obj-$(CONFIG_SEG_LED_GPIO) += seg-led-gpio.o obj-$(CONFIG_TM16XX) += tm16xx.o tm16xx-y += tm16xx_core.o +tm16xx-$(CONFIG_TM16XX_KEYPAD) += tm16xx_keypad.o
drivers/auxdisplay/tm16xx.h +27 -0
@@ -104,6 +104,7 @@struct tm16xx_display ;struct tm16xx_digit ;struct tm16xx_led ; +struct tm16xx_keypad ;/** * DOC: struct tm16xx_controller - Controller-specific operations and limits
@@ -136,6 +137,7 @@ struct tm16xx_controller {* @controller: Controller-specific function table and limits. * @client: Union of I2C and SPI client pointers. * @spi_buffer: DMA-safe buffer for SPI transactions, or NULL for I2C. +* @keypad: Opaque pointer to tm16xx_keypad struct. * @num_grids: Number of controller grids in use. * @num_segments: Number of controller segments in use. * @main_led: LED class device for the entire display.
@@ -157,6 +159,7 @@ struct tm16xx_display {struct spi_device *spi; } client;u8 *spi_buffer; +struct tm16xx_keypad *keypad;u8 num_grids;u8 num_segments;struct led_classdev main_led;
@@ -174,4 +177,28 @@ struct tm16xx_display {int tm16xx_probe (struct tm16xx_display *display);void tm16xx_remove (struct tm16xx_display *display); +/* keypad support */ +#if IS_ENABLED (CONFIG_TM16XX_KEYPAD ) +int tm16xx_keypad_probe (struct tm16xx_display *display); +void tm16xx_set_key (const struct tm16xx_display *display,const u8 row, +const u8 col,const bool pressed); +#else +static inline int tm16xx_keypad_probe (struct tm16xx_display *display) +{ +return 0 ; +} + +static inline void tm16xx_set_key (const struct tm16xx_display *display, +const u8 row,const u8 col, +const bool pressed) +{ +} +#endif + +#define tm16xx_for_each_key (display, _r, _c) \ + for (unsigned int _r = 0; \ + _r < (display)->controller->max_key_rows; _r++) \ + for (unsigned int _c = 0; \ + _c < (display)->controller->max_key_cols; _c++) +#endif /* _TM16XX_H */
drivers/auxdisplay/tm16xx_core.c +4 -0
@@ -566,6 +566,10 @@ int tm16xx_probe(struct tm16xx_display *display) goto unregister_leds; } + ret =tm16xx_keypad_probe (display); +if (ret <0 ) +dev_warn (dev,"Failed to initialize keypad: %d\n" , ret); +return 0 ; unregister_leds:
drivers/auxdisplay/tm16xx_keypad.c new file +208 -0
208 lines not on this page · raw message
Signature · 1 line
2.43.0
PATCH v4 5/6 auxdisplay: TM16xx: Add support for I2C-based controllers
In reply to Jean-François LessardAdd support for TM16xx-compatible auxiliary display controllers connected via the I2C bus.
The implementation includes:
- I2C driver registration and initialization
- Probe/remove logic for I2C devices
- Controller-specific handling and communication sequences
- Integration with the TM16xx core driver for common functionality
This allows platforms using TM16xx or compatible controllers over I2C to be managed by the TM16xx driver infrastructure.
--- MAINTAINERS | 1 + drivers/auxdisplay/Kconfig | 7 + drivers/auxdisplay/Makefile | 1 + drivers/auxdisplay/tm16xx_i2c.c | 332 ++++++++++++++++++++++++++++++++ 4 files changed, 341 insertions(+) create mode 100644 drivers/auxdisplay/tm16xx_i2c.c
MAINTAINERS +1 -0
@@ -25409,6 +25409,7 @@ F: Documentation/ABI/testing/sysfs-class-leds-tm16xx F: Documentation/devicetree/bindings/auxdisplay/titanmec,tm16xx.yaml F: drivers/auxdisplay/tm16xx.h F: drivers/auxdisplay/tm16xx_core.c +F: drivers/auxdisplay/tm16xx_i2c.c F: drivers/auxdisplay/tm16xx_keypad.c TMIO/SDHI MMC DRIVER
drivers/auxdisplay/Kconfig +7 -0
@@ -535,6 +535,7 @@ config TM16XX select LEDS_TRIGGERS select INPUT_MATRIXKMAP select TM16XX_KEYPAD if (INPUT) + select TM16XX_I2C if (I2C) help This driver supports the following TM16XX compatible I2C and SPI 7-segment led display chips:
@@ -553,6 +554,12 @@ config TM16XX_KEYPAD help Enable keyscan support for TM16XX driver. +config TM16XX_I2C + tristate + depends on TM16XX + help + Enable I2C support for TM16XX driver. + # # Character LCD with non-conforming interface section #
drivers/auxdisplay/Makefile +1 -0
@@ -19,3 +19,4 @@ obj-$(CONFIG_SEG_LED_GPIO) += seg-led-gpio.o obj-$(CONFIG_TM16XX) += tm16xx.o tm16xx-y += tm16xx_core.o tm16xx-$(CONFIG_TM16XX_KEYPAD) += tm16xx_keypad.o +obj-$(CONFIG_TM16XX_I2C) += tm16xx_i2c.o
drivers/auxdisplay/tm16xx_i2c.c new file +332 -0
332 lines not on this page · raw message
Signature · 1 line
2.43.0
Re: [PATCH v4 5/6] auxdisplay: TM16xx: Add support for I2C-based controllers
Quoted 11 lines · Jean-François Lessard
Add support for TM16xx-compatible auxiliary display controllers connected via the I2C bus.
The implementation includes:
- I2C driver registration and initialization
- Probe/remove logic for I2C devices
- Controller-specific handling and communication sequences
- Integration with the TM16xx core driver for common functionalityThis allows platforms using TM16xx or compatible controllers over I2C to be managed by the TM16xx driver infrastructure.
...
drivers/auxdisplay/tm16xx_i2c.c line 10
Quoted 2 lines
drivers/auxdisplay/tm16xx_i2c.c new file +2
-0+#include <linux/i2c.h> +#include <linux/mod_devicetable.h>
IWYU everywhere, too little header inclusions, you use much more.
drivers/auxdisplay/tm16xx_i2c.c line 58
Quoted 4 lines
drivers/auxdisplay/tm16xx_i2c.c new file +3
-0+static int tm16xx_i2c_write (struct tm16xx_display *display,u8 *data,size_t len) +{ +dev_dbg (display->dev,"i2c_write %*ph" , (char )len, data);
Noise.
Quoted 4 lines
drivers/auxdisplay/tm16xx_i2c.c new file +4
-0+/* expected sequence: S Command [A] Data [A] P */ +struct i2c_msg msg = { + .addr = data[0 ] >>1 , + .flags =0 ,
drivers/auxdisplay/tm16xx_i2c.c line 73
Quoted 10 lines
drivers/auxdisplay/tm16xx_i2c.c new file +10
-0+ .len = len - 1, + .buf = &data[1], + }; +int ret; + + ret =i2c_transfer (display->client.i2c->adapter, &msg,1 ); +if (ret <0 ) +return ret; + +return (ret ==1 ) ?0 : -EIO ;
Can we use regmap for all parts of the driver? Why not?
Quoted 1 line
+}
...
drivers/auxdisplay/tm16xx_i2c.c line 283
Quoted 10 lines
drivers/auxdisplay/tm16xx_i2c.c new file +9
-0+static const struct tm16xx_controller fd6551_controller = { + .max_grids =5 , + .max_segments =7 , + .max_brightness =8 , + .max_key_rows =0 , + .max_key_cols =0 , + .init = fd6551_init, + .data = fd655_data, + .keys =NULL ,
Redundant initialiser.
Quoted 1 line
+};
...
Quoted 1 line
+#if
IS_ENABLED(CONFIG_OF)
No, please remove all these ugly ifdefferies.
Quoted 9 lines
drivers/auxdisplay/tm16xx_i2c.c new file +9
-0+static const struct of_device_id tm16xx_i2c_of_match[] = { + { .compatible ="titanmec,tm1650" , .data = &tm1650_controller }, + { .compatible ="fdhisi,fd6551" , .data = &fd6551_controller }, + { .compatible ="fdhisi,fd655" , .data = &fd655_controller }, + { .compatible ="winrise,hbs658" , .data = &hbs658_controller }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, tm16xx_i2c_of_match); +#endif
...
drivers/auxdisplay/tm16xx_i2c.c line 320
Quoted 1 line
drivers/auxdisplay/tm16xx_i2c.c new file +1
-0+ .of_match_table = of_match_ptr(tm16xx_i2c_of_match),
Definitely no to of_match_ptr(). Must be not used in a new code.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v4 5/6] auxdisplay: TM16xx: Add support for I2C-based controllers
Le 25 août 2025 11 h 18 min 27 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 13 lines · Jean-François Lessard
Quoted 11 lines
Add support for TM16xx-compatible auxiliary display controllers connected via the I2C bus.
The implementation includes:
- I2C driver registration and initialization
- Probe/remove logic for I2C devices
- Controller-specific handling and communication sequences
- Integration with the TM16xx core driver for common functionalityThis allows platforms using TM16xx or compatible controllers over I2C to be managed by the TM16xx driver infrastructure.
Quoted 7 lines
...
drivers/auxdisplay/tm16xx_i2c.c line 10
Quoted 2 lines
drivers/auxdisplay/tm16xx_i2c.c new file +2
-0+#include <linux/i2c.h> +#include <linux/mod_devicetable.h> IWYU everywhere, too little header inclusions, you use much more.
I'll explicitly include all required headers in each source file instead of relying on transitive includes from the header.
Quoted 7 lines
drivers/auxdisplay/tm16xx_i2c.c line 58
Quoted 4 lines
drivers/auxdisplay/tm16xx_i2c.c new file +3
-0+static int tm16xx_i2c_write (struct tm16xx_display *display,u8 *data,size_t len) +{ +dev_dbg (display->dev,"i2c_write %*ph" , (char )len, data);Noise.
Understood, I'll remove the debug noise.
Quoted 8 lines
Quoted 8 lines
drivers/auxdisplay/tm16xx_i2c.c new file +8
-0+/* expected sequence: S Command [A] Data [A] P */ +struct i2c_msg msg = { + .addr = data[0 ] >>1 , + .flags =0 , + .len = len -1 , + .buf = &data[1 ], + }; +int ret;
Quoted 9 lines
drivers/auxdisplay/tm16xx_i2c.c line 73
Quoted 6 lines
drivers/auxdisplay/tm16xx_i2c.c new file +6
-0+ + ret =i2c_transfer (display->client.i2c->adapter, &msg,1 ); +if (ret <0 ) +return ret; + +return (ret ==1 ) ?0 : -EIO ;Can we use regmap for all parts of the driver? Why not?
These controllers implement custom 2-wire/3-wire protocols that share sufficient commonalities with I2C/SPI to leverage those subsystems, but are not fully compliant with standard register-based access patterns.
Specific regmap incompatibilities:
I2C protocol:
- Dynamic addressing: slave address embedded in command byte (data[0] >> 1)
- Custom message flags: requires I2C_M_NO_RD_ACK for reads
SPI protocol:
- Inter-transfer timing: mandatory TM16XX_SPI_TWAIT_US delay between command/data
- CS control: requires cs_change = 0 to maintain assertion across phases
Regmap's I2C/SPI bus implementations use fixed addressing and standard transfer patterns without support for these protocol-specific requirements. A custom regmap bus would internally call these same helper functions without providing practical benefit.
The explicit transfer approach better reflects the actual hardware protocol requirements.
Quoted 13 lines
Quoted 1 line
+}
...
Quoted 8 lines
drivers/auxdisplay/tm16xx_i2c.c new file +8
-0+static const struct tm16xx_controller fd6551_controller = { + .max_grids =5 , + .max_segments =7 , + .max_brightness =8 , + .max_key_rows =0 , + .max_key_cols =0 , + .init = fd6551_init, + .data = fd655_data,
Quoted 4 lines
drivers/auxdisplay/tm16xx_i2c.c line 283
Quoted 1 line
drivers/auxdisplay/tm16xx_i2c.c new file +1
-0+ .keys = NULL,Redundant initialiser.
Acknowledged. Will remove.
Quoted 8 lines
Quoted 1 line
+};
...
Quoted 1 line
+#if
IS_ENABLED(CONFIG_OF)No, please remove all these ugly ifdefferies.
Acknowledged. Will remove.
Quoted 12 lines
Quoted 9 lines
drivers/auxdisplay/tm16xx_i2c.c new file +9
-0+static const struct of_device_id tm16xx_i2c_of_match[] = { + { .compatible ="titanmec,tm1650" , .data = &tm1650_controller }, + { .compatible ="fdhisi,fd6551" , .data = &fd6551_controller }, + { .compatible ="fdhisi,fd655" , .data = &fd655_controller }, + { .compatible ="winrise,hbs658" , .data = &hbs658_controller }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, tm16xx_i2c_of_match); +#endif ...
Quoted 4 lines
drivers/auxdisplay/tm16xx_i2c.c line 320
Quoted 1 line
drivers/auxdisplay/tm16xx_i2c.c new file +1
-0+ .of_match_table = of_match_ptr(tm16xx_i2c_of_match),Definitely no to
of_match_ptr(). Must be not used in a new code.
Well received. Will ban usage of of_match_ptr.
Re: [PATCH v4 5/6] auxdisplay: TM16xx: Add support for I2C-based controllers
Quoted 2 lines · Jean-François Lessard
Le 25 août 2025 11 h 18 min 27 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 1 line · Jean-François Lessard
...
Quoted 10 lines
Quoted 1 line
Can we use regmap for all parts of the driver? Why not?
These controllers implement custom 2-wire/3-wire protocols that share sufficient commonalities with I2C/SPI to leverage those subsystems, but are not fully compliant with standard register-based access patterns.
Specific regmap incompatibilities:
I2C protocol:
- Dynamic addressing: slave address embedded in command byte (data[0] >> 1)
Isn't this called paging? Or actually we have also non-standard (non-power-of-2) regmap implementations, perhaps one of them (7 + 9) if exists is what you need?
Quoted 1 line
- Custom message flags: requires
I2C_M_NO_RD_ACKfor reads
Hmm... If we have more than one device like this, we might implement the support in regmap. Or, perhaps, the custom regmap IO accessors can solve this.
Quoted 3 lines
SPI protocol:
- Inter-transfer timing: mandatoryTM16XX_SPI_TWAIT_USdelay between command/data
One may implement custom regmap IO accessors.
Quoted 6 lines
- CS control: requires
cs_change= 0 to maintain assertion across phasesRegmap's I2C/SPI bus implementations use fixed addressing and standard transfer patterns without support for these protocol-specific requirements. A custom regmap bus would internally call these same helper functions without providing practical benefit.
regmap provides a few benefits on top of the raw implementations. First of all, it takes care about synchronisation (and as a side effect enables configurations of the multi-functional HW, if ever needed in this case). It also gives a debugfs implementation, and paging support (if it's what we need). And many more...
Quoted 2 lines
The explicit transfer approach better reflects the actual hardware protocol requirements.
That said, please, try to look into it closer.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v4 5/6] auxdisplay: TM16xx: Add support for I2C-based controllers
Le 26 août 2025 11 h 30 min 41 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 45 lines · Jean-François Lessard
Quoted 2 lines
Le 25 août 2025 11 h 18 min 27 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 1 line · Jean-François Lessard
...
Quoted 10 lines
Quoted 1 line
Can we use regmap for all parts of the driver? Why not?
These controllers implement custom 2-wire/3-wire protocols that share sufficient commonalities with I2C/SPI to leverage those subsystems, but are not fully compliant with standard register-based access patterns.
Specific regmap incompatibilities:
I2C protocol:
- Dynamic addressing: slave address embedded in command byte (data[0] >> 1)Isn't this called paging? Or actually we have also non-standard (non-power-of-2) regmap implementations, perhaps one of them (7 + 9) if exists is what you need?
Quoted 1 line
- Custom message flags: requires
I2C_M_NO_RD_ACKfor readsHmm... If we have more than one device like this, we might implement the support in regmap. Or, perhaps, the custom regmap IO accessors can solve this.
Quoted 3 lines
SPI protocol:
- Inter-transfer timing: mandatoryTM16XX_SPI_TWAIT_USdelay between command/dataOne may implement custom regmap IO accessors.
Quoted 6 lines
- CS control: requires
cs_change= 0 to maintain assertion across phasesRegmap's I2C/SPI bus implementations use fixed addressing and standard transfer patterns without support for these protocol-specific requirements. A custom regmap bus would internally call these same helper functions without providing practical benefit.
regmap provides a few benefits on top of the raw implementations. First of all, it takes care about synchronisation (and as a side effect enables configurations of the multi-functional HW, if ever needed in this case). It also gives a debugfs implementation, and paging support (if it's what we need). And many more...
Quoted 5 lines
Quoted 2 lines
The explicit transfer approach better reflects the actual hardware protocol requirements.
That said, please, try to look into it closer.
I investigated your regmap suggestions thoroughly:
Custom IO accessors:
While technically possible, TM16xx protocols create significant implementation challenges:
- TM1650: Commands 0x48 (control) and 0x4F (key read) appear as I2C addresses but represent completely different operations with different data structures. Custom accessors would need complex command routing logic.
- TM1628: Requires coordinated command sequences (mode -> write command -> control command -> data transfers). A single regmap_write() call can't express this multi-step initialization.
Paging/non-standard addressing:
TM1650's 0x68-0x6E digit commands could theoretically map to regmap pages, but the 0x48/0x4F control/read commands break the model since they're fundamentally different operations, not register variants.
You're correct that regmap provides valuable synchronization, debugfs, and abstraction benefits. However, implementing custom accessors for TM16xx would essentially recreate the existing controller functions while forcing them into register semantics they don't naturally fit.
Custom regmap implementation is possible but would add significant complexity to achieve register abstraction over inherently command-based protocols, while the current approach directly expresses the hardware's actual command structure.
Re: [PATCH v4 5/6] auxdisplay: TM16xx: Add support for I2C-based controllers
Quoted 4 lines · Jean-François Lessard
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Jean-François Lessard
Quoted 1 line · Andy Shevchenko
On Sun, Aug 24, 2025 at 11:32:31PM -0400, Jean-François Lessard wrote:
...
Quoted 47 lines
Quoted 39 lines
Quoted 10 lines
Quoted 1 line
Can we use regmap for all parts of the driver? Why not?
These controllers implement custom 2-wire/3-wire protocols that share sufficient commonalities with I2C/SPI to leverage those subsystems, but are not fully compliant with standard register-based access patterns.
Specific regmap incompatibilities:
I2C protocol:
- Dynamic addressing: slave address embedded in command byte (data[0] >> 1)Isn't this called paging? Or actually we have also non-standard (non-power-of-2) regmap implementations, perhaps one of them (7 + 9) if exists is what you need?
Quoted 1 line
- Custom message flags: requires
I2C_M_NO_RD_ACKfor readsHmm... If we have more than one device like this, we might implement the support in regmap. Or, perhaps, the custom regmap IO accessors can solve this.
Quoted 3 lines
SPI protocol:
- Inter-transfer timing: mandatoryTM16XX_SPI_TWAIT_USdelay between command/dataOne may implement custom regmap IO accessors.
Quoted 6 lines
- CS control: requires
cs_change= 0 to maintain assertion across phasesRegmap's I2C/SPI bus implementations use fixed addressing and standard transfer patterns without support for these protocol-specific requirements. A custom regmap bus would internally call these same helper functions without providing practical benefit.
regmap provides a few benefits on top of the raw implementations. First of all, it takes care about synchronisation (and as a side effect enables configurations of the multi-functional HW, if ever needed in this case). It also gives a debugfs implementation, and paging support (if it's what we need). And many more...
Quoted 5 lines
Quoted 2 lines
The explicit transfer approach better reflects the actual hardware protocol requirements.
That said, please, try to look into it closer.
I investigated your regmap suggestions thoroughly:
Quoted 7 lines
Custom IO accessors:
While technically possible, TM16xx protocols create significant implementation challenges:- TM1650: Commands
0x48(control) and0x4F(key read) appear as I2C addresses but represent completely different operations with different data structures. Custom accessors would need complex command routing logic.
So, to me it sounds like mutli-functional I²C device with two clients, hence would be two drivers under the same umbrella.
Quoted 3 lines
- TM1628: Requires coordinated command sequences (mode -> write command -> control command -> data transfers). A single
regmap_write()call can't express this multi-step initialization.
I believe we have something like that done in a few cases in the kernel, but I don't remember for sure.
Quoted 4 lines
Paging/non-standard addressing:
TM1650's 0x68-0x6E digit commands could theoretically map to regmap pages, but the 0x48/0x4F control/read commands break the model since they're fundamentally different operations, not register variants.
Paging can be partial.
Quoted 8 lines
You're correct that regmap provides valuable synchronization, debugfs, and abstraction benefits. However, implementing custom accessors for TM16xx would essentially recreate the existing controller functions while forcing them into register semantics they don't naturally fit.
Custom regmap implementation is possible but would add significant complexity to achieve register abstraction over inherently command-based protocols, while the current approach directly expresses the hardware's actual command structure.
Okay, if you still think regmap doesn't fit this case, please provide a summary in the cover letter to describe all your discoveries and thoughts.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v4 5/6] auxdisplay: TM16xx: Add support for I2C-based controllers
Le 26 août 2025 14 h 26 min 37 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 86 lines
Quoted 4 lines · Jean-François Lessard
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Jean-François Lessard
Quoted 1 line · Andy Shevchenko
On Sun, Aug 24, 2025 at 11:32:31PM -0400, Jean-François Lessard wrote:
...
Quoted 47 lines
Quoted 39 lines
Quoted 10 lines
Quoted 1 line
Can we use regmap for all parts of the driver? Why not?
These controllers implement custom 2-wire/3-wire protocols that share sufficient commonalities with I2C/SPI to leverage those subsystems, but are not fully compliant with standard register-based access patterns.
Specific regmap incompatibilities:
I2C protocol:
- Dynamic addressing: slave address embedded in command byte (data[0] >> 1)Isn't this called paging? Or actually we have also non-standard (non-power-of-2) regmap implementations, perhaps one of them (7 + 9) if exists is what you need?
Quoted 1 line
- Custom message flags: requires
I2C_M_NO_RD_ACKfor readsHmm... If we have more than one device like this, we might implement the support in regmap. Or, perhaps, the custom regmap IO accessors can solve this.
Quoted 3 lines
SPI protocol:
- Inter-transfer timing: mandatoryTM16XX_SPI_TWAIT_USdelay between command/dataOne may implement custom regmap IO accessors.
Quoted 6 lines
- CS control: requires
cs_change= 0 to maintain assertion across phasesRegmap's I2C/SPI bus implementations use fixed addressing and standard transfer patterns without support for these protocol-specific requirements. A custom regmap bus would internally call these same helper functions without providing practical benefit.
regmap provides a few benefits on top of the raw implementations. First of all, it takes care about synchronisation (and as a side effect enables configurations of the multi-functional HW, if ever needed in this case). It also gives a debugfs implementation, and paging support (if it's what we need). And many more...
Quoted 5 lines
Quoted 2 lines
The explicit transfer approach better reflects the actual hardware protocol requirements.
That said, please, try to look into it closer.
I investigated your regmap suggestions thoroughly:
Quoted 7 lines
Custom IO accessors:
While technically possible, TM16xx protocols create significant implementation challenges:- TM1650: Commands
0x48(control) and0x4F(key read) appear as I2C addresses but represent completely different operations with different data structures. Custom accessors would need complex command routing logic.So, to me it sounds like mutli-functional I²C device with two clients, hence would be two drivers under the same umbrella.
Quoted 3 lines
- TM1628: Requires coordinated command sequences (mode -> write command -> control command -> data transfers). A single
regmap_write()call can't express this multi-step initialization.I believe we have something like that done in a few cases in the kernel, but I don't remember for sure.
Quoted 4 lines
Paging/non-standard addressing:
TM1650's 0x68-0x6E digit commands could theoretically map to regmap pages, but the 0x48/0x4F control/read commands break the model since they're fundamentally different operations, not register variants.Paging can be partial.
Quoted 5 lines
You're correct that regmap provides valuable synchronization, debugfs, and abstraction benefits. However, implementing custom accessors for TM16xx would essentially recreate the existing controller functions while forcing them into register semantics they don't naturally fit.
Quoted 8 lines
Quoted 3 lines
Custom regmap implementation is possible but would add significant complexity to achieve register abstraction over inherently command-based protocols, while the current approach directly expresses the hardware's actual command structure.
Okay, if you still think regmap doesn't fit this case, please provide a summary in the cover letter to describe all your discoveries and thoughts.
Understood. I'll provide a summary of the regmap evaluation and design decisions in the cover letter of the next submission.
PATCH v4 6/6 auxdisplay: TM16xx: Add support for SPI-based controllers
In reply to Jean-François LessardAdd support for TM16xx-compatible auxiliary display controllers connected via the SPI bus.
The implementation includes:
- SPI driver registration and initialization
- Probe/remove logic for SPI devices
- Controller-specific handling and communication sequences
- Integration with the TM16xx core driver for common functionality
This allows platforms using TM16xx or compatible controllers over SPI to be managed by the TM16xx driver infrastructure.
---
Notes:
include <linux/of.h> is required for of_match_ptr
MAINTAINERS | 1 + drivers/auxdisplay/Kconfig | 7 + drivers/auxdisplay/Makefile | 1 + drivers/auxdisplay/tm16xx_spi.c | 398 ++++++++++++++++++++++++++++++++ 4 files changed, 407 insertions(+) create mode 100644 drivers/auxdisplay/tm16xx_spi.c
MAINTAINERS +1 -0
@@ -25411,6 +25411,7 @@ F: drivers/auxdisplay/tm16xx.h F: drivers/auxdisplay/tm16xx_core.c F: drivers/auxdisplay/tm16xx_i2c.c F: drivers/auxdisplay/tm16xx_keypad.c +F: drivers/auxdisplay/tm16xx_spi.c TMIO/SDHI MMC DRIVER M: Wolfram Sang <[email protected]>
drivers/auxdisplay/Kconfig +7 -0
@@ -536,6 +536,7 @@ config TM16XX select INPUT_MATRIXKMAP select TM16XX_KEYPAD if (INPUT) select TM16XX_I2C if (I2C) + select TM16XX_SPI if (SPI) help This driver supports the following TM16XX compatible I2C and SPI 7-segment led display chips:
@@ -560,6 +561,12 @@ config TM16XX_I2C help Enable I2C support for TM16XX driver. +config TM16XX_SPI + tristate + depends on TM16XX + help + Enable SPI support for TM16XX driver. + # # Character LCD with non-conforming interface section #
drivers/auxdisplay/Makefile +1 -0
@@ -20,3 +20,4 @@ obj-$(CONFIG_TM16XX) += tm16xx.o tm16xx-y += tm16xx_core.o tm16xx-$(CONFIG_TM16XX_KEYPAD) += tm16xx_keypad.o obj-$(CONFIG_TM16XX_I2C) += tm16xx_i2c.o +obj-$(CONFIG_TM16XX_SPI) += tm16xx_spi.o
drivers/auxdisplay/tm16xx_spi.c new file +398 -0
398 lines not on this page · raw message
Signature · 1 line
2.43.0
Re: [PATCH v4 6/6] auxdisplay: TM16xx: Add support for SPI-based controllers
Quoted 9 lines · Jean-François Lessard
Add support for TM16xx-compatible auxiliary display controllers connected via the SPI bus.
The implementation includes:
- SPI driver registration and initialization
- Probe/remove logic for SPI devices
- Controller-specific handling and communication sequences
- Integration with the TM16xx core driver for common functionality
Quoted 8 lines
This allows platforms using TM16xx or compatible controllers over SPI to be managed by the TM16xx driver infrastructure.
Signed-off-by Jean-François Lessard <[email protected]>---
Notes:
include <linux/of.h> is required forof_match_ptr
Yeah, please drop the latter and remove the former.
All other comments are the same as per I²C counterpart of the driver.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v4 6/6] auxdisplay: TM16xx: Add support for SPI-based controllers
Le 25 août 2025 11 h 19 min 21 s HAE, Andy Shevchenko <[email protected]> a écrit :
Quoted 13 lines · Jean-François Lessard
Quoted 12 lines
Add support for TM16xx-compatible auxiliary display controllers connected via the SPI bus.
The implementation includes:
- SPI driver registration and initialization
- Probe/remove logic for SPI devices
- Controller-specific handling and communication sequences
- Integration with the TM16xx core driver for common functionalityThis allows platforms using TM16xx or compatible controllers over SPI to be managed by the TM16xx driver infrastructure.
Quoted 8 lines
Quoted 5 lines
Signed-off-by Jean-François Lessard <[email protected]>---
Notes:
include <linux/of.h> is required forof_match_ptrYeah, please drop the latter and remove the former.
Well received.
Quoted 2 lines
All other comments are the same as per I²C counterpart of the driver.
Acknowledged.