• Linux SPI通过设备树文件添加设备


    一、设备树文件编写

     1 spi_master: spi_master
     2 {
     3     #address-cells = <1>;
     4     #size-cells = <0>;
     5     compatible = "spi_master";
     6     io_phy_addr = <0x1f000000>;
     7     banks = <0x1110>,<0x1111>,<0x1038>,<0x101E>;
     8     interrupts = <GIC_SPI INT_IRQ_MSPI_0 IRQ_TYPE_LEVEL_HIGH>,<GIC_SPI INT_IRQ_MSPI_1 IRQ_TYPE_LEVEL_HIGH>;
     9     spi0_mode = <1>;
    10     spi1_mode = <3>;
    11     status = "okay";
    12 
    13     spi_device: spi_device
    14     {
    15          compatible = "spi_device";
    16          reg = <0x0>;
    17          spi-max-frequency = <10000000>;
    18          status = "okay";
    19     };
    20 };

           如上DTS文件片段,SPI Device 节点必须定义在 SPI Master 节点下,其中 compatible 属性和 reg 属性,以上 compatible 属性用于匹配对应的 Driver 程序,reg 属性用于指定使用的 SPI Master 的编号,SPI 相关设备树文件识别见下文讲解。

    二、代码流程

           匹配设备树文件在SPI子系统中有两个地方:在 spi_register_master() 中匹配和在 device register 时通过内核的通知链(notifier_block)来调用设备树匹配相关程序。

           在 spi_register_master() 中匹配:

     1 //driver/spi/spi.c
     2 int spi_register_master(struct spi_master *master)
     3 {
     4     static atomic_t      dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
     5     struct device        *dev = master->dev.parent;
     6     struct boardinfo     *bi;
     7     int            status = -ENODEV;
     8     int            dynamic = 0;
     9 
    10     if (!dev)
    11         return -ENODEV;
    12 
    13     status = of_spi_register_master(master);
    14     if (status)
    15         return status;
    16 
    17     /* even if it's just one always-selected device, there must
    18      * be at least one chipselect
    19      */
    20     if (master->num_chipselect == 0)
    21         return -EINVAL;
    22 
    23     if ((master->bus_num < 0) && master->dev.of_node)
    24         master->bus_num = of_alias_get_id(master->dev.of_node, "spi");
    25 
    26     /* convention:  dynamically assigned bus IDs count down from the max */
    27     if (master->bus_num < 0) {
    28         /* FIXME switch to an IDR based scheme, something like
    29          * I2C now uses, so we can't run out of "dynamic" IDs
    30          */
    31         master->bus_num = atomic_dec_return(&dyn_bus_id);
    32         dynamic = 1;
    33     }
    34 
    35     INIT_LIST_HEAD(&master->queue);
    36     spin_lock_init(&master->queue_lock);
    37     spin_lock_init(&master->bus_lock_spinlock);
    38     mutex_init(&master->bus_lock_mutex);
    39     mutex_init(&master->io_mutex);
    40     master->bus_lock_flag = 0;
    41     init_completion(&master->xfer_completion);
    42     if (!master->max_dma_len)
    43         master->max_dma_len = INT_MAX;
    44 
    45     /* register the device, then userspace will see it.
    46      * registration fails if the bus ID is in use.
    47      */
    48     dev_set_name(&master->dev, "spi%u", master->bus_num);
    49     status = device_add(&master->dev);
    50     if (status < 0)
    51         goto done;
    52     dev_dbg(dev, "registered master %s%s
    ", dev_name(&master->dev),
    53             dynamic ? " (dynamic)" : "");
    54 
    55     /* If we're using a queued driver, start the queue */
    56     if (master->transfer)
    57         dev_info(dev, "master is unqueued, this is deprecated
    ");
    58     else {
    59         status = spi_master_initialize_queue(master);
    60         if (status) {
    61             device_del(&master->dev);
    62             goto done;
    63         }
    64     }
    65     /* add statistics */
    66     spin_lock_init(&master->statistics.lock);
    67 
    68     mutex_lock(&board_lock);
    69     list_add_tail(&master->list, &spi_master_list);
    70     list_for_each_entry(bi, &board_list, list)
    71         spi_match_master_to_boardinfo(master, &bi->board_info);
    72     mutex_unlock(&board_lock);
    73 
    74     /* Register devices from the device tree and ACPI */
    75     of_register_spi_devices(master);  // 设备树匹配操作
    76     acpi_register_spi_devices(master);
    77 done:
    78     return status;
    79 }
     1 //driver/spi/spi.c
     2 static void of_register_spi_devices(struct spi_master *master)
     3 {
     4     struct spi_device *spi;
     5     struct device_node *nc;
     6 
     7     if (!master->dev.of_node)
     8         return;
     9 
    10     for_each_available_child_of_node(master->dev.of_node, nc) {
    11         if (of_node_test_and_set_flag(nc, OF_POPULATED))
    12             continue;
    13         spi = of_register_spi_device(master, nc);  // 设备树匹配操作
    14         if (IS_ERR(spi)) {
    15             dev_warn(&master->dev, "Failed to create SPI device for %s
    ",
    16                 nc->full_name);
    17             of_node_clear_flag(nc, OF_POPULATED);
    18         }
    19     }
    20 }

            在 device register 时匹配:

     1 //driver/spi/spi.c
     2 static int __init spi_init(void)
     3 {
     4     int    status;
     5 
     6     buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
     7     if (!buf) {
     8         status = -ENOMEM;
     9         goto err0;
    10     }
    11 
    12     status = bus_register(&spi_bus_type);
    13     if (status < 0)
    14         goto err1;
    15 
    16     status = class_register(&spi_master_class);
    17     if (status < 0)
    18         goto err2;
    19 
    20     if (IS_ENABLED(CONFIG_OF_DYNAMIC))
    21         WARN_ON(of_reconfig_notifier_register(&spi_of_notifier));
    22     if (IS_ENABLED(CONFIG_ACPI))
    23         WARN_ON(acpi_reconfig_notifier_register(&spi_acpi_notifier));
    24 
    25     return 0;
    26 
    27 err2:
    28     bus_unregister(&spi_bus_type);
    29 err1:
    30     kfree(buf);
    31     buf = NULL;
    32 err0:
    33     return status;
    34 }
    35 
    36 postcore_initcall(spi_init);

             在 device register 时,需配置 CONFIG_OF_DYNAMIC 宏以开启动态匹配才能够使用设备树添加设备,该宏在 menuconfig/Device Drivers/Device Tree and Open Firmware support 中开启,如下图:

     1 //driver/spi/spi.c
     2 static struct notifier_block spi_of_notifier = {
     3     .notifier_call = of_spi_notify,
     4 };
     5 
     6 static int of_spi_notify(struct notifier_block *nb, unsigned long action,
     7              void *arg)
     8 {
     9     struct of_reconfig_data *rd = arg;
    10     struct spi_master *master;
    11     struct spi_device *spi;
    12 
    13     switch (of_reconfig_get_state_change(action, arg)) {
    14     case OF_RECONFIG_CHANGE_ADD:
    15         master = of_find_spi_master_by_node(rd->dn->parent);
    16         if (master == NULL)
    17             return NOTIFY_OK;    /* not for us */
    18 
    19         if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) {
    20             put_device(&master->dev);
    21             return NOTIFY_OK;
    22         }
    23 
    24         spi = of_register_spi_device(master, rd->dn);  // 设备树匹配操作
    25         put_device(&master->dev);
    26 
    27         if (IS_ERR(spi)) {
    28             pr_err("%s: failed to create for '%s'
    ",
    29                     __func__, rd->dn->full_name);
    30             of_node_clear_flag(rd->dn, OF_POPULATED);
    31             return notifier_from_errno(PTR_ERR(spi));
    32         }
    33         break;
    34 
    35     case OF_RECONFIG_CHANGE_REMOVE:
    36         /* already depopulated? */
    37         if (!of_node_check_flag(rd->dn, OF_POPULATED))
    38             return NOTIFY_OK;
    39 
    40         /* find our device by node */
    41         spi = of_find_spi_device_by_node(rd->dn);
    42         if (spi == NULL)
    43             return NOTIFY_OK;    /* no? not meant for us */
    44 
    45         /* unregister takes one ref away */
    46         spi_unregister_device(spi);
    47 
    48         /* and put the reference of the find */
    49         put_device(&spi->dev);
    50         break;
    51     }
    52 
    53     return NOTIFY_OK;
    54 }
      1 //driver/spi/spi.c
      2 static struct spi_device *
      3 of_register_spi_device(struct spi_master *master, struct device_node *nc)
      4 {
      5     struct spi_device *spi;
      6     int rc;
      7     u32 value;
      8 
      9     /* Alloc an spi_device */
     10     spi = spi_alloc_device(master);
     11     if (!spi) {
     12         dev_err(&master->dev, "spi_device alloc error for %s
    ",
     13             nc->full_name);
     14         rc = -ENOMEM;
     15         goto err_out;
     16     }
     17 
     18     /* Select device driver */
     19     rc = of_modalias_node(nc, spi->modalias,
     20                 sizeof(spi->modalias));
     21     if (rc < 0) {
     22         dev_err(&master->dev, "cannot find modalias for %s
    ",
     23             nc->full_name);
     24         goto err_out;
     25     }
     26 
     27     /* Device address */
     28     rc = of_property_read_u32(nc, "reg", &value);
     29     if (rc) {
     30         dev_err(&master->dev, "%s has no valid 'reg' property (%d)
    ",
     31             nc->full_name, rc);
     32         goto err_out;
     33     }
     34     spi->chip_select = value;
     35 
     36     /* Mode (clock phase/polarity/etc.) */
     37     if (of_find_property(nc, "spi-cpha", NULL))
     38         spi->mode |= SPI_CPHA;
     39     if (of_find_property(nc, "spi-cpol", NULL))
     40         spi->mode |= SPI_CPOL;
     41     if (of_find_property(nc, "spi-cs-high", NULL))
     42         spi->mode |= SPI_CS_HIGH;
     43     if (of_find_property(nc, "spi-3wire", NULL))
     44         spi->mode |= SPI_3WIRE;
     45     if (of_find_property(nc, "spi-lsb-first", NULL))
     46         spi->mode |= SPI_LSB_FIRST;
     47 
     48     /* Device DUAL/QUAD mode */
     49     if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
     50         switch (value) {
     51         case 1:
     52             break;
     53         case 2:
     54             spi->mode |= SPI_TX_DUAL;
     55             break;
     56         case 4:
     57             spi->mode |= SPI_TX_QUAD;
     58             break;
     59         default:
     60             dev_warn(&master->dev,
     61                 "spi-tx-bus-width %d not supported
    ",
     62                 value);
     63             break;
     64         }
     65     }
     66 
     67     if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {
     68         switch (value) {
     69         case 1:
     70             break;
     71         case 2:
     72             spi->mode |= SPI_RX_DUAL;
     73             break;
     74         case 4:
     75             spi->mode |= SPI_RX_QUAD;
     76             break;
     77         default:
     78             dev_warn(&master->dev,
     79                 "spi-rx-bus-width %d not supported
    ",
     80                 value);
     81             break;
     82         }
     83     }
     84 
     85     /* Device speed */
     86     rc = of_property_read_u32(nc, "spi-max-frequency", &value);
     87     if (rc) {
     88         dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)
    ",
     89             nc->full_name, rc);
     90         goto err_out;
     91     }
     92     spi->max_speed_hz = value;
     93 
     94     /* Store a pointer to the node in the device structure */
     95     of_node_get(nc);
     96     spi->dev.of_node = nc;
     97 
     98     /* Register the new device */
     99     rc = spi_add_device(spi);
    100     if (rc) {
    101         dev_err(&master->dev, "spi_device register error %s
    ",
    102             nc->full_name);
    103         goto err_of_node_put;
    104     }
    105 
    106     return spi;
    107 
    108 err_of_node_put:
    109     of_node_put(nc);
    110 err_out:
    111     spi_dev_put(spi);
    112     return ERR_PTR(rc);
    113 }

    end

  • 相关阅读:
    最短路径:HDU2006-一个人的旅行(多个起点,多个终点)
    最短路径(最基础,经典的模板和思想):HDU-2544最短路
    数学算法:poweroj1026-丑数(根据固定倍数得到从小到大的序列)
    动态规划:ZOJ1074-最大和子矩阵 DP(最长子序列的升级版)
    数论:HDU1066-Last non-zero Digit in N!
    容斥原理:HDU-4135Co-prime
    数学算法:求一个数的质因子
    动态规划(入门,滚动数组,记录的都是状态):SWUSTACM-1010 魔兽争霸之最后的反击
    动态规划(入门):各种数字三角形
    动态规划:HDU2571-命运
  • 原文地址:https://www.cnblogs.com/xujiawei29/p/12157566.html
Copyright © 2020-2023  润新知