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

本文详细介绍了SPI控制器如何通过 spi_register_master 加载,并解析了片选配置和SPI设备的添加过程,包括从设备树中读取配置信息,如modalias、reg、spi-max-frequency等。同时,文中提及SPI中断在驱动匹配后的处理。必须的配置项为reg和spi-max-frequency。

 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

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bruk_spp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值