基于linux2.6.33 spi驱动移植总结
Written by jinx
Linux版本:2.6.33
处理器:DM644x
Spi实现:采用DM644X的spi0片内外设模块,设置PINMUX1[8]=1,使能spi功能。
Spi主机:dm644x;spi从机:w25x80
Spi驱动包括三部分:dm644x上的spi功能模块驱动(spi主机驱动) (davinci_spi.c);w25x80的芯片驱动(m25p80.c),以及spi总线驱动(spi.c)。
1. dm644x的上的spi功能模块驱动(spi主机驱动)
由于dm644x的上的spi功能模块是dm644x的片上资源,因此,linux把它注册为平台设备和平台驱动
即包括davinci_spi_device和davinci_spi_driver;挂载到platform总线下。
2. w25x80设备芯片驱动
把设备芯片驱动注册到spi bus总线上,根据bus_num的值来确定是挂到spi.0总线上,还是spi.1总线上。用flash_platform_data表示设备芯片信息。即表示硬件上连接到spi主机的从设备信息。
3. 由于dm644x包含有两个spi功能模块,因此,linux系统还注册了spi bus总线。
spi_board_info表示spi bus总线属性,其中用bus_num=0表示spi.0(GPIO37为片选信号)或者spi.1=1总线(GPIO42为片选信号)。platform_data成员用来表示此spi bus挂载的设备信息,即flash_platform_data。
4. 通过spi_register_master调用scan_boardinfo函数把w25x80设备芯片驱动的spi时序实现使用dm644x的spi主机驱动去实现。即把spi bus总线的属性或者说是spi bus设备与spi主机驱动进行挂载,实现方法:用一个board_list链表来维护通过spi_register_board_info函数注册的spi 设备(spi_board_info),通过查询board_list链表所有设备的bus_num与驱动所属的bus_num是否一致进行匹配。一旦匹配成功就相当于把spi从设备挂载到了spi主机上spi总线上了。
5. Spi上的数据交互都是驱动里面的工作队列来维护的:
create_singlethread_workqueue();
INIT_WORK(&bitbang->work, bitbang_work);
相关数据结构说明
static struct davinci_spi_platform_data用来描述dm644x上的spi功能模块属性设置,包括是能使用dma通道处理数据,时钟信号源(spi clock)的选择等
static struct davinci_spi_platform_data davinci_spi_data =
{
.version = 1,
.num_chipselect = 1,
.wdelay = 100,
.odd_parity = 1,
.parity_enable = 0,
.wait_enable = 0,
.timer_disable = 1,
.clk_internal = 1,
.cs_hold = 1,
.intr_level = 0,
.poll_mode = 0,
.use_dma = 0,
.c2tdelay = NULL,
.t2cdelay = NULL,
};
static struct resource描述dm644x片上资源:spi功能模块相关寄存器地址和中断号。
static struct resource davinci_spi_resources[] = {
{
.start = DAVINCI_SPI_BASE,
.end = DAVINCI_SPI_BASE + (SZ_4K/2),
.flags = IORESOURCE_MEM,
},
{
.start = IRQ_SPINT0,
.end = IRQ_SPINT0,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device挂载到platform总线上的spi功能模块描述.linux系统把所有的设备都挂载到BUS上,即都是通过BUS总线的方式挂载所有设备,同时处理器的片内外设资源当作设备看待,这些片内外设也都挂载到BUS上,这个BUS的名字就是platform。也就是说,platform总线上挂载的所有设备就是处理器上所有的片内外设模块,包括iic模块,edma模块,spi模块等等。
static struct platform_device davinci_spi_device = {
.name = "spi",
.id = 0,
.dev = {
.platform_data = &davinci_spi_data,//描述spi功能模块的工作属性
},
.num_resources = ARRAY_SIZE(davinci_spi_resources),
.resource = davinci_spi_resources,
};
static struct platform_driver描述spi功能模块的驱动,也就是处理器片内外设spi模块的配置和工作方式。即称为平台驱动,通过注册,把davinci_spi_driver与davinci_spi_device绑定,并在挂在platform总线上。
static struct platform_driver davinci_spi_driver = {
.driver.name = "spi", //"spi_davinci",//modified by jinx
.probe = davinci_spi_probe,
.remove = __exit_p(davinci_spi_remove),
};
static struct mtd_partition spiflash_partitions[] =
{
{
.name = "log",
.size = 0xe0000,
//.size = 0x100000,
.offset = 0,
},
/**/
{
.name = "config1",
//.size = 0x80000,
.size = 0x10000,
.offset = 0xE0000,
},
{
.name = "config2",
//.size = 0x80000,
.size = 0x10000,
.offset = 0xF0000,
},
/**/
};
struct flash_platform_data和static struct spi_board_info是从spi从设备的角度来描述的,即根据硬件连接通过这两个结构体描述spi从设备名字,挂到哪个spi总线上(dm644x有两个spi总线,用不同的片选管脚区分),由于是spiflash,所以platform_data指向分区信息。Spi_board_info由一个board_list链表维护。
struct flash_platform_data dm644x_spi_flash_info =
{
.name = "w25x80",
.parts = &spiflash_partitions,
.nr_parts = ARRAY_SIZE(spiflash_partitions),
.type = "w25x80",
};
static struct spi_board_info dm644x_evm_spi_info[] = {
{
.modalias = "w25x80",
.platform_data = &dm644x_spi_flash_info,
.max_speed_hz = 10 * 1000 * 1000, /* at 3v3 */
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_0,
},
};