SPI设备树处理过程
一、spi_device结构体
/*** struct spi_device - Controller side proxy for an SPI slave device* @dev: Driver model representation of the device.* @controller: SPI controller used with the device.* @master: Copy of controller, for backwards compatibility.* @max_speed_hz: Maximum clock rate to be used with this chip* (on this board); may be changed by the device's driver.* The spi_transfer.speed_hz can override this for each transfer.* @chip_select: Chipselect, distinguishing chips handled by @controller.* @mode: The spi mode defines how data is clocked out and in.* This may be changed by the device's driver.* The "active low" default for chipselect mode can be overridden* (by specifying SPI_CS_HIGH) as can the "MSB first" default for* each word in a transfer (by specifying SPI_LSB_FIRST).* @bits_per_word: Data transfers involve one or more words; word sizes* like eight or 12 bits are common. In-memory wordsizes are* powers of two bytes (e.g. 20 bit samples use 32 bits).* This may be changed by the device's driver, or left at the* default (0) indicating protocol words are eight bit bytes.* The spi_transfer.bits_per_word can override this for each transfer.* @irq: Negative, or the number passed to request_irq() to receive* interrupts from this device.* @controller_state: Controller's runtime state* @controller_data: Board-specific definitions for controller, such as* FIFO initialization parameters; from board_info.controller_data* @modalias: Name of the driver to use with this device, or an alias* for that name. This appears in the sysfs "modalias" attribute* for driver coldplugging, and in uevents used for hotplugging* @cs_gpio: gpio number of the chipselect line (optional, -ENOENT when* not using a GPIO line)** @statistics: statistics for the spi_device** A @spi_device is used to interchange data between an SPI slave* (usually a discrete chip) and CPU memory.** In @dev, the platform_data is used to hold information about this* device that's meaningful to the device's protocol driver, but not* to its controller. One example might be an identifier for a chip* variant with slightly different functionality; another might be* information about how this particular board wires the chip's pins.*/
struct spi_device {struct device dev;struct spi_controller *controller;struct spi_controller *master; /* compatibility layer */u32 max_speed_hz; //该设备能支持的SPI设备的最大时钟u8 chip_select; //在spi_master下的第几个设备,在spi_master中有一个cs_gpio数组,里面存放了各个spi设备的片选引脚,//spi_device的片选引脚就是:cs_gpios[spi_device.chip_select]u8 bits_per_word; //每个基本的SPI传输涉及多少位,在使用spi控制器时,一般往寄存器里写入数据,SPI控制器会一位一位地发送出去。//一个寄存器是32位,通常叫word。寄存器里有多少位会被发送出去,这取决于bits_per_word。//扩展:bits_per_word可以大于32位,这适用于DMA突发模式u16 mode;
#define SPI_CPHA 0x01 /* clock phase */ //采样周期,第一个周期还是第二个周期
#define SPI_CPOL 0x02 /* clock polarity */ //平时的时钟极性
#define SPI_MODE_0 (0|0) /* (original MicroWire) */ //组合起来有四种,SCK平时为低电平,第1个周期采样
#define SPI_MODE_1 (0|SPI_CPHA) //SCK为低,第2个周期采样
#define SPI_MODE_2 (SPI_CPOL|0) //SCK为高电平,第1个周期采样
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) //SCK平时为高电平,第2个周期采样
#define SPI_CS_HIGH 0x04 /* chipselect active high? */ //引脚信号高电平有效
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ //一般来说都是MSB,高位先传输。这个表示低位先传输。有些SPI设备并不支持低位传输
#define SPI_3WIRE 0x10 /* SI/SO signals shared */ //SDO、SDI共用一条线
#define SPI_LOOP 0x20 /* loopback mode */ //回环模式,SDO、SDI连接在一起
#define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */ //只有一个spi设备,没有片选,也不需要
#define SPI_READY 0x80 /* slave pulls low to pause */ //spi信号可以拉低信号,表示暂停、表示未就绪
#define SPI_TX_DUAL 0x100 /* transmit with 2 wires */ //发送数据时有2条信号线
#define SPI_TX_QUAD 0x200 /* transmit with 4 wires */ //发送数据时有4条信号线
#define SPI_RX_DUAL 0x400 /* receive with 2 wires */ //接收数据时有2条信号线
#define SPI_RX_QUAD 0x800 /* receive with 4 wires */ //接收数据时有4条信号线int irq;void *controller_state;void *controller_data;char modalias[SPI_NAME_SIZE];int cs_gpio; /* chip select gpio */ //可选项,也可以把spi_device的片选引脚记录在这里/* the statistics */struct spi_statistics statistics;/** likely need more hooks for more protocol options affecting how* the controller talks to each chip, like:* - memory packing (12 bit samples into low bits, others zeroed)* - priority* - drop chipselect after each word* - chipselect delays* - ...*/
};
二、SPI设备树格式
对于SPI master,就是SPI控制器,它下面可以连接多个SPI设备。
在设备树里,使用一个节点来表示SPI Master,使用子节点来表示挂在下面的SPI设备
2.1 SPI Master
必须的属性:
- #address-cells:这个SPI Master下的SPI设备,需要多少个cell来表述它的片选引脚
- #size-cells:必须设置为0
- compatible:根据它找到SPI Master驱动
可选属性: - cs-gpios: SPI Master可以使用多个GPIO当作片选,可以在这个属性列出那些GPIO
- num-cs: 片选引脚总数
其他属性和驱动程序相关,不同SPI Master驱动程序要求的属性不一样
2.2 SPI device
在对应的SPI Master设备树节点下,每一个节点都对应一个SPI设备,
这些SPI Device必选的属性如下:
- compatible:根据它找到SPI Device驱动
- reg:用来表示它使用哪个片选引脚
- spi-max-frequency:必选,该SPI设备支持的最大SPI时钟
可选属性如下: - spi-cpol:这是一个空属性(没有值),表示CPOL为1,即平时SPI时钟为低电平
- spi-cpha:这是一个空属性(没有值),表示CPHA为1,即在时钟的第2个边沿采样数据
- spi-cs-high:这是一个空属性(没有值),表示片选引脚高电平有效
- spi-3wire:这是一个空属性(没有值),表示使用SPI 三线模式
- spi-lsb-first:这是一个空属性(没有值),表示使用SPI传输数据时先传输最低为(LSB)
- spi-tx-bus-width:表示有几条MOSI引脚,没有这个属性时默认只有1条MOSI引脚
- spi-rx-bus-width:表示有几条MISO引脚,没有这个属性时默认只有1条MISO引脚
- spi-rx-delay-us:单位时毫秒,表示每次读传输后要延时多久
- spi-tx-delay-us:单位时毫秒,表示每次写传输后要延时多久
2.3 设备树示例
spi@f00 { //表示一个spi_master#address-cells = <1>; //reg属性需要多上长度描述#size-cells = <0>; //必须是0compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi"; //用于匹配spi_master驱动程序reg = <0xf00 0x20>;interrupts = <2 13 0 2 14 0>;interrupt-parent = <&mpc5200_pic>;//cs-gpios = <&gpio1 0 0>, <0>, <&gpio1 1 0>, <&gpio1 2 0>; 可以定义使用多少个片选引脚ethernet-switch@0 { //表示挂载在spi下的设备0compatible = "micrel,ks8995m";spi-max-frequency = <1000000>; //spi的最大频率reg = <0>;};codec@1 { //表示挂载在spi下的设备1compatible = "ti,tlv320aic26";spi-max-frequency = <100000>;reg = <1>;};};
三、设备树实例
在设备树里,会有一个节点用来表示SPI控制器
在这个SPI控制器下面,连接有哪些SPI设备?会在设备树里使用子节点来描述SPI设备
3.1 使用GPIO模拟的SPI控制器
spi3{compatible = "spi-gpio";status = "okay";gpio-sck = <&gpio0 5 GPIO_ACTIVE_LOW>;gpio-mosi = <&gpio1 15 GPIO_ACTIVE_LOW>;cs-gpio = <&gpio0 27 GPIO_ACTIVE_LOW>;num-chipselects = <1>;#address-cells = <1>;#size-cells = <0>;gpio_spi: gpio_spi@0 {compatible = "fairchild,74hc595";gpio-controller;#gpio-cells = <2>;reg = <0>;registers-number = <1>;spi-max-frequency = <100000>;};
};
驱动中的调用:
//driver/spi/spi-gpio.c
//在compatible="spi-gpio"匹配后,调用probe函数
static int spi_gpio_probe(struct platform_device *pdev)
{int status;struct spi_master *master;struct spi_gpio *spi_gpio;struct spi_gpio_platform_data *pdata;u16 master_flags = 0;bool use_of = 0;status = spi_gpio_probe_dt(pdev);//...pdata = dev_get_platdata(&pdev->dev);//分配一个spi_mastermaster = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio));//...spi_gpio = spi_master_get_devdata(master);spi_gpio->cs_gpios = devm_kcalloc(&pdev->dev,pdata->num_chipselect,sizeof(*spi_gpio->cs_gpios),GFP_KERNEL);//....status = spi_gpio_request(&pdev->dev, spi_gpio,pdata->num_chipselect, &master_flags);//...设置spi_mastermaster->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);master->mode_bits = SPI_3WIRE | SPI_CPHA | SPI_CPOL;master->flags = master_flags;master->bus_num = pdev->id;/* The master needs to think there is a chipselect even if not connected */master->num_chipselect = spi_gpio->has_cs ? pdata->num_chipselect : 1;master->setup = spi_gpio_setup;master->cleanup = spi_gpio_cleanup;
#ifdef CONFIG_OFmaster->dev.of_node = pdev->dev.of_node;
#endifspi_gpio->bitbang.master = master;spi_gpio->bitbang.chipselect = spi_gpio_chipselect;spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction;if ((master_flags & SPI_MASTER_NO_TX) == 0) {spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;} else {spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3;}spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;spi_gpio->bitbang.flags = SPI_CS_HIGH;//这里注册spi_masterstatus = spi_bitbang_start(&spi_gpio->bitbang);if (status)spi_master_put(master);return status;
}int spi_bitbang_start(struct spi_bitbang *bitbang)
{struct spi_master *master = bitbang->master;int ret;//....注册spi_masterret = spi_register_master(spi_master_get(master));//...return 0;
}
3.2 IMX6ULL SPI控制器
arch/arm/boot/dts/imx6ull.dtsi
ecspi3: ecspi@02010000 {#address-cells = <1>;#size-cells = <0>;compatible = "fsl,imx6ul-ecspi","fsl,imx5l-ecspi";reg = <0x02010000> <0x4000>;interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_ECSPI3>,<&clks IMX6UL_CLK_ECSPI3>;clock-names = "jpg", "per";dmas = <&sdma 7 7 1>, <&sdma 8 7 2>;dma-names = "rx", "tx";status = "disabled";
};
arch/arm/boot/dts/100ask_imx6ull-14x14.dts
&ecspi3 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_ecspi3>;cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;status = "okay";spidev: icm20608@0 {compatible = "invensense,icm20608";interrupt-parent = <&gpio1>;interrupts = <1 1>;spi-max-frequency = <8000000>;reg = <0>;};
};
3.3 STM32MP157 SPI控制器
arch/arm/boot/dts/stm32mp151.dtsi
spi5: spi@44009000 {#address-cells = <1>;#size-cells = <0>;compatible = "st,stm32h7-spi";reg = <0x44009000 0x400>;interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;clocks = <&rcc SPI5_K>;resets = <&rcc SPI5_R>;dmas = <&dmamux1 85 0x400 0x01>,<&dmamux1 86 0x400 0x01>;dma-names = "rx", "tx";power-domains = <&pd_core>;status = "disabled";
};
arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts
&spi5 {pinctrl-names = "default", "sleep";pinctrl-0 = <&spi5_pins_a>;pinctrl-1 = <&spi5_sleep_pins_a>;status = "okay";cs-gpios = <&gpioh 5 GPIO_ACTIVE_LOW>;spidev: icm20608@0 {compatible = "invensense,icm20608";interrupts = <0 IRQ_TYPE_EDGE_FALLING>;interrupt-parent = <&gpioz>;spi-max-frequency = <8000000>;reg = <0>;};
};
四、设备树处理过程
在注册spi_master时,调用spi_register_controller
int spi_register_controller(struct spi_controller *ctlr)
{//...注册spi_masterif (!spi_controller_is_slave(ctlr)) {status = of_spi_register_master(ctlr);if (status)return status;}//...注册完master注册device/* Register devices from the device tree and ACPI */of_register_spi_devices(ctlr);acpi_register_spi_devices(ctlr);
done:return status;
}
内核源码:drivers/spi/spi.c
static int of_spi_register_master(struct spi_controller *ctlr)
{int nb, i, *cs;struct device_node *np = ctlr->dev.of_node;if (!np)return 0;nb = of_gpio_named_count(np, "cs-gpios"); //解析片选引脚节点ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect);/* Return error only for an incorrectly formed cs-gpios property */if (nb == 0 || nb == -ENOENT)return 0;else if (nb < 0)return nb;cs = devm_kcalloc(&ctlr->dev, ctlr->num_chipselect, sizeof(int),GFP_KERNEL);ctlr->cs_gpios = cs; //把片选引脚信息记录在这里if (!ctlr->cs_gpios)return -ENOMEM;for (i = 0; i < ctlr->num_chipselect; i++)cs[i] = -ENOENT;for (i = 0; i < nb; i++)cs[i] = of_get_named_gpio(np, "cs-gpios", i);return 0;
}//解析每个spi_device
static void of_register_spi_devices(struct spi_controller *ctlr)
{//...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); //对每个节点进行解析//...}
}static struct spi_device *
of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
{struct spi_device *spi;int rc;/* Alloc an spi_device */spi = spi_alloc_device(ctlr);//.../* Select device driver */rc = of_modalias_node(nc, spi->modalias,sizeof(spi->modalias));//...rc = of_spi_parse_dt(ctlr, spi, nc); //这里解析spi_device节点的所有属性//.../* Store a pointer to the node in the device structure */of_node_get(nc);spi->dev.of_node = nc;/* Register the new device */rc = spi_add_device(spi);//...return spi;//...
}
SPI设备树处理过程相关推荐
- 高通平台msm8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程)
本系列导航: 高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...
- Linux kernel 有关 spi 多个片选设备树参数解析
一.最近做了一个 spi 设备驱动从板级设备驱动升级到设备树设备驱动,这其中要了解 spi 设备树代码的解析. 二. 设备树配置如下: 503 &spi0 {504 status = &quo ...
- linux spidev 应用_嵌入式Linux设备树语法总结
1 设备树的说明 在写完嵌入式驱动总结后,对于设备树相关的语法和使用一直都想进行系统的描述,但是因为最近比较忙碌,所以一直拖到现在才完成初版,对于整个嵌入式Linux驱动开发中,设备树语法和构建是其中 ...
- Linux SPI设备驱动
实现了SPI OLED外设驱动,OLED型号为SH1106. 1.主机驱动与外设驱动分离 Linux中的I2C.SPI.USB等总线驱动,都采用了主机(控制器)驱动与外设(设备)驱动分离的思想.主机端 ...
- 高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)
本系列导航: 高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...
- 奇小葩讲设备树(4/5)-- Linux设备树详解(四)kernel的解析
uboot将一些参数,设备树文件传给内核,那么内核如何处理这些设备树文件呢?本章就kernel解析设备树的过程和原理,本章的主要内容以Device Tree相关的数据流分析为索引,对ARM linux ...
- imx6ul spi 设备驱动开发
imx6ul spi 设备驱动开发 spi设备树格式 spi设备树配置 spi 驱动 设备树解析 spi设备驱动使用 spi通用设备驱动 spi测试工具 spi时序对比 spi api 接口 spi设 ...
- 探索Linux设备树:硬件描述与驱动程序的桥梁
目录标题 引言:Linux设备树简介 | Introduction: Linux Device Tree Overview a. 设备树的背景与发展 | Background and Developm ...
- 设备树语法,加载过程和与驱动的关系
文章目录 一.设备树语法 1.1 简介 1.2 基本数据格式 1.3 一个例子 1.3.1 根节点 2.3.2 CPU 1.3.3 节点名称 1.3.4 设备 1.3.5 status 1.3.6 编 ...
最新文章
- leetcode C++ 42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 上面是由数组 [0,1,0,2,1,0,1,3,2,
- 学习实例.文章管理.数据库操作类.DBUtil.java
- 云痕大数据考试中途可以退出吗_2020CPA考试出考率,创新低?
- 我们能用 lua 做什么
- git 添加公钥的命令
- iOS上应用Static Framework
- js JavaScript实战练习——小球碰撞反弹(详细)
- lmdb数据库的读取与转换(一) —— 基本操作
- 【吐血整理】Python 常用模块(二):json 模块
- 计算机黑屏时间,电脑开机黑屏时间长怎么办?Win10开机黑屏时间很久的解决方法...
- eact Native开发IDE安装及配置
- Itext使用 Java导出PDF
- 香槐路的香槐花,匆匆四年无归期。
- 序列到序列模型(一)(基本模型,RNN Search,注意力机制)
- ndnSIM学习(八)——examples之ndn-simple.cpp每个函数逐行剖析
- css动画和js动画_CSS与JS动画:哪个更快?
- 笔记本无线网卡失效(红叉)故障排除
- JavaWeb防止表单重复提交
- 通过ua区分QQ内置浏览器与QQ浏览器
- Ripro子主题Eeesucai-child集成后台美化包源码QIW
热门文章
- 传统的 8 小时工作制为什么会效率低下?
- 启动eclipse出现“A Java Runtime Environment (JRE) or Java Development Kit (JDK)must be available”错误处理
- android 副mic测试,如何检测Android中是否存在麦克风?
- E: The repository ‘http://extras.ubuntu.com/ubuntu xenial Release‘ does not have a Release file.
- python xlwings Excel 内容截图
- 商城系统搭建:三方平台入驻与独立部署优缺点对比
- 纯css绘制的疲惫表情包
- java第三十一天---mysql习题
- 2023年IT行业就业前景分析,准职场人必看!
- 默默无闻七年 最终成就一个优秀的IT人