天天看點

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裝置樹的節點描述如下:

        [email protected] {

            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>;

            [email protected]{

                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                                             

[<c0015930>] (unwind_backtrace) from [<c0012648>] (show_stack+0x10/0x14)        

[<c0012648>] (show_stack) from [<c01ae354>] (dump_stack+0x80/0xa0)              

[<c01ae354>] (dump_stack) from [<c0021b24>] (__warn+0xcc/0xfc)                  

[<c0021b24>] (__warn) from [<c0021bf8>] (warn_slowpath_null+0x1c/0x24)          

[<c0021bf8>] (warn_slowpath_null) from [<c029b818>] (spidev_probe+0x16c/0x1a0)  

[<c029b818>] (spidev_probe) from [<c0298f78>] (spi_drv_probe+0x84/0xa0)         

[<c0298f78>] (spi_drv_probe) from [<c024a754>] (driver_probe_device+0x134/0x29c)

[<c024a754>] (driver_probe_device) from [<c0248f44>] (bus_for_each_drv+0x84/0x9)

[<c0248f44>] (bus_for_each_drv) from [<c024a588>] (__device_attach+0x88/0xfc)   

[<c024a588>] (__device_attach) from [<c0249c18>] (bus_probe_device+0x28/0x80)   

[<c0249c18>] (bus_probe_device) from [<c0248330>] (device_add+0x3f0/0x504)      

[<c0248330>] (device_add) from [<c029abac>] (spi_add_device+0xd4/0x124)         

[<c029abac>] (spi_add_device) from [<c029b2d8>] (spi_register_master+0x5ec/0x6f)

[<c029b2d8>] (spi_register_master) from [<c029da94>] (cdns_spi_probe+0x2d4/0x35)

[<c029da94>] (cdns_spi_probe) from [<c024bf14>] (platform_drv_probe+0x50/0xa0)  

[<c024bf14>] (platform_drv_probe) from [<c024a754>] (driver_probe_device+0x134/)

[<c024a754>] (driver_probe_device) from [<c024a93c>] (__driver_attach+0x80/0xa4)

[<c024a93c>] (__driver_attach) from [<c0248e88>] (bus_for_each_dev+0x6c/0x90)   

[<c0248e88>] (bus_for_each_dev) from [<c0249e20>] (bus_add_driver+0xc8/0x1e4)   

[<c0249e20>] (bus_add_driver) from [<c024b14c>] (driver_register+0x9c/0xe0)     

[<c024b14c>] (driver_register) from [<c00097c0>] (do_one_initcall+0x100/0x1b4)  

[<c00097c0>] (do_one_initcall) from [<c0699d58>] (kernel_init_freeable+0x120/0x)

[<c0699d58>] (kernel_init_freeable) from [<c0480ef8>] (kernel_init+0x8/0xf4)    

[<c0480ef8>] (kernel_init) from [<c000ef38>] (ret_from_fork+0x14/0x3c)          

---[ end trace 799ecf1d804db820 ]---

問題分析:

根據我的參考文章,研究了一下,應該是不能直接使用 驅動名:“spidev”。

方法1:

查詢spidev.c的源碼後,把裝置樹中使用的"spidev" 替換為 "rohm,dh2228fv",就成功加載了。

方法2:

文章裡還教了另外的方法,在 spidev_dt_ids裡,添加自己的驅動名,比如"myspidriver"。

在裝置樹裡使用自己定義的名字。

最後裝置樹如下:

        [email protected] {

            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>;

            [email protected]{

                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;

    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));

    }

    spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);

    if (!spidev)

        return -ENOMEM;

    spidev->spi = spi;

    spin_lock_init(&spidev->spi_lock);

    mutex_init(&spidev->buf_lock);

    INIT_LIST_HEAD(&spidev->device_entry);

    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);

    spin_lock_irq(&spidev->spi_lock);

    spidev->spi = NULL;

    spin_unlock_irq(&spidev->spi_lock);

    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,

};

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

繼續閱讀