开发板:E9(飞思卡尔的imx6q主控)
内核:Linux 3.0.35
PC OS:Ubuntu 11.04
本文对ENC28J60模块的驱动移植进行简单梳理。该模块购于淘宝。
按照一般移植要素,有如下几个步骤:
1. 按照各引脚所对应的功能进行初始化操作。
2. 确定总线类型,在bsp中注册相应的主控制器信息。
3.在bsp中添加设备信息。
4. 配置内核,打开设备配置选项。
IMX6开发板 ENC28J60
CSPI2_CLK ---> SCK
CSPI2_MISO <--- SO
CSPI2_MOSI ---> SI
CSPI_CS0 ---> CS
EIM_D21 <--- INT
VCC 3.3v ---> VCC
GND --> GND
从硬件连线方式可以看出,SPI总线使用的是imx6的SPI2控制器,同时额外需要一个GPIO作为中断引脚。
在原文件arch/arm/mach-mx6/board-mx6q_sabresd.h的数组mx6q_sabresd_pads数组中添加如下内容:
/* ECSPI2*/ MX6Q_PAD_EIM_CS0__ECSPI2_SCLK, MX6Q_PAD_EIM_CS1__ECSPI2_MOSI, MX6Q_PAD_EIM_OE__ECSPI2_MISO, MX6Q_PAD_CSI0_DAT11__GPIO_5_29, //MX6Q_PAD_EIM_D17__GPIO_3_17, MX6Q_PAD_EIM_D21__GPIO_3_21, /* gpio interrupt for enc2860j */
由于ENC28J60使用SPI总线,因此,在注册板级设备设备前,需要弄SPI的一些参数。
ENC28J60使用SPI模式0进行传输,最大速率为10Mbps。
在原文件arch/arm/mach-mx6/board-mx6q_sabresd.c中添加如下结构体的声明:
/* Following is added by Jone Yim for enc28j60 */ #define SABRESD_ECSPI2_CS0 IMX_GPIO_NR(5, 29) /* CSPI2_CS0 */ #define ENC28J60_INTERRUPT_GPIO IMX_GPIO_NR(3, 21) /* EIM_D21 */ static int mx6q_sabresd_spi2_cs[] = { SABRESD_ECSPI2_CS0, }; static const struct spi_imx_master mx6q_sabresd_spi2_data __initconst = { .chipselect = mx6q_sabresd_spi2_cs, .num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi2_cs), }; static struct spi_board_info mx6_sabresd_spi2_board[]={ [0] = { .modalias = "enc28j60", .bus_num = 1, .chip_select = 0, .max_speed_hz = 5000 * 1000, .mode = SPI_MODE_0, }, };
首先通过宏定义了CS和INT所使用的引脚号,并定义了SPI板级设备。
接下来我们需要注册该SPI板级设备信息到内核中。
在同一文件下的mx6_sabresd_board_init函数中添加如下代码:
/* Following is added by Jone Yim for enc28j60 */ imx6q_add_ecspi(1, &mx6q_sabresd_spi2_data); /*using ecspi2*/ ret = gpio_request(ENC28J60_INTERRUPT_GPIO, "ENC28J60-int"); if (ret) { printk(KERN_ERR"request ENC28J60-int error!!\n"); }else{ gpio_direction_input(ENC28J60_INTERRUPT_GPIO); //printk("enc28j60 gpio %d irq %d\n", ENC28J60_INTERRUPT_GPIO, irq); irq = gpio_to_irq(ENC28J60_INTERRUPT_GPIO); if(irq < 0){ printk(KERN_ERR"claim gpio irq error!!\n"); }else{ printk("enc28j60 gpio %d irq %d\n", ENC28J60_INTERRUPT_GPIO, irq); mx6_sabresd_spi2_board[0].irq = irq; irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING); spi_register_board_info(mx6_sabresd_spi2_board, ARRAY_SIZE(mx6_sabresd_spi2_board)); } }首先注册SPI2控制器,然后在调用spi_register_board_info注册SPI板级设备信息之前,我们向系统申请了用于中断的GPIO引脚,并获取了其irq号,并将该irq号保存到SPI板级设备信息。
其次,我们需要设置GPIO的中断类型为下降沿中断,这跟datasheet里面描述的一致。这里提一句为什么要在这里设置中断类型,这是因为在ENC28J60驱动源码的probe方法中并未设置其中断类型,反而是有一段注释要求在bsp中设置中断类型。
一切就绪,最后spi_register_board_info调用注册SPI板级设备信息。
配置完以后即可编译。
系统启动后执行如下命令:
ifconfig eth0 down //关闭原有的网口
ifconfig eth1 up 192.168.0.116 //打开ENC28J60对应的网口并设置IP地址
然后ping以下虚拟机试试:
ping通了,至此大功告成。