首页/目录/全部文章

全部文章

八个专题的源码、算法与协议笔记都在这里。

笔记列表

RK3588 HID 配置、部署、调试与安全

RK3588 HID 配置、部署、调试与安全

1. 默认配置画像

arch/arm64/configs/rockchip_linux_defconfig 显式包含:

1
2
3
4
5
6
7
8
CONFIG_BT_HIDP=y
CONFIG_HID_BATTERY_STRENGTH=y
CONFIG_HIDRAW=y
CONFIG_UHID=y
CONFIG_HID_KENSINGTON=y
CONFIG_HID_MULTITOUCH=y
CONFIG_USB_HIDDEV=y
CONFIG_I2C_HID_OF=y

HID、HID_GENERIC、USB_HID 有默认 y 关系,但最终产品必须检查合并后的 .config。vehicle 片段关闭 USB HIDDEV。

2. 场景建议

场景 必要能力
USB 键鼠 HID、HID_GENERIC、USB_HID
USB 游戏手柄 USB_HID + 对应 vendor/FF
蓝牙键鼠 BT、BT_HIDP;BLE 还依赖 BlueZ/UHID
I2C HID 触摸屏 I2C_HID_OF + HID_MULTITOUCH
Android 虚拟 HID UHID
专有控制设备 HIDRAW
旧 UPS/显示器应用 USB_HIDDEV

3. 枚举分层

1
2
3
4
5
6
USB/I2C/Bluetooth device exists?
-> transport driver bound?
-> /sys/bus/hid/devices node exists?
-> hid-generic/vendor driver bound?
-> input/hidraw node created?
-> udev/SELinux permission allows userspace?

逐层定位比反复重插或重启服务有效。

4. USB 排查

1
2
3
4
5
lsusb -t
lsusb -v
cat /sys/bus/usb/devices/*/power/runtime_status
cat /proc/interrupts
dmesg | grep -Ei 'usb|usbhid|hid'

RK3588 还需检查 USB2/USB3 PHY、Type-C role、hub 电源和 VBUS。

5. I2C 排查

  • DTS status/address;
  • IRQ GPIO 和极性;
  • reset GPIO;
  • regulator;
  • descriptor address;
  • I2C pinctrl/rate;
  • suspend wake;
  • reset/post-power delay。

IRQ 增长但无 input 事件时检查 packet length/report ID;无 IRQ 时先查 GPIO/供电。

6. 输入排查

1
2
3
4
cat /proc/bus/input/devices
evtest /dev/input/eventX
getevent -lt
libinput debug-events

确认事件映射、属性 DIRECT/POINTER、ABS range、MT slots 和 keycode。

7. HID 原始层

1
2
3
4
5
for d in /sys/bus/hid/devices/*; do
echo "$d"; cat "$d/uevent"
done

cat /sys/bus/hid/devices/DEVICE/report_descriptor > /tmp/rdesc

抓 raw 数据时避免向生产设备盲发 Feature/Output report。

8. 性能

  • 高频 gaming mouse 会增加 USB IRQ/input event;
  • ALWAYS_POLL 阻止空闲停轮询;
  • I2C 大 report + 低 bus rate 增加延迟;
  • multitouch contact 数显著增加每帧处理;
  • debugfs/dynamic debug 会改变时序;
  • userspace input stack 也会增加手势和合成延迟。

9. PM/wakeup

唤醒链必须同时满足:

  • device wake capability;
  • HID/transport driver;
  • USB hub 或 I2C IRQ;
  • RK3588 controller/power domain;
  • DT wakeup-source
  • userspace /sys/.../power/wakeup

10. 安全

HID 外设可伪装键盘并立即注入按键。建议:

  • 量产关闭不用的 UHID/HIDDEV/vendor drivers;
  • 限制 hidraw/uhid 权限;
  • USB authorization/port policy;
  • 不信任 descriptor/report;
  • 容器不默认映射 input/hidraw/uhid;
  • 固件升级协议需签名和长度校验;
  • 启用必要 LSM/udev allowlist。

11. 裁剪

嵌入式固定硬件可保留:

1
2
3
4
HID + HID_GENERIC
USB_HID and/or I2C_HID_OF
HID_MULTITOUCH if required
specific vendor driver

按需求关闭 Wacom、游戏 FF、x86 sensor hub、HIDDEV、UHID、HIDRAW。关闭前确认工厂测试、蓝牙栈、升级工具是否依赖。

HID 子系统架构与源码总览

HID 子系统架构与源码总览

1. 目标

HID 将 USB、Bluetooth、I2C、虚拟用户态等不同传输统一为报告模型,并向上提供:

  • Linux input:键盘、鼠标、触控、游戏手柄;
  • hidraw:不解释的原始报告;
  • hiddev:USB 专用旧接口;
  • 专用 HID driver;
  • LED、力反馈、电池、传感器等功能。

2. 分层

1
2
3
4
5
6
7
8
9
10
11
12
13
Userspace
├─ evdev / input
├─ /dev/hidrawN
├─ /dev/uhid
└─ /dev/usb/hiddevN
|
HID Core: hid-core + hid-input + hid-quirks
|
HID Driver: generic / multitouch / vendor-specific
|
Low-level transport: usbhid / i2c-hid / hidp / uhid / sensor hub
|
USB / I2C / Bluetooth / userspace transport

3. 核心对象

结构 作用
hid_device 一台 HID 逻辑设备
hid_driver HID 总线驱动
hid_ll_driver USB/I2C/UHID 等传输操作
hid_report_enum Input/Output/Feature report 集合
hid_report 一个 report ID 的布局
hid_field 位段及逻辑/物理范围
hid_usage Usage Page + Usage ID 语义
hid_input HID 到 input_dev 的映射

4. 枚举链

1
2
3
4
5
6
7
8
9
10
11
12
13
transport probe
-> hid_allocate_device()
-> fill bus/vendor/product/name/phys/ll_driver
-> hid_add_device()
-> ll_driver->parse(): fetch report descriptor
-> hid_scan_report(): determine group
-> device_add() to hid_bus_type
-> HID driver match/probe
-> report_fixup (optional)
-> hid_parse_report()/hid_open_report()
-> hid_hw_start()
-> ll_driver->start()
-> hid_connect(INPUT/HIDRAW/HIDDEV/DRIVER)

5. 输入链

1
2
3
4
5
6
7
8
9
10
USB URB / I2C IRQ / HIDP packet / UHID write
-> hid_input_report()
-> driver->raw_event()
-> hid_report_raw_event()
-> hidraw_report_event()
-> parse fields and usages
-> driver->event()/report()
-> hidinput_report_event()
-> input_event()/input_sync()
-> evdev userspace

6. 输出链

LED、rumble、Feature 报告通过:

1
2
3
4
input/driver/hidraw
-> hid_hw_request() / hid_hw_raw_request() / hid_hw_output_report()
-> hid_ll_driver
-> USB control/interrupt OUT, I2C command, Bluetooth transaction...

7. 驱动匹配

hid_device_id 可匹配 bus、group、vendor、product。专用驱动可提供:

  • match
  • probe/remove
  • report_fixup
  • input_mapping/input_mapped
  • raw_event/event/report
  • PM 回调。

没有专用驱动时由 hid-generic 处理。

8. RK3588 重点

  • USB 键鼠/手柄:usbhid
  • 蓝牙键鼠/手柄:Bluetooth HIDP;
  • I2C HID 触摸屏/触控板能力:i2c-hid-of(本树 RK3588 DTS 未见标准 hid-over-i2c 实例);
  • 多点触控:hid-multitouch
  • Android/容器代理:UHID;
  • rockchip_linux_defconfig 开启 HIDRAW、UHID、MULTITOUCH、USB HIDDEV、I2C_HID_OF 和 HID 电池。

HID 本身一般不直接绑定 RK3588 SoC compatible;平台相关性主要来自 USB host、I2C controller、GPIO IRQ、电源和板级 DT。

Linux 6.1 HID 子系统文档索引

Linux 6.1 HID 子系统文档索引

源码:rk3588/kernel-6.1/drivers/hid/
平台:RK3588 / ARM64,Rockchip Linux 6.1 厂商树

文档

编号 文档 内容
总览 HID子系统架构与源码总览.md 分层、对象、数据路径
索引 源码目录与模块索引.md 文件、Kconfig、Makefile
01 HID-Core设备驱动模型与生命周期.md HID bus、匹配、probe/remove
02 Report描述符解析与报告处理.md item、collection、report/field/usage
03 HID-Input事件映射与输出控制.md input、LED、FF、电池
04 USB-HID传输与错误恢复.md URB、control/interrupt、PM
05 I2C-HID与RK3588设备树.md I2C HID、OF、IRQ、复位
06 HIDRAW-UHID-HIDDEV用户接口.md 原始接口与虚拟传输
07 蓝牙HIDP与其它传输边界.md HIDP、sensor hub、SPI 边界
08 Multitouch触控与手写设备.md MT、Wacom、RMI、UC-Logic
09 厂商专用HID驱动与Quirk机制.md fixup、raw_event、专用能力
10 HID-Sensor-Hub与传感器框架.md sensor usage、MFD/IIO
11 RK3588配置部署调试与安全.md defconfig、调试、裁剪、安全

推荐阅读顺序

1
2
3
4
5
总览 -> 01 生命周期 -> 02 报告解析 -> 03 Input
├-> 04 USB
├-> 05 I2C
├-> 06 用户态接口
└-> 08/09 专用设备

快速定位

1
2
3
4
5
cat /sys/bus/hid/devices/*/uevent
cat /sys/bus/hid/devices/*/report_descriptor > /tmp/rdesc.bin
ls -l /dev/hidraw* /dev/input/event*
cat /proc/bus/input/devices
udevadm info /dev/hidraw0

注意:drivers/hid/ 是总线无关 HID core 和部分传输/专用驱动;Bluetooth HIDP 位于 net/bluetooth/hidp/,SPI HID 等实现也可能位于其它目录。

drivers/hid/ 源码目录与模块索引

drivers/hid/ 源码目录与模块索引

1. 构建核心

drivers/hid/Makefile

1
2
3
hid.o = hid-core.o + hid-input.o + hid-quirks.o
+ hid-debug.o [CONFIG_DEBUG_FS]
+ hidraw.o [CONFIG_HIDRAW]
Kconfig 模块 说明
HID hid.o HID bus/core
HID_GENERIC hid-generic.o 通用驱动
HIDRAW 合入 hid.o /dev/hidrawN
UHID uhid.o 用户态传输

2. 核心文件

文件 职责
hid-core.c parser、bus、匹配、报告收发、生命周期
hid-input.c usage 到 input event 映射
hid-quirks.c VID/PID quirk 表和动态覆盖
hid-generic.c 通用 HID driver
hidraw.c 原始字符设备
uhid.c /dev/uhid 虚拟低层传输
hid-debug.c debugfs 描述符和事件
hid-ids.h 厂商/产品 ID

3. 传输目录

目录 Kconfig 说明
usbhid/ USB_HID USB HID transport
i2c-hid/ I2C_HID_* ACPI/OF I2C HID
intel-ish-hid/ INTEL_ISH_HID Intel sensor hub
amd-sfh-hid/ AMD_SFH_HID AMD sensor fusion hub
surface-hid/ Surface 相关 Microsoft Surface transport

Bluetooth HIDP 位于 net/bluetooth/hidp/,并非本目录。

4. 专用驱动分类

类别 代表文件
多点触控 hid-multitouch.chid-ntrig.c
数位板 wacom_*.chid-uclogic-*hid-waltop.c
游戏手柄 hid-playstation.chid-sony.chid-nintendo.chid-steam.c
Logitech hid-lg*.chid-logitech-dj.chid-logitech-hidpp.c
键鼠 hid-apple.chid-microsoft.chid-lenovo.c
HID sensor hid-sensor-hub.chid-sensor-custom.c
桥接芯片 hid-cp2112.chid-ft260.chid-mcp2221.c
显示/LED hid-picolcd_*hid-led.c

5. USB 子目录

1
2
3
usbhid.o = hid-core.o
+ hiddev.o [USB_HIDDEV]
+ hid-pidff.o [HID_PID]

usbkbd.c/usbmouse.c 是受限 Boot Protocol 驱动,不能与完整 USB HID 常规配置混用。

6. I2C 子目录

1
2
3
4
5
i2c-hid.o              = i2c-hid-core.o [+ DMI quirks]
i2c-hid-acpi.o = ACPI glue
i2c-hid-of.o = generic DT glue
i2c-hid-of-elan.o = Elan DT power/reset glue
i2c-hid-of-goodix.o = Goodix DT power/reset glue

7. 配置事实

Rockchip 主配置显式启用:

1
2
3
4
5
6
7
8
CONFIG_BT_HIDP=y
CONFIG_HID_BATTERY_STRENGTH=y
CONFIG_HIDRAW=y
CONFIG_UHID=y
CONFIG_HID_KENSINGTON=y
CONFIG_HID_MULTITOUCH=y
CONFIG_USB_HIDDEV=y
CONFIG_I2C_HID_OF=y

HIDHID_GENERICUSB_HID 具有默认 y 语义,但应以最终 .config 为准。rk3588_vehicle.config 明确关闭 USB HIDDEV。

HWMON Core 注册与生命周期

HWMON Core 注册与生命周期

1. Class

hwmon_class

  • name:hwmon
  • 默认属性:name、可选 label
  • release:释放自动属性、groups、label 和 hwmon_device

IDA 动态分配 hwmonN,编号会随 probe 顺序变化。

2. 现代 API

推荐:

1
2
devm_hwmon_device_register_with_info(parent, name, drvdata,
chip_info, extra_groups);

非 devm:

1
2
hwmon_device_register_with_info();
hwmon_device_unregister();

hwmon_device_register() 已 deprecated。

3. 参数

  • parent:真实 I2C/SPI/platform device;
  • name:name 属性,不允许 - * 空白
  • drvdata:传给 ops;
  • hwmon_chip_info:ops + channel info;
  • extra groups:非标准属性,应该极少使用。

4. 注册链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
devm_hwmon_device_register_with_info()
-> allocate devres
-> hwmon_device_register_with_info()
-> __hwmon_device_register()
-> ida_alloc()
-> allocate hwmon_device
-> __hwmon_create_attrs()
-> walk channel info/config bits
-> is_visible()
-> create attribute metadata
-> inherit OF node
-> device_register(hwmonN)
-> optional thermal sensor registration
-> attach devres cleanup

5. 属性生成

hwmon_channel_info.config[] 以 0 结尾。每个 channel 的 bit mask决定候选属性;is_visible() 最终决定:

  • 0:不创建;
  • 0444:只读;
  • 0644:root 可写;
  • 其它合理 sysfs mode。

Core 根据 type/attr 选择标准文件名模板。

6. 读写

1
2
3
4
5
6
show -> hwmon_attr_show()
-> ops->read()
-> sysfs_emit("%ld\n")

store -> kstrtol()
-> ops->write()

字符串属性(主要 label)走 read_string()

7. label

若 parent firmware property 有 label,Core复制并暴露顶层 label。各 channel label 则由 read_string(type, *_label, channel) 提供。

8. Thermal bridge

满足以下条件才尝试:

  • OF node;
  • chip info;
  • ops->read;
  • 第一个 info 是 hwmon_chip
  • config 含 HWMON_C_REGISTER_TZ

Core按温度 channel 调 devm_thermal_of_zone_register()hwmon_notify_event() 也会更新关联 thermal zone。

9. 卸载

devm 在 parent detach 时调用 hwmon_device_unregister()

1
2
3
4
5
device_unregister(hwmonN)
-> sysfs removed
-> thermal devres cleanup
-> class release
-> ida_free

driver 的 worker/timer/IRQ 必须先停止,避免 sysfs 消失后仍访问 drvdata。

10. 错误

  • -EINVAL:name/chip/ops/info 无效;
  • -ENOMEM:属性或 device 分配失败;
  • -ENOENTis_visible 隐藏属性时内部跳过;
  • thermal -ENODEV:没有匹配 OF zone,通常不使 hwmon 注册失败;
  • probe defer:底层 regulator/I2C/PWM provider 未就绪。

HWMON Sysfs ABI、属性单位与告警

HWMON Sysfs ABI、属性单位与告警

1. 规则

HWMON ABI 是文本十进制整数,每次 read 返回一个值。文件名和单位由 Documentation/hwmon/sysfs-interface.rst 规定。

2. 单位

类型 典型文件 单位
温度 tempN_input millidegree Celsius
电压 inN_input millivolt
电流 currN_input milliampere
功率 powerN_input/average microwatt
能量 energyN_input microjoule
湿度 humidityN_input milli-percent
风扇 fanN_input RPM
PWM pwmN 通常 0..255
alarm/fault *_alarm 0/1

驱动必须在内核中完成寄存器比例、符号和单位换算。

3. Channel

用户文件从 1 编号:

1
2
temp1_input
temp2_input

hwmon_ops 的 channel 参数从 0 编号。Core使用每类 attribute base 将二者转换。

4. 温度

常见:

  • input;
  • min/max/crit/emergency;
  • hysteresis;
  • alarm/fault;
  • offset;
  • lowest/highest/reset_history;
  • type;
  • label。

阈值是硬件阈值还是软件缓存由驱动和芯片决定。

5. 电力

  • inN_*:电压;
  • currN_*:电流;
  • powerN_input:瞬时功率;
  • powerN_average:平均功率;
  • powerN_cap:功率限制;
  • energyN_input:积分能量。

shunt monitor 的结果依赖板级 shunt resistor 参数,DTS/平台数据错误会造成成比例的错误。

6. 风扇

  • fanN_input
  • min/max/target;
  • pulses;
  • alarm/fault;
  • pwmN
  • pwmN_enable
  • pwmN_mode

pwm_enable 数值语义按通用 ABI和驱动能力,不可假设所有驱动的自动控制模式相同。

7. 可写性

is_visible() 决定 mode。即使文件存在并可写,write() 仍应验证:

  • range;
  • channel;
  • hardware capability;
  • state/mode;
  • conversion;
  • rounding。

超范围通常返回 -EINVAL,通信失败返回底层 errno。

8. Alarm 与事件

alarm 文件通常是轮询读取。支持主动通知的驱动可调用:

1
hwmon_notify_event(dev, type, attr, channel)

Core 执行:

  • sysfs_notify()
  • KOBJ_CHANGE uevent,环境变量 NAME=<attribute>
  • 若为温度则通知 thermal zone。

它不保证所有传感器都有硬件 IRQ。

9. 稳定识别

不要使用固定 /sys/class/hwmon/hwmon0。应:

  • 读取 name
  • 解析 device symlink;
  • 使用 libsensors label/config;
  • 必要时 udev 创建稳定 symlink。

10. 错误值

读取失败应返回 errno,不应伪造 0。0°C、0 RPM、0 mV 都可能是真实值;监控程序必须区分 read error、alarm 和物理 0。

驱动模型:hwmon_ops 与 Legacy 接口

驱动模型:hwmon_ops 与 Legacy 接口

1. 现代模型

1
2
3
4
5
6
7
8
9
10
11
12
static const struct hwmon_ops ops = {
.is_visible = chip_is_visible,
.read = chip_read,
.read_string = chip_read_string,
.write = chip_write,
};

static const struct hwmon_channel_info *info[] = {
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX),
NULL
};

hwmon_chip_info 关联 opsinfo

2. 回调

is_visible

1
is_visible(drvdata, type, attr, channel) -> umode_t

根据芯片 variant/channel/只读状态决定属性是否生成。

read

1
read(dev, type, attr, channel, long *val)

返回 0 或负 errno,值必须换算到 HWMON ABI 单位。

read_string

用于 label 等字符串;返回指向生命周期足够长的字符串。

write

解析已由 Core 完成,driver验证并写寄存器。

3. Channel config

每个 config entry 表示一个 channel 的属性位,末尾 0。宏:

1
2
3
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_MAX,
HWMON_T_INPUT)

表示两个温度 channel。

4. 私有数据

Core把 drvdata 设置到新建 hwmon device。ops收到的是 hwmon device,通常:

1
struct chip_data *data = dev_get_drvdata(dev);

不能假设 dev 是原 I2C client;parent 才是物理设备。

5. Extra groups

仅为硬件独有、无法标准化的属性使用。若已有标准 HWMON attribute,应优先标准 ABI,避免用户工具不识别。

6. Legacy

旧驱动使用:

  • SENSOR_DEVICE_ATTR
  • SENSOR_DEVICE_ATTR_2
  • sysfs_create_grouphwmon_device_register_with_groups
  • 自己实现 show/store;
  • hwmon_device_register()

这类驱动仍可工作,但容易出现命名、单位和权限不一致;新驱动应使用 with_info。

7. Detection

老式 I2C hwmon driver常有 detect/address list,服务不可枚举 SMBus 设备。Device Tree 系统应优先显式节点,避免 sensors-detect 或强制 probe 误访问未知地址。

8. 名称

name 应稳定、简短,不含 -* 和空白。Core只警告非法字符,并不自动修复普通注册调用;可使用 devm_hwmon_sanitize_name() 处理设备名来源。

9. 迁移建议

  1. 列出 legacy sysfs attrs;
  2. 映射到 sensor type/attr;
  3. 构造 channel config;
  4. 将 show/store 改为 read/write;
  5. is_visible 表达 variant;
  6. 保留真正非标准的 extra group;
  7. 对照 sysfs-interface.rst 检查单位;
  8. 测试 libsensors 兼容。

温度与湿度传感器驱动

温度与湿度传感器驱动

1. 驱动族

类别 代表
本地温度 LM75、TMP102/103/108
远端二极管 LM90、TMP401/421/464
DIMM 温度 JC42
SPI 温度 ADT7310、LM70、MAX31722
温湿度 SHT21/3x/4x、AHT10、HIH6130
热敏电阻 NTC thermistor

2. Probe

典型 I2C:

1
2
3
4
5
6
7
i2c probe
-> identify variant
-> devm_regmap_init_i2c()
-> read ID/config
-> set conversion rate/resolution
-> build hwmon_chip_info
-> devm_hwmon_device_register_with_info()

部分 legacy driver直接用 SMBus helpers 和自建 attributes。

3. 转换

数字温度寄存器常是:

  • two’s complement;
  • fixed-point;
  • 不同 resolution;
  • 左对齐;
  • 摄氏度 LSB 为 1/16、1/256 等。

驱动输出 millidegree Celsius,负温必须正确符号扩展。

4. 更新率

芯片 conversion rate 决定:

  • 新数据延迟;
  • 功耗;
  • I2C 流量;
  • self-heating;
  • alarm 响应。

update_interval 若可写,应取芯片支持档位并返回实际值。

5. 缓存

多寄存器 sensor常使用:

1
2
3
4
5
6
mutex
if !valid or time_after(jiffies, last_updated + interval):
bulk read
update cache
valid = true
return cached value

缓存避免用户一次 sensors 读取多个属性产生重复总线访问。

6. 阈值

温度 max/crit/hyst 对应芯片寄存器。写入时:

  1. clamp/check ABI value;
  2. 转成寄存器单位;
  3. round 到可表示精度;
  4. write;
  5. 更新/失效 cache。

硬件 hysteresis 可能表示绝对温度或相对差值,驱动必须转换成标准 ABI语义。

7. 远端二极管

远端 channel 可检测:

  • open/short fault;
  • diode ideality;
  • offset;
  • local/remote temperature;
  • emergency limit。

板级走线和晶体管模型影响精度,不是纯软件问题。

8. 湿度

湿度通常需要:

  • measurement command;
  • conversion wait;
  • CRC;
  • temperature compensation;
  • milli-percent 输出。

高频读取会使器件忙或自热,应尊重 conversion time。

9. NTC

ntc_thermistor.c 根据电阻/电压和查表换算温度,依赖 pull-up/pull-down、电阻值与 IIO/ADC 输入。DTS 参数错误会导致非线性温差。

10. RK3588

RK3588 内部 SoC 温度不是 LM/TMP hwmon 驱动,而是 TSADC thermal driver。只有板上明确安装外部 sensor 并在 DTS 声明时,本章这些驱动才会出现于 /sys/class/hwmon

电压、电流、功率与能量监控

电压、电流、功率与能量监控

1. 代表驱动

  • INA209/INA2xx/INA238/INA3221;
  • LTC2945/LTC2990/LTC4151;
  • ADM1177;
  • ADC128D818、ADS7828、MCP3021;
  • PMBus power monitors。

2. Shunt monitor

1
2
3
4
bus voltage = measured supply voltage
shunt voltage = differential voltage across resistor
current = shunt_voltage / shunt_resistance
power = bus_voltage * current

有些芯片硬件计算 current/power,驱动仍需配置 calibration register。

3. INA2xx

典型流程:

1
2
3
4
5
6
7
8
9
10
11
probe
-> select chip config
-> obtain shunt-resistor property/platform data
-> regmap init
-> program config/calibration
-> register hwmon

read
-> regmap read bus/shunt/current/power
-> sign extend
-> scale to mV/mA/uW

shunt 电阻常用 micro-ohm 表示。写错 10 倍会令电流和功率错 10 倍。

4. 多通道

INA3221 等可监控多 rail。channel label 应描述:

  • VDD_CPU;
  • VDD_GPU;
  • VDD_NPU;
  • VIN;
  • 其它板级 rail。

label 来自 DTS/firmware 或 driver固定表,用户程序应按 label 匹配。

5. ADC voltage

纯 ADC 通常只知道引脚电压。分压电阻和 rail 语义可能在:

  • driver platform data;
  • Device Tree;
  • userspace sensors config。

若通过 IIO,iio_hwmon 把处理后的 channel 暴露为 inN_input

6. Power average/cap

支持的芯片可提供:

  • instant input;
  • average;
  • averaging interval;
  • highest/lowest;
  • cap 和 cap alarm。

并非所有名为 power monitor 的设备都能直接硬件限制功率。

7. Energy

energyN_input 是累计值,可能:

  • 寄存器 wrap;
  • 上电清零;
  • 读取清零;
  • 由软件积分;
  • 睡眠期间停止。

长期统计程序必须处理 wrap/reset。

8. 告警

阈值包括 min/max/lcrit/crit。状态寄存器可能 write-one-to-clear 或 read-to-clear,driver不能因一次 sysfs读取意外丢失关键事件;需遵循芯片语义。

9. 精度

误差来源:

  • shunt tolerance/temperature coefficient;
  • ADC gain/offset;
  • PCB Kelvin routing;
  • conversion/averaging;
  • integer rounding;
  • rail ripple;
  • calibration。

HWMON 输出整数不意味着精度达到最后一位。

10. RK3588

源码树中 INA 等驱动可用,但 RK3588 公共 DTS 搜索未显示统一的板载 INA 节点。具体 EVB/产品应以原理图和板级 DTS 为准,不能把 regulator 电压或 PMIC setpoint 当作实际测量值。

风扇转速、PWM 与热管理

风扇转速、PWM 与热管理

1. 驱动

  • pwm-fan.c:PWM 输出 + 可选 tach;
  • gpio-fan.c:离散 GPIO 档位;
  • EMC/MAX/NCT 等外部 fan controller;
  • SoC PWM/tacho controller。

2. RK3588 pwm-fan

本树多个 RK3588 EVB/vehicle/toybrick DTS 有:

1
2
3
4
5
6
fan: pwm-fan {
compatible = "pwm-fan";
#cooling-cells = <2>;
pwms = <&pwm3 0 50000 0>;
cooling-levels = <0 50 100 150 200 255>;
};

厂商树还支持 rockchip,temp-trips notifier 路径。

3. Probe

1
2
3
4
5
6
7
8
9
10
11
pwm_fan_probe()
-> devm_pwm_get()
-> optional fan regulator
-> initialize max PWM
-> enumerate tach IRQs
-> request pulse IRQ
-> timer for RPM sampling
-> build PWM + optional FAN channel info
-> devm_hwmon_device_register_with_info("pwmfan")
-> parse cooling-levels
-> register Rockchip notifier or thermal cooling device

4. HWMON

  • pwm1:0..255 duty command;
  • pwm1_enable:enable mode;
  • fanN_input:RPM(仅有 tach IRQ 时)。

没有 tach 输入时仍有 PWM control,但无法证明风扇真的转动。

5. RPM

tach IRQ累积脉冲,定时器按采样窗口计算:

1
RPM = pulses * 60 / (sample_seconds * pulses_per_revolution)

pulses-per-revolution 默认通常为 2,必须匹配风扇规格。

6. PWM

driver把 0..255 转为 duty cycle:

1
duty = pwm * (period - 1) / 255

低 duty 可能无法克服启动转矩。实际曲线常需要:

  • kick-start;
  • 最低稳定 duty;
  • hysteresis;
  • spin-up delay;
  • stall detection。

7. Cooling device

cooling-levels[] 将 thermal state 映射到 PWM。Thermal governor选择 state,driver调用 set_pwm()。这与用户直接写 pwm1 存在控制权冲突,生产系统应明确由谁控制。

8. Rockchip notifier

如果启用 ROCKCHIP_SYSTEM_MONITOR 且 DT 有 rockchip,temp-trips,本厂商驱动注册 notifier并直接按温度映射 state,然后提前返回,不再注册通用 OF cooling device。调试时必须识别实际走哪条控制路径。

9. 配置事实

公共主 defconfig未显式写 SENSORS_PWM_FANrk3588_edge.config 明确设置 CONFIG_SENSORS_PWM_FAN=y。DTS 有 fan 节点不代表最终内核一定能 probe。

10. 排查

1
2
3
4
5
6
cat /sys/class/hwmon/hwmon*/name
cat /sys/class/hwmon/hwmon*/pwm1
cat /sys/class/hwmon/hwmon*/fan1_input
cat /sys/class/thermal/cooling_device*/type
cat /sys/class/thermal/cooling_device*/cur_state
cat /proc/interrupts

写 PWM 前确认 cooling governor/daemon 没有同时改值。