linux中spi驱动框架

2016年09月14日 15:57:06 andylauren 阅读数:403

                                                  <span class="tags-box artic-tag-box"><span class="label">标签:</span><a data-track-click="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;con&quot;:&quot;linux&quot;}" class="tag-link" href="http://so.csdn.net/so/search/s.do?q=linux&amp;t=blog" target="_blank">linux                                                             </a><a data-track-click="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;con&quot;:&quot;spi驱动&quot;}" class="tag-link" href="http://so.csdn.net/so/search/s.do?q=spi驱动&amp;t=blog" target="_blank">spi驱动                                                             </a><span class="article_info_click">更多</span></span><div class="tags-box space"><span class="label">个人分类:</span><a class="tag-link" href="https://blog.csdn.net/andylauren/article/category/6289579" target="_blank">嵌入式系统驱动                                                              </a></div></div><div class="operating"></div></div></div>
</div>
<article><div id="article_content" class="article_content clearfix csdn-tracking-statistics" data-pid="blog" data-mod="popu_307" data-dsm="post" style="height: 996px; overflow: hidden;"><link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-bb1edad192.css"><div class="htmledit_views">

linux下的SPI总线驱动在driver/spi目录中。

SPI驱动分为三层

SPI核心层  drivers/spi/spi.c 与平台无关

SPI控制器驱动层

SPI设备驱动层

每层的主要结构体和函数

SPI控制器驱动层(include/linux/spi/spi.h)

struct spi_master {struct device dev;s16 bus_num;//控制器对应的SPI总线号u16 num_chipselect;//支持片选数量int (* setup) (struct spi_device *spi);//SPI模式设备,在spi_add_device中调用int (* transfer) (struct spi_device *spi,struct spi_message *mesg);//读写方法的函数,可能会睡眠void (* cleanup) (struct spi_device *spi);//注销时候调用
};  

SPI设备驱动层

spi_device对应某个特定的slave
struct spi_driver {int (* probe) (struct spi_device *spi);//匹配时调用,完成spi_transfer,spi_message,spi_message_init,spi_meassage_add_tail,spi_sync,spi_write_then_read的调用int (* remove) (struct spi_device *spi);void (* shutdown) (struct spi_device *spi);int (* suspend) (struct spi_device *spi, pm_message_t mesg);int (* resume) (struct spi_device *spi);struct device_driver driver;
};
struct spi_device {struct device dev;struct spi_master * master;u32 max_speed_hz;u8 chip_select;u8 mode;
#define SPI_CPHA    0x01
#define SPI_CPOL    0x02
#define SPI_MODE_0  (0|0)
#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
#define SPI_LSB_FIRST   0x08
#define SPI_3WIRE   0x10
#define SPI_LOOP    0x20u8 bits_per_word;int irq;void * controller_state;void * controller_data;const char * modalias;
};  
struct spi_transfer {const void * tx_buf;void * rx_buf;unsigned len;dma_addr_t tx_dma;dma_addr_t rx_dma;unsigned cs_change:1;u8 bits_per_word;u16 delay_usecs;u32 speed_hz;struct list_head transfer_list;
}; 
int spi_register_driver (    struct spi_driver *     sdrv);
struct spi_message {struct list_head transfers;struct spi_device * spi;unsigned is_dma_mapped:1;void (* complete) (void *context);void * context;unsigned actual_length;int status;struct list_head queue;void * state;
};  

在每次使用spi_message可以使用函数:
void spi_message_init(structspi_message *m);
来初始化。
向spi_message添加transfers可以使用spi_message_add_tail()函数:
void spi_message_add_tail(structspi_transfer *t, struct spi_message *m);
一旦你准备好了spi_message,就可以使用spi_async()来向SPI系统提交了:
int spi_async(struct spi_device *spi,struct spi_message *message);
因为是异步的,一提交就立马返回了,这也就是说需要同步机制(complete就是了)。他确保不会睡眠,可安全的在中断handler或其他不可休眠的代码中调用。稍后会念念他的好的。
使用spi_async()需要注意的是,在complete()未返回前不要轻易访问你一提交的spi_transfer中的buffer。也不能释放SPI系统正在使用的buffer。一旦你的complete返回了,这些buffer就又是你的了。
使用完成回调机制稍显复杂,可以使用SPI系统提供的另一个同步版本:spi_sync():
int spi_sync(struct spi_device *spi,struct spi_message *message);
因为是同步的,spi_sync提交完spi_message后不会立即返回,会一直等待其被处理。一旦返回就可以重新使用buffer了。spi_sync()在drivers/spi/spi.c中实现,其调用了spi_async(),并休眠直至complete返回。

spi_device的板信息用spi_board_info来描述,在init函数调用时会初始化。

struct spi_board_info {char modalias[KOBJ_NAME_LEN];const void * platform_data;void * controller_data;int irq;u32 max_speed_hz;u16 bus_num;u16 chip_select;u8 mode;
};  
int __init spi_register_board_info ( struct spi_board_info const *   info,unsigned   n);

会把spi_board_info注册到链表board_list上。

之后,spi_master注册会调用scan_board_info扫描board_list找到挂接在它上面的spi设备。

然后创建并注册spi_device.

一个结构体spi_board_info对应着一个SPI设备spi_device

struct boardinfo{struct list_head list;struct spi_board_info board_info;
}
static LIST_HEAD(board_list);
static LIST_HEAD(spi_master_list);//初始化一个空链表

#define LIST_HEAD(name)

struct list_head name=LIST_HEAD_INIT(name)

#define LIST_HEAD_INIT(name)  {&(name),&(name)}

struct list_head {struct list_head* next,*prev;};

struct device_driver结构体被定义在/include/linux/device.h,原型是:

struct device_driver {const char        *name;struct bus_type        *bus;
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">module</span>        *<span class="hljs-title">owner</span>;</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>        *mod_name;    <span class="hljs-comment">/* used for built-in modules */</span><span class="hljs-keyword">bool</span> suppress_bind_attrs;    <span class="hljs-comment">/* disables bind/unbind via sysfs */</span><span class="hljs-keyword">int</span> (*probe) (struct device *dev);
<span class="hljs-keyword">int</span> (*remove) (struct device *dev);
<span class="hljs-keyword">void</span> (*shutdown) (struct device *dev);
<span class="hljs-keyword">int</span> (*suspend) (struct device *dev, <span class="hljs-keyword">pm_message_t</span> state);
<span class="hljs-keyword">int</span> (*resume) (struct device *dev);
<span class="hljs-keyword">const</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">attribute_group</span> **<span class="hljs-title">groups</span>;</span><span class="hljs-keyword">const</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">dev_pm_ops</span> *<span class="hljs-title">pm</span>;</span><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">driver_private</span> *<span class="hljs-title">p</span>;</span>

};

举例SPI驱动

spi_device设备

spi_board_info

init入口调用,spi_register_board_info(S3C_SPI_devs,ARRAY_SIZE(S3C_SPI_devs));

会把spi_board_info注册到board_list链表上。

之后会创建并注册spi_device

spi_driver驱动

1、声明并设置spi_driver结构体

2、注册spi_register_driver(&spi_driver);

3、实现probe操作,spi_transfer,spi_message的构建

spi_message_init,spi_message_add_tail,spi_sync调用

3.1、定义并设置 spi_transfer结构体

3.2、定义spi_message结构体

3.3、初始化meg,spi_message_init(&meg);

3.4、将st放入message队列spi_message_add_tail(&st,&meg);

3.5、将message与spi_device关联,发送meg,spi_sync(spi_device,&meg);

linux中spi驱动框架相关推荐

  1. imx6 通过移植XRM117x(SPI转串口)对Linux中的SPI驱动框架进行分析

    最近分析了一下Linux 中的SPI驱动框架,将自己的理解总结一下,不足之处还请斧正! 1.SPI通信基础知识 SPI(Serial Peripheral Interface)是一种串行(一次发送1b ...

  2. 转载:Linux kernel SPI驱动解释

    From: http://www.cnblogs.com/liugf05/archive/2012/12/03/2800457.html 下面有两个大的模块: 一个是SPI总线驱动的分析        ...

  3. Linux驱动修炼之道-SPI驱动框架源码分析(上)

    Linux驱动修炼之道-SPI驱动框架源码分析(上)   SPI协议是一种同步的串行数据连接标准,由摩托罗拉公司命名,可工作于全双工模式.相关通讯设备可工作于m/s模式.主设备发起数据帧,允许多个从设 ...

  4. Linux SPI驱动框架(2)——控制器驱动层

    SPI控制器驱动层   上节中,讲了SPI核心层的东西,这一部分,以全志平台SPI控制器驱动为例,对SPI控制器驱动进行说明. SPI控制器驱动,即SPI硬件控制器对应的驱动,核心部分需要实现硬件SP ...

  5. Linux SPI驱动框架(3)——设备驱动层

    SPI设备驱动层   Linux SPI驱动框架(1)和(2)中分别介绍了SPI框架中核心层,和控制器驱动层.其实实际开发过程中,不是IC原厂工程师比较少会接触控制器驱动层,设备驱动层才是接触比较多的 ...

  6. i.MX6ULL驱动开发 | 13 - Linux SPI 驱动框架

    Linux SPI 驱动框架分为两部分: SPI总线控制器驱动:SOC的 SPI 控制器外设驱动 SPI设备驱动:基于SPI总线控制器驱动编写,针对具体的SPI从机设备 一.SPI总线控制器驱动 基于 ...

  7. Linux SPI驱动框架(1)——核心层

    概述   linux SPI驱动框架主要分为核心层,控制器驱动层以及设备驱动层.具体结构可参考下图   图中,最下层是硬件空间,SPI总线控制器,总线控制器负责硬件上的数据交互.内核空间中,需要有对应 ...

  8. SPI驱动框架源码分析

     SPI驱动框架源码分析 2013-04-12 16:13:08 分类: LINUX SPI驱动框架源码分析 SPI协议是一种同步的串行数据连接标准,由摩托罗拉公司命名,可工作于全双工模式.相关通讯设 ...

  9. windows linux 融合,Windows和Linux的设备驱动框架的对比融合研究

    摘要:把驱动框架分为三层,针对各层在Windows和Linux中的实现方法的不同,对Windows和Linux的设备驱动框架进行对比研究.从接口函数,应用程序访问驱动程序的路径,驱动程序具体实现及安装 ...

最新文章

  1. TCP/IP详解--第十五章
  2. 数据库表设计、 数据库分层、myslq水平拆分、oracle表分区
  3. JAVA程序中 + 号的使用
  4. .net动态控件的使用(listview ,treeview,tabControl)
  5. js怎么图表在html中显示,使用Charts.js在HTML5中创建图表
  6. 1024 许个愿吧,万一实现了呢?
  7. php代码 intval( ),php intval的测试代码发现问题_PHP教程
  8. Unity3D方向键控制人物移动的代码
  9. 从嵌入式系统到无线模组 周立功单片机欲站在物联网的风口
  10. 计算字符串相似度算法——Levenshtein
  11. GnomeSort 又是一个O(n2),不过,只用一次循环……
  12. qdu yzm10与大富翁的故事 (01背包+输出路径)
  13. 2022必看花展 IFEX昆明国际花卉园艺展,新展期11月11-13日
  14. 共享租赁汽车,必将重新设计中国汽车产业链游戏规则
  15. “完数”问题 求1000以内的完数
  16. sql语句查询某字段中包含某值(模糊查找)
  17. 计算机病毒语音,新病毒:让被感染的计算机发出语音提醒
  18. 无线交换机故障分析排查
  19. JMeter测试文档
  20. 【流式细胞仪软件】上海道宁为您带来FCS Express,让您轻松缩小流式细胞术和结果之间的差距

热门文章

  1. win7的aero特效无法启动的处理方法
  2. 【立哥】【每日一个小知识】铁扇公主和太上老君到底是什么关系?
  3. Qt 2D绘图(5):绘制图像基础
  4. uniapp 九宫格抽奖
  5. Windows CE6.0官方安装步骤、安装方法
  6. adobe acrobat pro dc 无法打开PDF_怎么把pdf转成PPT?PDF转PPT免费方法大分享!
  7. 如何突破工业品生意的困境?
  8. php如何删除数组中的空元素,php - 删除空数组元素
  9. asp.net设置301跳转
  10. 计算机最新技术ppt,计算机新技术学术讲座.ppt