Post Go back to editing

Perform full reset on AD9361 from running Linux (Zynq)

I have a use-case where either,

(1) the AD9361 may go through a hard reset (toggle voltage rail)

(2) the Zynq FPGA may be reloaded while Linux is running (/dev/xdevcfg).

After this I would like to perform whatever necessary steps there are to reset everything needed to use the AD9361 again like the system is coming up out of a fresh boot.

So without doing either (1) or (2) I want to just prove I can reset everything on a working image... I'm trying to follow this older post and hope it is still relevant. The two major issues I have with this are that I can't figure out how to assert the RESETB pin as it it looks to be held up by the ADI driver and I can't seem to unbind the driver following the steps from the linked post :

~/unit_test/support # ls /sys/bus/platform/drivers/dma-axi-dmac/unbind
/sys/bus/platform/drivers/dma-axi-dmac/unbind
~/unit_test/support # echo 7c40000.dma > /sys/bus/platform/drivers/dma-axi-dmac/
unbind
sh: write error: No such device

Attempting to write to the RESETB pin using the GPIO system in Linux I get a "Device or resource busy" error (same when writing to the sync pin). I can write to the EN_AGC pin just fine.

Thanks

Some additional snippets which may/may not be useful

dmesg @ startup :

~/unit_test/support # dmesg | grep ad9361
[    5.762957] ad9361 spi32766.0: ad9361_probe : enter (ad9361)
[    6.040763] ad9361 spi32766.0: ad9361_probe : AD936x Rev 2 successfully initialized
[    7.007410] cf_axi_adc 79020000.cf-ad9361-lpc: ADI AIM (10.00.b) at 0x79020000 mapped to 0xf0bc8000, probed ADC AD9361 as MASTER
[    7.033738] cf_axi_dds 79024000.cf-ad9361-dds-core-lpc: Analog Devices CF_AXI_DDS_DDS MASTER (9.00.b) at 0x79024000 mapped to 0xf0bed000, probed DDS AD9361

relevant dts :

        // https://www.kernel.org/doc/Documentation/devicetree/bindings/dma/adi%2Caxi-dmac.txt
        rx_dma: dma@7c400000 {
                compatible = "adi,axi-dmac-1.00.a";
                reg = <0x7c400000 0x10000>;
                interrupts = <0 59 0>;
                clocks = <&clkc 16>;
                #dma-cells = <1>;
                // adi,channels {
                //     #size-cells = <0>;
                //     #address-cells = <1>;

                //     dma-channel@0 {
                //             reg = <0x0>;
                //             adi,length-width = <0x18>;
                //             adi,source-bus-width = <0x40>;
                //             adi,destination-bus-width = <0x40>;
                //             adi,source-bus-type = <0x2>;
                //             adi,destination-bus-type = <0x0>;
                //     };
                // };
                dma-channel {
                        adi,buswidth = <64>;
                        adi,type = <0>;
                };
        };

        // https://www.kernel.org/doc/Documentation/devicetree/bindings/dma/adi%2Caxi-dmac.txt
        tx_dma: dma@7c420000 {
                compatible = "adi,axi-dmac-1.00.a";
                reg = <0x7c420000 0x10000>;
                interrupts = <0 58 0>;
                clocks = <&clkc 16>;
                #dma-cells = <1>;
                // adi,channels {
                //     #size-cells = <0>;
                //     #address-cells = <1>;

                //     dma-channel@0 {
                //             reg = <0x0>;
                //             adi,length-width = <0x18>;
                //             adi,source-bus-width = <0x40>;
                //             adi,destination-bus-width = <0x40>;
                //             adi,source-bus-type = <0x0>;
                //             adi,destination-bus-type = <0x2>;
                //             adi,cyclic;
                //     };
                // };
                dma-channel {
                        adi,buswidth = <64>;
                        adi,type = <1>;
                        adi,cyclic;
                };
        };

        cf_ad9361_adc_core_0: cf-ad9361-lpc@79020000 {
                compatible = "adi,axi-ad9361-6.00.a";
                reg = <0x79020000 0x6000>;
                dmas = <&rx_dma 0>;
                dma-names = "rx";
                spibus-connected = <&adc0_ad9361>;
                xlnx,dphase-timeout = <0x8>;
                xlnx,num-mem = <0x1>;
                xlnx,num-reg = <0x1>;
                xlnx,s-axi-min-size = <0x1ff>;
                xlnx,slv-awidth = <0x20>;
                xlnx,slv-dwidth = <0x20>;
                xlnx,use-wstrb = <0x0>;
        };

        cf_ad9361_dac_core_0: cf-ad9361-dds-core-lpc@79024000 {
                compatible = "adi,axi-ad9361-dds-6.00.a";
                reg = <0x79024000 0x1000>;
                clocks = <&adc0_ad9361 13>;
                clock-names = "sampl_clk";
                dmas = <&tx_dma 0>;
                dma-names = "tx";
                dac-sample-frequency = <491520000>;
                xlnx,dphase-timeout = <0x8>;
                xlnx,num-mem = <0x1>;
                xlnx,num-reg = <0x1>;
                xlnx,s-axi-min-size = <0x1ff>;
                xlnx,slv-awidth = <0x20>;
                xlnx,slv-dwidth = <0x20>;
                xlnx,use-wstrb = <0x0>;
        };

&adc0_ad9361 {
        en_agc-gpios = <&gpio0 55 0>;
        sync-gpios = <&gpio0 56 0>;
        reset-gpios = <&gpio0 54 0>;
};



added other relevant system info
[edited by: jgutel at 9:22 PM (GMT 0) on 4 May 2020]
Parents
  • There RESETB pin is tied to the AD9361 driver, because the driver has all the proper sequence to init the driver within Linux.

    What you want to do, seems to be more along the lines of a no-OS/baremetal driver:

    https://github.com/analogdevicesinc/no-OS/tree/master/ad9361

    That would give you full control, but you also need to manually configure everything.

    One thing that is implemented in the Linux driver though, is a debugfs entry that resets the chip.

    As root:

    cd /sys/kernel/debug/iio

    cd iio:deviceX   [whichever is the ad9361]

    echo 1 > initialize

    This should perform a device reset and reconfigure.

    Not sure when this was the last time it was tested thoroughly, as this is mostly a debug/development feature.

    But the idea still holds.

    This is one of the recommended ways to do this in Linux.

Reply
  • There RESETB pin is tied to the AD9361 driver, because the driver has all the proper sequence to init the driver within Linux.

    What you want to do, seems to be more along the lines of a no-OS/baremetal driver:

    https://github.com/analogdevicesinc/no-OS/tree/master/ad9361

    That would give you full control, but you also need to manually configure everything.

    One thing that is implemented in the Linux driver though, is a debugfs entry that resets the chip.

    As root:

    cd /sys/kernel/debug/iio

    cd iio:deviceX   [whichever is the ad9361]

    echo 1 > initialize

    This should perform a device reset and reconfigure.

    Not sure when this was the last time it was tested thoroughly, as this is mostly a debug/development feature.

    But the idea still holds.

    This is one of the recommended ways to do this in Linux.

Children
  • Thanks for the reply. Unfortunately I don't have the option to use the baremetal drivers; I have to use Linux for this particular design.

    After reloading the bitstream through xdevcfg (identical bitstream that was on it previously) attempting to initialize results in,

    /sys/kernel/debug/iio/iio:device1 # echo 1 > initialize 
    [  488.266951] ad9361 spi32766.0: Failed to restore state
    [  488.307832] ad9361 spi32766.0: Failed to restore state
    [  488.325433] ad9361 spi32766.0: Failed to restore state
    /sys/kernel/debug/iio/iio:device1 # echo 1 > bist_timing_analysis 
    /sys/kernel/debug/iio/iio:device1 # cat bist_timing_analysis 
    CLK: 30720000 Hz 'o' = PASS
    DC0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:
    0:. . . . . . . . . . . . . . . . 
    1:. . . . . . . . . . . . . . . . 
    2:. . . . . . . . . . . . . . . . 
    3:. . . . . . . . . . . . . . . . 
    4:. . . . . . . . . . . . . . . . 
    5:. . . . . . . . . . . . . . . . 
    6:. . . . . . . . . . . . . . . . 
    7:. . . . . . . . . . . . . . . . 
    8:. . . . . . . . . . . . . . . . 
    9:. . . . . . . . . . . . . . . . 
    a:. . . . . . . . . . . . . . . . 
    b:. . . . . . . . . . . . . . . . 
    c:. . . . . . . . . . . . . . . . 
    d:. . . . . . . . . . . . . . . . 
    e:. . . . . . . . . . . . . . . . 
    f:. . . . . . . . . . . . . . . . 

    As suggested in another thread maybe the only way is to build the driver as a module and rmmod/insmod it before/after to reset it then? In the original question the first code snippet was an attempt to unbind it manually without having to build the driver as a module but that failed with the "No such device" error.

  • We don't typically use kmods. We typically build them as builtins into the kernel.

    rmmod/insmod works if the driver is built as a kmod.

    With some effort, it may work to use this driver as a kmod.

    The bind/unbind method doesn't always work great.

    It could for this driver though.

    I'd go with trying to make 'echo 1 > initialize' work.

  • Any suggestions to that end? Clearly simply using 'echo 1 > initialize' didn't cut it when I tried it. Can you all verify on any board you have by reproducing steps?

    1) load board with standard linux/fw 

    2) reload bitstream through /dev/xdevcfg

    3) 'echo 1 > initialize'

    After thinking about it I decided I'm just going to pull another EMIO pin and OR it with the one that is bound to the driver for asserting the ADI Reset. That way I can still manually hit it from software without mucking with the driver. Hopefully the initialize will then work.

    Update: manually asserting the reset (confirmed with an ILA) didn't change the outcome.

  • Any chance you could verify this works on your end? It's certainly not on mine. Thanks.