xilinx zynq7000, ad9361与spi驱动移植问题

心上枫叶红 2018-07-23 11:47:50
各位大神请教一下。我用的是xilinux zynq7000的板子。我现在,需要移植SPI驱动和ADI的AD9361驱动进去。添加spidev.c驱动执行到init函数之后probe函数就没执行了。在/sys/bus/spi/drivers目录下有spidev驱动。但是/dev目录下一直没有设备文件。而且ad9361编译之后在报错好像就是因为是spi驱动的问题。我想知道这是怎么回事?谢谢
spidev.c的部分驱动
static int spidev_probe(struct spi_device *spi)
{
printk("========================enter spi0_probe======================\n");
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);
printk("========================enter spi remove======================\n");
/* 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.
*/
};

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

static int __init spidev_init(void)
{
int status;

/* Claim our 256 reserved device numbers. Then register a class
* that will key udev/mdev to add/remove /dev nodes. Last, register
* the driver which manages those device numbers.
*/
BUILD_BUG_ON(N_SPI_MINORS > 256);
status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
if (status < 0)
return status;

spidev_class = class_create(THIS_MODULE, "spidev");
if (IS_ERR(spidev_class)) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
return PTR_ERR(spidev_class);
}
status = spi_register_driver(&spidev_spi_driver);
if (status < 0) {
class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
}
printk("==============:%d:==========spi0_init out ======================\n",status);
return status;
}
module_init(spidev_init);
内核打印信息::
bootconsole [earlycon0] disabled
bootconsole [earlycon0] disabled
xdevcfg f8007000.devcfg: ioremap 0xf8007000 to f08b0000
[drm] Initialized drm 1.1.0 20060810
brd: module loaded
loop: module loaded
==============:0:==========spi0_init out ======================
m25p80 spi0.0: SPI-NOR-UniqueID 0000000000000000000000000000000000
m25p80 spi0.0: m25p80 (2048 Kbytes)
4 ofpart partitions found on MTD device spi0.0
Creating 4 MTD partitions on "spi0.0":
0x000000000000-0x000000500000 : "boot"
mtd: partition "boot" extends beyond the end of device "spi0.0" -- size truncated to 0x200000
0x000000500000-0x000000520000 : "bootenv"
mtd: partition "bootenv" is out of reach -- disabled
0x000000520000-0x000000fa0000 : "kernel"
mtd: partition "kernel" is out of reach -- disabled
0x000000fa0000-0x000000200000 : "spare"
mtd: partition "spare" is out of reach -- disabled
CAN device driver interface
libphy: MACB_mii_bus: probed
macb e000b000.ethernet eth0: Cadence GEM rev 0x00020118 at 0xe000b000 irq 146 (00:0a:35:00:1e:53)
Generic PHY e000b000.etherne:00: attached PHY driver [Generic PHY] (mii_bus:phy_addr=e000b000.etherne:00, irq=-1)
e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
ehci-pci: EHCI PCI platform driver
usbcore: registered new interface driver usb-storage
mousedev: PS/2 mouse device common for all mice
i2c /dev entries driver
EDAC MC: ECC not enabled
Xilinx Zynq CpuIdle Driver started
sdhci: Secure Digital Host Controller Interface driver
sdhci: Copyright(c) Pierre Ossman
sdhci-pltfm: SDHCI platform and OF driver helper
mmc0: SDHCI controller on e0101000.sdhci [e0101000.sdhci] using ADMA
ledtrig-cpu: registered to indicate activity on CPUs
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
ad9361 spi32766.0: ad9361_probe : enter (ad9361)
ad9361 spi32766.0: ---------------gpio:0--------------------------!
ad9361 spi32766.0: --------------------------1----------------!
ad9361 spi32766.0: SPI transfer timed out
ad9361 spi32766.0: Write Error -110
ad9361 spi32766.0: SPI transfer timed out
ad9361 spi32766.0: Write Error -110
ad9361 spi32766.0: ad9361_reset: by SPI, this may cause unpredicted behavior!
ad9361 spi32766.0: SPI transfer timed out
ad9361 spi32766.0: Read Error -110
ad9361 spi32766.0: ad9361_probe : Unsupported PRODUCT_ID 0xFFFFFF92
NET: Registered protocol family 10
sit: IPv6 over IPv4 tunneling driver
NET: Registered protocol family 17
can: controller area network core (rev 20120528 abi 9)
NET: Registered protocol family 29
can: raw protocol (rev 20120528)
can: broadcast manager protocol (rev 20120528 t)
can: netlink gateway (rev 20130117) max_hops=1
zynq_pm_remap_ocm: OCM pool is not available
zynq_pm_suspend_init: Unable to map OCM.
Registering SWP/SWPB emulation handler
hctosys: unable to open rtc device (rtc0)

这里ad9361的部分驱动代码:
static int ad9361_reset(struct ad9361_rf_phy *phy)
{

dev_err(&phy->spi->dev, " ---------------gpio:%d--------------------------!\n",phy->pdata->reset_gpio);
if (phy->pdata->reset_gpio) {
dev_err(&phy->spi->dev, " --------------------------in----------------!\n");
gpiod_set_value(phy->pdata->reset_gpio, 0);
mdelay(1);
gpiod_set_value(phy->pdata->reset_gpio, 1);
mdelay(1);
dev_dbg(&phy->spi->dev, "%s: by GPIO", __func__);
return 0;
}
dev_err(&phy->spi->dev, " --------------------------1----------------!\n");

/* SPI Soft Reset was removed from the register map, since it doesn't
* work reliably. Without a prober HW reset randomness may happen.
* Please specify a RESET GPIO.
*/

ad9361_spi_write(phy->spi, REG_SPI_CONF, SOFT_RESET | _SOFT_RESET);
ad9361_spi_write(phy->spi, REG_SPI_CONF, 0x0);
dev_err(&phy->spi->dev,
"%s: by SPI, this may cause unpredicted behavior!", __func__);

return -ENODEV;
}

static int ad9361_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ad9361_rf_phy *phy;
struct clk *clk = NULL;
int ret, rev;

dev_info(&spi->dev, "%s : enter (%s)", __func__,
spi_get_device_id(spi)->name);

clk = devm_clk_get(&spi->dev, NULL);
if (IS_ERR(clk)) {
return -EPROBE_DEFER;
}

indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*phy));
if (indio_dev == NULL)
return -ENOMEM;

phy = iio_priv(indio_dev);
phy->indio_dev = indio_dev;
phy->spi = spi;
phy->clk_refin = clk;

phy->pdata = ad9361_phy_parse_dt(indio_dev, &spi->dev);
if (phy->pdata == NULL)
return -EINVAL;

phy->pdata->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
GPIOD_OUT_HIGH);


if (IS_ERR(phy->pdata->reset_gpio))
return PTR_ERR(phy->pdata->reset_gpio);

/* Optional: next three used for MCS synchronization */
phy->pdata->sync_gpio = devm_gpiod_get_optional(&spi->dev, "sync",
GPIOD_OUT_LOW);
if (IS_ERR(phy->pdata->sync_gpio))
return PTR_ERR(phy->pdata->sync_gpio);

phy->pdata->cal_sw1_gpio = devm_gpiod_get_optional(&spi->dev, "cal-sw1",
GPIOD_OUT_LOW);
if (IS_ERR(phy->pdata->cal_sw1_gpio))
return PTR_ERR(phy->pdata->cal_sw1_gpio);

phy->pdata->cal_sw2_gpio = devm_gpiod_get_optional(&spi->dev, "cal-sw2",
GPIOD_OUT_LOW);
if (IS_ERR(phy->pdata->cal_sw2_gpio))
return PTR_ERR(phy->pdata->cal_sw2_gpio);


phy->current_table = -1;
phy->bypass_tx_fir = true;
phy->bypass_rx_fir = true;
phy->rate_governor = 1;
phy->rfdc_track_en = true;
phy->bbdc_track_en = true;
phy->quad_track_en = true;

phy->gt_info = ad9361_adi_gt_info;

ad9361_request_gt(phy, NULL);

ad9361_reset(phy);


ret = ad9361_spi_read(spi, REG_PRODUCT_ID);
if ((ret & PRODUCT_ID_MASK) != PRODUCT_ID_9361) {
dev_err(&spi->dev, "%s : Unsupported PRODUCT_ID 0x%X",
__func__, ret);
return -ENODEV;

}

rev = ret & REV_MASK;

if (spi_get_device_id(spi)->driver_data == ID_AD9364) {
phy->pdata->rx2tx2 = false;
phy->pdata->rx1tx1_mode_use_rx_num = 1;
phy->pdata->rx1tx1_mode_use_tx_num = 1;
}
.....................................
...全文
2383 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
皓皓在线教学 2019-12-10
  • 打赏
  • 举报
回复
你是怎么做的,交流一下
心上枫叶红 2018-07-27
  • 打赏
  • 举报
回复
引用 8 楼 woshidahuaidan2011 的回复:
没看到spidev_dt_ids在哪里定义


在spidev.c文件里面有定义,只是没有贴出来,谢谢了,不是这里的问题,已经好了。
心上枫叶红 2018-07-27
  • 打赏
  • 举报
回复
ad9361还是在/dev下面没有设备文件,但是初始化没有任何错误。在/sys/bus/spi/devices下面也有设备。我是没有把BIT流加载进去才有的错误,而且要把复位、使能、发送管脚配置正确才行。SPI核心驱动没问题,是我没有把spidev的名字对应上去。才会在SPIdev这个设备。


===========设备树===============
spi@e0006000 {
compatible = "xlnx,zynq-spi-r1p6";
reg = <0xe0006000 0x1000>;
status = "okay";
interrupt-parent = <0x3>;
interrupts = <0x0 0x1a 0x4>;
clocks = <0x1 0x19 0x1 0x22>;
clock-names = "ref_clk", "pclk";
#address-cells = <0x1>;
#size-cells = <0x0>;
is-decoded-cs = <0x0>;
num-cs = <0x3>;


ad9361-phy@0{
#address-cells = <0x1>;
#size-cells = <0x0>;
#clock-cells = <0x1>;
compatible = "adi,ad9361";
//sync-gpios = <0x4 0x63 0x0>;
reset-gpios = <0x4 0x36 0x0>;
enable-gpios = <0x4 0x37 0x0>;
txnrx-gpios = <0x4 0x38 0x0>;
reg = <0x0>;
spi-cpha;
spi-max-frequency = <0x989680>;
clocks = <0x5 0x0>;
clock-names = "ad9361_ext_refclk";
clock-output-names = "rx_sampl_clk", "tx_sampl_clk";
adi,digital-interface-tune-skip-mode = <0x0>;
adi,pp-tx-swap-enable;
adi,pp-rx-swap-enable;
adi,rx-frame-pulse-mode-enable;
adi,lvds-mode-enable;
adi,lvds-bias-mV = <0x96>;
adi,lvds-rx-onchip-termination-enable;
adi,rx-data-delay = <0x4>;
adi,tx-fb-clock-delay = <0x7>;
adi,dcxo-coarse-and-fine-tune = <0x8 0x1720>;
adi,2rx-2tx-mode-enable;
adi,frequency-division-duplex-mode-enable;
adi,rx-rf-port-input-select = <0x0>;
adi,tx-rf-port-input-select = <0x0>;
adi,tx-attenuation-mdB = <0x2710>;
adi,rf-rx-bandwidth-hz = <0x112a880>;
adi,rf-tx-bandwidth-hz = <0x112a880>;
adi,rx-synthesizer-frequency-hz = <0x0 0x8f0d1800>;
adi,tx-synthesizer-frequency-hz = <0x0 0x92080880>;
adi,rx-path-clock-frequencies = <0x3a980000 0xea60000 0x7530000 0x3a98000 0x1d4c000 0x1d4c000>;
adi,tx-path-clock-frequencies = <0x3a980000 0x7530000 0x7530000 0x3a98000 0x1d4c000 0x1d4c000>;
adi,gc-rx1-mode = <0x2>;
adi,gc-rx2-mode = <0x2>;
adi,gc-adc-ovr-sample-size = <0x4>;
adi,gc-adc-small-overload-thresh = <0x2f>;
adi,gc-adc-large-overload-thresh = <0x3a>;
adi,gc-lmt-overload-high-thresh = <0x320>;
adi,gc-lmt-overload-low-thresh = <0x2c0>;
adi,gc-dec-pow-measurement-duration = <0x2000>;
adi,gc-low-power-thresh = <0x18>;
adi,mgc-inc-gain-step = <0x2>;
adi,mgc-dec-gain-step = <0x2>;
adi,mgc-split-table-ctrl-inp-gain-mode = <0x0>;
adi,agc-attack-delay-extra-margin-us = <0x1>;
adi,agc-outer-thresh-high = <0x5>;
adi,agc-outer-thresh-high-dec-steps = <0x2>;
adi,agc-inner-thresh-high = <0xa>;
adi,agc-inner-thresh-high-dec-steps = <0x1>;
adi,agc-inner-thresh-low = <0xc>;
adi,agc-inner-thresh-low-inc-steps = <0x1>;
adi,agc-outer-thresh-low = <0x12>;
adi,agc-outer-thresh-low-inc-steps = <0x2>;
adi,agc-adc-small-overload-exceed-counter = <0xa>;
adi,agc-adc-large-overload-exceed-counter = <0xa>;
adi,agc-adc-large-overload-inc-steps = <0x2>;
adi,agc-lmt-overload-large-exceed-counter = <0xa>;
adi,agc-lmt-overload-small-exceed-counter = <0xa>;
adi,agc-lmt-overload-large-inc-steps = <0x2>;
adi,agc-gain-update-interval-us = <0x3e8>;
adi,fagc-dec-pow-measurement-duration = <0x40>;
adi,fagc-lp-thresh-increment-steps = <0x1>;
adi,fagc-lp-thresh-increment-time = <0x5>;
adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt = <0x8>;
adi,fagc-final-overrange-count = <0x3>;
adi,fagc-gain-index-type-after-exit-rx-mode = <0x0>;
adi,fagc-lmt-final-settling-steps = <0x1>;
adi,fagc-lock-level = <0xa>;
adi,fagc-lock-level-gain-increase-upper-limit = <0x5>;
adi,fagc-lock-level-lmt-gain-increase-enable;
adi,fagc-lpf-final-settling-steps = <0x1>;
adi,fagc-optimized-gain-offset = <0x5>;
adi,fagc-power-measurement-duration-in-state5 = <0x40>;
adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable;
adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll = <0xa>;
adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable;
adi,fagc-rst-gla-if-en-agc-pulled-high-mode = <0x0>;
adi,fagc-rst-gla-large-adc-overload-enable;
adi,fagc-rst-gla-large-lmt-overload-enable;
adi,fagc-rst-gla-stronger-sig-thresh-above-ll = <0xa>;
adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable;
adi,fagc-state-wait-time-ns = <0x104>;
adi,fagc-use-last-lock-level-for-set-gain-enable;
adi,rssi-restart-mode = <0x3>;
adi,rssi-delay = <0x1>;
adi,rssi-wait = <0x1>;
adi,rssi-duration = <0x3e8>;
adi,ctrl-outs-index = <0x0>;
adi,ctrl-outs-enable-mask = <0xff>;
adi,temp-sense-measurement-interval-ms = <0x3e8>;
adi,temp-sense-offset-signed = <0xce>;
adi,temp-sense-periodic-measurement-enable;
adi,aux-dac-manual-mode-enable;
adi,aux-dac1-default-value-mV = <0x0>;
adi,aux-dac1-rx-delay-us = <0x0>;
adi,aux-dac1-tx-delay-us = <0x0>;
adi,aux-dac2-default-value-mV = <0x0>;
adi,aux-dac2-rx-delay-us = <0x0>;
adi,aux-dac2-tx-delay-us = <0x0>;
};
device@1 {
compatible = "rohm,dh2228fv";
reg = <0x1>;
spi-max-frequency = <0xf4240>;
#address-cells = <0x1>;
#size-cells = <0x1>;//0
};



};
bigPillow 2018-07-26
  • 打赏
  • 举报
回复
没看到spidev_dt_ids在哪里定义
心上枫叶红 2018-07-23
  • 打赏
  • 举报
回复
引用 1 楼 zhao4zhong1 的回复:
Windows驱动开发 http://www.osronline.com/

您好,我的是Linux驱动,不是Windows。
心上枫叶红 2018-07-23
  • 打赏
  • 举报
回复
spi0: spi@e0006000 {
compatible = "xlnx,zynq-spi-r1p6";
reg = <0xe0006000 0x1000>;
status = "okay";
interrupt-parent = <&intc>;
interrupts = <0 26 4>;
clocks = <&clkc 25>, <&clkc 34>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;

device@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "spidev";
spi-cpha;
reg = <0>;
status = "okay";
spi-max-frequency = <10000000>;
};
device@1 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "spidev";
spi-cpha;
reg = <1>;
status = "okay";
spi-max-frequency = <10000000>;
};



};

spi1: spi@e0007000 {
compatible = "xlnx,zynq-spi-r1p6";
reg = <0xe0007000 0x1000>;
status = "okay";

interrupt-parent = <&intc>;
interrupts = <0 49 4>;
clocks = <&clkc 26>, <&clkc 35>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;

device@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "spidev";
spi-cpha;
reg = <0x1>;
spi-max-frequency = <10000000>;
};



};
这是我是用的设备树,不知道有没有错。
赵4老师 2018-07-23
  • 打赏
  • 举报
回复
Windows驱动开发 http://www.osronline.com/
心上枫叶红 2018-07-23
  • 打赏
  • 举报
回复
引用 6 楼 fafactx 的回复:
HDF 文件是自己跑出来的吗?这个一般 hdf跑的对。初始化就不会出问题的。
HDF是硬件那边直接给的,硬件直接裸机的AD9361的驱动能够运行,但在系统上就不行了。最后跟踪到是这个函数的rbuf的值不对,ret = spi_write_then_read(spi, &buf[0], 2, rbuf, num);

int spi_write_then_read(struct spi_device *spi,
const void *txbuf, unsigned n_tx,
void *rxbuf, unsigned n_rx)
{
static DEFINE_MUTEX(lock);
printk("====spi.c=rxbuf===\n");
int status;
struct spi_message message;
struct spi_transfer x[2];
u8 *local_buf;

/* Use preallocated DMA-safe buffer if we can. We can't avoid
* copying here, (as a pure convenience thing), but we can
* keep heap costs out of the hot path unless someone else is
* using the pre-allocated buffer or the transfer is too large.
*/
if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) {
local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx),
GFP_KERNEL | GFP_DMA);
if (!local_buf)
return -ENOMEM;
} else {
local_buf = buf;
}

spi_message_init(&message);
memset(x, 0, sizeof(x));
if (n_tx) {
x[0].len = n_tx;
spi_message_add_tail(&x[0], &message);
}
if (n_rx) {
x[1].len = n_rx;
spi_message_add_tail(&x[1], &message);
}

memcpy(local_buf, txbuf, n_tx);
x[0].tx_buf = local_buf;
x[1].rx_buf = local_buf + n_tx;

/* do the i/o */
status = spi_sync(spi, &message);
if (status == 0)
memcpy(rxbuf, x[1].rx_buf, n_rx);
printk("=spi.c=====rxbuf:%X========\n",&rxbuf);
printk("=spi.c=====rxbuf:%X========\n",rxbuf);
if (x[0].tx_buf == buf)
mutex_unlock(&lock);
else
kfree(local_buf);

return status;
}
EXPORT_SYMBOL_GPL(spi_write_then_read);
文虫并雕 2018-07-23
  • 打赏
  • 举报
回复
HDF 文件是自己跑出来的吗?这个一般 hdf跑的对。初始化就不会出问题的。
心上枫叶红 2018-07-23
  • 打赏
  • 举报
回复
引用 4 楼 zhao4zhong1 的回复:
不过还是谢谢您。
赵4老师 2018-07-23
  • 打赏
  • 举报
回复

1,318

社区成员

发帖
与我相关
我的任务
社区描述
主要是开发驱动技术
社区管理员
  • 驱动程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧