Linux 设备树添加spi设备

Linux:4.6

应用开发板:zynq系列 zc706、zedboard

文件系统:ubuntu12

参考帖子:https://stackoverflow.com/questions/53634892/linux-spidev-why-it-shouldnt-be-directly-in-devicetree

之前实验过spi控制器下面挂载spi设备,当时,关于spi设备树的节点描述如下:

        spi@e0007000 {
            compatible = "xlnx,zynq-spi-r1p6";
            reg = <0xe0007000 0x1000>;
            status = "okay";
            interrupt-parent = <0x3>;
            interrupts = <0x0 0x31 0x4>;
            clocks = <0x1 0x1a 0x1 0x23>;
            clock-names = "ref_clk", "pclk";
            #address-cells = <0x1>;
            #size-cells = <0x0>;
            num-cs = <0x1>;
            device@0{
                compatible = "spidev";
                reg = <0x0>;
                spi-max-frequency = <0x100000>;
            };
        };

这次在在上述板子上,依然按照上面的方法忽然就不行了,报错信息如下:

spidev spi32766.0: buggy DT: spidev listed directly in DT                       

------------[ cut here ]------------                                            
WARNING: CPU: 0 PID: 1 at drivers/spi/spidev.c:719 spidev_probe+0x16c/0x1a0     
Modules linked in:                                                              
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.6.0 #21                             
Hardware name: Xilinx Zynq Platform                                             
[] (unwind_backtrace) from [] (show_stack+0x10/0x14)        
[] (show_stack) from [] (dump_stack+0x80/0xa0)              
[] (dump_stack) from [] (__warn+0xcc/0xfc)                  
[] (__warn) from [] (warn_slowpath_null+0x1c/0x24)          
[] (warn_slowpath_null) from [] (spidev_probe+0x16c/0x1a0)  
[] (spidev_probe) from [] (spi_drv_probe+0x84/0xa0)         
[] (spi_drv_probe) from [] (driver_probe_device+0x134/0x29c)
[] (driver_probe_device) from [] (bus_for_each_drv+0x84/0x9)
[] (bus_for_each_drv) from [] (__device_attach+0x88/0xfc)   
[] (__device_attach) from [] (bus_probe_device+0x28/0x80)   
[] (bus_probe_device) from [] (device_add+0x3f0/0x504)      
[] (device_add) from [] (spi_add_device+0xd4/0x124)         
[] (spi_add_device) from [] (spi_register_master+0x5ec/0x6f)
[] (spi_register_master) from [] (cdns_spi_probe+0x2d4/0x35)
[] (cdns_spi_probe) from [] (platform_drv_probe+0x50/0xa0)  
[] (platform_drv_probe) from [] (driver_probe_device+0x134/)
[] (driver_probe_device) from [] (__driver_attach+0x80/0xa4)
[] (__driver_attach) from [] (bus_for_each_dev+0x6c/0x90)   
[] (bus_for_each_dev) from [] (bus_add_driver+0xc8/0x1e4)   
[] (bus_add_driver) from [] (driver_register+0x9c/0xe0)     
[] (driver_register) from [] (do_one_initcall+0x100/0x1b4)  
[] (do_one_initcall) from [] (kernel_init_freeable+0x120/0x)
[] (kernel_init_freeable) from [] (kernel_init+0x8/0xf4)    
[] (kernel_init) from [] (ret_from_fork+0x14/0x3c)          
---[ end trace 799ecf1d804db820 ]---

问题分析:

根据我的参考帖子,研究了一下,应该是不能直接使用 驱动名:“spidev”。

方法1:

查询spidev.c的源码后,把设备树中使用的"spidev" 替换为 "rohm,dh2228fv",就成功加载了。

方法2:

帖子里还教了另外的方法,在 spidev_dt_ids里,添加自己的驱动名,比如"myspidriver"。

在设备树里使用自己定义的名字。

 

最后设备树如下:

        spi@e0007000 {
            compatible = "xlnx,zynq-spi-r1p6";
            reg = <0xe0007000 0x1000>;
            status = "okay";
            interrupt-parent = <0x3>;
            interrupts = <0x0 0x31 0x4>;
            clocks = <0x1 0x1a 0x1 0x23>;
            clock-names = "ref_clk", "pclk";
            #address-cells = <0x1>;
            #size-cells = <0x0>;
            num-cs = <0x1>;
            device@0{
                compatible = "rohm,dh2228fv";
                reg = <0x0>;
                spi-max-frequency = <0x100000>;
            };
        };

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 参 考 代 码 开 始  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

spidev.c 的685行开始:
#ifdef CONFIG_OF
static const struct of_device_id spidev_dt_ids[] = {
    { .compatible = "rohm,dh2228fv" },
    { .compatible = "lineartechnology,ltc2488" },

    // { .compatible = "myspidriver" }, 这里可以加自命名驱动,注意:内核编译要满足#ifdef CONFIG_OF条件
    {},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
#endif

/*-------------------------------------------------------------------------*/

static int spidev_probe(struct spi_device *spi)
{
    struct spidev_data    *spidev;
    int            status;
    unsigned long        minor;

    /*
     * spidev should never be referenced in DT without a specific
     * compatible string, it is a Linux implementation thing
     * rather than a description of the hardware.
     */
    if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
        dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");        //报错的地方
        WARN_ON(spi->dev.of_node &&
            !of_match_device(spidev_dt_ids, &spi->dev));
    }

    /* Allocate driver data */
    spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
    if (!spidev)
        return -ENOMEM;

    /* Initialize the driver data */
    spidev->spi = spi;
    spin_lock_init(&spidev->spi_lock);
    mutex_init(&spidev->buf_lock);

    INIT_LIST_HEAD(&spidev->device_entry);

    /* If we can allocate a minor number, hook up this device.
     * Reusing minors is fine so long as udev or mdev is working.
     */
    mutex_lock(&device_list_lock);
    minor = find_first_zero_bit(minors, N_SPI_MINORS);
    if (minor < N_SPI_MINORS) {
        struct device *dev;

        spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
        dev = device_create(spidev_class, &spi->dev, spidev->devt,
                    spidev, "spidev%d.%d",
                    spi->master->bus_num, spi->chip_select);
        status = PTR_ERR_OR_ZERO(dev);
    } else {
        dev_dbg(&spi->dev, "no minor number available!\n");
        status = -ENODEV;
    }
    if (status == 0) {
        set_bit(minor, minors);
        list_add(&spidev->device_entry, &device_list);
    }
    mutex_unlock(&device_list_lock);

    spidev->speed_hz = spi->max_speed_hz;

    if (status == 0)
        spi_set_drvdata(spi, spidev);
    else
        kfree(spidev);

    return status;
}

static int spidev_remove(struct spi_device *spi)
{
    struct spidev_data    *spidev = spi_get_drvdata(spi);

    /* make sure ops on existing fds can abort cleanly */
    spin_lock_irq(&spidev->spi_lock);
    spidev->spi = NULL;
    spin_unlock_irq(&spidev->spi_lock);

    /* prevent new opens */
    mutex_lock(&device_list_lock);
    list_del(&spidev->device_entry);
    device_destroy(spidev_class, spidev->devt);
    clear_bit(MINOR(spidev->devt), minors);
    if (spidev->users == 0)
        kfree(spidev);
    mutex_unlock(&device_list_lock);

    return 0;
}

static struct spi_driver spidev_spi_driver = {
    .driver = {
        .name =        "spidev",
        .of_match_table = of_match_ptr(spidev_dt_ids),
    },
    .probe =    spidev_probe,
    .remove =    spidev_remove,

    /* NOTE:  suspend/resume methods are not necessary here.
     * We don't do anything except pass the requests to/from
     * the underlying controller.  The refrigerator handles
     * most issues; the controller driver handles the rest.
     */
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

你可能感兴趣的:(设备树)