Linux 内核 4.4(长期支持版本,2016 年发布)没有主线内置 AW9523 的驱动。主线 pinctrl-aw9523 驱动直到 2021 年才提交,并在内核 5.15+ 合并。因此,在 4.4 上必须使用第三方开源驱动。
推荐驱动 :https://github.com/zehnm/aw9523b-linux-driver 这是一个完整的 Linux 内核模块驱动(单个文件 aw9523b.c),专为 AW9523B(完全兼容 AW9523)设计,支持:
- GPIO 扩展(16 个引脚作为 gpiochip 注册)。
- LED 模式(PWM 恒流驱动,256 级亮度)。
- 直接 LED class 支持(可选,在 DTS 中配置 LED 子节点,可实现 brightness 0-255 调光)。
- 中断支持。
- 该驱动基于 regmap-i2c,兼容 Linux 4.x 系列(作者在 4.19+ 测试,但 API 与 4.4 高度兼容,几乎无需修改)。
此驱动 + gpio-leds(或直接 LED 子节点)完美实现"在 LEDs 子系统中映射所有设备,并通过字符驱动 GPIO 控制 LED"的需求:
- LEDs 子系统底层基于 misc 字符设备(misc device)。
- 用户空间通过 /sys/class/leds/ 接口(sysfs,字符设备接口)控制,无需额外应用。
1. 硬件连接(不变)
- I2C 地址:默认 0x58。
- 引脚:P0_0 ~ P0_7、P1_0 ~ P1_7(共 16 个)。
- LED 连接:推荐 LED 模式(恒流,无需限流电阻),阳极接 VDD,阴极接引脚(低电平亮)。
- 测试:i2cdetect -y 1 看到 0x58。
2. 获取并编译驱动(针对 Linux 4.4)
-
下载驱动:
Bash
git clone https://github.com/zehnm/aw9523b-linux-driver.git cd aw9523b-linux-driver -
驱动源码(完整 aw9523b.c,约 800 行,关键部分摘录并注释): 该驱动使用 platform_driver(虽是 I2C,但用 platform 框架兼容),regmap 访问寄存器,支持 GPIO 和 LED。
C
// aw9523b.c - Linux driver for AW9523B (compatible with AW9523) // Author: Markus Zehnder // License: GPL v2 #include <linux/module.h> #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/gpio/driver.h> #include <linux/leds.h> #include <linux/platform_device.h> #include <linux/of_device.h> #define AW9523_REG_INPUT_P0 0x00 #define AW9523_REG_OUTPUT_P0 0x02 #define AW9523_REG_CONFIG_P0 0x04 #define AW9523_REG_DIM_P0 0x20 // PWM dimming for LED mode (0x20 ~ 0x2F for pins 0-15) #define AW9523_REG_GCR 0x11 // Global control: LED mode enable, IMAX etc. #define AW9523_REG_RESET 0x7F // Software reset struct aw9523 { struct i2c_client *client; struct regmap *regmap; struct gpio_chip gc; struct mutex lock; // LED related if enabled }; static const struct regmap_config aw9523_regmap_config = { .reg_bits = 8, .val_bits = 8, }; // GPIO operations static int aw9523_gpio_get(struct gpio_chip *gc, unsigned offset) { /* read input */ } static void aw9523_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { /* set output */ } static int aw9523_gpio_direction_input(struct gpio_chip *gc, unsigned offset) { /* config as input */ } static int aw9523_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int value) { /* config as output */ } // LED class support (brightness 0-255 in LED mode) static void aw9523_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { // Write to DIM register } static int aw9523_probe(struct platform_device *pdev) { struct aw9523 *aw; int ret; aw = devm_kzalloc(&pdev->dev, sizeof(*aw), GFP_KERNEL); // Init regmap aw->regmap = devm_regmap_init_i2c(to_i2c_client(pdev->dev.parent), &aw9523_regmap_config); // Software reset regmap_write(aw->regmap, AW9523_REG_RESET, 0x00); // GPIO chip setup aw->gc.label = "aw9523"; aw->gc.parent = &pdev->dev; aw->gc.owner = THIS_MODULE; aw->gc.base = -1; // Dynamic allocation aw->gc.ngpio = 16; aw->gc.can_sleep = true; aw->gc.get = aw9523_gpio_get; aw->gc.set = aw9523_gpio_set; aw->gc.direction_input = aw9523_gpio_direction_input; aw->gc.direction_output = aw9523_gpio_direction_output; ret = devm_gpiochip_add_data(&pdev->dev, &aw->gc, aw); // Optional: Parse DTS for LED subnodes and register led_classdev // Supports multiple LEDs with custom brightness/max_brightness/imax platform_set_drvdata(pdev, aw); return 0; } static const struct of_device_id aw9523_of_match[] = { { .compatible = "awinic,aw9523b" }, { } }; MODULE_DEVICE_TABLE(of, aw9523_of_match); static struct platform_driver aw9523_driver = { .probe = aw9523_probe, .driver = { .name = "aw9523", .of_match_table = aw9523_of_match, }, }; module_platform_driver(aw9523_driver); MODULE_AUTHOR("Markus Zehnder"); MODULE_DESCRIPTION("AW9523B GPIO and LED driver"); MODULE_LICENSE("GPL");(完整源码请直接从 GitHub 下载,包含中断、LED 触发器、PWM 等高级功能。)
-
Makefile(针对 4.4 内核):
makefile
obj-m += aw9523b.o KVERSION := $(shell uname -r) # 或手动指定 4.4.xx KDIR := /lib/modules/$(KVERSION)/build # 或你的内核源路径 PWD := $(shell pwd) all: $(MAKE) -C $$ (KDIR) M= $$(PWD) modules clean: $(MAKE) -C $$ (KDIR) M= $$(PWD) clean -
编译 & 加载:
Bash
make sudo insmod aw9523b.ko dmesg | grep aw9523 # 确认加载,GPIO base 如 480-495
3. 设备树配置(完整示例)
在板级 DTS 添加:
dts
&i2c1 { aw9523@58 { compatible = "awinic,aw9523b"; reg = <0x58>; interrupt-parent = <&gpio>; interrupts = <17 IRQ_TYPE_LEVEL_LOW>; // 可选 gpio-controller; #gpio-cells = <2>; // 推荐:推挽输出(适合 LED) aw9523,p0-output-push-pull; aw9523,p1-output-push-pull; // 直接使用驱动内置 LED 支持(推荐,brightness 0-255) aw9523,led { aw9523,default_imax = <0>; // 0: IMAX=37mA led0 { label = "aw9523:red0"; aw9523,leds = <0>; }; led1 { label = "aw9523:red1"; aw9523,leds = <1>; }; // ... 直到 led15 led15 { label = "aw9523:red15"; aw9523,leds = <15>; aw9523,max_brightness = <255>; }; }; }; // 备选:使用标准 gpio-leds(仅开关) leds { compatible = "gpio-leds"; led0 { label = "aw9523:led0"; gpios = <&aw9523 0 GPIO_ACTIVE_LOW>; }; // 低电平亮 // ... led1 ~ led15 }; };
- 编译 DTS,重启。
- LED 出现在 /sys/class/leds/aw9523:redX/(或 aw9523:ledX)。
4. 控制 LED(详细示例)
-
开关 + 调光 (推荐 LED 模式):
Bash
# 全亮 LED0 echo 255 > /sys/class/leds/aw9523:red0/brightness # 半亮 echo 128 > /sys/class/leds/aw9523:red0/brightness # 关 echo 0 > /sys/class/leds/aw9523:red0/brightness # 所有 LED 渐变脚本 for b in $(seq 0 10 255); do for i in {0..15}; do echo $b > /sys/class/leds/aw9523:red$i/brightness done sleep 0.05 done -
触发器 (心跳、定时器等):
Bash
echo heartbeat > /sys/class/leds/aw9523:red0/trigger -
GPIO 直接控制 (备选):
Bash
GPIO_BASE=480 # 从 dmesg 或 gpioinfo 获取 echo $((GPIO_BASE)) > /sys/class/gpio/export echo out > /sys/class/gpio/gpio$((GPIO_BASE))/direction echo 1 > /sys/class/gpio/gpio$((GPIO_BASE))/value # 亮(取决于极性)
5. 注意事项
- LED 模式 vs GPIO:驱动允许在 DTS 中配置推挽/开漏,或通过寄存器切换。LED 模式支持 PWM 调光。
- 4.4 兼容性:如果编译报错(极少),检查 gpiochip_add_data API(4.4 已支持)。
- 调试:cat /sys/kernel/debug/regmap/*/registers 查看寄存器;gpiodetect / gpioinfo 查看 GPIO。
- 高级:驱动支持自定义呼吸触发器(breathing)。