8-Linux spi system

Linux spi system

SPI是由Motorola提出的一种全双工同步串行通信接口,通信波特率可以高达5Mbps,但具体速度大小取决于SPI硬件,SPI接口具有全双工操作,操作简单,数据传输速率较高的优点,但也存在没有指定的流控制,没有应答机制确认是否接收到数据的缺点。

1.Linux下SPI的驱动架构


如下:

SPI框架

从图中可以观察到SPI系统的整个框架,发现跟I2C的框架很十分相似;

硬件和用户空间就不多说了,直接看内核空间部分。

内核空间主要分为三个模块,控制器驱动,设备器驱动,和连接两个驱动的SPI核心;

spi与i2c内核空间的对比

  • master就相当于i2c中的apapter
  • spi_device即i2c中的i2c_client
  • spi core 即i2c core

不同于i2c的目录框架比较忙明确,i2c的控制器驱动在/drivers/i2c/busses/下面,设备器驱动在/drivers/i2c/chips/下面。而spi的控制器就直接放在spi/目录下,设备器驱动根据功能分开在各个地方,如spi flash的一般就在/drivers/mtd/device/下,siwtch的spi接口就放在/drivers/net/ethernet/下。

2.SPI master驱动


SPI控制器的驱动分为两部分,device和driver,使用platform总线进行连接。

platform_device的注册一般在arch下面实现,使用platform_add_devices(arch_devices, ARRAY_SIZE(arch_devices));进行添加,由于内核中有很多使用platform注册的总线,所以一般会统一使用一次platform_add_devices函数进行添加,如下:

static struct platform_device *arch_devices[] __initdata = {
    &arch_nor,
    &arch_i2c,
    &arch_wdt,
    &arch_spi,
    &arch_tdm_device,
    &arch_pfe_device,
}

一个arch_devices里面包含很多platform_device,每个device各自实现后,再一块儿添加。

static struct platform_device comcerto_spi = {
    .name = "comcerto_spi",
    .id = 0,
    .num_resources = ARRAY_SIZE(comcerto_spi_resource),
    .resource = comcerto_spi_resource,
    .dev = {
        .platform_data = &ls_spi_pdata,
    },
};

platform_driver的实现在/driver/spi/中实现,使用platform_driver_registerplatform_driver_unregister进行加载下载。

static struct platform_driver designware_spi_driver = {
    .probe  = designware_spi_probe,
    .remove = __devexit_p(designware_spi_remove),
#if CONFIG_PM
        .suspend        = designware_spi_suspend,
        .resume         = designware_spi_resume,
#endif
    .driver = {
        .name = DESIGNWARE_SPI_NAME,
        .owner = THIS_MODULE,
    },
};

static int __init designware_spi_init(void)
{
    return platform_driver_register(&designware_spi_driver);
}

static void __exit designware_spi_exit(void)
{
    platform_driver_unregister(&designware_spi_driver);
}

module_init(designware_spi_init);
module_exit(designware_spi_exit);

designware_spi_probe函数里面就是master的实现部分,里面会对spi进行很多处理,如中断/dma/等,最后会使用spi_register_master函数进行注册spi_master,该函数就是spi的核心层了,位于/driver/spi/spi.c中,这一部分的内容还不知道如何描述,后面有思路时在更新。

3.SPI device驱动


SPI设备的驱动也是分为两部分,device和driver,使用spi总线进行连接。

spi_device的注册一般在arch下面实现,使用spi_register_board_info(arch_spi_board_info, ARRAY_SIZE(arch_spi_board_info))函数进行添加,函数里面的arch_spi_board_info
spi_board_info结构体,需要我们对里面的参数进行配置,如下例子:

static struct spi_board_info comcerto_spi_board_info[] = {
    {
        /* FIXME: for chipselect-0 */
        .modalias = "s25fl256s0",
        .chip_select = 0,
        .max_speed_hz = 4*1000*1000,
        .bus_num = 1,
        .irq = -1,
        .mode = SPI_MODE_3,
        .platform_data = &spi_pdata,
        .controller_data = &spi_ctrl_data,
    },
}

spi_driver的实现也比较简单,一般就是通过spi_register_driver来进行添加,spi_unregister_driver进行卸载。

如下例子:

static struct spi_driver m25p80_driver = {
    .driver = {
        .name   = "m25p80",
        .bus    = &spi_bus_type,
        .owner  = THIS_MODULE,
    },
    .id_table   = m25p_ids,
    .probe  = m25p_probe,
    .remove = __devexit_p(m25p_remove),
};

static int __init m25p80_init(void)
{
    return spi_register_driver(&m25p80_driver);
}

static void __exit m25p80_exit(void)
{
    spi_unregister_driver(&m25p80_driver);
}

module_init(m25p80_init);
module_exit(m25p80_exit);

spi_driver.id_table信息与spi_board_info所指向的设备(或者设备树中的节点)匹配成功,则执行spi_driver.probe(),对应probe函数里面实现的内容就要根据spi所使用的场景进行对于的实现了。

如spi flash一般是作为存储介质位于mtd下面的,所以probe函数里面就要使用mtd_device_parse_register来实现mtd的添加;switch的spi接口是用来跟switch进行数据通信,probe函数里面就可以使用register_chrdev_region来添加个字符设备进行操作。

调试驱动的时候最常用的方法就是使用printk来进行交互,进行定位、验证,但是要在哪边进行printk呢,个人觉得调试spi驱动有一个地方一定要进行printk,那就是位于spi.c下的spi_match_id()函数,如下:

static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,
                                                const struct spi_device *sdev)
{
        while (id->name[0]) {
                if (!strcmp(sdev->modalias, id->name))
                        return id;
                id++;
        }
        return NULL;
}

总结:分析调试I2C/SPI的驱动后,有以下几点感悟:

  • 不管什么驱动,大致都可以分为两个动作响应,或者说两个probe接口,一个是控制器的probe(根据cpu的不同进行改变),一个是设备的probe(根据设备的不同就行改变)。
  • 每一个probe接口有与之对于的device和driver,并且需要一种总线相连。
  • 控制器的probe一般使用platform总线,对应platform_deviceplatform_driver;设备的probe使用相关的总线,如i2c总线,则对应i2c_devicei2c_driver,i2c总线,则对应spi_devicespi_driver
  • probe函数的触发都是对应的match_id函数,如platform_match_idi2c_match_idspi_match_id
  • platform的device的注册在arch下面,使用platform_add_devices添加,platform对应的driver,位于各目录下,如i2c位于i2c/busses/里面,使用i2c_register_adapter来添加。
  • 驱动如i2c的device的注册位于arch下,使用i2c_register_board_info或dts添加,对应i2c的driver位于i2c/chips/下面,使用i2c_add_driver来添加。

Linux spi system的分析就到这边,有感悟时会持续会更新。

注:以上内容都是本人在学习过程积累的一些心得,难免会有参考到其他文章的一些知识,如有侵权,请及时通知我,我将及时删除或标注内容出处,如有错误之处也请指出,进行探讨学习。文章只是起一个引导作用,详细的数据解析内容还请查看Linux相关教程,感谢您的查阅。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
sina33备份的文件20150609_2100.7z 全志a33要生成设备节点需要改动的地方: sina33打开spidev0.0的步骤.txt (全志a33下生成设备节点/dev/spidev0.0) 0、 S:\lichee\tools\pack\chips\sun8iw5p1\configs\default\env.cfg bootdelay=0 修改为 bootdelay=3 方便按 enter 进u-boot,进行调试。 1、 rootroot@rootroot-E400:~/wyb/sina33/lichee/linux-3.4$ rootroot@rootroot-E400:~/wyb/sina33/lichee/linux-3.4$ make ARCH=arm menuconfig (sina33的原始menuconfig) Device Drivers ---> [*] SPI support ---> --- SPI support [ ] Debug support for SPI drivers *** SPI Master Controller Drivers *** < > Altera SPI Controller < > Utilities for Bitbanging SPI masters < > GPIO-based bitbanging SPI Master < > OpenCores tiny SPI <*> SUNXI SPI Controller < > Xilinx SPI controller common module < > DesignWare SPI controller core support *** SPI Protocol Masters *** < > User mode SPI device driver support < > Infineon TLE62X0 (for power switching) (sina33的原始menuconfig) Device Drivers ---> [*] SPI support ---> --- SPI support [ ] Debug support for SPI drivers *** SPI Master Controller Drivers *** < > Altera SPI Controller < > Utilities for Bitbanging SPI masters < > GPIO-based bitbanging SPI Master < > OpenCores tiny SPI <*> SUNXI SPI Controller < > Xilinx SPI controller common module < > DesignWare SPI controller core support *** SPI Protocol Masters *** (需要打开这里才能够生成设备节点:/dev/spidev0.0) <*> User mode SPI device driver support < > Infineon TLE62X0 (for power switching) 2、 S:\lichee\tools\pack\chips\sun8iw5p1\configs\y3\sys_config.fex ;---------------------------------------------------------------------------------- ;SPI controller configuration ;spi_used = SPIx enable ;spi_cs_bitmap = SPI bit mapping ;---------------------------------------------------------------------------------- [spi0] spi_used = 1 spi_cs_bitmap = 1 spi_mosi = port:PC00<3><default><default><default> spi_miso = port:PC01<3><default><default><de
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值