82 lines
3.4 KiB
C++
82 lines
3.4 KiB
C++
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
||
|
|
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||
|
|
|
||
|
|
// lint-disable-file fixed-width-types
|
||
|
|
/*
|
||
|
|
Fingerprintd:Sensor unit tests.
|
||
|
|
|
||
|
|
Mostly one thing. gpio8-11 are the fingerprint SPI pads, they are
|
||
|
|
XPU-protected, and touching one from the normal world is not an error return --
|
||
|
|
it is an immediate SError and the phone reboots where it stands. Mainline's DTS
|
||
|
|
reserves the range but a userspace chardev request never consults that, so the
|
||
|
|
guard is ours and it is worth a test that spells out every pin.
|
||
|
|
*/
|
||
|
|
import std;
|
||
|
|
import Fingerprintd;
|
||
|
|
|
||
|
|
using namespace fingerprintd::sensor;
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
int Failures = 0;
|
||
|
|
void Check(bool cond, std::string_view msg) {
|
||
|
|
if (!cond) {
|
||
|
|
std::println(std::cerr, "FAIL: {}", msg);
|
||
|
|
++Failures;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int main() {
|
||
|
|
// ---- The XPU-protected range, pin by pin
|
||
|
|
Check(IsReserved(8) && IsReserved(9) && IsReserved(10) && IsReserved(11),
|
||
|
|
"gpio8-11 are all reserved");
|
||
|
|
Check(!IsReserved(7), "gpio7 is below the range");
|
||
|
|
Check(!IsReserved(12), "gpio12 is above it");
|
||
|
|
Check(ReservedSpiFirst == 8 && ReservedSpiCount == 4,
|
||
|
|
"the range matches the DTS gpio-reserved-ranges = <8 4>");
|
||
|
|
|
||
|
|
for (unsigned l = 8; l <= 11; l++)
|
||
|
|
Check(!IsSafeLine(l), std::format("gpio{} must never be opened", l));
|
||
|
|
|
||
|
|
// ---- Every line we own is outside it
|
||
|
|
for (unsigned l : OwnedLines)
|
||
|
|
Check(IsSafeLine(l), std::format("owned line gpio{} is safe", l));
|
||
|
|
Check(OwnedLines.size() == 3, "three lines: power, reset, irq");
|
||
|
|
|
||
|
|
// ---- The pins themselves, from the stock device tree
|
||
|
|
Check(PowerLine == 29, "vdd-gpio = <&tlmm 29>");
|
||
|
|
Check(ResetLine == 74, "reset-gpio = <&tlmm 74>");
|
||
|
|
Check(IrqLine == 75, "irq-gpio = <&tlmm 75>");
|
||
|
|
Check(PowerLine != ResetLine && ResetLine != IrqLine && PowerLine != IrqLine,
|
||
|
|
"the three are distinct");
|
||
|
|
|
||
|
|
// The vendor calls it FPS_INT_N but the DT says edge-rising: it idles low
|
||
|
|
// and pulses high. Reading it as active-low sees the finger backwards.
|
||
|
|
Check(IrqIsActiveHigh, "the interrupt is active high despite the _N");
|
||
|
|
|
||
|
|
// ---- The chip is found by label
|
||
|
|
//
|
||
|
|
// The chardev reports the DT unit address, not the binding's name. "tlmm"
|
||
|
|
// is what every DT reference calls it and matching on that finds nothing.
|
||
|
|
Check(ChipLabel == "f100000.pinctrl", "TLMM advertises its DT unit address");
|
||
|
|
Check(ChipLabel != "tlmm", "the binding name is not the chardev label");
|
||
|
|
Check(!ChipLabel.empty(), "never an index: /dev/gpiochipN is not stable");
|
||
|
|
|
||
|
|
// The line-count check has to actually exclude the other pinctrl on this
|
||
|
|
// SoC, which has 23 lines, while admitting TLMM's 168.
|
||
|
|
Check(MinChipLines > IrqLine, "a valid chip can contain every line we open");
|
||
|
|
Check(MinChipLines > 23, "excludes the 23-line 3440000.pinctrl");
|
||
|
|
Check(MinChipLines <= 168, "admits TLMM");
|
||
|
|
|
||
|
|
// ---- Sequencing
|
||
|
|
Check(PowerSettle > ResetSettle, "the rail gets the longer settle");
|
||
|
|
Check(PowerSettle.count() == 250 && ResetSettle.count() == 50, "the proven delays");
|
||
|
|
Check(AssertResetBeforePower, "a warm restart starts from the cold state");
|
||
|
|
|
||
|
|
// ---- The reason the daemon owns the rail at all
|
||
|
|
Check(RcDeviceNotFound == -205,
|
||
|
|
"a second init in one power cycle answers -205, so recovery is a power cycle");
|
||
|
|
|
||
|
|
if (Failures == 0) std::println("Sensor: all tests passed");
|
||
|
|
return Failures;
|
||
|
|
}
|