一:

SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void)。

1: static int __init spi_init(void) 2: { 3: int status; 4:   5: buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); /* 初始化缓存 */ 6: if (!buf) { 7: status = -ENOMEM; 8: goto err0; 9: } 10:   11: status = bus_register(&spi_bus_type); /* 注册spi总线,此步骤之后就会在/sys/bus目录下生成spi子目录 */ 12: if (status < 0) 13: goto err1; 14:   15: status = class_register(&spi_master_class);;/* 注册spi类,此步骤之后就会在/sys/class目录下生成spi_master子目录 */ 16: if (status < 0) 17: goto err2; 18: return 0; 19:   20: err2: 21: bus_unregister(&spi_bus_type); 22: err1: 23: kfree(buf); 24: buf = NULL; 25: err0: 26: return status; 27: }
1: struct bus_type spi_bus_type = { 2: .name = "spi", 3: .dev_attrs = spi_dev_attrs, 4: .match = spi_match_device, 5: .uevent = spi_uevent, 6: .pm = &spi_pm, 7: };

1: static struct class spi_master_class = { 2: .name = "spi_master", 3: .owner = THIS_MODULE, 4: .dev_release = spi_master_release, 5: };

 
 

1: postcore_initcall(spi_init); /* 注册 */

 

说明:
        1) 由postcore_initcall(spi_init);可以看出,此宏在系统初始化时是先于module_init()执行的。

2) 申请的buf空间用于在spi数据传输中。

3) 接下来是总线注册和类注册。

二:

此函数是半双工的形式写then读

1: int spi_write_then_read(struct spi_device *spi,
2: const void *txbuf, unsigned n_tx,
3: void *rxbuf, unsigned n_rx)
4: {
5: static DEFINE_MUTEX(lock);
6:  
7: int status;
8: struct spi_message message;
9: struct spi_transfer x[2];
10: u8 *local_buf;
11:  
12: /* Use preallocated DMA-safe buffer. We can't avoid copying here,
13: * (as a pure convenience thing), but we can keep heap costs
14: * out of the hot path ...
15: */
16: if ((n_tx + n_rx) > SPI_BUFSIZ)
17: return -EINVAL;
18:  
19: spi_message_init(&message);
20: memset(x, 0, sizeof x);
21: if (n_tx) {
22: x[0].len = n_tx;
23: spi_message_add_tail(&x[0], &message);
24: }
25: if (n_rx) {
26: x[1].len = n_rx;
27: spi_message_add_tail(&x[1], &message);
28: }
29:  
30: /* ... unless someone else is using the pre-allocated buffer */
31: if (!mutex_trylock(&lock)) {
32: local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
33: if (!local_buf)
34: return -ENOMEM;
35: } else
36: local_buf = buf;
37:  
38: memcpy(local_buf, txbuf, n_tx);
39: x[0].tx_buf = local_buf;
40: x[1].rx_buf = local_buf + n_tx;
41:  
42: /* do the i/o */
43: status = spi_sync(spi, &message);
44: if (status == 0)
45: memcpy(rxbuf, x[1].rx_buf, n_rx);
46:  
47: if (x[0].tx_buf == buf)
48: mutex_unlock(&lock);
49: else
50: kfree(local_buf);
51:  
52: return status;
53: }
 
1: 对master操作的加锁与解锁
2: int spi_bus_lock(struct spi_master *master)
3: {
4: unsigned long flags;
5:  
6: mutex_lock(&master->bus_lock_mutex);
7:  
8: spin_lock_irqsave(&master->bus_lock_spinlock, flags);
9: master->bus_lock_flag = 1;
10: spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
11:  
12: /* mutex remains locked until spi_bus_unlock is called */
13:  
14: return 0;
15: }
16: int spi_bus_unlock(struct spi_master *master)
17: {
18: master->bus_lock_flag = 0;
19:  
20: mutex_unlock(&master->bus_lock_mutex);
21:  
22: return 0;
23: }
 
同步数据交互
1: int spi_sync(struct spi_device *spi, struct spi_message *message) 2: { 3: return __spi_sync(spi, message, 0); 4: } 5: int spi_sync_locked(struct spi_device *spi, struct spi_message *message) 6: { 7: return __spi_sync(spi, message, 1); 8: }

 
 

异步数据交互
1: int spi_async(struct spi_device *spi, struct spi_message *message) 2: { 3: struct spi_master *master = spi->master; 4: int ret; 5: unsigned long flags; 6:   7: spin_lock_irqsave(&master->bus_lock_spinlock, flags); 8:   9: if (master->bus_lock_flag) 10: ret = -EBUSY; 11: else 12: ret = __spi_async(spi, message); 13:   14: spin_unlock_irqrestore(&master->bus_lock_spinlock, flags); 15:   16: return ret; 17: } 18:   19: int spi_async_locked(struct spi_device *spi, struct spi_message *message) 20: { 21: struct spi_master *master = spi->master; 22: int ret; 23: unsigned long flags; 24:   25: spin_lock_irqsave(&master->bus_lock_spinlock, flags); 26:   27: ret = __spi_async(spi, message); 28:   29: spin_unlock_irqrestore(&master->bus_lock_spinlock, flags); 30:   31: return ret; 32:   33: }

 
//创建master
1: struct spi_master *spi_alloc_master(struct device *dev, unsigned size) 2: { 3: struct spi_master *master; 4:   5: if (!dev) 6: return NULL; 7:   8: master = kzalloc(size + sizeof *master, GFP_KERNEL); 9: if (!master) 10: return NULL; 11:   12: device_initialize(&master->dev); 13: master->dev.class = &spi_master_class; 14: master->dev.parent = get_device(dev); 15: spi_master_set_devdata(master, &master[1]); 16:   17: return master; 18: }

//spi_register_master

1: int spi_register_master(struct spi_master *master) 2: { 3: static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); 4: struct device *dev = master->dev.parent; 5: struct boardinfo *bi; 6: int status = -ENODEV; 7: int dynamic = 0; 8:   9: if (!dev) 10: return -ENODEV; 11:   12: /* even if it's just one always-selected device, there must 13: * be at least one chipselect 14: */ 15: if (master->num_chipselect == 0) 16: return -EINVAL; 17:   18: /* convention: dynamically assigned bus IDs count down from the max */ 19: if (master->bus_num < 0) { 20: /* FIXME switch to an IDR based scheme, something like 21: * I2C now uses, so we can't run out of "dynamic" IDs 22: */ 23: master->bus_num = atomic_dec_return(&dyn_bus_id); 24: dynamic = 1; 25: } 26:   27: spin_lock_init(&master->bus_lock_spinlock); 28: mutex_init(&master->bus_lock_mutex); 29: master->bus_lock_flag = 0; 30:   31: /* register the device, then userspace will see it. 32: * registration fails if the bus ID is in use. 33: */ 34: dev_set_name(&master->dev, "spi%u", master->bus_num); 35: status = device_add(&master->dev); 36: if (status < 0) 37: goto done; 38: dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev), 39: dynamic ? " (dynamic)" : ""); 40:   41: mutex_lock(&board_lock); 42: list_add_tail(&master->list, &spi_master_list); 43: list_for_each_entry(bi, &board_list, list) 44: spi_match_master_to_boardinfo(master, &bi->board_info); 45: mutex_unlock(&board_lock); 46:   47: status = 0; 48:   49: /* Register devices from the device tree */ 50: of_register_spi_devices(master); 51: done: 52: return status; 53: }



分析以上spi_register_master代码:

1.  spi_match_master_to_boardinfo会将master和每个注册进来的device board联系起来

linux SPI驱动——spi core(四)的更多相关文章

  1. Linux TTY驱动--Serial Core层【转】

    转自:http://blog.csdn.net/sharecode/article/details/9197567 版权声明:本文为博主原创文章,未经博主允许不得转载. 接上一节: Linux TTY ...

  2. linux SPI驱动——spi协议(一)

    一:SPI简介以及应用 SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在 ...

  3. Linux内核驱动学习(四)Platform设备驱动模型

    Linux platform设备驱动模型 文章目录 Linux platform设备驱动模型 前言 框架 设备与驱动的分离 设备(device) 驱动(driver) 匹配(match) 参考 前言 ...

  4. Linux设备驱动剖析之SPI(四)

    781行之前没什么好说的,直接看783行,将work投入到工作队列里,然后就返回,在这里就可以回答之前为什么是异步的问题.以后在某个合适的时间里CPU会执行这个work指定的函数,这里是s3c64xx ...

  5. Linux spi驱动分析(二)----SPI核心(bus、device_driver和device)

    一.spi总线注册 这里所说的SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void).程序如下: 点击(此处 ...

  6. linux spi驱动开发学习-----spidev.c和spi test app

    一.spidev.c文件 看一个设备驱动的方法: module_init标识的入口初始化函数spidev_init,(module_exit标识的出口函数) 设备与设备驱动匹配时候调用的probe方法 ...

  7. Linux内核中SPI总线驱动分析

    本文主要有两个大的模块:一个是SPI总线驱动的分析 (研究了具体实现的过程): 另一个是SPI总线驱动的编写(不用研究具体的实现过程). 1 SPI概述 SPI是英语Serial Peripheral ...

  8. Linux设备驱动剖析之SPI(一)

    写在前面 初次接触SPI是因为几年前玩单片机的时候,由于普通的51单片机没有SPI控制器,所以只好用IO口去模拟.最近一次接触SPI是大三时参加的校内选拔赛,当时需要用2440去控制nrf24L01, ...

  9. linux驱动基础系列--linux spi驱动框架分析

    前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...

随机推荐

  1. LOJ#2084. 「NOI2016」网格

    $n,m \leq 1e9$,$n*m$的网格中有$c \leq 1e5$个是黑的,其他是白的.问:使至少两个白的不连通,最少需要再把几个白的涂黑. 可以发现答案是-1,0,1,2啦.-1要么没白的, ...

  2. Android启动过程深入解析【转】

    转自:http://www.open-open.com/lib/view/open1403250347934.html 当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么 ...

  3. Python 数据类型-3

    字典 (dict) Python中唯一的映射的类型(哈希表) 字典对象是可变的,但是字典的键必须使用不可变的对象,一个字典可以使用不同类型的键值 定义字典: In [68]: dic = {} #使用 ...

  4. 【C/C++】知识点

    1.C++中的参数传递机制:值传递.指针传递.引用传递 2.C++的内部类和外部类: 一个讲得不错的博客,不过不让转载:C++内部类 3.static 可以修饰局部变量.全局变量和函数. 不可修饰类! ...

  5. Android进阶之Fragment与Activity之间的数据交互

    1 为什么 因为Fragment和Activity一样是具有生命周期,不是一般的bean通过构造函数传值,会造成异常. 2 Activity把值传递给Fragment 2.1 第一种方式,也是最常用的 ...

  6. js 值类型和引用类型

    function chainStore() { var store1='Nike China'; var store2=store1; store1='Nike U.S.A.'; alert(stor ...

  7. CSS定位与布局:浮动

    浮动的特点   浮动(float)属性提出的作用是实现文字的环绕效果,一个元素浮动后,会脱离普通流.主要的特点如下: 浮动的元素会向左或者向右移动直到它的外边缘接触容器框(containing blo ...

  8. luogu P3800 Power收集

    题目背景 据说在红雾异变时,博丽灵梦单身前往红魔馆,用十分强硬的手段将事件解决了. 然而当时灵梦在Power达到MAX之前,不具有“上线收点”的能力,所以她想要知道她能收集多少P点,然而这个问题她答不 ...

  9. Linux下通过端口号查询占用的进程,并知道其所在的位置

    比如要查询2181端口. 1.查询端口占用的进程ID netstat -anp | grep 2181 tcp6 0 0 :::2181 :::* LISTEN 10997/java 2181为端口号 ...

  10. Java中Properties配置文件读取

    以下实践的是Properties配置文件的基本操作方法.像spring使用xml做依赖注入时,这个配置文件起到非常实用的作用. 一.格式规范 参考wiki百科的格式简介:https://zh.wiki ...