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,
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~