• linux SPI驱动——spi core(四)


    一:

    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 ", 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联系起来

  • 相关阅读:
    触摸屏测试:Tslib
    Ubuntu:我不小心把/var/lock文件夹给删了
    驱动开发学习笔记. 0.02 基于EASYARM-IMX283 烧写uboot和linux系统
    驱动开发学习笔记. 0.01 配置arm-linux-gcc 交叉编译器
    驱动开发学习笔记.0.00 从拿到一块开发板开始
    利用联合体通过串口收发浮点数
    stm32 MDK5软件仿真之查看io口输出
    ListView 类
    INotifyPropertyChanged 接口
    ItemsControl 类绑定数据库
  • 原文地址:https://www.cnblogs.com/xuyh/p/6027242.html
Copyright © 2020-2023  润新知