From dd8f085fc0232b77f3db885b0670a3e8d3094d36 Mon Sep 17 00:00:00 2001 From: Mel Date: Mon, 13 Jul 2026 20:00:00 +0200 Subject: Wrap into NixOS and Nix flake Signed-off-by: Mel --- module.nix | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 module.nix (limited to 'module.nix') diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..2cb054c --- /dev/null +++ b/module.nix @@ -0,0 +1,117 @@ +# nixos module to fully configure mhs35 support both in kernel and userland. +{ + config, + lib, + ... +}: + +let + inherit (lib) + mkEnableOption + mkIf + mkOption + optional + types + ; + + cfg = config.hardware.mhs35; + + mhs35-module = config.boot.kernelPackages.callPackage ./package.nix { }; + + # just replace the text to avoid messing with merging device trees, + # it's just simpler this way... :) + panelDts = builtins.replaceStrings + [ "rotation = <180>" "spi-max-frequency = <8000000>" ] + [ + "rotation = <${toString cfg.rotation}>" + "spi-max-frequency = <${toString cfg.spiFrequencyHz}>" + ] + (builtins.readFile ./dts/mhs35-overlay.dts); + + # touch matrices for panel. (libinput) + # TODO(mel): 90 & 270 are missing, but are of course supported. + # let's write the matrix out for them, too! + defaultMatrices = { + "0" = "0 1 0 -1 0 1"; + "180" = "0 -1 1 1 0 0"; + }; +in +{ + options.hardware.mhs35 = { + enable = mkEnableOption "goodtft MHS-3.5 SPI display support"; + + rotation = mkOption { + type = types.enum [ 0 90 180 270 ]; + default = 180; + description = '' + The panel rotation. + ''; + # orientations (for pi4, when looking at screen upright): + # * 0 - landscape, usb/rj-45 ports on the left + # * 90 - portrait, ports on top + # * 180 - landscape, ports on the right + # * 270 - portrait, ports on bottom + }; + + spiFrequencyHz = mkOption { + type = types.ints.positive; + default = 8000000; + description = '' + Panel SPI frequency. + 8 MHz is the very very conservative default, the panel + claims to support upto 125MHz. + ''; + }; + + touch = { + enable = mkEnableOption "MHS-3.5 ADS7846 touch support" // { + default = true; + }; + + calibrationMatrix = mkOption { + type = types.nullOr types.str; + default = defaultMatrices.${toString cfg.rotation} or null; + description = '' + Touch calibration matrix for touchscreen (libinput). + Set as LIBINPUT_CALIBRATION_MATRIX in udev. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + { + assertion = !cfg.touch.enable || cfg.touch.calibrationMatrix != null; + message = '' + hardware.mhs35: no known touch calibration matrix for + rotation ${toString cfg.rotation}! + set `hardware.mhs35.touch.calibrationMatrix` explicitly. + (and consider contributing the matrix! :3) + ''; + } + ]; + + boot.extraModulePackages = [ mhs35-module ]; + + # do not let the default in-tree ili9486 win control over our device! + # (it also lists compatibility with "waveshare,rpi-lcd-35") + boot.blacklistedKernelModules = [ "ili9486" ]; + + hardware.deviceTree.overlays = [ + { + name = "mhs35-overlay"; + dtsText = panelDts; + } + ] ++ optional cfg.touch.enable { + name = "mhs35-touch-overlay"; + dtsFile = ./dts/mhs35-touch-overlay.dts; + }; + + services.libinput.enable = mkIf cfg.touch.enable true; + + services.udev.extraRules = mkIf cfg.touch.enable '' + ATTRS{name}=="ADS7846 Touchscreen", ENV{LIBINPUT_CALIBRATION_MATRIX}="${cfg.touch.calibrationMatrix}" + ''; + }; +} -- cgit 1.4.1