在RK3562和RK3568平台上集成AIC8800(FCS960K-N)WiFi蓝牙二合一模块时,Rockchip官方提供了两种主要的驱动集成方式。这两种方式在实际项目开发中各有特点,需要根据具体平台和SDK版本进行选择。
方法一(传统内核集成方式):
方法二(外部模块化方式):
重要提示:方法二实际上是方法一的迭代升级版本,Rockchip已明确建议新项目采用方法二。方法一主要保留用于兼容已有项目。
设备树配置是WiFi蓝牙模块正常工作的基础,需要特别注意以下几个关键部分:
dts复制sdio_pwrseq: sdio-pwrseq {
compatible = "mmc-pwrseq-simple";
clocks = <&rk809 1>;
clock-names = "ext_clock";
pinctrl-names = "default";
pinctrl-0 = <&wifi_enable_h>;
post-power-on-delay-ms = <200>;
reset-gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_LOW>;
};
关键参数说明:
post-power-on-delay-ms:电源稳定延时,200ms是AIC8800的典型值reset-gpios:WiFi模块复位引脚,注意电平极性pinctrl-0:对应的GPIO引脚配置dts复制wireless-wlan {
compatible = "wlan-platdata";
rockchip,grf = <&sys_grf>;
wifi_chip_type = "aic8800";
pinctrl-names = "default";
pinctrl-0 = <&wifi_host_wake_irq>;
WIFI,host_wake_irq = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>;
status = "okay";
};
特别注意:
wifi_chip_type必须准确设置为"aic8800"host_wake_irq是WiFi唤醒主机的中断引脚dts复制wireless-bluetooth {
compatible = "bluetooth-platdata";
clocks = <&rk809 1>;
clock-names = "ext_clock";
uart_rts_gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_LOW>;
pinctrl-names = "default", "rts_gpio";
pinctrl-0 = <&uart1m0_rtsn>;
pinctrl-1 = <&uart1_gpios>;
BT,wake_gpio = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
BT,wake_host_irq = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>;
status = "okay";
};
关键点:
将驱动代码放置到内核目录:
bash复制kernel/drivers/net/wireless/aic8800/
修改Kconfig配置:
makefile复制# kernel/drivers/net/wireless/Kconfig
source "drivers/net/wireless/aic8800/Kconfig"
修改Makefile:
makefile复制# kernel/drivers/net/wireless/Makefile
obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800/
配置内核选项:
config复制# kernel/arch/arm64/configs/rockchip_linux_defconfig
CONFIG_AIC_WLAN_SUPPORT=y
CONFIG_AIC8800_WLAN_SUPPORT=m
基础配置:
config复制# buildroot/configs/rockchip_rk3568_defconfig
BR2_PACKAGE_RKWIFIBT_AIC8800=y
BR2_PACKAGE_RKWIFIBT_BTUART="ttyS1"
蓝牙补丁应用:
文件系统部署:
makefile复制# buildroot/package/rockchip/rkwifibt/rkwifibt.mk
define RKWIFIBT_TB_INSTALL
mkdir -p $(TARGET_DIR)/vendor/etc/firmware
mkdir -p $(TARGET_DIR)/data/local/tmp
mkdir -p $(TARGET_DIR)/usr/lib/modules
cp -rf $(TOPDIR)/../external/rkwifibt/firmware/FCS960K/* \
$(TARGET_DIR)/vendor/etc/firmware/
cp -f $(TOPDIR)/../kernel/drivers/net/wireless/aic8800/aic8800_bsp/aic8800_bsp.ko \
$(TARGET_DIR)/usr/lib/modules/
cp -f $(TOPDIR)/../kernel/drivers/net/wireless/aic8800/aic8800_btlpm/aic8800_btlpm.ko \
$(TARGET_DIR)/usr/lib/modules/
cp -f $(TOPDIR)/../kernel/drivers/net/wireless/aic8800/aic8800_fdrv/aic8800_fdrv.ko \
$(TARGET_DIR)/usr/lib/modules/
cp -f $(TOPDIR)/../external/rkwifibt/conf/wpa_supplicant.conf $(TARGET_DIR)/etc/
cp -f $(TOPDIR)/../external/rkwifibt/drivers/bluetooth_uart_driver/hci_uart.ko $(TARGET_DIR)/usr/lib/modules/
endef
蓝牙启动服务:
bash复制# buildroot/package/bluez5_utils/S40bluetoothd
#!/bin/sh
case "$1" in
start)
killall rtk_hciattach
echo 0 >/sys/class/rfkill/rfkill0/state
echo 0 >/proc/bluetooth/sleep/btwrite
sleep 0.5
echo 1 >/sys/class/rfkill/rfkill0/state
echo 1 >/proc/bluetooth/sleep/btwrite
sleep 0.5
wpa_supplicant -i wlan0 -c /etc/wpa_supplicant.conf -B
insmod ./usr/lib/modules/hci_uart.ko
hciattach -s 1500000 /dev/ttyS1 aic 1500000 flow
hciconfig hci0 up &
/usr/libexec/bluetooth/bluetoothd -C -E -n &
sleep 2
gatt-service &
;;
*)
echo "usage: $0 {start}"
;;
esac
WiFi/BT初始化脚本:
bash复制# external/rkwifibt/S36wifibt-init.sh
case "$1" in
start|stop|restart)
/usr/bin/wifibt-init.sh $1
insmod ./usr/lib/modules/aic8800_bsp.ko
insmod ./usr/lib/modules/aic8800_fdrv.ko
insmod ./usr/lib/modules/aic8800_btlpm.ko
;;
*)
echo "Usage: [start|stop|restart]" >&2
exit 3
;;
esac
驱动代码位置:
code复制external/rkwifibt/drivers/aic8800_sdio
固件文件位置:
code复制external/rkwifibt/firmware/aic/sdio/aic8800
编译脚本:
bash复制# device/rockchip/common/scripts/post-wifibt.sh
if [[ "$RK_WIFIBT_MODULES" = "AIC8800_SDIO" ]];then
echo "building AIC8800 SDIO"
$KMAKE M=$RKWIFIBT_DIR/drivers/aic8800_sdio
fi
bash复制if [[ "$RK_WIFIBT_MODULES" =~ "AIC8800_SDIO" ]];then
echo "Install AIC file to rootfs"
cp $RKWIFIBT_DIR/firmware/aic/sdio/*/* \
$TARGET_DIR/lib/firmware/
cp $RKWIFIBT_DIR/drivers/aic8800_sdio/aic8800_btlpm/*.ko \
$TARGET_DIR/lib/modules/
cp $RKWIFIBT_DIR/drivers/aic8800_sdio/aic8800_fdrv/*.ko \
$TARGET_DIR/lib/modules/
cp $RKWIFIBT_DIR/drivers/aic8800_sdio/aic8800_bsp/*.ko \
$TARGET_DIR/lib/modules/
fi
config复制# device/rockchip/.chips/rk3562/rockchip_rk3562_evb2_ddr4_v10_defconfig
RK_WIFIBT_CHIP="AIC8800_SDIO"
bash复制# debian/mk-rootfs-bullseye.sh
#wireless driver
sudo mkdir -p $TARGET_ROOTFS_DIR/usr/lib/modules
if [ -e "$TARGET_ROOTFS_DIR/usr/bin/hciattach" ];
then sudo rm $TARGET_ROOTFS_DIR/usr/bin/hciattach
fi
sudo cp ../buildroot/output/rockchip_rk3562/target/usr/bin/hciattach $TARGET_ROOTFS_DIR/usr/bin/hciattach
WiFi/BT启动服务:
bash复制# debian/overlay/etc/init.d/open_wifibt.sh
# Wi-Fi
insmod /usr/lib/modules/aic8800_bsp.ko 2>/dev/null
insmod /usr/lib/modules/aic8800_fdrv.ko 2>/dev/null
insmod /usr/lib/modules/aic8800_btlpm.ko 2>/dev/null
sleep 1
# Bluetooth
echo 0 >/sys/class/rfkill/rfkill0/state
echo 0 >/proc/bluetooth/sleep/btwrite
sleep 0.5
echo 1 >/sys/class/rfkill/rfkill0/state
echo 1 >/proc/bluetooth/sleep/btwrite
sleep 0.5
insmod /usr/lib/modules/hci_uart.ko 2>/dev/null
btattach -B /dev/ttyS1 -S 1500000 -P h4
sleep 2
蓝牙配置服务:
bash复制# debian/overlay/etc/init.d/open_bt.sh
#!/bin/bash
hciconfig hci0 up
sleep 5
rfkill unblock bluetooth
systemd服务文件:
ini复制# debian/overlay/etc/systemd/system/open_wifibt.service
[Unit]
Description=My Startup Script
[Service]
ExecStart=/etc/init.d/open_wifibt.sh
[Install]
WantedBy=multi-user.target
检查设备节点:
bash复制ip addr show wlan0
检查内核日志:
bash复制dmesg | grep aic
检查后台进程:
bash复制ps aux | grep wpa_supplicant
检查驱动文件:
bash复制ls /usr/lib/modules/aic8800_*.ko
手动加载测试:
bash复制insmod /usr/lib/modules/aic8800_bsp.ko
insmod /usr/lib/modules/aic8800_fdrv.ko
检查设备节点:
bash复制hciconfig -a
检查内核日志:
bash复制dmesg | grep -i bluetooth
检查hciattach进程:
bash复制ps aux | grep hciattach
手动测试:
bash复制hciattach -s 1500000 /dev/ttyS1 aic 1500000 flow
hciconfig hci0 up
固件版本匹配:
电源时序控制:
中断配置:
UART波特率:
驱动加载顺序:
在实际项目开发中,我遇到过因GPIO极性配置错误导致模块无法启动的情况。通过逻辑分析仪抓取电源序列波形,最终发现是复位信号极性设置反了。这个经验告诉我,对于嵌入式外设集成,硬件信号的验证与软件配置同等重要。建议在初期调试时,使用示波器或逻辑分析仪验证所有关键信号的时序和电平是否符合预期。