spi控制器和spi设备的加载过程

news/2024/10/21 11:49:42/

 spi控制器都是挂在platform总线上的,所以要等platform总线上的设备驱动加载spi控制器完成后才能加载spi设备。

1.spi控制器加载

由spi控制器驱动程序调用spi_register_master来完成spi控制器驱动加载

int spi_register_master(struct spi_master *master)
{
...

    status = of_spi_register_master(master);    //片选gpio的解析,片选是在控制器配置的

    ...
    if (master->transfer)
        dev_info(dev, "master is unqueued, this is deprecated\n");
    else {
        status = spi_master_initialize_queue(master);   //消息队列的初始化
        if (status) {
            device_del(&master->dev);
            goto done;
        }
    }
    /* add statistics */
    spin_lock_init(&master->statistics.lock);

    mutex_lock(&board_lock);
    list_add_tail(&master->list, &spi_master_list);
    list_for_each_entry(bi, &board_list, list)
        spi_match_master_to_boardinfo(master, &bi->board_info)

//这里是通过spi_register_board_info调用,产生的spi device需要解析并添加到maste链表上
    mutex_unlock(&board_lock);

    /* Register devices from the device tree and ACPI */
    of_register_spi_devices(master);   //spi device的添加
    acpi_register_spi_devices(master);  //acpi设备的添加,这里不关注
done:
    return status;
}

2.片选的解析 

以上是spi master,基本上芯片提供商都有自己的解决方案一般不需要我们改动。与我们相关的是spi device dtsi的配置

3.spi device的添加

static void of_register_spi_devices(struct spi_master *master)
{
    struct spi_device *spi;
    struct device_node *nc;

    if (!master->dev.of_node)
        return;

    for_each_available_child_of_node(master->dev.of_node, nc) {
        if (of_node_test_and_set_flag(nc, OF_POPULATED))
            continue;
        spi = of_register_spi_device(master, nc);
        if (IS_ERR(spi))
            dev_warn(&master->dev, "Failed to create SPI device for %s\n",
                nc->full_name);
    }
}

of_register_spi_device(struct spi_master *master, struct device_node *nc)
{
    struct spi_device *spi;
    int rc;
    u32 value;

    /* Alloc an spi_device */
    spi = spi_alloc_device(master);
    if (!spi) {
        dev_err(&master->dev, "spi_device alloc error for %s\n",
            nc->full_name);
        rc = -ENOMEM;
        goto err_out;
    }

    /* Select device driver */从node中获取compatible属性,然后填充
    rc = of_modalias_node(nc, spi->modalias,
                sizeof(spi->modalias));
    if (rc < 0) {
        dev_err(&master->dev, "cannot find modalias for %s\n",
            nc->full_name);
        goto err_out;
    }

    /* Device address */
    rc = of_property_read_u32(nc, "reg", &value);
    if (rc) {
        dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
            nc->full_name, rc);
        goto err_out;
    }
    spi->chip_select = value;

//这个reg是spi device必需配置项,且不能大于master设置的最大片选值。主要是设置片选的下标,因为片选数组是在master里面配置的

    /* Mode (clock phase/polarity/etc.) */
    if (of_find_property(nc, "spi-cpha", NULL))
        spi->mode |= SPI_CPHA;
    if (of_find_property(nc, "spi-cpol", NULL))
        spi->mode |= SPI_CPOL;
    if (of_find_property(nc, "spi-cs-high", NULL))
        spi->mode |= SPI_CS_HIGH;
    if (of_find_property(nc, "spi-3wire", NULL))
        spi->mode |= SPI_3WIRE;
    if (of_find_property(nc, "spi-lsb-first", NULL))
        spi->mode |= SPI_LSB_FIRST;

    /* Device DUAL/QUAD mode */
    if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
        switch (value) {
        case 1:
            break;
        case 2:
            spi->mode |= SPI_TX_DUAL;
            break;
        case 4:
            spi->mode |= SPI_TX_QUAD;
            break;
        default:
            dev_warn(&master->dev,
                "spi-tx-bus-width %d not supported\n",
                value);
            break;
        }
    }

    if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {
        switch (value) {
        case 1:
            break;
        case 2:
            spi->mode |= SPI_RX_DUAL;
            break;
        case 4:
            spi->mode |= SPI_RX_QUAD;
            break;
        default:
            dev_warn(&master->dev,
                "spi-rx-bus-width %d not supported\n",
                value);
            break;
        }
    }

     //上面是spi mode配置,可以在dtsi里面直接配置,也可以在spi_driver匹配成功后,调用spi_setup重新设定mode

    /* Device speed */
    rc = of_property_read_u32(nc, "spi-max-frequency", &value);
    if (rc) {
        dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",
            nc->full_name, rc);
        goto err_out;
    }
    spi->max_speed_hz = value;

     //spi最大速率,必需配置

    /* Store a pointer to the node in the device structure */
    of_node_get(nc);
    spi->dev.of_node = nc;

     //主要是作一些检测,没有问题完成device添加。这里注意的是如果同相的控制器上片选配置已经存在链表上,那么这个spi device将会添加失败
    rc = spi_add_device(spi);
    if (rc) {
        dev_err(&master->dev, "spi_device register error %s\n",
            nc->full_name);
        goto err_out;
    }

    return spi;

err_out:
    spi_dev_put(spi);
    return ERR_PTR(rc);
}

从上面大体可知,一个spi device dtsi有两个配置项必需存在

1.reg

2.spi-max-frequency

4.spi中断的解析

 

在驱动匹配成功后,probe加载时会解析中断。这里只需要按中断配置的方式来正常配置中断就好了. eg:

 #interrupt-cells : Defines the width of cells used to represent interrupts.  Typically this value is <2>,

which includes a 32-bit number that represents the interrupt number,

and a 32-bit number that represents the interrupt sense and level.

一般device我们用到的#interrupt-cells配置是2,表示有2个参数。一个是中断后,另一个是中断触发方式
#define IRQ_TYPE_NONE        0
#define IRQ_TYPE_EDGE_RISING    1
#define IRQ_TYPE_EDGE_FALLING    2
#define IRQ_TYPE_EDGE_BOTH    (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH    4
#define IRQ_TYPE_LEVEL_LOW    8

 

 


http://www.ppmy.cn/news/550542.html

相关文章

新能源车牌 普通车牌 特殊车牌正则校验

新能源车牌&#xff1a; 第二位和最后一位 必须是数字或者是DF 字母“D”代表纯电动汽车&#xff0c;字母“ F”代表非纯电动汽车&#xff08;包括插电式混合动力和燃料电池汽车等&#xff09; 小型车字母在签发单位后 第一位 大型车字母车牌号最后一位 final String patte…

车牌号归属地查询,免费API

接口地址: https://api.kertennet.com/live/licencePlate 返回格式: json 请求方式: GET 请求示例: https://api.kertennet.com/live/licencePlate?num京A12345 接口完整地址:跳转 请求参数说明&#xff1a; 返回数据:

车牌输入法 车牌号快捷输入法 支持普通车牌新能源车牌

车牌输入法 车牌号快捷输入法 支持普通车牌&新能源车牌 效果图如下 上代码 前提&#xff1a;import plateInput from ‘/components/uni-plate-input/uni-plate-input.vue’; 下载1&#xff1a;uni-plate-input.less 下载2&#xff1a;uni-plate-input.css 下载2&#xf…

JAVA根据车牌获取归属地

最近在项目中遇到根据车牌判断归属地&#xff0c;特此记录一下 JSON文件 直接贴代码&#xff1a;应该能看懂吧&#xff01;&#xff01;&#xff01; {"codeInfo": [{"Hp": "冀A","city": "石家庄","province"…

怎样看车牌

转载自 http://chengtianle.blog.hexun.com/3071909_d.html 2006年4月10日 北京[京] AB&#xff08;出租车&#xff09;CEFHG&#xff08;远郊区县&#xff09; 上海[沪] ABC(远郊区县)D 天津[津] ABCE&#xff08;出租车&#xff09; 重庆[渝] A直属…

车牌识别(中国)

摘要 代码&#xff1a;(https://download.csdn.net/download/ALiLiLiYa/86885535) 提出了LPRNet端到端方法自动车牌识别&#xff0c;无需初步字符分割。我们的方法灵感来自于-在深度神经网络方面取得突破实时&#xff0c;中文识别准确率高达95% 车牌&#xff1a; LPRNet由轻量…

中国车牌

第一个汉字 "京","沪","津","渝","冀","晋","蒙","辽","吉","黑","苏","浙","皖","闽","赣","鲁","…

车牌号

&#xfeff;&#xfeff; 描述 茵茵很喜欢研究车牌号码&#xff0c;从车牌号码上可以看出号码注册的早晚&#xff0c;据研究发现&#xff0c;车牌号码是按字典序发放的&#xff0c;现在她收集了很多车牌号码&#xff0c;请你设计程序帮她判断注册较早的号码。车牌号码由5个字母…