一、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设备树处理过程相关推荐

  1. 高通平台msm8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程)

    本系列导航: 高通平台8953  Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...

  2. Linux kernel 有关 spi 多个片选设备树参数解析

    一.最近做了一个 spi 设备驱动从板级设备驱动升级到设备树设备驱动,这其中要了解 spi 设备树代码的解析. 二. 设备树配置如下: 503 &spi0 {504 status = &quo ...

  3. linux spidev 应用_嵌入式Linux设备树语法总结

    1 设备树的说明 在写完嵌入式驱动总结后,对于设备树相关的语法和使用一直都想进行系统的描述,但是因为最近比较忙碌,所以一直拖到现在才完成初版,对于整个嵌入式Linux驱动开发中,设备树语法和构建是其中 ...

  4. Linux SPI设备驱动

    实现了SPI OLED外设驱动,OLED型号为SH1106. 1.主机驱动与外设驱动分离 Linux中的I2C.SPI.USB等总线驱动,都采用了主机(控制器)驱动与外设(设备)驱动分离的思想.主机端 ...

  5. 高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)

    本系列导航: 高通平台8953  Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...

  6. 奇小葩讲设备树(4/5)-- Linux设备树详解(四)kernel的解析

    uboot将一些参数,设备树文件传给内核,那么内核如何处理这些设备树文件呢?本章就kernel解析设备树的过程和原理,本章的主要内容以Device Tree相关的数据流分析为索引,对ARM linux ...

  7. imx6ul spi 设备驱动开发

    imx6ul spi 设备驱动开发 spi设备树格式 spi设备树配置 spi 驱动 设备树解析 spi设备驱动使用 spi通用设备驱动 spi测试工具 spi时序对比 spi api 接口 spi设 ...

  8. 探索Linux设备树:硬件描述与驱动程序的桥梁

    目录标题 引言:Linux设备树简介 | Introduction: Linux Device Tree Overview a. 设备树的背景与发展 | Background and Developm ...

  9. 设备树语法,加载过程和与驱动的关系

    文章目录 一.设备树语法 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 编 ...

最新文章

  1. leetcode C++ 42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 上面是由数组 [0,1,0,2,1,0,1,3,2,
  2. 学习实例.文章管理.数据库操作类.DBUtil.java
  3. 云痕大数据考试中途可以退出吗_2020CPA考试出考率,创新低?
  4. 我们能用 lua 做什么
  5. git 添加公钥的命令
  6. iOS上应用Static Framework
  7. js JavaScript实战练习——小球碰撞反弹(详细)
  8. lmdb数据库的读取与转换(一) —— 基本操作
  9. 【吐血整理】Python 常用模块(二):json 模块
  10. 计算机黑屏时间,电脑开机黑屏时间长怎么办?Win10开机黑屏时间很久的解决方法...
  11. eact Native开发IDE安装及配置
  12. Itext使用 Java导出PDF
  13. 香槐路的香槐花,匆匆四年无归期。
  14. 序列到序列模型(一)(基本模型,RNN Search,注意力机制)
  15. ndnSIM学习(八)——examples之ndn-simple.cpp每个函数逐行剖析
  16. css动画和js动画_CSS与JS动画:哪个更快?
  17. 笔记本无线网卡失效(红叉)故障排除
  18. JavaWeb防止表单重复提交
  19. 通过ua区分QQ内置浏览器与QQ浏览器
  20. Ripro子主题Eeesucai-child集成后台美化包源码QIW

热门文章

  1. 传统的 8 小时工作制为什么会效率低下?
  2. 启动eclipse出现“A Java Runtime Environment (JRE) or Java Development Kit (JDK)must be available”错误处理
  3. android 副mic测试,如何检测Android中是否存在麦克风?
  4. E: The repository ‘http://extras.ubuntu.com/ubuntu xenial Release‘ does not have a Release file.
  5. python xlwings Excel 内容截图
  6. 商城系统搭建:三方平台入驻与独立部署优缺点对比
  7. 纯css绘制的疲惫表情包
  8. java第三十一天---mysql习题
  9. 2023年IT行业就业前景分析,准职场人必看!
  10. 默默无闻七年 最终成就一个优秀的IT人