linux spi 驱动
创始人
2024-06-02 14:18:10
0

linux 5.15 armv8-a64

本文主要讲述spi 驱动的master和slave的初始化过程,linux中抽象spi master为spi_controler,spi slave 为spi_device,其中spi_controler实质是platform device,理解spi需要先从platform开始。

platform bus的由来

linux最基本的驱动的模型是设备device,驱动driver,bus总线。device是对物理设备的抽象,总线会枚举设备,并连接设备与驱动。CPU一般通过特定的总线访问设备,比如usb总线,这些总线会发现并通知system 该bus所连接的设备,但有一类设备不是特殊的总线连接到system也没有办法让system知道自己的存在,例如spi controler cpu可以直接访问它的寄存器,但是他不会枚举自己,这种设备就满足不了linux标准驱动模型。为了用标准驱动模型来抽象这类设备,linux引入了platform bus(virtual bus)利用这个软件虚拟bus实现这类设备的枚举和驱动的连接,linux Document解释如下。

Platform devices are devices that typically appear as autonomous entities
in the system. This includes legacy port-based devices and host bridges
to peripheral buses, and most controllers integrated into system-on-chip
platforms. What they usually have in common is direct addressing from
a CPU bus. Rarely, a platform_device will be connected through a segment
of some other kind of bus; but its registers will still be directly addressable.

spi controler的初始化过程

platform bus 初始化在start_kernel的最后kernel_init线程中

start_kernel --> rest_init --> kernel_init --> kernel_init_freeable --> do_basic_setup --> driver_init --> platform_bus_init

int __init platform_bus_init(void)
{int error;early_platform_cleanup();error = device_register(&platform_bus);if (error) {put_device(&platform_bus);return error;}error =  bus_register(&platform_bus_type);if (error)device_unregister(&platform_bus);of_platform_register_reconfig_notifier();return error;
}
"platform.c" 1524 lines --99%--

do_basic_setup --> do_initcalls(driver_init之后)

arch_initcall_sync(of_platform_default_populate_init);

/*** of_platform_populate() - Populate platform_devices from device tree data* @root: parent of the first level to probe or NULL for the root of the tree* @matches: match table, NULL to use the default* @lookup: auxdata table for matching id and platform_data with device nodes* @parent: parent to hook devices from, NULL for toplevel** Similar to of_platform_bus_probe(), this function walks the device tree* and creates devices from nodes.  It differs in that it follows the modern* convention of requiring all device nodes to have a 'compatible' property,* and it is suitable for creating devices which are children of the root* node (of_platform_bus_probe will only create children of the root which* are selected by the @matches argument).** New board support should be using this function instead of* of_platform_bus_probe().** Return: 0 on success, < 0 on failure.*/
int of_platform_populate(struct device_node *root,const struct of_device_id *matches,const struct of_dev_auxdata *lookup,struct device *parent)

matches参数of_default_bus_match_table

of_platform_populate(root, of_default_bus_match_table, lookup, parent);
const struct of_device_id of_default_bus_match_table[] = {{ .compatible = "simple-bus", },{ .compatible = "simple-mfd", },{ .compatible = "isa", },
#ifdef CONFIG_ARM_AMBA{ .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */{} /* Empty terminated list */
};
/** 
* of_platform_bus_create() - Create a device for a node and its children. 
* @bus: device node of the bus to instantiate 
* @matches: match table for bus nodes 
* @lookup: auxdata table for matching id and platform_data with device nodes 
* @parent: parent for new device, or NULL for top level. 
* @strict: require compatible property 
*
* Creates a platform_device for the provided device_node, and optionally 
* recursively create devices for all the child nodes. */static int of_platform_bus_create(structdevice_node*bus,conststructof_device_id*matches,conststructof_dev_auxdata*lookup,structdevice*parent,boolstrict);/*** of_platform_device_create_pdata - Alloc, initialize and register an of_device* @np: pointer to node to create device for* @bus_id: name to assign device* @platform_data: pointer to populate platform_data pointer with* @parent: Linux device model parent device.** Return: Pointer to created platform device, or NULL if a device was not* registered.  Unavailable devices will not get registered.*/
static struct platform_device *of_platform_device_create_pdata(struct device_node *np,const char *bus_id,void *platform_data,struct device *parent)
{struct platform_device *dev;if (!of_device_is_available(np) ||of_node_test_and_set_flag(np, OF_POPULATED))return NULL;dev = of_device_alloc(np, bus_id, parent);if (!dev)goto err_clear_flag;dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);if (!dev->dev.dma_mask)dev->dev.dma_mask = &dev->dev.coherent_dma_mask;dev->dev.bus = &platform_bus_type;dev->dev.platform_data = platform_data;of_msi_configure(&dev->dev, dev->dev.of_node);if (of_device_add(dev) != 0) {platform_device_put(dev);goto err_clear_flag;}return dev;err_clear_flag:of_node_clear_flag(np, OF_POPULATED);return NULL;
}

of_platform_bus_create --> of_platform_device_create_pdata 创建paltform_device

例如qcom 的sm8250.dtsi 中soc 节点的compatible属性simple-bus,of_platform_bus_create函数递归的将compatible属性为simple-bus的节点以及其一级子节点都创建为platform device,spi controler spi14同理。

        soc: soc@0 {#address-cells = <2>;#size-cells = <2>;ranges = <0 0 0 0 0x10 0>;dma-ranges = <0 0 0 0 0x10 0>;compatible = "simple-bus";spi14: spi@880000 {compatible = "qcom,geni-spi";reg = <0 0x00880000 0 0x4000>;status = "disabled";};i2c15: i2c@884000 {compatible = "qcom,geni-i2c";reg = <0 0x00884000 0 0x4000>;};};

platform bus he platform device ready后,只缺platform driver

module_platform_driver(spi_geni_driver);

do_initcalls --> module_init --> platform_driver_register --> driver_register --> bus_add_driver

--> driver_attatch --> __driver_attatch --> driver_probe_device

spi controler的probe方法在注册platform driver的时候被调用

当然在driver_probe_device之前有一个driver与device match的过程,使用的driver->bus的match 方法

static inline int driver_match_device(struct device_driver *drv,struct device *dev)
{return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

spi slave的初始化过程

postcore_initcall(spi_init);

do_basic_setup --> do_initcalls --> postcore_initcall

spi_init过程会register spi bus

struct bus_type spi_bus_type = {.name           = "spi",.dev_groups     = spi_dev_groups,.match          = spi_match_device,.uevent         = spi_uevent,.probe          = spi_probe,.remove         = spi_remove,.shutdown       = spi_shutdown,
};
EXPORT_SYMBOL_GPL(spi_bus_type);

spi slave在dts中需要以spi controler节点的子节点存在如下

&main_spi0 {pinctrl-names = "default";pinctrl-0 = <&main_spi0_pins_default>;ti,pindir-d0-out-d1-in;eeprom@0 {compatible = "microchip,93lc46b";reg = <0>;spi-max-frequency = <1000000>;spi-cs-high;data-size = <16>;};
};

spi controler的子节点是怎样被创建成device的呢

spi controler的probe方法中又调用spi_register_master --> of_register_spi_devices --> spi_add_device,of_register_spi_devices会遍历spi controler的子节点然后创建为spi_device

/*** of_register_spi_devices() - Register child devices onto the SPI bus* @ctlr:       Pointer to spi_controller device** Registers an spi_device for each child node of controller node which* represents a valid SPI slave.*/
static void of_register_spi_devices(struct spi_controller *ctlr)
{struct spi_device *spi;struct device_node *nc;if (!ctlr->dev.of_node)return;for_each_available_child_of_node(ctlr->dev.of_node, nc) {if (of_node_test_and_set_flag(nc, OF_POPULATED))continue;spi = of_register_spi_device(ctlr, nc);if (IS_ERR(spi)) {dev_warn(&ctlr->dev,"Failed to create SPI device for %pOF\n", nc);of_node_clear_flag(nc, OF_POPULATED);}}
}

spi slave的driver代码如下 module_spi_driver --> module_init --> spi_driver_register --> driver_register

spi_driver_register 设置sdrv->bus = spi_bus_type,后面的driver_register到spi slave probe方法被调用的过程与platform driver的过程类似

static struct spi_driver eeprom_93xx46_driver = {.driver = {.name   = "93xx46",.of_match_table = of_match_ptr(eeprom_93xx46_of_table),},.probe          = eeprom_93xx46_probe,.remove         = eeprom_93xx46_remove,.id_table       = eeprom_93xx46_spi_ids,
};module_spi_driver(eeprom_93xx46_driver);

至此controler slave 与spi bus 都已经准备完成

相关内容

热门资讯

“倾听您的心声,服务您的需求”... 中国人民人寿保险股份有限公司(以下简称“人保寿险”)“倾听您的心声 服务您的需求”第十七届客户节于2...
佩斯科夫:俄不会对媒体有关俄乌... 转自:财联社【佩斯科夫:俄不会对媒体有关俄乌谈判报道发表评论】财联社5月18日电,据塔斯社当地时间1...
穆杰,调任新职 编辑 | 余晖山东省人民政府近日发布任免通知,山东省人民政府决定,任命穆杰为山东省煤田地质局副局长。...
融合文化、体育与生态,房山举办... 新京报讯(记者陈璐)5月18日,“登峰揽胜在房山”山地绿道徒步活动在房山区周口店镇永寿禅寺广场启幕。...
5月19日,“同”赴一场有“法... 【5月19日,“同”赴一场有“法”的旅行】锦绣河山,美好旅程。在第15个中国旅游日,人民法院新闻传媒...
探索电影+旅游的创新合作,盐城... 转自:上观新闻当120年胶片齿轮撞上Z世代的赛博心跳,一座城正用“轻舟计划”重构青年与电影的时空契约...
十位艺术大师联袂,绘就江南诗意... 转自:上观新闻艺术的笔触邂逅江南的灵韵,共赏“吴越江南”的水墨诗意。近日,位于闵行区万源路2800号...
痛惜!突发呼吸心跳骤停,他于深... 南京艺术学院5月17日发布讣告:南京艺术学院教授、博士生导师尹悟铭同志,因突发呼吸心跳骤停,经抢救无...
2024年我国卫星导航产业产值... 原标题:2024年我国卫星导航产业产值达5758亿元来源:人民日报客户端5月18日,中国卫星导航定位...
龙牙刀、结界兽、天元鼎……《哪... 新京报记者 展圣洁 编辑 白爽 校对 赵琳5月19日,年度重磅特展——“看·见殷商”展览将在北京大运...
中国铁建相关公司中标一项349... (转自:快查一企业中标了)快查APP显示,中国铁建相关公司中铁十八局集团有限公司于2025年5月15...
上海家庭医生签约数超1100万... 转自:中工网中新网上海5月18日电 (记者 陈静)家庭医生是居民健康的“第一道防线”。世界家庭医生日...
50多岁2女子无视预警爬野山被... 转自:京报网_北京日报官方网站 【#50多岁2女子无视预...
广东建工全资子公司中标一项31... (转自:快查一企业中标了)快查APP显示,广东建工相关公司广东省基础工程集团有限公司于2025年5月...
从工具到生态:金融科技的角色升... 转自:企业观察网数字金融,作为传统金融与现代信息技术深度融合的产物,正在重塑金融业务模式的底层逻辑。...
义乌至迪拜“铁海快线+中东快航... 5月18日,澎湃新闻(www.thepaper.cn)记者从中国铁路上海局集团有限公司(以下简称“上...
文化中国行|探寻国宝里的中国智... 03:12今年5月18日是第49个国际博物馆日。山西历史悠久,素有“地上文物看山西”的美誉。山西博物...
祝姜同学前程似锦!救人小伙姜昭... 来源:人民日报 【祝姜同学前程似锦!#救人小伙姜昭鹏完成...
印度南部一建筑起火,至少17人... 转自:上观新闻当地时间5月18日,印度南部特伦甘纳邦海得拉巴市一栋建筑发生火灾,目前已造成至少17人...
墨西哥海军船只撞上布鲁克林大桥... 转自:央视新闻  当地时间17日晚,一艘载有277人的墨西哥海军大型帆船在穿越美国纽约布鲁克林大桥时...