当前位置: 首页 > news >正文

网站建设的公司合肥顺德品牌网站建设价位

网站建设的公司合肥,顺德品牌网站建设价位,视频类网站怎么做,安装安全狗网站打不开前言 Linux的spi接口驱动实现目录在kernel\drivers\spi下。这个目录和一些层次比较明显的驱动目录布局不同#xff0c;全放在这个文件夹下#xff0c;因此还是只好通过看Kconfig 和 Makefile来找找思路 先看Makefile#xff0c;里面关键几行#xff1a; obj-$(CONFIG_SPI…前言 Linux的spi接口驱动实现目录在kernel\drivers\spi下。这个目录和一些层次比较明显的驱动目录布局不同全放在这个文件夹下因此还是只好通过看Kconfig 和 Makefile来找找思路 先看Makefile里面关键几行 obj-$(CONFIG_SPI_MASTER) spi.o //这个是针对有spi控制器的soc选项一般的soc都有spi控制器吧。 # SPI master controller drivers (bus) //下面的这些就是针对不同soc上的spi控制器的驱动了我们可以通过make menuconfig的时候选上自己对应平台的 # SPI master controller drivers (bus) obj-$(CONFIG_SPI_ALTERA) spi-altera.o obj-$(CONFIG_SPI_ARMADA_3700) spi-armada-3700.o ............ obj-$(CONFIG_SPI_AXI_SPI_ENGINE) spi-axi-spi-engine.o下面这些就是针对于主机作为spi从设备的时候用的暂时貌似没支持毕竟现实中几乎没有用过而是作为master端出现 # SPI slave protocol handlers obj-$(CONFIG_SPI_SLAVE_TIME) spi-slave-time.o obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL) spi-slave-system-control.o再看Kconfig第一个SPI选项我觉得有必要贴一下首先只有选择它了才能进行后面的配置其次它的help对spi的描述说的很清楚 # # SPI driver configuration # menuconfig SPIbool SPI supportdepends on HAS_IOMEMhelpThe Serial Peripheral Interface is a low level synchronousprotocol. Chips that support SPI can have data transfer ratesup to several tens of Mbit/sec. Chips are addressed with acontroller and a chipselect. Most SPI slaves dont supportdynamic device discovery; some are even write-only or read-only.SPI is widely used by microcontrollers to talk with sensors,eeprom and flash memory, codecs and various other controllerchips, analog to digital (and d-to-a) converters, and more.MMC and SD cards can be accessed using SPI protocol; and forDataFlash cards used in MMC sockets, SPI must always be used.SPI is one of a family of similar protocols using a four wireinterface (select, clock, data in, data out) including Microwire(half duplex), SSP, SSI, and PSP. This driver framework shouldwork with most such devices and controllers.我们其次需要配上的选项就是SPI_MASTER和CONFIG_SPI_ROCKCHIP我手上的是RK的SDK。 config SPI_MASTER # bool SPI Master Supportbooldefault SPIhelpIf your system has an master-capable SPI controller (whichprovides the clock and chipselect), you can enable thatcontroller and the protocol drivers for the SPI slave chipsthat are connected.config SPI_ROCKCHIPtristate Rockchip SPI controller driverhelpThis selects a driver for Rockchip SPI controller.If you say yes to this option, support will be included forRK3066, RK3188 and RK3288 families of SPI controller.Rockchip SPI controller support DMA transport and PIO mode.The main usecase of this controller is to use spi flash as bootdevice.于是从Makefile里得到如下语句和我们相关 obj-$(CONFIG_SPI_ROCKCHIP) spi-rockchip.o于是我们要分析的代码主要有spi.c spi-rockchip.c瞬间没压力了就两个文件呵呵 下面主要从三个方面来分析spi框架 spi控制器驱动的实现毕竟spi控制器的驱动还是有可能要接触的spi设备的驱动我们更多的是编写设备的驱动还是以eeprom为例吧虽然我很想以spi接口的nor flash驱动为例但是那又会牵涉出mtd子系统这个留在mtd子系统分析吧spi核心层的实现上面1、2都是以各自的驱动实现为目标并不深入到spi核心层也就是至于spi核心层怎么为我们提供的服务不去关心只需要按spi核心层使用它提供的服务就是了。所以现在统一分析spi核心层看它是怎么提供的服务 spi控制器驱动的实现 以spi-rockchip.c为例直接看module_platform_driver static struct platform_driver rockchip_spi_driver {.driver {.name DRIVER_NAME,.pm rockchip_spi_pm,.of_match_table of_match_ptr(rockchip_spi_dt_match),},.probe rockchip_spi_probe,.remove rockchip_spi_remove, };平台驱动的内部流程就不分析了直接看匹配成功后rockchip_spi_probe的调用但这里还是插入平台spi控制器设备端相关的代码 使用spi_alloc_master函数为平台设备pdev分配一个SPI主设备结构体并将其大小设置为sizeof(struct rockchip_spi)。这个函数会分配内存并初始化主设备结构体的各个字段。调用platform_set_drvdata函数将主设备结构体指针保存在平台设备的私有数据中以便后续在驱动的其他函数中可以访问该指针。使用spi_master_get_devdata函数获取之前保存在私有数据中的主设备结构体指针rs。 master spi_alloc_master(pdev-dev, sizeof(struct rockchip_spi));if (!master)return -ENOMEM;platform_set_drvdata(pdev, master);rs spi_master_get_devdata(master);使用platform_get_resource函数获取SPI控制器的IO资源。这些资源包括寄存器地址、中断号等信息向操作系统请求资源空间并建立起映射为以后所用。 mem platform_get_resource(pdev, IORESOURCE_MEM, 0);rs-regs devm_ioremap_resource(pdev-dev, mem);if (IS_ERR(rs-regs)) {ret PTR_ERR(rs-regs);goto err_ioremap_resource;}使用devm_clk_get函数获取SPI控制器所需的时钟包括apb_pclk和spiclk。这些时钟用于控制SPI控制器的时序和传输速率。 rs-apb_pclk devm_clk_get(pdev-dev, apb_pclk);if (IS_ERR(rs-apb_pclk)) {dev_err(pdev-dev, Failed to get apb_pclk\n);ret PTR_ERR(rs-apb_pclk);goto err_ioremap_resource;}rs-spiclk devm_clk_get(pdev-dev, spiclk);if (IS_ERR(rs-spiclk)) {dev_err(pdev-dev, Failed to get spi_pclk\n);ret PTR_ERR(rs-spiclk);goto err_ioremap_resource;}使用clk_prepare_enable函数使获取到的时钟生效确保SPI控制器可以正常工作。 ret clk_prepare_enable(rs-apb_pclk);if (ret) {dev_err(pdev-dev, Failed to enable apb_pclk\n);goto err_ioremap_resource;}ret clk_prepare_enable(rs-spiclk);if (ret) {dev_err(pdev-dev, Failed to enable spi_clk\n);goto err_spiclk_enable;}调用spi_enable_chip函数使SPI芯片处于可用状态。这个函数会执行一些特定的SPI控制器寄存器的配置以便使芯片可以正常通信。设置SPI主设备的属性。这些属性包括SPI总线类型、主设备指针、设备指针、最大频率等。 spi_enable_chip(rs, 0);rs-type SSI_MOTO_SPI;rs-master master;rs-dev pdev-dev;rs-max_freq clk_get_rate(rs-spiclk);使用of_property_read_u32函数从设备节点中读取属性值。在这个例子中它读取了rx-sample-delay-ns属性并将其存储在rsd_nsecs变量中。调用get_fifo_len函数获取FIFO的长度。FIFO用于在SPI传输过程中暂存数据。 if (!of_property_read_u32(pdev-dev.of_node, rx-sample-delay-ns,rsd_nsecs))rs-rsd_nsecs rsd_nsecs;rs-fifo_len get_fifo_len(rs); if (!rs-fifo_len) {dev_err(pdev-dev, Failed to get fifo length\n);ret -EINVAL;goto err_get_fifo_len; }初始化自旋锁。自旋锁用于保护共享资源防止多个进程同时访问造成冲突。设置设备的运行时PM状态为活动并启用运行时PM。允许系统在不需要SPI设备时将其置于低功耗状态。 spin_lock_init(rs-lock);pm_runtime_set_active(pdev-dev); pm_runtime_enable(pdev-dev);设置主设备的一些属性例如自动运行时PM、总线号、模式位、芯片选择数量、设备节点等。同时设置主设备的回调函数。这些回调函数将在SPI传输中的不同阶段被调用以执行相应的操作 master-auto_runtime_pm true;master-bus_num pdev-id;master-mode_bits SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST;master-num_chipselect 2;master-dev.of_node pdev-dev.of_node;master-bits_per_word_mask SPI_BPW_MASK(16) | SPI_BPW_MASK(8);master-set_cs rockchip_spi_set_cs;master-prepare_message rockchip_spi_prepare_message;master-unprepare_message rockchip_spi_unprepare_message;master-transfer_one rockchip_spi_transfer_one;master-handle_err rockchip_spi_handle_err;使用dma_request_slave_channel函数请求DMA通道如果同时成功请求到了TX和RX的DMA通道则设置DMA传输的地址和方向并将相应的DMA通道设置为主设备的属性。 rs-dma_tx.ch dma_request_slave_channel(rs-dev, tx);if (IS_ERR_OR_NULL(rs-dma_tx.ch)) {/* Check tx to see if we need defer probing driver */if (PTR_ERR(rs-dma_tx.ch) -EPROBE_DEFER) {ret -EPROBE_DEFER;goto err_get_fifo_len;}dev_warn(rs-dev, Failed to request TX DMA channel\n);}rs-dma_rx.ch dma_request_slave_channel(rs-dev, rx);if (!rs-dma_rx.ch) {if (rs-dma_tx.ch) {dma_release_channel(rs-dma_tx.ch);rs-dma_tx.ch NULL;}dev_warn(rs-dev, Failed to request RX DMA channel\n);}使用pinctrl_lookup_state函数查找高速模式的引脚控制状态。检查查找高速模式的引脚控制状态是否成功。 rs-high_speed_state pinctrl_lookup_state(rs-dev-pins-p,high_speed);if (IS_ERR_OR_NULL(rs-high_speed_state)) {dev_warn(pdev-dev, no high_speed pinctrl state\n);rs-high_speed_state NULL;}使用devm_spi_register_master函数注册SPI主设备。 ret devm_spi_register_master(pdev-dev, master);if (ret) {dev_err(pdev-dev, Failed to register master\n);goto err_register_master;}暂时不进入到spi核心层分析这里我们只需要知道调用核心层的注册函数后核心层会遍历所有注册到核心层的设备实际最开始是加入到一个全局链表里和I2C核心层的实现类似然后尝试着添加每一个总线号为该控制器衍生出的总线号的设备到该spi控制器上当然如果该spi控制器不支持某一个设备那就取消添加这个设备如果添加成功那么该设备将会添加到spi总线上去这条总线是spi核心层注册的用来管理spi接口的设备和spi接口的驱动。 总结下probe函数的主要工作 分配和初始化SPI主设备结构体。获取并映射IO资源。获取和使能时钟。设置SPI主设备的属性和回调函数。请求并设置DMA通道。注册SPI主设备。 spi设备的驱动 以eeprom为例我们分析下文件at25.c 同样的driver的注册过程我们就不深入了解了其实就是一个总线设备驱动模型。我们直接看probe函数做了什么。 static const struct of_device_id at25_of_match[] {{ .compatible atmel,at25, },{ } }; MODULE_DEVICE_TABLE(of, at25_of_match);static struct spi_driver at25_driver {.driver {.name at25,.of_match_table at25_of_match,},.probe at25_probe,.remove at25_remove, };检查spi-dev.platform_data是否存在如果不存在则调用at25_fw_to_chip函数将固件信息转换为芯片描述并将其存储在chip结构体中。如果存在则直接将spi-dev.platform_data强制类型转换为spi_eeprom结构体并将其赋值给chip。 /* Chip description */if (!spi-dev.platform_data) {err at25_fw_to_chip(spi-dev, chip);if (err)return err;} elsechip *(struct spi_eeprom *)spi-dev.platform_data;根据chip结构体中的标志位判断EEPROM的地址长度是8位、16位还是24位并将相应的值赋给addrlen变量。 /* For now we only support 8/16/24 bit addressing */if (chip.flags EE_ADDR1)addrlen 1;else if (chip.flags EE_ADDR2)addrlen 2;else if (chip.flags EE_ADDR3)addrlen 3;else {dev_dbg(spi-dev, unsupported address type\n);return -EINVAL;}通过发送AT25_RDSR指令读取EEPROM的状态寄存器。如果读取失败或状态寄存器中的AT25_SR_nRDY位为1表示EEPROM不可用返回错误码-ENXIO。 /* Ping the chip ... the status register is pretty portable,* unlike probing manufacturer IDs. We do expect that system* firmware didnt write it in the past few milliseconds!*/sr spi_w8r8(spi, AT25_RDSR);if (sr 0 || sr AT25_SR_nRDY) {dev_dbg(spi-dev, rdsr -- %d (%02x)\n, sr, sr);return -ENXIO;}使用devm_kzalloc函数为at25_data结构体分配内存并使用GFP_KERNEL标志指定内存分配的上下文。初始化互斥锁at25-lock用于保护共享资源的访问。将chip结构体和spi设备保存在at25_data结构体中。使用spi_set_drvdata函数将at25_data结构体指针存储在spi设备的私有数据中以便在后续的函数中可以方便地访问。将地址长度addrlen保存在at25_data结构体的addrlen字段中。 at25 devm_kzalloc(spi-dev, sizeof(struct at25_data), GFP_KERNEL);if (!at25)return -ENOMEM;mutex_init(at25-lock);at25-chip chip;at25-spi spi_dev_get(spi);spi_set_drvdata(spi, at25);at25-addrlen addrlen;创建应用层用来操作的文件使用sysfs_bin_attr_init函数初始化at25-bin成员变量其中at25-bin是struct bin_attribute类型的变量。设置at25-bin的属性名称为eeprom访问权限为用户只读模式S_IRUSR。设置at25-bin的读回调函数为at25_bin_read写回调函数为at25_bin_write。 sysfs_bin_attr_init(at25-bin);at25-bin.attr.name eeprom;at25-bin.attr.mode S_IRUSR;at25-bin.read at25_bin_read;at25-mem.read at25_mem_read;根据chip的只读标志位EE_READONLY确定是否将写回调函数和写权限添加到at25-bin。 at25-bin.size at25-chip.byte_len;if (!(chip.flags EE_READONLY)) {at25-bin.write at25_bin_write;at25-bin.attr.mode | S_IWUSR;at25-mem.write at25_mem_write;}使用sysfs_create_bin_file函数将at25-bin添加到SPI设备的内核对象spi-dev.kobj中以便将EEPROM字节通过sysfs导出。 err sysfs_create_bin_file(spi-dev.kobj, at25-bin);if (err)return err;如果chip的setup字段不为空将调用chip.setup函数并将at25-mem和chip.context作为参数传递。使用dev_info函数打印一条设备信息消息包括EEPROM的大小、名称、是否只读以及页面大小。 if (chip.setup)chip.setup(at25-mem, chip.context);dev_info(spi-dev, %Zd %s %s eeprom%s, pagesize %u\n,(at25-bin.size 1024)? at25-bin.size: (at25-bin.size / 1024),(at25-bin.size 1024) ? Byte : KByte,at25-chip.name,(chip.flags EE_READONLY) ? (readonly) : ,at25-chip.page_size);该代码的功能是在SPI设备上探测并初始化一个EEPROM芯片然后将EEPROM的字节通过sysfs导出以便其他内核代码或用户空间程序可以方便地访问和操作EEPROM数据。 spi核心层的实现 主要看spi.c文件 static int __init spi_init(void) postcore_initcall(spi_init); 从这里可以知道spi_init的调用也就是spi核心层的初始化是在驱动加载前的。 调用kmalloc函数为SPI子系统分配一个大小为SPI_BUFSIZ的内核内存缓冲区并将返回的指针赋值给buf。 buf kmalloc(SPI_BUFSIZ, GFP_KERNEL); if (!buf) {status -ENOMEM;goto err0; }调用bus_register函数注册SPI总线类型将其添加到系统总线列表中。如果注册失败将status设置为返回的错误码并跳转到err1标签处进行错误处理。 status bus_register(spi_bus_type); if (status 0)goto err1;调用class_register函数注册SPI主控制器类将其添加到系统设备类列表中。如果注册失败将status设置为返回的错误码并跳转到err2标签处进行错误处理。 status class_register(spi_master_class); if (status 0)goto err2;所有注册到核心层的spi控制器都属于这个class。
http://www.sadfv.cn/news/116014/

相关文章:

  • 做图文网站要什么配置的服务器网站什么认证对做电商好
  • 公司网站改版需要怎么做企业网站建设感想
  • html5手机app网站模板wordpress里修改网页
  • wordpress+3d线条西安关键词seo
  • 网站内容建设评估简单的企业网站
  • 深圳 营销型网站公司知乎seo优化
  • 网站教程设计网站建站策划
  • 怎么做网站广告联盟全网网站推广
  • 美妆网站怎么做唐山门户网站建设
  • 在网站上怎么做招聘信息企业网站设计苏州
  • 苏州企业网站外链工具xg
  • 国内营销策划公司seo谷歌外贸推广
  • 游戏设计师网站有哪些网站开发语言有哪些
  • 建设校园标准信息服务网站论文推广线上渠道
  • 网站建设公司 深圳wordpress专题页面
  • 重庆企业服务建站网站开发建设网站时seo标题
  • 上海婚纱网站设计如何制作网站新手教程
  • 广告公司可以开网站建设费吗php网站开发和js
  • 工程建设标准下载网站为古汉字老人做网站
  • 做带支付平台的网站常用的h5制作工具有哪些
  • 游戏网站模商城网站布局
  • php不用框架怎么做网站wordpress媒体库格式
  • 杭州网站建设机构2021网络营销成功案例
  • 网站的设计流程有哪些步骤wordpress支持php7
  • 无极网络qq关键词排名优化
  • 各大网站官网的导航栏怎么做网站运营一般做那些分析
  • 怎么做公众号小程序广东搜索引擎优化
  • 设计类专业学什么南通做网站优化
  • 成都wap网站建设网站项目策划书内容模板
  • 高端企业网站建设好的公司wordpress 半天打不开