前言
rk3288芯片没有can数据线路,但是客户提出需求要用can通信,硬件就设计了一个简易的转接板,在spi通信线路下挂了一个mcp2515模块,实现spi转can通信。
1、mcp2515电路设计
can收发器
2、kernel配置
当前rk3288 kernel源码中已有mcp2515驱动代码,只需打开内核配置即可
kernel/arch/arm/configs/rockchip_defconfig
+CONFIG_CAN=y
+CONFIG_CAN_MCP251X=y
设备树配置
+&spi1 {
+ status = "okay";
+
+ can0: can@0 {
+ compatible = "microchip,mcp2515";
+ pinctrl-names = "default";
+ pinctrl-0 = <&can0_pins>;
+ reg = <0>;
+ clocks = <&clk16m>;
+ spi-max-frequency = <10000000>;
+ interrupt-parent = <&gpio8>;
+ interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+ };
+};
+
+ clk16m: clk16m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <16000000>;
+ };
+ can0 {
+ can0_pins: can0_pins {
+ rockchip,pins = <8 3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
调试遇到问题:
问题1:mcp2515驱动加载失败
在内核启动过程中,会概率性出现can0节点加载失败问题,分析源码发现,在读取mcp2515模块寄存器是会读取失败,为排除硬件问题,个人买了一个独立的mcp2515模块,经测试发现与硬件工程师设计的模块出现同一问题,猜测可能是驱动问题,检查spi引脚定义,发现当前spi与isp节点下的gpio引脚有复用,考虑到当前系统并未用到isp功能,随即关闭isp节点,修复此问题
&isp {
- status = "okay";
+ status = "disabled";
gpios-cifpower1 = <&gpio2 12 GPIO_ACTIVE_HIGH>;
gpios-cifpower2 = <&gpio2 13 GPIO_ACTIVE_HIGH>;
pinctrl-0 = <&isp_mipi &cifpower_gpio>;
--
问题2:can0 节点启动失败
调试时发现在执行ifconfig can0 up命令是,会低概率的出现can设备open失败的情况,再次执行命令可以正常启动can设备,在git代码仓库中查找到kernel4.4源码关于mcp2515驱动更新部分,发现有处理过这种情况,随即将该补丁移植过来
@@ -627,7 +627,7 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
static int mcp251x_hw_reset(struct spi_device *spi)
{
struct mcp251x_priv *priv = spi_get_drvdata(spi);
- u8 reg;
+ unsigned long timeout;
int ret;
/* Wait for oscillator startup timer after power up */
@@ -640,11 +640,20 @@ static int mcp251x_hw_reset(struct spi_device *spi)
/* Wait for oscillator startup timer after reset */
mdelay(MCP251X_OST_DELAY_MS);
-
- reg = mcp251x_read_reg(spi, CANSTAT);
- if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
- return -ENODEV;
+ /* Wait for reset to finish */
+ timeout = jiffies + HZ;
+ while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) !=
+ CANCTRL_REQOP_CONF) {
+ usleep_range(MCP251X_OST_DELAY_MS * 1000,
+ MCP251X_OST_DELAY_MS * 1000 * 2);
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(&spi->dev,
+ "MCP251x didn't enter in conf mode after reset\n");
+ return -EBUSY;
+ }
+ }
return 0;
}