Linux驱动分析之SPI驱动架构

简介: Linux驱动分析之SPI驱动架构

 SPI体系结构

主要由三部分组成:

(1) SPI核心

(2) SPI控制器驱动

(3) SPI设备驱动

基本和I2C的架构差不多

重要结构体

内核版本:3.7.6

    • spi_master
    //SPI控制器structspi_master {
    structdevicedev;
    structlist_headlist; //控制器链表//控制器对应的SPI总线号 SPI-2 对应bus_num= 2s16bus_num;
    u16num_chipselect;//控制器支持的片选数量,即能支持多少个spi设备 u16dma_alignment;//DMA缓冲区对齐方式u16mode_bits;// mode标志/* other constraints relevant to this driver */u16flags;
    #define SPI_MASTER_HALF_DUPLEX  BIT(0)  /* can't do full duplex */#define SPI_MASTER_NO_RX  BIT(1)    /* can't do buffer read */#define SPI_MASTER_NO_TX  BIT(2)    /* can't do buffer write */// 并发同步时使用spinlock_tbus_lock_spinlock;
    structmutexbus_lock_mutex;
    /* flag indicating that the SPI bus is locked for exclusive use */boolbus_lock_flag;
    //设置SPI mode和时钟, 在spi_add_device中调用int      (*setup)(structspi_device*spi);
    //传输数据函数, 实现数据的双向传输int      (*transfer)(structspi_device*spi,
    structspi_message*mesg);
    //注销时回调void      (*cleanup)(structspi_device*spi);
    /** These hooks are for drivers that want to use the generic* master transfer queueing mechanism. If these are used, the* transfer() function above must NOT be specified by the driver.* Over time we expect SPI drivers to be phased over to this API.*/boolqueued;
    structkthread_workerkworker;
    structtask_struct*kworker_task;
    structkthread_workpump_messages;
    spinlock_tqueue_lock;
    structlist_headqueue;
    structspi_message*cur_msg;
    boolbusy;
    boolrunning;
    boolrt;
    int (*prepare_transfer_hardware)(structspi_master*master);
    int (*transfer_one_message)(structspi_master*master,
    structspi_message*mesg);
    int (*unprepare_transfer_hardware)(structspi_master*master);
    }

    image.gif

      • spi_driver
      //SPI驱动,和platform_driver,i2c_driver类似structspi_driver {
      conststructspi_device_id*id_table;
      int  (*probe)(structspi_device*spi);
      int  (*remove)(structspi_device*spi);
      void  (*shutdown)(structspi_device*spi);
      int  (*suspend)(structspi_device*spi, pm_message_tmesg);
      int  (*resume)(structspi_device*spi);
      structdevice_driverdriver;
      };

      image.gif

        • spi_device
        //SPI 设备structspi_device {
        structdevicedev;
        structspi_master*master; //指向SPI控制器u32max_speed_hz; //最大速率u8chip_select; //片选u8mode; //SPI设备模式,使用下面的宏#define  SPI_CPHA  0x01      /* clock phase */#define  SPI_CPOL  0x02      /* clock polarity */#define  SPI_MODE_0  (0|0)      /* (original MicroWire) */#define  SPI_MODE_1  (0|SPI_CPHA)#define  SPI_MODE_2  (SPI_CPOL|0)#define  SPI_MODE_3  (SPI_CPOL|SPI_CPHA)#define  SPI_CS_HIGH  0x04      /* chipselect active high? */#define  SPI_LSB_FIRST  0x08      /* per-word bits-on-wire */#define  SPI_3WIRE  0x10      /* SI/SO signals shared */#define  SPI_LOOP  0x20      /* loopback mode */#define  SPI_NO_CS  0x40      /* 1 dev/bus, no chipselect */#define  SPI_READY  0x80      /* slave pulls low to pause */u8bits_per_word;
        intirq;
        void*controller_state; //控制器运行状态void*controller_data; //特定板子为控制器定义的数据charmodalias[SPI_NAME_SIZE];
        };

        image.gif

          • spi_message
          //SPI传输数据结构体structspi_message {
          structlist_headtransfers; // spi_transfer链表头structspi_device*spi; //spi设备unsignedis_dma_mapped:1;
          //发送完成回调void      (*complete)(void*context);
          void*context;
          unsignedactual_length;
          intstatus;
          /* for optional use by whatever driver currently owns the* spi_message ...  between calls to spi_async and then later* complete(), that's the spi_master controller driver.*/structlist_headqueue;
          void*state;
          };

          image.gif

            • spi_transfer
            // 该结构体是spi_message下的子单元,structspi_transfer {
            constvoid*tx_buf;// 发送的数据缓存区void*rx_buf;// 接收的数据缓存区unsignedlen;
            dma_addr_ttx_dma; //tx_buf的DMA地址dma_addr_trx_dma; //rx_buf的DMA地址unsignedcs_change:1;
            u8bits_per_word;
            u16delay_usecs;
            u32speed_hz;
            structlist_headtransfer_list;
            };

            image.gif

            总结上面结构体关系:

            1. spi_driver和spi_device

            spi_driver对应一套驱动方法,包含probe,remove等方法。spi_device对应真实的物理设备,每个spi设备都需要一个spi_device来描述。spi_driver与spi_device是一对多的关系,一个spi_driver上可以支持多个同类型的spi_device。


            2. spi_master和spi_device

            spi_master 与 spi_device 的关系和硬件上控制器与设备的关系一致,即spi_device依附于spi_master。


            3. spi_message和spi_transfer

            spi传输数据是以 spi_message 为单位的,我们需要传输的内容在 spi_transfer 中。spi_transfer是spi_message的子单元。

            1 . 将本次需要传输的 spi_transfer 以 spi_transfer->transfer_list 为链表项,连接成一个transfer_list链表,挂接在本次传输的spi_message spi_message->transfers链表下。

            2 . 将所有等待传输的 spi_message 以 spi_message->queue 为链表项,连接成个链表挂接在queue下。

            image.gif


            API函数

            //分配一个spi_masterstructspi_master*spi_alloc_master(structdevice*dev, unsignedsize)
            //注册和注销spi_masterintspi_register_master(structspi_master*master)
            voidspi_unregister_master(structspi_master*master)
            //注册和注销spi_driverintspi_register_driver(structspi_driver*sdrv)
            voidspi_unregister_driver(structspi_driver*sdrv)
            //初始化spi_messagevoidspi_message_init(structspi_message*m)
            //向spi_message添加transfersvoidspi_message_add_tail(structspi_transfer*t, structspi_message*m)
            //异步发送spi_messageintspi_async(structspi_device*spi, structspi_message*message)
            //同步发送spi_messageintspi_sync(structspi_device*spi, structspi_message*message)
            //spi同步写(封装了上面的函数)intspi_write(structspi_device*spi, constvoid*buf, size_tlen)
            //spi同步读(封装了上面的函数)intspi_read(structspi_device*spi, void*buf, size_tlen)
            //同步写并读取(封装了上面的函数)intspi_write_then_read(structspi_device*spi,
            constvoid*txbuf, unsignedn_tx,
            void*rxbuf, unsignedn_rx)

            image.gif

               使用spi_async()需要注意的是,在complete未返回前不要轻易访问你一提交的spi_transfer中的buffer。也不能释放SPI系统正在使用的buffer。一旦你的complete返回了,这些buffer就又是你的了。

               spi_sync是同步的,spi_sync提交完spi_message后不会立即返回,会一直等待其被处理。一旦返回就可以重新使用buffer了。spi_sync()调用了spi_async(),并休眠直至complete返回。

               上面的传输函数最终都是调用spi_master的transfer()函数。


            总结

               SPI的架构和之前的I2C的结构基本差不多,我们会发现其实驱动中大量的结构体都是对参数和数据的封装。站在宏观的角度看,就是填充结构体,调用函数注册或发送。

               上面是对Linux中SPI相关架构的分析,后面依然会拿出一些相对应的驱动来进行具体分析。希望能做到理论和实践相结合!


            相关文章
            |
            2月前
            |
            安全 数据处理 数据安全/隐私保护
            C/S架构与B/S架构的适用场景分析
            C/S架构(客户端/服务器架构)与B/S架构(浏览器/服务器架构)在适用场景上各有特点,主要取决于应用的具体需求、用户群体、系统维护成本、跨平台需求等因素。
            199 6
            |
            6天前
            |
            存储 SQL Apache
            Apache Doris 开源最顶级基于MPP架构的高性能实时分析数据库
            Apache Doris 是一个基于 MPP 架构的高性能实时分析数据库,以其极高的速度和易用性著称。它支持高并发点查询和复杂分析场景,适用于报表分析、即席查询、数据仓库和数据湖查询加速等。最新发布的 2.0.2 版本在性能、稳定性和多租户支持方面有显著提升。社区活跃,已广泛应用于电商、广告、用户行为分析等领域。
            Apache Doris 开源最顶级基于MPP架构的高性能实时分析数据库
            |
            7天前
            |
            运维 NoSQL Java
            后端架构演进:微服务架构的优缺点与实战案例分析
            【10月更文挑战第28天】本文探讨了微服务架构与单体架构的优缺点,并通过实战案例分析了微服务架构在实际应用中的表现。微服务架构具有高内聚、低耦合、独立部署等优势,但也面临分布式系统的复杂性和较高的运维成本。通过某电商平台的实际案例,展示了微服务架构在提升系统性能和团队协作效率方面的显著效果,同时也指出了其带来的挑战。
            43 4
            |
            16天前
            |
            消息中间件 监控 NoSQL
            驱动系统架构
            【10月更文挑战第29天】
            21 2
            |
            26天前
            |
            存储 SQL 分布式计算
            湖仓一体架构深度解析:构建企业级数据管理与分析的新基石
            【10月更文挑战第7天】湖仓一体架构深度解析:构建企业级数据管理与分析的新基石
            41 1
            |
            1月前
            |
            存储 前端开发 API
            DDD领域驱动设计实战-分层架构
            DDD分层架构通过明确各层职责及交互规则,有效降低了层间依赖。其基本原则是每层仅与下方层耦合,分为严格和松散两种形式。架构演进包括传统四层架构与改良版四层架构,后者采用依赖反转设计原则优化基础设施层位置。各层职责分明:用户接口层处理显示与请求;应用层负责服务编排与组合;领域层实现业务逻辑;基础层提供技术基础服务。通过合理设计聚合与依赖关系,DDD支持微服务架构灵活演进,提升系统适应性和可维护性。
            |
            2月前
            |
            存储 监控 安全
            SaaS业务架构:业务能力分析
            【9月更文挑战第20天】在数字化时代,软件即服务(SaaS)模式逐渐成为企业软件解决方案的首选。SaaS 业务架构设计对于提供高效、可靠的服务至关重要。其核心业务能力包括:用户管理(注册登录、角色权限)、数据管理(存储备份、安全共享)、业务流程管理(设计定制、工作流自动化)、应用集成(第三方应用、移动应用)及客户服务(支持培训、反馈改进)。通过优化这些能力,可为企业提供更高效、可靠的 SaaS 服务。
            54 11
            |
            2月前
            |
            缓存 负载均衡 数据管理
            深入探索微服务架构的核心要素与实践策略在当今软件开发领域,微服务架构以其独特的优势和灵活性,已成为众多企业和开发者的首选。本文将深入探讨微服务架构的核心要素,包括服务拆分、通信机制、数据管理等,并结合实际案例分析其在不同场景下的应用策略,旨在为读者提供一套全面、深入的微服务架构实践指南。**
            **微服务架构作为软件开发领域的热门话题,正引领着一场技术革新。本文从微服务架构的核心要素出发,详细阐述了服务拆分的原则与方法、通信机制的选择与优化、数据管理的策略与挑战等内容。同时,结合具体案例,分析了微服务架构在不同场景下的应用策略,为读者提供了实用的指导和建议。
            |
            2月前
            |
            Linux API
            Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
            Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
            |
            3月前
            |
            前端开发 大数据 数据库
            🔥大数据洪流下的决战:JSF 表格组件如何做到毫秒级响应?揭秘背后的性能魔法!💪
            【8月更文挑战第31天】在 Web 应用中,表格组件常用于展示和操作数据,但在大数据量下性能会成瓶颈。本文介绍在 JavaServer Faces(JSF)中优化表格组件的方法,包括数据处理、分页及懒加载等技术。通过后端分页或懒加载按需加载数据,减少不必要的数据加载和优化数据库查询,并利用缓存机制减少数据库访问次数,从而提高表格组件的响应速度和整体性能。掌握这些最佳实践对开发高性能 JSF 应用至关重要。
            65 0