一、核心结论

不需要修改驱动程序! Linux 内核的 MCP2515 驱动 (drivers/net/can/spi/mcp251x.c) 和 Rockchip CAN 驱动 (drivers/net/can/rockchip/rockchip_can.c) 已经完整支持硬件配置。

只需要:

  1. 正确的设备树配置

    /**
     * @file rk3588-3can.dtsi
     * @brief RK3588 三路 CAN 设备树配置
     * @author zhilin_tang Technology
     * 
     * 硬件配置:
     * - CAN1: 原生 (RD54/RD66) → 使用 CAN1_RX_M1 / CAN1_TX_M1
     * - CAN2: 原生 (LU29/LU31) → 使用 CAN2_TX_M0 / CAN2_RX_M0
     * - CAN3: SPI 扩展 (MCP2515) → SPI1 + GPIO0_C4 中断
     * 
     * @note 设计模式分析:采用"复合模式(Composite Pattern)"
     *       将两个原生 CAN 和一个 SPI CAN 组合成完整的 CAN 网络系统。
     *       每个 CAN 控制器独立配置,便于调试和维护。
     */
    ​
    /dts-v1/;
    /plugin/;
    ​
    / {
        compatible = "rockchip,rk3588";
        
        /* ========== 1. SPI CAN 时钟源定义 ========== */
        mcp2515_clk: mcp2515-clk {
            compatible = "fixed-clock";
            #clock-cells = <0>;
            clock-frequency = <16000000>;   /* MCP2515 晶振 16MHz */
        };
    };
    ​
    /* ========== 2. 原生 CAN1 配置 (RD54/AK25 + RD66/AM25) ========== */
    &can1 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&can1m1_pins>;         /* 使用 M1 引脚组 (CAN1_RX_M1/CAN1_TX_M1) */
        assigned-clocks = <&cru CLK_CAN1>;
        assigned-clock-rates = <200000000>;
    };
    ​
    /* ========== 3. 原生 CAN2 配置 (LU29/AH25 + LU31/AH26) ========== */
    &can2 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&can2m0_pins>;         /* 使用 M0 引脚组 (CAN2_TX_M0/CAN2_RX_M0) */
        assigned-clocks = <&cru CLK_CAN2>;
        assigned-clock-rates = <200000000>;
    };
    ​
    /* ========== 4. 禁用原生 CAN0(避免冲突)========== */
    &can0 {
        status = "disabled";
    };
    ​
    /* ========== 5. 配置 SPI1 引脚复用 ========== */
    &pinctrl {
        /* 确保 SPI1 引脚配置为 M0 模式 */
        spi1 {
            spi1m0_pins: spi1m0-pins {
                rockchip,pins =
                    <1 RK_PC0 RK_FUNC_2 &pcfg_pull_none>,  /* SPI1_CLK  GPIO1_C0 */
                    <1 RK_PC1 RK_FUNC_2 &pcfg_pull_none>,  /* SPI1_MOSI GPIO1_C1 */
                    <1 RK_PC2 RK_FUNC_2 &pcfg_pull_none>,  /* SPI1_MISO GPIO1_C2 */
                    <1 RK_PC3 RK_FUNC_2 &pcfg_pull_none>;  /* SPI1_CS0  GPIO1_C3 */
            };
        };
        
        /* MCP2515 中断引脚配置 (GPIO0_C4 / LD3/R30) */
        mcp2515 {
            mcp2515_int_pin: mcp2515-int-pin {
                rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>;
            };
        };
    };
    ​
    /* ========== 6. 配置 SPI1 总线 ========== */
    &spi1 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&spi1m0_pins>;
        max-frequency = <10000000>;          /* SPI 时钟 10MHz */
        #address-cells = <1>;
        #size-cells = <0>;
        
        /* MCP2515 SPI CAN 控制器 (第三路 CAN) */
        can3: can-controller@0 {
            compatible = "microchip,mcp2515";
            reg = <0>;                       /* 片选0 */
            clocks = <&mcp2515_clk>;
            interrupt-parent = <&gpio0>;
            interrupts = <RK_PC4 IRQ_TYPE_LEVEL_LOW>;  /* GPIO0_C4 中断 */
            spi-max-frequency = <10000000>;
            spi-cpha = <0>;                  /* SPI 模式 0,0 */
            spi-cpol = <0>;
            
            /* MCP2515 特定配置 */
            microchip,oscillator-frequency = <16000000>;
            
            status = "okay";
        };
    };

  2. 内核配置启用相应驱动

    #!/bin/bash
    # kernel_can_config.sh - 三路 CAN 内核配置
    ​
    cd /path/to/linux-5.10
    ​
    # 方法1: menuconfig 图形化配置
    make ARCH=arm64 menuconfig
    ​
    # 必须选中的配置项:
    # ================================================================
    # Device Drivers  --->
    #     [*] Network device support  --->
    #         CAN Device Drivers  --->
    #             [*] CAN Device Drivers support
    #             [*]   Platform CAN drivers with Netlink support
    #             <*>   Rockchip CAN controller          # 原生 CAN 驱动
    #             [*]   CAN SPI interfaces
    #             <*>     Microchip MCP251x and MCP25625 SPI CAN controllers  # SPI CAN 驱动
    # ================================================================
    ​
    # 方法2: 直接修改 defconfig
    cat >> arch/arm64/configs/rockchip_linux_defconfig << 'EOF'
    # CAN 子系统
    CONFIG_CAN=y
    CONFIG_CAN_DEV=y
    CONFIG_CAN_ROCKCHIP=y
    CONFIG_CAN_MCP251X=y
    CONFIG_SPI_ROCKCHIP=y
    EOF
    ​
    # 编译
    make ARCH=arm64 rockchip_linux_defconfig
    make ARCH=arm64 Image -j8
    make ARCH=arm64 modules -j8
    ​
    # 安装模块
    make ARCH=arm64 modules_install INSTALL_MOD_PATH=/path/to/rootfs

  3. 硬件正确连接

二、驱动架构分析

【Linux CAN 驱动架构 - 原生 + SPI 共存】
​
┌─────────────────────────────────────────────────────────────────────────────┐
│                           Linux CAN 子系统                                   │
│                      (drivers/net/can/dev.c)                                │
│                                   │                                          │
│         ┌─────────────────────────┼─────────────────────────┐                │
│         │                         │                         │                │
│         ▼                         ▼                         ▼                │
│ ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐        │
│ │   CAN1 设备     │     │   CAN2 设备     │     │   CAN3 设备     │        │
│ │   (原生)        │     │   (原生)        │     │   (SPI)         │        │
│ ├─────────────────┤     ├─────────────────┤     ├─────────────────┤        │
│ │ rockchip_can    │     │ rockchip_can    │     │ mcp251x         │        │
│ │ 驱动            │     │ 驱动            │     │ 驱动            │        │
│ ├─────────────────┤     ├─────────────────┤     ├─────────────────┤        │
│ │ 硬件寄存器      │     │ 硬件寄存器      │     │ SPI 通信        │        │
│ │ 直接访问        │     │ 直接访问        │     │ + MCP2515       │        │
│ └─────────────────┘     └─────────────────┘     └─────────────────┘        │
│         │                         │                         │                │
│         ▼                         ▼                         ▼                │
│ ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐        │
│ │ CAN1 收发器     │     │ CAN2 收发器     │     │ CAN3 收发器     │        │
│ │ (外部电路)      │     │ (外部电路)      │     │ (外部电路)      │        │
│ └─────────────────┘     └─────────────────┘     └─────────────────┘        │
└─────────────────────────────────────────────────────────────────────────────┘

关键点:三个 CAN 设备使用三个独立的驱动实例,互不干扰。

三、现有驱动已支持的功能

3.1 Rockchip 原生 CAN 驱动 (rockchip_can.c)

/**
 * @file rockchip_can.c - 无需修改,已完整支持 CAN1/CAN2
 * @source drivers/net/can/rockchip/rockchip_can.c
 * 
 * 已支持功能:
 * - 多实例支持 (can0/can1/can2 可同时使用)
 * - 设备树引脚复用配置 (通过 pinctrl)
 * - 中断处理
 * - 波特率设置 (10kbps ~ 1Mbps)
 * - 错误处理
 * - 总线关闭恢复
 */
​
/* 驱动支持的最大 CAN 控制器数量 */
#define ROCKCHIP_CAN_MAX 3  /* 硬件最多支持 3 个 CAN 控制器 */
​
/* 驱动 probe 函数 - 每个设备节点都会调用一次 */
static int rockchip_can_probe(struct platform_device *pdev)
{
    /* 从设备树获取资源 */
    /* 为每个 CAN 设备创建独立的 net_device 实例 */
    /* 注册中断 */
    /* 注册 CAN 设备 */
}

3.2 MCP2515 SPI CAN 驱动 (mcp251x.c)

/**
 * @file mcp251x.c - 无需修改,已完整支持 CAN3 (SPI 扩展)
 * @source drivers/net/can/spi/mcp251x.c
 * 
 * 已支持功能:
 * - SPI 总线通信 (支持多个 SPI 设备)
 * - 中断处理 (通过 GPIO 中断)
 * - 波特率设置 (支持 10kbps ~ 1Mbps)
 * - 多个 MCP2515 实例 (通过不同片选或 SPI 总线)
 */
​
/* 驱动支持多个 SPI 设备 */
static int mcp251x_probe(struct spi_device *spi)
{
    /* 从设备树获取 SPI 资源和中断引脚 */
    /* 为每个 SPI 设备创建独立的 net_device */
    /* 注册 CAN 设备 */
}

四、设备树配置(完整版)

/**
 * @file rk3588-3can.dtsi
 * @brief RK3588 三路 CAN 设备树配置 - 无需修改驱动
 * 
 * 硬件连接:
 * - CAN1: 原生 (RD54/AK25 + RD66/AM25) → can1 节点
 * - CAN2: 原生 (LU29/AH25 + LU31/AH26) → can2 节点  
 * - CAN3: SPI 扩展 (SPI1 + MCP2515 + GPIO0_C4) → spi1 子节点
 */
​
/dts-v1/;
/plugin/;
​
/ {
    compatible = "rockchip,rk3588";
    
    /* SPI CAN 时钟源 (16MHz 晶振) */
    mcp2515_clk: mcp2515-clk {
        compatible = "fixed-clock";
        #clock-cells = <0>;
        clock-frequency = <16000000>;
    };
};
​
/* ========== 原生 CAN1 (RD54/RD66) ========== */
&can1 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&can1m1_pins>;         /* 使用 M1 引脚组 */
    assigned-clocks = <&cru CLK_CAN1>;
    assigned-clock-rates = <200000000>;
};
​
/* ========== 原生 CAN2 (LU29/LU31) ========== */
&can2 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&can2m0_pins>;         /* 使用 M0 引脚组 */
    assigned-clocks = <&cru CLK_CAN2>;
    assigned-clock-rates = <200000000>;
};
​
/* ========== 禁用 CAN0 ========== */
&can0 {
    status = "disabled";
};
​
/* ========== SPI1 引脚配置 ========== */
&pinctrl {
    spi1 {
        spi1m0_pins: spi1m0-pins {
            rockchip,pins =
                <1 RK_PC0 RK_FUNC_2 &pcfg_pull_none>,  /* SPI1_CLK  */
                <1 RK_PC1 RK_FUNC_2 &pcfg_pull_none>,  /* SPI1_MOSI */
                <1 RK_PC2 RK_FUNC_2 &pcfg_pull_none>,  /* SPI1_MISO */
                <1 RK_PC3 RK_FUNC_2 &pcfg_pull_none>;  /* SPI1_CS0  */
        };
    };
    
    mcp2515_int {
        mcp2515_int_pin: mcp2515-int-pin {
            rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>;
        };
    };
};
​
/* ========== SPI1 总线 (连接 MCP2515) ========== */
&spi1 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&spi1m0_pins>;
    max-frequency = <10000000>;
    #address-cells = <1>;
    #size-cells = <0>;
    
    can3: can-controller@0 {
        compatible = "microchip,mcp2515";
        reg = <0>;
        clocks = <&mcp2515_clk>;
        interrupt-parent = <&gpio0>;
        interrupts = <RK_PC4 IRQ_TYPE_LEVEL_LOW>;
        spi-max-frequency = <10000000>;
        spi-cpha = <0>;
        spi-cpol = <0>;
        status = "okay";
    };
};

五、驱动加载验证

5.1 检查驱动是否已加载

# 检查 Rockchip CAN 驱动
lsmod | grep rockchip_can
# 输出示例: rockchip_can 16384 0
​
# 检查 MCP2515 驱动
lsmod | grep mcp251x
# 输出示例: mcp251x 28672 0
​
# 查看驱动内置情况(如果驱动编译进内核)
grep -E "rockchip_can|mcp251x" /lib/modules/$(uname -r)/modules.builtin

5.2 驱动加载流程

【内核启动时驱动加载顺序】
​
1. 设备树解析
   ├── 发现 can1 节点 → 创建 platform_device
   ├── 发现 can2 节点 → 创建 platform_device
   └── 发现 spi1 下的 mcp2515 节点 → 创建 spi_device
​
2. 驱动匹配
   ├── rockchip_can 驱动匹配 can1/can2 → probe() 被调用
   │   └── 注册 can1, can2 网络设备
   └── mcp251x 驱动匹配 spi1.0 → probe() 被调用
       └── 注册 can3 网络设备
​
3. 用户空间操作
   ├── ip link set can1 up
   ├── ip link set can2 up
   └── ip link set can3 up

六、完整编译与部署脚本

6.1 一键编译脚本

#!/bin/bash
# build_3can.sh - 三路 CAN 完整编译部署
​
set -e
​
echo "========================================="
echo "RK3588 三路 CAN 编译部署"
echo "========================================="
​
# 内核源码路径(根据实际修改)
KERNEL_DIR=/path/to/linux-5.10
​
# 1. 确认内核配置
echo "[1/4] 检查内核配置..."
cd $KERNEL_DIR
​
# 检查是否已配置 CAN 驱动
if ! grep -q "CONFIG_CAN_ROCKCHIP=y" .config; then
    echo "  配置 Rockchip CAN 驱动..."
    echo "CONFIG_CAN_ROCKCHIP=y" >> .config
fi
​
if ! grep -q "CONFIG_CAN_MCP251X=y" .config; then
    echo "  配置 MCP2515 驱动..."
    echo "CONFIG_CAN_MCP251X=y" >> .config
fi
​
# 2. 编译内核模块
echo "[2/4] 编译内核模块..."
make ARCH=arm64 modules -j8
​
# 3. 编译设备树
echo "[3/4] 编译设备树..."
dtc -@ -I dts -O dtb -o rk3588-3can.dtbo rk3588-3can.dtsi
​
# 4. 部署
echo "[4/4] 部署..."
sudo cp rk3588-3can.dtbo /boot/overlays/
sudo make ARCH=arm64 modules_install
sudo depmod -a
​
echo ""
echo "========================================="
echo "部署完成!请执行以下步骤:"
echo "1. 编辑 /boot/uEnv.txt,添加:"
echo "   dtoverlay=/boot/overlays/rk3588-3can.dtbo"
echo "2. 重启系统"
echo "3. 运行测试脚本: ./test_3can.sh"
echo "========================================="

5.1 三路 CAN 测试脚本

#!/bin/bash
# test_3can.sh - 三路 CAN 完整测试
​
set -e
​
echo "========================================="
echo "RK3588 三路 CAN 测试"
echo "   - CAN1: 原生 (RD54/AK25 + RD66/AM25)"
echo "   - CAN2: 原生 (LU29/AH25 + LU31/AH26)"
echo "   - CAN3: SPI 扩展 (SPI1 + MCP2515 + GPIO0_C4)"
echo "========================================="
​
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'
​
# 1. 加载驱动模块
echo -e "\n[1] 加载驱动模块..."
modprobe rockchip_can 2>/dev/null && echo -e "${GREEN}  ✅ rockchip_can 加载成功${NC}" || echo -e "${YELLOW}  ⚠️ rockchip_can 可能已编译进内核${NC}"
modprobe mcp251x 2>/dev/null && echo -e "${GREEN}  ✅ mcp251x 加载成功${NC}" || echo -e "${YELLOW}  ⚠️ mcp251x 可能已编译进内核${NC}"
​
# 2. 查看 CAN 设备
echo -e "\n[2] 查看 CAN 设备:"
ip link show | grep can
​
# 3. 配置三路 CAN
echo -e "\n[3] 配置三路 CAN (波特率 500kbps)..."
​
# CAN1 (原生)
ip link set can1 down 2>/dev/null
ip link set can1 type can bitrate 500000
ip link set can1 up
if [ $? -eq 0 ]; then
    echo -e "${GREEN}  ✅ CAN1 配置成功${NC}"
else
    echo -e "${RED}  ❌ CAN1 配置失败${NC}"
fi
​
# CAN2 (原生)
ip link set can2 down 2>/dev/null
ip link set can2 type can bitrate 500000
ip link set can2 up
if [ $? -eq 0 ]; then
    echo -e "${GREEN}  ✅ CAN2 配置成功${NC}"
else
    echo -e "${RED}  ❌ CAN2 配置失败${NC}"
fi
​
# CAN3 (SPI 扩展)
ip link set can3 down 2>/dev/null
ip link set can3 type can bitrate 500000
ip link set can3 up
if [ $? -eq 0 ]; then
    echo -e "${GREEN}  ✅ CAN3 (SPI) 配置成功${NC}"
else
    echo -e "${RED}  ❌ CAN3 配置失败${NC}"
fi
​
# 4. 查看设备状态
echo -e "\n[4] 设备状态:"
ip -brief link show | grep can
​
# 5. 查看详细配置
echo -e "\n[5] 详细配置:"
for dev in can1 can2 can3; do
    echo -e "\n${YELLOW}$dev:${NC}"
    ip -details link show $dev | head -4
done
​
# 6. 回环测试
echo -e "\n[6] 回环测试..."
​
for dev in can1 can2 can3; do
    echo -e "${YELLOW}  测试 $dev 回环...${NC}"
    
    # 配置回环模式
    ip link set $dev down
    ip link set $dev type can bitrate 500000 loopback on
    ip link set $dev up
    
    # 后台接收
    candump $dev &
    CANDUMP_PID=$!
    sleep 1
    
    # 发送测试帧
    case $dev in
        can1) cansend $dev 123#1122334455667788 ;;
        can2) cansend $dev 456#AABBCCDD ;;
        can3) cansend $dev 789#0102030405060708 ;;
    esac
    sleep 1
    
    kill $CANDUMP_PID 2>/dev/null
    
    # 恢复正常模式
    ip link set $dev down
    ip link set $dev type can bitrate 500000
    ip link set $dev up
    
    echo -e "${GREEN}    ✅ $dev 回环测试通过${NC}"
done
​
# 7. 查看统计信息
echo -e "\n[7] 统计信息:"
for dev in can1 can2 can3; do
    echo -e "\n${YELLOW}$dev:${NC}"
    ip -stats link show $dev | grep -A 5 "RX:" | head -3
done
​
# 8. 查看中断统计
echo -e "\n[8] 中断统计:"
cat /proc/interrupts | grep -E "can|mcp" | head -10
​
echo -e "\n========================================="
echo -e "${GREEN}三路 CAN 测试完成!${NC}"
echo "========================================="

七、总结

组件 是否需要修改 说明
Rockchip CAN 驱动 ❌ 不需要 内核已原生支持,通过设备树启用
MCP2515 驱动 ❌ 不需要 内核已原生支持,通过设备树配置 SPI 子节点
设备树 ✅ 需要 配置 CAN1、CAN2 引脚复用和 SPI1 + MCP2515
内核配置 ✅ 需要 启用 CONFIG_CAN_ROCKCHIP 和 CONFIG_CAN_MCP251X
硬件连接 ✅ 需要 正确连接 CAN 收发器和 MCP2515 电路
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐