Linux spi system

题图:gratisography

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相关教程,感谢您的查阅。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容