* [PATCH 0/2] Input: add support for aXiom touchscreen controller using SPI or I2C
@ 2026-01-26 16:38 Andrew Thomas
2026-01-26 16:38 ` [PATCH 1/2] dt-bindings: input: touchscreen: add TouchNetix aXiom device tree Andrew Thomas
2026-01-26 16:38 ` [PATCH 2/2] Input: add support for aXiom touchscreen controller using SPI or I2C Andrew Thomas
0 siblings, 2 replies; 5+ messages in thread
From: Andrew Thomas @ 2026-01-26 16:38 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Henrik Rydberg
Cc: linux-input, devicetree, linux-kernel, Andrew Thomas,
Marco Felsch
Summary of the added features:
- Add input driver support for TouchNetix aXiom touchscreen controller
using either I2C or SPI.
- Support ABS_MT touch reports in axiom_process_u41_report().
- Support both polling and interrupt mode.
- Add basic documentation and provide example device tree bindings.
- Provide the basic structure to add firmware and config download in
the future via both I2C and SPI.
Many thanks,
Andrew
Signed-off-by: Andrew Thomas <andrew.thomas@touchnetix.com>
---
Andrew Thomas (2):
dt-bindings: input: touchscreen: add TouchNetix aXiom device tree
Input: add support for aXiom touchscreen controller using SPI or I2C
.../bindings/input/touchscreen/tnx,axiom.yaml | 70 +++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
drivers/input/touchscreen/Kconfig | 25 ++
drivers/input/touchscreen/Makefile | 3 +
drivers/input/touchscreen/axiom_core.c | 473 +++++++++++++++++++++
drivers/input/touchscreen/axiom_core.h | 118 +++++
drivers/input/touchscreen/axiom_i2c.c | 150 +++++++
drivers/input/touchscreen/axiom_spi.c | 155 +++++++
8 files changed, 996 insertions(+)
---
base-commit: 7ff574599464bd0e30da88aabc7be9de1021204a
change-id: 20260126-axiom-driver-submission3-f892e1ae9ec0
Best regards,
--
Andrew Thomas <andrew.thomas@touchnetix.com>
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 1/2] dt-bindings: input: touchscreen: add TouchNetix aXiom device tree 2026-01-26 16:38 [PATCH 0/2] Input: add support for aXiom touchscreen controller using SPI or I2C Andrew Thomas @ 2026-01-26 16:38 ` Andrew Thomas 2026-01-26 17:32 ` Rob Herring (Arm) 2026-01-27 14:16 ` Rob Herring 2026-01-26 16:38 ` [PATCH 2/2] Input: add support for aXiom touchscreen controller using SPI or I2C Andrew Thomas 1 sibling, 2 replies; 5+ messages in thread From: Andrew Thomas @ 2026-01-26 16:38 UTC (permalink / raw) To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg Cc: linux-input, devicetree, linux-kernel, Andrew Thomas, Marco Felsch --- .../bindings/input/touchscreen/tnx,axiom.yaml | 70 ++++++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.yaml | 2 + 2 files changed, 72 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.yaml b/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.yaml new file mode 100644 index 000000000000..7b532471c17f --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/tnx,axiom.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TouchNetix aXiom Touchscreen Controller + +maintainers: + - Andrew Thomas <andrew.thomas@touchnetix.com> + +description: | + The TouchNetix aXiom series are high-performance touchscreen controllers + supporting various interface methods including I2C and SPI. + +properties: + compatible: + enum: + - tnx,axiom + + reg: + maxItems: 1 + + interrupts: + description: Both IRQ_TYPE_LEVEL_LOW and IRQ_TYPE_EDGE_FALLING are supported + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +allOf: + - $ref: touchscreen.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@66 { + compatible = "tnx,axiom-i2c"; + reg = <0x66>; + interrupt-parent = <&gpio>; + interrupts = <24 IRQ_TYPE_LEVEL_LOW>; + axiom,poll-enable; + axiom,poll-period = <15>; + }; + }; + + - | + #include <dt-bindings/interrupt-controller/irq.h> + + spi { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@0 { + compatible = "tnx,axiom-spi"; + reg = <0>; + interrupt-parent = <&gpio>; + interrupts = <24 IRQ_TYPE_EDGE_FALLING>; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index f1d1882009ba..dadfc7036ed7 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1636,6 +1636,8 @@ patternProperties: description: Trusted Logic Mobility "^tmt,.*": description: Tecon Microprocessor Technologies, LLC. + "^tnx,.*": + description: TouchNetix "^topeet,.*": description: Topeet "^topic,.*": -- 2.43.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] dt-bindings: input: touchscreen: add TouchNetix aXiom device tree 2026-01-26 16:38 ` [PATCH 1/2] dt-bindings: input: touchscreen: add TouchNetix aXiom device tree Andrew Thomas @ 2026-01-26 17:32 ` Rob Herring (Arm) 2026-01-27 14:16 ` Rob Herring 1 sibling, 0 replies; 5+ messages in thread From: Rob Herring (Arm) @ 2026-01-26 17:32 UTC (permalink / raw) To: Andrew Thomas Cc: linux-kernel, devicetree, Marco Felsch, Conor Dooley, Dmitry Torokhov, Krzysztof Kozlowski, Henrik Rydberg, linux-input On Mon, 26 Jan 2026 16:38:23 +0000, Andrew Thomas wrote: > --- > .../bindings/input/touchscreen/tnx,axiom.yaml | 70 ++++++++++++++++++++++ > .../devicetree/bindings/vendor-prefixes.yaml | 2 + > 2 files changed, 72 insertions(+) > My bot found errors running 'make dt_binding_check' on your patch: yamllint warnings/errors: dtschema/dtc warnings/errors: Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.example.dtb: /example-0/i2c/touchscreen@66: failed to match any schema with compatible: ['tnx,axiom-i2c'] /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.example.dtb: touchscreen@66 (tnx,axiom-i2c): 'axiom,poll-enable', 'axiom,poll-period' do not match any of the regexes: '^#.*', '^(at25|bm|devbus|dmacap|dsa|exynos|fsi[ab]|gpio-fan|gpio-key|gpio|gpmc|hdmi|i2c-gpio),.*', '^(keypad|m25p|max8952|max8997|max8998|mpmc),.*', '^(pciclass|pinctrl-single|#pinctrl-single|PowerPC),.*', '^(pl022|pxa-mmc|rcar_sound|rotary-encoder|s5m8767|sdhci),.*', '^(simple-audio-card|st-plgpio|st-spics|ts|vsc8531),.*', '^100ask,.*', '^70mai,.*', '^8dev,.*', '^9tripod,.*', '^GEFanuc,.*', '^IBM,.*', '^ORCL,.*', '^SUNW,.*', '^[a-zA-Z0-9#_][a-zA-Z0-9#+\\-._@]{0,63}$', '^[a-zA-Z0-9+\\-._]*@[0-9a-zA-Z,]*$', '^abb,.*', '^abilis,.*', '^abracon,.*', '^abt,.*', '^acbel,.*', '^acelink,.*', '^acer,.*', '^acme,.*', '^actions,.*', '^actiontec,.*', '^active-semi,.*', '^ad,.*', '^adafruit,.*', '^adapteva,.*', '^adaptrum,.*', '^adh,.*', '^adi,.*', '^adieng,.*', '^admatec,.*', '^advantech,.*', '^aeroflexgaisler,.*', '^aesop,.*', '^airoha,.*', '^al,.*', '^alcatel,.*', '^aldec,.*', '^alfa-network,.*', '^algoltek,.*', '^allegro,.*', '^allegromicro,.*', '^alliedtelesis,.*', '^alliedvision,.*', '^allo,.*', '^allwinner,.*', '^alphascale,.*', '^alps,.*', '^alt,.*', '^altr,.*', '^amarula,.*', '^amazon,.*', '^amcc,.*', '^amd,.*', '^amediatech,.*', '^amlogic,.*', '^ampere,.*', '^amphenol,.*', '^ampire,.*', '^ams,.*', '^amstaos,.*', '^analogix,.*', '^anbernic,.*', '^andestech,.*', '^anlogic,.*', '^anvo,.*', '^aoly,.*', '^aosong,.*', '^apm,.*', '^apple,.*', '^aptina,.*', '^arasan,.*', '^archermind,.*', '^arcom,.*', '^arctic,.*', '^arcx,.*', '^arduino,.*', '^argon40,.*', '^ariaboard,.*', '^aries,.*', '^arm,.*', '^armadeus,.*', '^armsom,.*', '^arrow,.*', '^artesyn,.*', '^asahi-kasei,.*', '^asc,.*', '^asix,.*', '^asl-tek,.*', '^aspeed,.*', '^asrock,.*', '^asteralabs,.*', '^asus,.*', '^atheros,.*', '^atlas,.*', '^atmel,.*', '^auo,.*', '^auvidea,.*', '^avago,.*', '^avia,.*', '^avic,.*', '^avnet,.*', '^awinic,.*', '^axentia,.*', '^axiado,.*', '^axis,.*', '^azoteq,.*', '^azw,.*', '^baikal,.*', '^bananapi,.*', '^beacon,.*', '^beagle,.*', '^belling,.*', '^bestar,.*', '^bhf,.*', '^bigtreetech,.*', '^bitmain,.*', '^blaize,.*', '^bluegiga,.*', '^blutek,.*', '^boe,.*', '^bosch,.*', '^boundary,.*', '^brcm,.*', '^broadmobi,.*', '^bsh,.*', '^bst,.*', '^bticino,.*', '^buffalo,.*', '^buglabs,.*', '^bur,.*', '^bytedance,.*', '^calamp,.*', '^calao,.*', '^calaosystems,.*', '^calxeda,.*', '^cameo,.*', '^canaan,.*', '^caninos,.*', '^capella,.*', '^cascoda,.*', '^catalyst,.*', '^cavium,.*', '^cct,.*', '^cdns,.*', '^cdtech,.*', '^cellwise,.*', '^ceva,.*', '^chargebyte,.*', '^checkpoint,.*', '^chefree,.*', '^chipidea,.*', '^chipone,.*', '^chipspark,.*', '^chongzhou,.*', '^chrontel,.*', '^chrp,.*', '^chunghwa,.*', '^chuwi,.*', '^ciaa,.*', '^cirrus,.*', '^cisco,.*', '^cix,.*', '^clockwork,.*', '^cloos,.*', '^cloudengines,.*', '^cnm,.*', '^cnxt,.*', '^colorfly,.*', '^compal,.*', '^compulab,.*', '^comvetia,.*', '^congatec,.*', '^coolpi,.*', '^coreriver,.*', '^corpro,.*', '^cortina,.*', '^cosmic,.*', '^crane,.*', '^creative,.*', '^crystalfontz,.*', '^csky,.*', '^csot,.*', '^csq,.*', '^csr,.*', '^ctera,.*', '^ctu,.*', '^cubietech,.*', '^cudy,.*', '^cui,.*', '^cypress,.*', '^cyx,.*', '^cznic,.*', '^dallas,.*', '^dataimage,.*', '^davicom,.*', '^deepcomputing,.*', '^dell,.*', '^delta,.*', '^densitron,.*', '^denx,.*', '^devantech,.*', '^dfi,.*', '^dfrobot,.*', '^dh,.*', '^difrnce,.*', '^digi,.*', '^digilent,.*', '^dimonoff,.*', '^diodes,.*', '^dioo,.*', '^djn,.*', '^dlc,.*', '^dlg,.*', '^dlink,.*', '^dmo,.*', '^domintech,.*', '^dongwoon,.*', '^dptechnics,.*', '^dragino,.*', '^dream,.*', '^ds,.*', '^dserve,.*', '^dynaimage,.*', '^ea,.*', '^ebang,.*', '^ebbg,.*', '^ebs-systart,.*', '^ebv,.*', '^eckelmann,.*', '^econet,.*', '^edgeble,.*', '^edimax,.*', '^edt,.*', '^ees,.*', '^eeti,.*', '^egnite,.*', '^einfochips,.*', '^eink,.*', '^elan,.*', '^element14,.*', '^elgin,.*', '^elida,.*', '^elimo,.*', '^elpida,.*', '^embedfire,.*', '^embest,.*', '^emcraft,.*', '^emlid,.*', '^emmicro,.*', '^empire-electronix,.*', '^emtrion,.*', '^enbw,.*', '^enclustra,.*', '^endian,.*', '^endless,.*', '^ene,.*', '^energymicro,.*', '^engicam,.*', '^engleder,.*', '^epcos,.*', '^epfl,.*', '^epson,.*', '^esp,.*', '^est,.*', '^eswin,.*', '^ettus,.*', '^eukrea,.*', '^everest,.*', '^everspin,.*', '^evervision,.*', '^exar,.*', '^excito,.*', '^exegin,.*', '^ezchip,.*', '^ezurio,.*', '^facebook,.*', '^fairchild,.*', '^fairphone,.*', '^faraday,.*', '^fascontek,.*', '^fastrax,.*', '^fcs,.*', '^feixin,.*', '^feiyang,.*', '^fii,.*', '^firefly,.*', '^fitipower,.*', '^flipkart,.*', '^focaltech,.*', '^forlinx,.*', '^foursemi,.*', '^foxlink,.*', '^freebox,.*', '^freecom,.*', '^frida,.*', '^friendlyarm,.*', '^fsl,.*', '^fujitsu,.*', '^fxtec,.*', '^galaxycore,.*', '^gameforce,.*', '^gardena,.*', '^gateway,.*', '^gateworks,.*', '^gcw,.*', '^ge,.*', '^geekbuying,.*', '^gef,.*', '^gehc,.*', '^gemei,.*', '^gemtek,.*', '^genesys,.*', '^genexis,.*', '^geniatech,.*', '^giantec,.*', '^giantplus,.*', '^glinet,.*', '^globalscale,.*', '^globaltop,.*', '^gmt,.*', '^gocontroll,.*', '^goldelico,.*', '^goodix,.*', '^google,.*', '^goramo,.*', '^gplus,.*', '^grinn,.*', '^grmn,.*', '^gumstix,.*', '^gw,.*', '^hannstar,.*', '^haochuangyi,.*', '^haoyu,.*', '^hardkernel,.*', '^hce,.*', '^headacoustics,.*', '^hechuang,.*', '^hideep,.*', '^himax,.*', '^hinlink,.*', '^hirschmann,.*', '^hisi,.*', '^hisilicon,.*', '^hit,.*', '^hitex,.*', '^holt,.*', '^holtek,.*', '^honestar,.*', '^honeywell,.*', '^hoperf,.*', '^hoperun,.*', '^hp,.*', '^hpe,.*', '^hsg,.*', '^htc,.*', '^huawei,.*', '^hugsun,.*', '^huiling,.*', '^hwacom,.*', '^hxt,.*', '^hycon,.*', '^hydis,.*', '^hynitron,.*', '^hynix,.*', '^hyundai,.*', '^i2se,.*', '^ibm,.*', '^icplus,.*', '^idt,.*', '^iei,.*', '^ifi,.*', '^ifm,.*', '^ilitek,.*', '^imagis,.*', '^img,.*', '^imi,.*', '^inanbo,.*', '^incircuit,.*', '^incostartec,.*', '^indiedroid,.*', '^inet-tek,.*', '^infineon,.*', '^inforce,.*', '^ingenic,.*', '^ingrasys,.*', '^injoinic,.*', '^innocomm,.*', '^innolux,.*', '^inside-secure,.*', '^insignal,.*', '^inspur,.*', '^intel,.*', '^intercontrol,.*', '^invensense,.*', '^inventec,.*', '^inversepath,.*', '^iom,.*', '^irondevice,.*', '^isee,.*', '^isil,.*', '^issi,.*', '^ite,.*', '^itead,.*', '^itian,.*', '^ivo,.*', '^iwave,.*', '^jadard,.*', '^jasonic,.*', '^jdi,.*', '^jedec,.*', '^jenson,.*', '^jesurun,.*', '^jethome,.*', '^jianda,.*', '^jide,.*', '^joz,.*', '^jty,.*', '^jutouch,.*', '^kam,.*', '^karo,.*', '^keithkoep,.*', '^keymile,.*', '^khadas,.*', '^kiebackpeter,.*', '^kinetic,.*', '^kingdisplay,.*', '^kingnovel,.*', '^kionix,.*', '^kobo,.*', '^kobol,.*', '^koe,.*', '^kontron,.*', '^kosagi,.*', '^kvg,.*', '^kyo,.*', '^lacie,.*', '^laird,.*', '^lamobo,.*', '^lantiq,.*', '^lattice,.*', '^lckfb,.*', '^lctech,.*', '^leadtek,.*', '^leez,.*', '^lego,.*', '^lemaker,.*', '^lenovo,.*', '^lg,.*', '^lgphilips,.*', '^libretech,.*', '^licheepi,.*', '^linaro,.*', '^lincolntech,.*', '^lineartechnology,.*', '^linkease,.*', '^linksprite,.*', '^linksys,.*', '^linutronix,.*', '^linux,.*', '^linx,.*', '^liontron,.*', '^liteon,.*', '^litex,.*', '^lltc,.*', '^logicpd,.*', '^logictechno,.*', '^longcheer,.*', '^lontium,.*', '^loongmasses,.*', '^loongson,.*', '^lsi,.*', '^luckfox,.*', '^lunzn,.*', '^luxul,.*', '^lwn,.*', '^lxa,.*', '^m5stack,.*', '^macnica,.*', '^mantix,.*', '^mapleboard,.*', '^marantec,.*', '^marvell,.*', '^maxbotix,.*', '^maxim,.*', '^maxlinear,.*', '^maxtor,.*', '^mayqueen,.*', '^mbvl,.*', '^mcube,.*', '^meas,.*', '^mecer,.*', '^mediatek,.*', '^medion,.*', '^megachips,.*', '^mele,.*', '^melexis,.*', '^melfas,.*', '^mellanox,.*', '^memsensing,.*', '^memsic,.*', '^menlo,.*', '^mentor,.*', '^meraki,.*', '^merrii,.*', '^methode,.*', '^micrel,.*', '^microchip,.*', '^microcrystal,.*', '^micron,.*', '^microsoft,.*', '^microsys,.*', '^microtips,.*', '^mikroe,.*', '^mikrotik,.*', '^milianke,.*', '^milkv,.*', '^miniand,.*', '^minix,.*', '^mips,.*', '^miramems,.*', '^mitsubishi,.*', '^mitsumi,.*', '^mixel,.*', '^miyoo,.*', '^mntre,.*', '^mobileye,.*', '^modtronix,.*', '^moortec,.*', '^mosaixtech,.*', '^motorcomm,.*', '^motorola,.*', '^moxa,.*', '^mpl,.*', '^mps,.*', '^mqmaker,.*', '^mrvl,.*', '^mscc,.*', '^msi,.*', '^mstar,.*', '^mti,.*', '^multi-inno,.*', '^mundoreader,.*', '^murata,.*', '^mxic,.*', '^mxicy,.*', '^myir,.*', '^national,.*', '^neardi,.*', '^nec,.*', '^neofidelity,.*', '^neonode,.*', '^netcube,.*', '^netgear,.*', '^netlogic,.*', '^netron-dy,.*', '^netronix,.*', '^netxeon,.*', '^neweast,.*', '^newhaven,.*', '^newvision,.*', '^nexbox,.*', '^nextthing,.*', '^ni,.*', '^nicera,.*', '^nintendo,.*', '^nlt,.*', '^nokia,.*', '^nordic,.*', '^nothing,.*', '^novatech,.*', '^novatek,.*', '^novtech,.*', '^nuclei,.*', '^numonyx,.*', '^nutsboard,.*', '^nuvoton,.*', '^nvd,.*', '^nvidia,.*', '^nxp,.*', '^oceanic,.*', '^ocs,.*', '^oct,.*', '^okaya,.*', '^oki,.*', '^olimex,.*', '^olpc,.*', '^oneplus,.*', '^onie,.*', '^onion,.*', '^onnn,.*', '^ontat,.*', '^opalkelly,.*', '^openailab,.*', '^opencores,.*', '^openembed,.*', '^openpandora,.*', '^openrisc,.*', '^openwrt,.*', '^option,.*', '^oranth,.*', '^orisetech,.*', '^ortustech,.*', '^osddisplays,.*', '^osmc,.*', '^ouya,.*', '^overkiz,.*', '^ovti,.*', '^oxsemi,.*', '^ozzmaker,.*', '^panasonic,.*', '^parade,.*', '^parallax,.*', '^particle,.*', '^pda,.*', '^pegatron,.*', '^pericom,.*', '^pervasive,.*', '^phicomm,.*', '^phontech,.*', '^phytec,.*', '^picochip,.*', '^pinctrl-[0-9]+$', '^pine64,.*', '^pineriver,.*', '^pixcir,.*', '^plantower,.*', '^plathome,.*', '^plda,.*', '^plx,.*', '^ply,.*', '^pni,.*', '^pocketbook,.*', '^polaroid,.*', '^polyhex,.*', '^pool[0-3],.*', '^portwell,.*', '^poslab,.*', '^pov,.*', '^powertip,.*', '^powervr,.*', '^powkiddy,.*', '^pri,.*', '^primeview,.*', '^primux,.*', '^probox2,.*', '^prt,.*', '^pulsedlight,.*', '^purism,.*', '^puya,.*', '^qca,.*', '^qcom,.*', '^qemu,.*', '^qi,.*', '^qiaodian,.*', '^qihua,.*', '^qishenglong,.*', '^qnap,.*', '^quanta,.*', '^radxa,.*', '^raidsonic,.*', '^ralink,.*', '^ramtron,.*', '^raspberrypi,.*', '^raumfeld,.*', '^raydium,.*', '^raystar,.*', '^rda,.*', '^realtek,.*', '^relfor,.*', '^remarkable,.*', '^renesas,.*', '^rervision,.*', '^retronix,.*', '^revotics,.*', '^rex,.*', '^rfdigital,.*', '^richtek,.*', '^ricoh,.*', '^rikomagic,.*', '^riot,.*', '^riscv,.*', '^rockchip,.*', '^rocktech,.*', '^rohm,.*', '^ronbo,.*', '^ronetix,.*', '^roofull,.*', '^roseapplepi,.*', '^rve,.*', '^saef,.*', '^sakurapi,.*', '^samsung,.*', '^samtec,.*', '^sancloud,.*', '^sandisk,.*', '^satoz,.*', '^sbs,.*', '^schindler,.*', '^schneider,.*', '^schulercontrol,.*', '^sciosense,.*', '^sdmc,.*', '^seagate,.*', '^seeed,.*', '^seirobotics,.*', '^semtech,.*', '^senseair,.*', '^sensirion,.*', '^sensortek,.*', '^sercomm,.*', '^sff,.*', '^sgd,.*', '^sgmicro,.*', '^sgx,.*', '^sharp,.*', '^shift,.*', '^shimafuji,.*', '^shineworld,.*', '^shiratech,.*', '^si-en,.*', '^si-linux,.*', '^sielaff,.*', '^siemens,.*', '^sifive,.*', '^siflower,.*', '^sigma,.*', '^sii,.*', '^sil,.*', '^silabs,.*', '^silan,.*', '^silead,.*', '^silergy,.*', '^silex-insight,.*', '^siliconfile,.*', '^siliconmitus,.*', '^silvaco,.*', '^simtek,.*', '^sinlinx,.*', '^sinovoip,.*', '^sinowealth,.*', '^sipeed,.*', '^sirf,.*', '^sis,.*', '^sitronix,.*', '^skov,.*', '^skyworks,.*', '^smartfiber,.*', '^smartlabs,.*', '^smartrg,.*', '^smi,.*', '^smsc,.*', '^snps,.*', '^sochip,.*', '^socionext,.*', '^solidrun,.*', '^solomon,.*', '^somfy,.*', '^sony,.*', '^sophgo,.*', '^sourceparts,.*', '^spacemit,.*', '^spansion,.*', '^sparkfun,.*', '^spinalhdl,.*', '^sprd,.*', '^square,.*', '^ssi,.*', '^sst,.*', '^sstar,.*', '^st,.*', '^st-ericsson,.*', '^starfive,.*', '^starry,.*', '^startek,.*', '^starterkit,.*', '^ste,.*', '^stericsson,.*', '^storlink,.*', '^storm,.*', '^storopack,.*', '^summit,.*', '^sunchip,.*', '^sundance,.*', '^sunplus,.*', '^supermicro,.*', '^swir,.*', '^syna,.*', '^synaptics,.*', '^synology,.*', '^synopsys,.*', '^taos,.*', '^tbs,.*', '^tbs-biometrics,.*', '^tcg,.*', '^tcl,.*', '^tcs,.*', '^tcu,.*', '^tdo,.*', '^team-source-display,.*', '^technexion,.*', '^technologic,.*', '^techstar,.*', '^techwell,.*', '^teejet,.*', '^teltonika,.*', '^tempo,.*', '^tenda,.*', '^tenstorrent,.*', '^terasic,.*', '^tesla,.*', '^test,.*', '^tfc,.*', '^thead,.*', '^thine,.*', '^thingyjp,.*', '^thundercomm,.*', '^thwc,.*', '^ti,.*', '^tianma,.*', '^tlm,.*', '^tmt,.*', '^tnx,.*', '^topeet,.*', '^topic,.*', '^topland,.*', '^toppoly,.*', '^topwise,.*', '^toradex,.*', '^toshiba,.*', '^toumaz,.*', '^tpk,.*', '^tplink,.*', '^tpo,.*', '^tq,.*', '^transpeed,.*', '^traverse,.*', '^tronfy,.*', '^tronsmart,.*', '^truly,.*', '^tsd,.*', '^turing,.*', '^tuxedo,.*', '^tyan,.*', '^tyhx,.*', '^u-blox,.*', '^u-boot,.*', '^ubnt,.*', '^ucrobotics,.*', '^udoo,.*', '^ufispace,.*', '^ugoos,.*', '^ultrarisc,.*', '^ultratronik,.*', '^uni-t,.*', '^uniwest,.*', '^upisemi,.*', '^urt,.*', '^usi,.*', '^usr,.*', '^utoo,.*', '^v3,.*', '^vaisala,.*', '^valve,.*', '^vamrs,.*', '^variscite,.*', '^vdl,.*', '^vertexcom,.*', '^via,.*', '^vialab,.*', '^vicor,.*', '^videostrong,.*', '^virtio,.*', '^virtual,.*', '^vishay,.*', '^visionox,.*', '^vitesse,.*', '^vivante,.*', '^vivax,.*', '^vocore,.*', '^voipac,.*', '^voltafield,.*', '^vot,.*', '^vscom,.*', '^vxt,.*', '^wacom,.*', '^wanchanglong,.*', '^wand,.*', '^waveshare,.*', '^wd,.*', '^we,.*', '^welltech,.*', '^wetek,.*', '^wexler,.*', '^whwave,.*', '^wi2wi,.*', '^widora,.*', '^wiligear,.*', '^willsemi,.*', '^winbond,.*', '^wingtech,.*', '^winlink,.*', '^winsen,.*', '^winstar,.*', '^wirelesstag,.*', '^wits,.*', '^wlf,.*', '^wm,.*', '^wobo,.*', '^wolfvision,.*', '^x-powers,.*', '^xen,.*', '^xes,.*', '^xiaomi,.*', '^xicor,.*', '^xillybus,.*', '^xingbangda,.*', '^xinpeng,.*', '^xiphera,.*', '^xlnx,.*', '^xnano,.*', '^xunlong,.*', '^xylon,.*', '^yadro,.*', '^yamaha,.*', '^yes-optoelectronics,.*', '^yic,.*', '^yiming,.*', '^ylm,.*', '^yna,.*', '^yones-toptech,.*', '^ys,.*', '^ysoft,.*', '^yuridenki,.*', '^yuzukihd,.*', '^zarlink,.*', '^zealz,.*', '^zeitec,.*', '^zidoo,.*', '^zii,.*', '^zinitix,.*', '^zkmagic,.*', '^zte,.*', '^zyxel,.*' from schema $id: http://devicetree.org/schemas/vendor-prefixes.yaml Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.example.dtb: /example-1/spi/touchscreen@0: failed to match any schema with compatible: ['tnx,axiom-spi'] doc reference errors (make refcheckdocs): See https://patchwork.kernel.org/project/devicetree/patch/20260126-axiom-driver-submission3-v1-1-d462c4a608e3@touchnetix.com The base for the series is generally the latest rc1. A different dependency should be noted in *this* patch. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit after running the above command yourself. Note that DT_SCHEMA_FILES can be set to your schema file to speed up checking your schema. However, it must be unset to test all examples with your schema. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] dt-bindings: input: touchscreen: add TouchNetix aXiom device tree 2026-01-26 16:38 ` [PATCH 1/2] dt-bindings: input: touchscreen: add TouchNetix aXiom device tree Andrew Thomas 2026-01-26 17:32 ` Rob Herring (Arm) @ 2026-01-27 14:16 ` Rob Herring 1 sibling, 0 replies; 5+ messages in thread From: Rob Herring @ 2026-01-27 14:16 UTC (permalink / raw) To: Andrew Thomas Cc: Dmitry Torokhov, Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg, linux-input, devicetree, linux-kernel, Marco Felsch On Mon, Jan 26, 2026 at 04:38:23PM +0000, Andrew Thomas wrote: > --- Also needs a commit message and S-o-b. > .../bindings/input/touchscreen/tnx,axiom.yaml | 70 ++++++++++++++++++++++ > .../devicetree/bindings/vendor-prefixes.yaml | 2 + > 2 files changed, 72 insertions(+) > > diff --git a/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.yaml b/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.yaml > new file mode 100644 > index 000000000000..7b532471c17f > --- /dev/null > +++ b/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.yaml > @@ -0,0 +1,70 @@ > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/input/touchscreen/tnx,axiom.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: TouchNetix aXiom Touchscreen Controller > + > +maintainers: > + - Andrew Thomas <andrew.thomas@touchnetix.com> > + > +description: | Don't need '|' if no formatting to preserve. > + The TouchNetix aXiom series are high-performance touchscreen controllers > + supporting various interface methods including I2C and SPI. > + > +properties: > + compatible: > + enum: > + - tnx,axiom > + > + reg: > + maxItems: 1 > + > + interrupts: > + description: Both IRQ_TYPE_LEVEL_LOW and IRQ_TYPE_EDGE_FALLING are supported > + maxItems: 1 > + > +required: > + - compatible > + - reg > + - interrupts > + > +allOf: > + - $ref: touchscreen.yaml# > + - $ref: /schemas/spi/spi-peripheral-props.yaml# > + > +unevaluatedProperties: false > + > +examples: > + - | > + #include <dt-bindings/interrupt-controller/irq.h> > + > + i2c { > + #address-cells = <1>; > + #size-cells = <0>; > + > + touchscreen@66 { > + compatible = "tnx,axiom-i2c"; > + reg = <0x66>; > + interrupt-parent = <&gpio>; > + interrupts = <24 IRQ_TYPE_LEVEL_LOW>; > + axiom,poll-enable; > + axiom,poll-period = <15>; > + }; > + }; > + > + - | > + #include <dt-bindings/interrupt-controller/irq.h> > + > + spi { > + #address-cells = <1>; > + #size-cells = <0>; > + > + touchscreen@0 { > + compatible = "tnx,axiom-spi"; > + reg = <0>; > + interrupt-parent = <&gpio>; > + interrupts = <24 IRQ_TYPE_EDGE_FALLING>; > + }; > + }; > diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml > index f1d1882009ba..dadfc7036ed7 100644 > --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml > +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml > @@ -1636,6 +1636,8 @@ patternProperties: > description: Trusted Logic Mobility > "^tmt,.*": > description: Tecon Microprocessor Technologies, LLC. > + "^tnx,.*": > + description: TouchNetix > "^topeet,.*": > description: Topeet > "^topic,.*": > > -- > 2.43.0 > ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/2] Input: add support for aXiom touchscreen controller using SPI or I2C 2026-01-26 16:38 [PATCH 0/2] Input: add support for aXiom touchscreen controller using SPI or I2C Andrew Thomas 2026-01-26 16:38 ` [PATCH 1/2] dt-bindings: input: touchscreen: add TouchNetix aXiom device tree Andrew Thomas @ 2026-01-26 16:38 ` Andrew Thomas 1 sibling, 0 replies; 5+ messages in thread From: Andrew Thomas @ 2026-01-26 16:38 UTC (permalink / raw) To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg Cc: linux-input, devicetree, linux-kernel, Andrew Thomas, Marco Felsch --- drivers/input/touchscreen/Kconfig | 25 ++ drivers/input/touchscreen/Makefile | 3 + drivers/input/touchscreen/axiom_core.c | 473 +++++++++++++++++++++++++++++++++ drivers/input/touchscreen/axiom_core.h | 118 ++++++++ drivers/input/touchscreen/axiom_i2c.c | 150 +++++++++++ drivers/input/touchscreen/axiom_spi.c | 155 +++++++++++ 6 files changed, 924 insertions(+) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 7d5b72ee07fa..d27292ccabc9 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -162,6 +162,31 @@ config TOUCHSCREEN_AUO_PIXCIR To compile this driver as a module, choose M here: the module will be called auo-pixcir-ts. +config TOUCHSCREEN_AXIOM_CORE + tristate + +config TOUCHSCREEN_AXIOM_I2C + tristate "TouchNetix aXiom touchscreen (I2C)" + depends on I2C + select TOUCHSCREEN_AXIOM_CORE + help + Say Y here if the aXiom touchscreen is connected via + the I2C bus. + + To compile this driver as a module, choose M here: the + module will be called axiom_i2c. + +config TOUCHSCREEN_AXIOM_SPI + tristate "TouchNetix aXiom touchscreen (SPI)" + depends on SPI + select TOUCHSCREEN_AXIOM_CORE + help + Say Y here if the aXiom touchscreen is connected via + the SPI bus. + + To compile this driver as a module, choose M here: the + module will be called axiom_spi. + config TOUCHSCREEN_BU21013 tristate "BU21013 based touch panel controllers" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index ab9abd151078..9b7d572c4589 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -19,6 +19,9 @@ obj-$(CONFIG_TOUCHSCREEN_APPLE_Z2) += apple_z2.o obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o +obj-$(CONFIG_TOUCHSCREEN_AXIOM_CORE) += axiom_core.o +obj-$(CONFIG_TOUCHSCREEN_AXIOM_I2C) += axiom_i2c.o +obj-$(CONFIG_TOUCHSCREEN_AXIOM_SPI) += axiom_spi.o obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o obj-$(CONFIG_TOUCHSCREEN_BU21029) += bu21029_ts.o obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318) += chipone_icn8318.o diff --git a/drivers/input/touchscreen/axiom_core.c b/drivers/input/touchscreen/axiom_core.c new file mode 100644 index 000000000000..89a845ab90ba --- /dev/null +++ b/drivers/input/touchscreen/axiom_core.c @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TouchNetix aXiom Touchscreen Driver + * + * Copyright (C) 2020-2026 TouchNetix Ltd. + * + * Author(s): Mark Satterthwaite <mark.satterthwaite@touchnetix.com> + * Pedro Torruella <pedro.torruella@touchnetix.com> + * Bart Prescott <bartp@baasheep.co.uk> + * Hannah Rossiter <hannah.rossiter@touchnetix.com> + * Andrew Thomas <andrew.thomas@touchnetix.com> + */ + +#include <linux/device.h> +#include <linux/input/mt.h> +#include <linux/crc16.h> +#include <linux/property.h> +#include <linux/interrupt.h> +#include <linux/unaligned.h> +#include <linux/bitfield.h> +#include "axiom_core.h" + +static bool poll_enable; +module_param(poll_enable, bool, 0444); +MODULE_PARM_DESC(poll_enable, "Enable polling mode [default 0=no]"); + +static int poll_period = 10; +module_param(poll_period, uint, 0444); +MODULE_PARM_DESC(poll_period, "Polling period in ms [default = 10]"); + +/* u31 device info masks */ +#define AX_DEV_ID_MASK GENMASK(14, 0) +#define AX_MODE BIT(15) +#define AX_FW_REV_MINOR_MASK GENMASK(7, 0) +#define AX_FW_REV_MAJOR_MASK GENMASK(15, 8) +#define AX_VARIANT_MASK GENMASK(5, 0) +#define AX_FW_STATUS BIT(7) +#define AX_TCP_REV_MASK GENMASK(15, 8) +#define AX_BOOT_REV_MINOR_MASK GENMASK(7, 0) +#define AX_BOOT_REV_MAJOR_MASK GENMASK(15, 8) +#define AX_NUM_USAGES_MASK GENMASK(7, 0) +#define AX_SILICON_REV_MASK GENMASK(11, 8) +#define AX_RUNTIME_FW_PATCH_MASK GENMASK(15, 12) + +/* u31 usage table entry masks */ +#define AX_U31_USAGE_NUM_MASK GENMASK(7, 0) +#define AX_U31_START_PAGE_MASK GENMASK(15, 8) +#define AX_U31_NUM_PAGES_MASK GENMASK(7, 0) +#define AX_U31_MAX_OFFSET_MASK GENMASK(14, 8) +#define AX_U31_OFFSET_TYPE_BIT BIT(15) +#define AX_U31_UIF_REV_MASK GENMASK(7, 0) +#define AX_U31_USAGE_TYPE_MASK GENMASK(15, 8) + +/* u34 report masks */ +#define AX_U34_LEN_MASK GENMASK(6, 0) +#define AX_U34_OVERFLOW BIT(7) +#define AX_U34_USAGE_MASK GENMASK(15, 8) +#define AX_U34_PAYLOAD_BUFFER (2) + +/* u41 report masks */ +#define AX_U41_PRESENT_MASK GENMASK(9, 0) +#define U41_X_Y_OFFSET (2) +#define U41_COORD_SIZE (4) +#define U41_Z_OFFSET (42) + +static const char *const fw_variants[] = { + "3D", + "2D", + "FORCE", + "0D", + "XL", + "TOUCHPAD", +}; + +static int axiom_set_capabilities(struct input_dev *input_dev) +{ + input_dev->name = "TouchNetix aXiom Touchscreen"; + input_dev->phys = "input/ts"; + + // Multi Touch + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, 65535, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 65535, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_MT_DISTANCE, 0, 127, 0, 0); + input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 127, 0, 0); + + // each report id in u41 can be configured separately in u42, + // to keep it simple have all reports ids be touch. + input_mt_init_slots(input_dev, U41_MAX_TARGETS, INPUT_MT_DIRECT); + + return 0; +} + +static struct u31_usage_entry *usage_find_entry(struct axiom *ax, u16 usage) +{ + u16 i; + + for (i = 0; i < ax->dev_info.num_usages; i++) { + if (ax->usage_table[i].usage_num == usage) + return &ax->usage_table[i]; + } + + pr_err("aXiom-core: Usage u%02x not found in usage table\n", usage); + return ERR_PTR(-EINVAL); +} + +static void axiom_unpack_device_info(const u8 *buf, + struct axiom_device_info *info) +{ + u16 w; + + w = get_unaligned_le16(buf); + info->device_id = FIELD_GET(AX_DEV_ID_MASK, w); + info->mode = !!(w & AX_MODE); + + w = get_unaligned_le16(buf + 2); + info->runtime_fw_rev_minor = FIELD_GET(AX_FW_REV_MINOR_MASK, w); + info->runtime_fw_rev_major = FIELD_GET(AX_FW_REV_MAJOR_MASK, w); + + w = get_unaligned_le16(buf + 4); + info->device_build_variant = FIELD_GET(AX_VARIANT_MASK, w); + info->runtime_fw_status = !!(w & AX_FW_STATUS); + info->tcp_revision = FIELD_GET(AX_TCP_REV_MASK, w); + + w = get_unaligned_le16(buf + 6); + info->bootloader_fw_rev_minor = FIELD_GET(AX_BOOT_REV_MINOR_MASK, w); + info->bootloader_fw_rev_major = FIELD_GET(AX_BOOT_REV_MAJOR_MASK, w); + + info->jedec_id = get_unaligned_le16(buf + 8); + + w = get_unaligned_le16(buf + 10); + info->num_usages = FIELD_GET(AX_NUM_USAGES_MASK, w); + info->silicon_revision = FIELD_GET(AX_SILICON_REV_MASK, w); + info->runtime_fw_rev_patch = FIELD_GET(AX_RUNTIME_FW_PATCH_MASK, w); +} + +static void axiom_unpack_usage_table(u8 *buf, struct axiom *ax) +{ + struct u31_usage_entry *entry; + u16 report_len; + u8 *ptr; + int i; + u16 w; + + for (i = 0; i < ax->dev_info.num_usages && i < U31_MAX_USAGES; i++) { + entry = &ax->usage_table[i]; + /* Calculate offset for this specific entry */ + ptr = buf + (i * SIZE_U31_USAGE_ENTRY); + + w = get_unaligned_le16(ptr); + entry->usage_num = FIELD_GET(AX_U31_USAGE_NUM_MASK, w); + entry->start_page = FIELD_GET(AX_U31_START_PAGE_MASK, w); + + w = get_unaligned_le16(ptr + 2); + entry->num_pages = FIELD_GET(AX_U31_NUM_PAGES_MASK, w); + entry->max_offset = FIELD_GET(AX_U31_MAX_OFFSET_MASK, w); + entry->offset_type = !!(w & AX_U31_OFFSET_TYPE_BIT); + + w = get_unaligned_le16(ptr + 4); + entry->uifrevision = FIELD_GET(AX_U31_UIF_REV_MASK, w); + entry->usage_type = FIELD_GET(AX_U31_USAGE_TYPE_MASK, w); + + // Convert words to bytes + report_len = (entry->max_offset + 1) * 2; + if (entry->usage_type == REPORT && + report_len > ax->max_report_len) { + ax->max_report_len = report_len; + } + } +} + +static int axiom_init_dev_info(struct axiom *ax) +{ + struct u31_usage_entry *u; + const char *variant_str; + char silicon_rev; + int err; + int i; + + /* Read page 0 of u31 */ + err = ax->bus_ops->read(ax->dev, 0x0, SIZE_U31_DEVICE_INFO, + ax->read_buf); + if (err) + return -EIO; + + axiom_unpack_device_info(ax->read_buf, &ax->dev_info); + + silicon_rev = (char)(0x41 + ax->dev_info.silicon_revision); + + if (ax->dev_info.device_build_variant < ARRAY_SIZE(fw_variants)) + variant_str = fw_variants[ax->dev_info.device_build_variant]; + else + variant_str = "UNKNOWN"; + + dev_info(ax->dev, "Firmware Info:\n"); + dev_info(ax->dev, " BL Mode : %u\n", ax->dev_info.mode); + dev_info(ax->dev, " Device ID : %04x\n", ax->dev_info.device_id); + dev_info(ax->dev, " FW Revision : %u.%u.%u-%s %s\n", + ax->dev_info.runtime_fw_rev_major, + ax->dev_info.runtime_fw_rev_minor, + ax->dev_info.runtime_fw_rev_patch, + (ax->dev_info.runtime_fw_status == 0) ? "eng" : "prod", + variant_str); + dev_info(ax->dev, " BL Revision : %02x.%02x\n", + ax->dev_info.bootloader_fw_rev_major, + ax->dev_info.bootloader_fw_rev_minor); + dev_info(ax->dev, " Silicon : 0x%04X (Rev %c)\n", + ax->dev_info.jedec_id, silicon_rev); + dev_info(ax->dev, " Num Usages : %u\n", ax->dev_info.num_usages); + + if (ax->dev_info.num_usages > U31_MAX_USAGES) { + dev_err(ax->dev, + "Num usages (%u) exceeds maximum supported (%u)\n", + ax->dev_info.num_usages, U31_MAX_USAGES); + return -EINVAL; + } + + /* Read the second page of u31 to get the usage table */ + err = ax->bus_ops->read(ax->dev, 0x100, + sizeof(ax->usage_table[0]) * + ax->dev_info.num_usages, + ax->read_buf); + if (err) + return -EIO; + + axiom_unpack_usage_table(ax->read_buf, ax); + + dev_info(ax->dev, "Usage Table:\n"); + for (i = 0; i < ax->dev_info.num_usages; i++) { + u = &ax->usage_table[i]; + + dev_info(ax->dev, " Usage: u%02x Rev: %3u Page: 0x%02x00 Num Pages: %3u\n", + u->usage_num, u->uifrevision, u->start_page, + u->num_pages); + } + + if (ax->max_report_len > AXIOM_MAX_READ_SIZE) { + dev_err(ax->dev, + "aXiom maximum report length (%u) greater than allocated buffer size (%u).", + ax->max_report_len, AXIOM_MAX_READ_SIZE); + return -EINVAL; + } + + /* Set u34 address to allow direct access to report reading address */ + u = usage_find_entry(ax, 0x34); + if (IS_ERR(u)) + return PTR_ERR(u); + ax->u34_address = u->start_page << 8; + + return 0; +} + +static int axiom_process_u41_report(struct axiom *ax, u8 *report) +{ + enum u41_target_state_e state; + u16 target_present; + bool active; + u8 offset; + int i; + u16 x; + u16 y; + s8 z; + + target_present = + FIELD_GET(AX_U41_PRESENT_MASK, get_unaligned_le16(&report[0])); + + for (i = 0; i < U41_MAX_TARGETS; i++) { + active = !!((target_present >> i) & 1); + + offset = U41_X_Y_OFFSET + (i * U41_COORD_SIZE); + x = get_unaligned_le16(&report[offset]); + y = get_unaligned_le16(&report[offset + 2]); + z = report[U41_Z_OFFSET + i]; + + if (!active) + state = target_state_not_present; + else if (z >= 0) + state = target_state_touching; + else if ((z > U41_PROX_LEVEL) && (z < 0)) + state = target_state_hover; + else if (z == U41_PROX_LEVEL) + state = target_state_prox; + else + state = target_state_not_present; + + dev_dbg(ax->dev, "Target %d: x=%u y=%u z=%d present=%d\n", i, x, + y, z, active); + + switch (state) { + case target_state_not_present: + case target_state_prox: + + input_mt_slot(ax->input, i); + input_mt_report_slot_inactive(ax->input); + break; + + case target_state_hover: + case target_state_touching: + + input_mt_slot(ax->input, i); + input_report_abs(ax->input, ABS_MT_TRACKING_ID, i); + input_report_abs(ax->input, ABS_MT_POSITION_X, x); + input_report_abs(ax->input, ABS_MT_POSITION_Y, y); + + if (state == target_state_touching) { + input_report_abs(ax->input, ABS_MT_DISTANCE, 0); + input_report_abs(ax->input, ABS_MT_PRESSURE, z); + } else { /* Hover */ + input_report_abs(ax->input, ABS_MT_DISTANCE, -z); + input_report_abs(ax->input, ABS_MT_PRESSURE, 0); + } + break; + + default: + break; + } + } + + input_mt_sync_frame(ax->input); + input_sync(ax->input); + + return 0; +} + +static int axiom_process_report(struct axiom *ax, u8 *report) +{ + u16 hdr_buf = get_unaligned_le16(&report[0]); + struct u34_report_header hdr; + u16 crc_report; + u16 crc_calc; + int err; + u8 len; + + dev_dbg(ax->dev, "Payload Data %*ph\n", ax->max_report_len, report); + + hdr.report_length = FIELD_GET(AX_U34_LEN_MASK, hdr_buf); + hdr.overflow = !!(hdr_buf & AX_U34_OVERFLOW); + hdr.report_usage = FIELD_GET(AX_U34_USAGE_MASK, hdr_buf); + + len = hdr.report_length << 1; + if (hdr.report_length == 0) { + dev_err(ax->dev, "Zero length report discarded.\n"); + return -EIO; + } + + // Length is 16 bit words and remove the size of the CRC16 itself + crc_report = (report[len - 1] << 8) | (report[len - 2]); + crc_calc = crc16(0, report, (len - 2)); + + if (crc_calc != crc_report) { + dev_err(ax->dev, + "CRC mismatch! Expected: %04X, Calculated CRC: %04X. Report discarded.\n", + crc_report, crc_calc); + return -EIO; + } + + switch (hdr.report_usage) { + case AX_2DCTS_REPORT_ID: + err = axiom_process_u41_report(ax, + &report[AX_U34_PAYLOAD_BUFFER]); + break; + + default: + break; + } + + return err; +} + +static void axiom_poll(struct input_dev *input_dev) +{ + struct axiom *ax = input_get_drvdata(input_dev); + int err; + + /* Read touch reports from u34 */ + err = ax->bus_ops->read(ax->dev, ax->u34_address, ax->max_report_len, + ax->read_buf); + if (err) + return; + + err = axiom_process_report(ax, ax->read_buf); + if (err) + dev_err(ax->dev, "Failed to process report: %d\n", err); +} + +static irqreturn_t axiom_irq(int irq, void *handle) +{ + struct axiom *ax = handle; + int err; + + /* Read touch reports from u34 */ + err = ax->bus_ops->read(ax->dev, ax->u34_address, ax->max_report_len, + ax->read_buf); + if (err) + goto out; + + err = axiom_process_report(ax, ax->read_buf); + if (err) + dev_err(ax->dev, "Failed to process report: %d\n", err); + +out: + return IRQ_HANDLED; +} + +struct axiom *axiom_probe(const struct axiom_bus_ops *bus_ops, + struct device *dev, int irq) +{ + struct input_dev *input_dev; + struct axiom *ax; + int err; + + ax = devm_kzalloc(dev, sizeof(*ax), GFP_KERNEL); + if (!ax) + return ERR_PTR(-ENOMEM); + + input_dev = devm_input_allocate_device(dev); + if (!input_dev) { + pr_err("ERROR: aXiom-core: Failed to allocate memory for input device!\n"); + return ERR_PTR(-ENOMEM); + } + + ax->dev = dev; + ax->input = input_dev; + ax->bus_ops = bus_ops; + ax->irq = irq; + + dev_info(dev, "aXiom Probe\n"); + if (poll_enable) + dev_info(dev, "Polling Period : %u\n", poll_period); + else + dev_info(dev, "Device IRQ : %u\n", ax->irq); + + axiom_set_capabilities(input_dev); + + err = axiom_init_dev_info(ax); + if (err) { + dev_err(ax->dev, "Failed to read device info, err: %d\n", err); + return ERR_PTR(err); + } + + if (poll_enable) { + err = input_setup_polling(input_dev, axiom_poll); + if (err) { + dev_err(ax->dev, "could not set up polling mode, %d\n", + err); + return ERR_PTR(err); + } + + input_set_poll_interval(input_dev, poll_period); + } else { + err = devm_request_threaded_irq(ax->dev, ax->irq, NULL, + axiom_irq, + IRQF_ONESHOT, + "axiom_irq", ax); + if (err) + return ERR_PTR(err); + } + + err = input_register_device(input_dev); + if (err) { + dev_err(ax->dev, "Failed to register input device: %d\n", err); + return ERR_PTR(err); + } + + input_set_drvdata(input_dev, ax); + + return ax; +} +EXPORT_SYMBOL_GPL(axiom_probe); + +MODULE_AUTHOR("TouchNetix <support@touchnetix.com>"); +MODULE_DESCRIPTION("aXiom touchscreen core logic"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/axiom_core.h b/drivers/input/touchscreen/axiom_core.h new file mode 100644 index 000000000000..8ca46200bede --- /dev/null +++ b/drivers/input/touchscreen/axiom_core.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * TouchNetix aXiom Touchscreen Driver + * + * Copyright (C) 2020-2026 TouchNetix Ltd. + * + * Author(s): Mark Satterthwaite <mark.satterthwaite@touchnetix.com> + * Pedro Torruella <pedro.torruella@touchnetix.com> + * Bart Prescott <bartp@baasheep.co.uk> + * Hannah Rossiter <hannah.rossiter@touchnetix.com> + * Andrew Thomas <andrew.thomas@touchnetix.com> + */ + +#ifndef __AXIOM_CORE_H +#define __AXIOM_CORE_H + +#include <linux/input.h> + +#define AX_POLLING_PERIOD_MS (10) + +#define AXIOM_PAGE_SIZE (256) +// u31 has 2 pages for usage table entries. (2 * PAGE_SIZE) / U31_BYTES_PER_USAGE = 85 +#define AXIOM_MAX_READ_SIZE (2 * AXIOM_PAGE_SIZE) +#define SIZE_U31_DEVICE_INFO (12) +#define SIZE_U31_USAGE_ENTRY (6) +#define U31_MAX_USAGES (85U) +#define U41_MAX_TARGETS (10U) +#define U41_PROX_LEVEL (-128) +#define AXIOM_HOLDOFF_DELAY_US (40) + +enum ax_comms_op_e { AX_WR_OP = 0, AX_RD_OP = 1 }; + +enum report_ids_e { + AX_2DCTS_REPORT_ID = 0x41, +}; + +enum axiom_mode_e { + AX_RUNTIME_STATE = 0, + AX_BOOTLOADER_STATE = 1, +}; + +enum usage_type_e { + UNKNOWN = 0, + OTHER = 1, + REPORT = 2, + REGISTER = 3, + REGISTER_READ_ONLY_ = 4, + CDU = 5, + CDU_READ_ONLY_ = 6, +}; + +struct axiom_device_info { + u16 device_id; + u8 mode; + u8 runtime_fw_rev_minor; + u8 runtime_fw_rev_major; + u8 device_build_variant; + u8 runtime_fw_status; + u8 tcp_revision; + u8 bootloader_fw_rev_minor; + u8 bootloader_fw_rev_major; + u8 jedec_id; + u8 num_usages; + u8 silicon_revision; + u8 runtime_fw_rev_patch; +}; + +struct u31_usage_entry { + u8 usage_num; + u8 start_page; + u8 num_pages; + u8 max_offset; + u8 offset_type; + u8 uifrevision; + u8 usage_type; +}; + +struct axiom_cmd_header { + __le16 target_address; + __le16 length_and_op; +} __packed; + +struct axiom_bus_ops { + u16 bustype; + int (*write)(struct device *dev, u16 addr, u16 length, void *values); + int (*read)(struct device *dev, u16 addr, u16 length, void *values); +}; + +enum u41_target_state_e { + target_state_not_present = 0, + target_state_prox = 1, + target_state_hover = 2, + target_state_touching = 3, +}; + +struct axiom { + struct device *dev; + int irq; + struct input_dev *input; + const struct axiom_bus_ops *bus_ops; + struct axiom_device_info dev_info; + struct u31_usage_entry usage_table[U31_MAX_USAGES]; + u16 max_report_len; + u16 u34_address; + + u8 read_buf[AXIOM_MAX_READ_SIZE]; +}; + +struct u34_report_header { + u8 report_length; + u8 overflow; + u8 report_usage; +}; + +struct axiom *axiom_probe(const struct axiom_bus_ops *bus_ops, + struct device *dev, int irq); + +#endif /* __AXIOM_CORE_H */ diff --git a/drivers/input/touchscreen/axiom_i2c.c b/drivers/input/touchscreen/axiom_i2c.c new file mode 100644 index 000000000000..93b445f4ce54 --- /dev/null +++ b/drivers/input/touchscreen/axiom_i2c.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TouchNetix aXiom Touchscreen Driver + * + * Copyright (C) 2020-2026 TouchNetix Ltd. + * + * Author(s): Mark Satterthwaite <mark.satterthwaite@touchnetix.com> + * Pedro Torruella <pedro.torruella@touchnetix.com> + * Bart Prescott <bartp@baasheep.co.uk> + * Hannah Rossiter <hannah.rossiter@touchnetix.com> + * Andrew Thomas <andrew.thomas@touchnetix.com> + */ + +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/input.h> +#include <linux/unaligned.h> +#include "axiom_core.h" + +static int axiom_i2c_read_block_data(struct device *dev, u16 addr, u16 length, + void *values) +{ + struct i2c_client *client = to_i2c_client(dev); + struct axiom_cmd_header cmd_header; + u16 len_op; + int err; + + put_unaligned_le16(addr, &cmd_header.target_address); + len_op = (length & 0x7FFF) | (AX_RD_OP << 15); + put_unaligned_le16(len_op, &cmd_header.length_and_op); + + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = sizeof(cmd_header), + .buf = (u8 *)&cmd_header, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = values, + }, + }; + + err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (err < 0) { + dev_err(dev, "I2C transfer error: %d\n", err); + return err; + } + + udelay(AXIOM_HOLDOFF_DELAY_US); + + return err != ARRAY_SIZE(msgs) ? -EIO : 0; +} + +static int axiom_i2c_write_block_data(struct device *dev, u16 addr, u16 length, + void *values) +{ + struct i2c_client *client = to_i2c_client(dev); + struct axiom_cmd_header cmd_header; + u16 len_op; + int err; + + put_unaligned_le16(addr, &cmd_header.target_address); + len_op = (length & 0x7FFF) | (AX_WR_OP << 15); + put_unaligned_le16(len_op, &cmd_header.length_and_op); + + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = sizeof(cmd_header), + .buf = (u8 *)&cmd_header, + }, + { + .addr = client->addr, + .flags = 0, + .len = length, + .buf = values, + }, + }; + + err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (err < 0) { + dev_err(dev, "I2C transfer error: %d\n", err); + return err; + } + + udelay(AXIOM_HOLDOFF_DELAY_US); + + return err != ARRAY_SIZE(msgs) ? -EIO : 0; +} + +static const struct axiom_bus_ops axiom_i2c_bus_ops = { + .bustype = BUS_I2C, + .write = axiom_i2c_write_block_data, + .read = axiom_i2c_read_block_data, +}; + +static int axiom_i2c_probe(struct i2c_client *client) +{ + struct axiom *axiom; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "I2C functionality not Supported\n"); + return -EIO; + } + + axiom = axiom_probe(&axiom_i2c_bus_ops, &client->dev, client->irq); + if (IS_ERR(axiom)) + return dev_err_probe(&client->dev, PTR_ERR(axiom), + "failed to register input device\n"); + + return 0; +} + +static const struct i2c_device_id axiom_i2c_id_table[] = { + { "axiom-i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, axiom_i2c_id_table); + +static const struct of_device_id axiom_i2c_dt_ids[] = { + { + .compatible = "tnx,axiom-i2c", + .data = "axiom", + }, + {} +}; +MODULE_DEVICE_TABLE(of, axiom_i2c_dt_ids); + +static struct i2c_driver axiom_i2c_driver = { + .driver = { + .name = "axiom_i2c", + .of_match_table = axiom_i2c_dt_ids, + }, + .id_table = axiom_i2c_id_table, + .probe = axiom_i2c_probe, +}; + +module_i2c_driver(axiom_i2c_driver); + +MODULE_AUTHOR("TouchNetix <support@touchnetix.com>"); +MODULE_DESCRIPTION("aXiom touchscreen I2C bus driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0.0"); diff --git a/drivers/input/touchscreen/axiom_spi.c b/drivers/input/touchscreen/axiom_spi.c new file mode 100644 index 000000000000..a7d9d3dd66ce --- /dev/null +++ b/drivers/input/touchscreen/axiom_spi.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TouchNetix aXiom Touchscreen Driver + * + * Copyright (C) 2020-2026 TouchNetix Ltd. + * + * Author(s): Mark Satterthwaite <mark.satterthwaite@touchnetix.com> + * Pedro Torruella <pedro.torruella@touchnetix.com> + * Bart Prescott <bartp@baasheep.co.uk> + * Hannah Rossiter <hannah.rossiter@touchnetix.com> + * Andrew Thomas <andrew.thomas@touchnetix.com> + */ + +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/input.h> +#include <linux/unaligned.h> +#include "axiom_core.h" + +#define SPI_PADDING_LEN (32) + +static int axiom_spi_transfer(struct device *dev, enum ax_comms_op_e op, + u16 addr, u16 length, void *values) +{ + struct spi_device *spi = to_spi_device(dev); + u8 pad_buf[SPI_PADDING_LEN] = { 0 }; + struct axiom_cmd_header cmd_header; + struct spi_transfer xfr_header; + struct spi_transfer xfr_padding; + struct spi_transfer xfr_payload; + struct spi_message msg; + u16 len_op; + int err; + + put_unaligned_le16(addr, &cmd_header.target_address); + len_op = (length & 0x7FFF) | (AX_RD_OP << 15); + put_unaligned_le16(len_op, &cmd_header.length_and_op); + + memset(&xfr_header, 0, sizeof(xfr_header)); + memset(&xfr_padding, 0, sizeof(xfr_padding)); + memset(&xfr_payload, 0, sizeof(xfr_payload)); + + /* Setup the SPI transfer operations */ + xfr_header.tx_buf = &cmd_header; + xfr_header.len = sizeof(cmd_header); + + xfr_padding.tx_buf = pad_buf; + xfr_padding.len = sizeof(pad_buf); + + switch (op) { + case AX_WR_OP: + xfr_payload.tx_buf = values; + break; + case AX_RD_OP: + xfr_payload.rx_buf = values; + break; + default: + dev_err(dev, "%s: invalid operation: %d\n", __func__, op); + return -EINVAL; + } + xfr_payload.len = length; + + spi_message_init(&msg); + spi_message_add_tail(&xfr_header, &msg); + spi_message_add_tail(&xfr_padding, &msg); + spi_message_add_tail(&xfr_payload, &msg); + + err = spi_sync(spi, &msg); + if (err < 0) { + dev_err(&spi->dev, "Failed to SPI transfer, error: %d\n", err); + return err; + } + + udelay(AXIOM_HOLDOFF_DELAY_US); + + return 0; +} + +static int axiom_spi_read_block_data(struct device *dev, u16 addr, u16 length, + void *values) +{ + return axiom_spi_transfer(dev, AX_RD_OP, addr, length, values); +} + +static int axiom_spi_write_block_data(struct device *dev, u16 addr, u16 length, + void *values) +{ + return axiom_spi_transfer(dev, AX_WR_OP, addr, length, values); +} + +static const struct axiom_bus_ops axiom_spi_bus_ops = { + .bustype = BUS_SPI, + .write = axiom_spi_write_block_data, + .read = axiom_spi_read_block_data, +}; + +static int axiom_spi_probe(struct spi_device *spi) +{ + struct axiom *axiom; + int err; + + /* Set up SPI */ + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + spi->max_speed_hz = 4000000; + + if (spi->irq == 0) + dev_err(&spi->dev, "No IRQ specified!\n"); + + err = spi_setup(spi); + if (err < 0) { + dev_err(&spi->dev, "%s: SPI setup error %d\n", __func__, err); + return err; + } + axiom = axiom_probe(&axiom_spi_bus_ops, &spi->dev, spi->irq); + if (IS_ERR(axiom)) + return dev_err_probe(&spi->dev, PTR_ERR(axiom), + "failed to register input device\n"); + + return 0; +} + +static const struct spi_device_id axiom_spi_id_table[] = { + { "axiom-spi" }, + {}, +}; +MODULE_DEVICE_TABLE(spi, axiom_spi_id_table); + +static const struct of_device_id axiom_spi_dt_ids[] = { + { + .compatible = "tnx,axiom-spi", + .data = "axiom", + }, + {} +}; +MODULE_DEVICE_TABLE(of, axiom_spi_dt_ids); + +static struct spi_driver axiom_spi_driver = { + .id_table = axiom_spi_id_table, + .driver = { + .name = "axiom_spi", + .of_match_table = axiom_spi_dt_ids, + }, + .probe = axiom_spi_probe, +}; + +module_spi_driver(axiom_spi_driver); + +MODULE_AUTHOR("TouchNetix <support@touchnetix.com>"); +MODULE_DESCRIPTION("aXiom touchscreen SPI bus driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0.0"); -- 2.43.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-01-27 14:16 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-01-26 16:38 [PATCH 0/2] Input: add support for aXiom touchscreen controller using SPI or I2C Andrew Thomas 2026-01-26 16:38 ` [PATCH 1/2] dt-bindings: input: touchscreen: add TouchNetix aXiom device tree Andrew Thomas 2026-01-26 17:32 ` Rob Herring (Arm) 2026-01-27 14:16 ` Rob Herring 2026-01-26 16:38 ` [PATCH 2/2] Input: add support for aXiom touchscreen controller using SPI or I2C Andrew Thomas
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox