## ADF4350/ADF4351 Linux driver issues

Started by 2 years ago5 replieslatest reply 2 years ago375 views

Hello everyone,

I am trying to work with the adf4350 driver (its documentation by Analog Devices can be found here) on my Beaglebone board but I am experiencing some issues.

The problem I am facing is that when I load the driver, the folder

/sys/bus/iio/devices/

remains empty, and it doesn't agree to what is written in the section Driver testing, so anything is working fine.

If I am not wrong, I have two options to make it work:

Option # 1: modifying the driver source code adding the code listed into the section Declaring SPI slave devices.

Including that code into the beginning of adf4350.c driver is causing compile errors:

<code><span class="operator token">  CC [M]  drivers/iio/frequency/adf4350.o
In file included from drivers/iio/frequency/adf4350.c:16:0:
include/linux/module.h:128:27: error: redefinition of '__inittest'
static inline initcall_t __inittest(void)  \
^
include/linux/device.h:1329:1: note: in expansion of macro 'module_init'
module_init(__driver##_init); \
^
include/linux/spi/spi.h:284:2: note: in expansion of macro 'module_driver'
module_driver(__spi_driver, spi_register_driver, \
^
drivers/iio/frequency/adf4350.c:670:1: note: in expansion of macro 'module_spi_driver'
module_spi_driver(adf4350_driver);
^
include/linux/module.h:128:27: note: previous definition of '__inittest' was here
static inline initcall_t __inittest(void)  \
^
include/linux/module.h:112:28: note: in expansion of macro 'module_init'
#define arch_initcall(fn)  module_init(fn)
^
drivers/iio/frequency/adf4350.c:54:1: note: in expansion of macro 'arch_initcall'
arch_initcall(board_init);
^
include/linux/module.h:130:6: error: redefinition of 'init_module'
int init_module(void) __attribute__((alias(#initfn)));
^
include/linux/device.h:1329:1: note: in expansion of macro 'module_init'
module_init(__driver##_init); \
^
include/linux/spi/spi.h:284:2: note: in expansion of macro 'module_driver'
module_driver(__spi_driver, spi_register_driver, \
^
drivers/iio/frequency/adf4350.c:670:1: note: in expansion of macro 'module_spi_driver'
module_spi_driver(adf4350_driver);
^
include/linux/module.h:130:6: note: previous definition of 'init_module' was here
int init_module(void) __attribute__((alias(#initfn)));
^
include/linux/module.h:112:28: note: in expansion of macro 'module_init'
#define arch_initcall(fn)  module_init(fn)
^
drivers/iio/frequency/adf4350.c:54:1: note: in expansion of macro 'arch_initcall'
arch_initcall(board_init);
^
make[3]: *** [drivers/iio/frequency/adf4350.o] Error 1
scripts/Makefile.build:264: recipe for target 'drivers/iio/frequency/adf4350.o' failed
make[2]: *** [drivers/iio/frequency] Error 2
make[1]: *** [drivers/iio] Error 2
make: *** [drivers] Error 2
scripts/Makefile.build:403: recipe for target 'drivers/iio/frequency' failed
scripts/Makefile.build:403: recipe for target 'drivers/iio' failed
Makefile:947: recipe for target 'drivers' failed</span><span class="punctuation token"></span></code>

I tried other ways to use that code but no way. I can't compile it. So it's not clear to me how to use that code..

Option # 2: working with devicetree taking the example from the section Devicetree bindings. But I am not familiar with devicetree (bad !) and the example posted is incomplete or wrong because dtc refuses to compile, so I tried editing it as so:

/dts-v1/;
/ {        part-number = "adf4350";
lo_pll0_rx_adf4351: adf4351-rx-lpc@4
{
compatible = "adi,adf4351";
reg = <4>;
spi-max-frequency = <10000000>;
/* clocks = <&clk0_ad9523 9>;*/
clock-names = "clkin";
adi,channel-spacing = <10000>;
adi,power-up-frequency = <2400000000>;
adi,phase-detector-polarity-positive-enable;
adi,charge-pump-current = <2500>;
adi,output-power = <3>;
adi,mute-till-lock-enable;
};
};

I compile it with:

dtc -I dts -O dtb adf4350.dts -o adf4350.dtb

dtc returns the following warnings:

Warning (reg_format): "reg" property in /adf4351-rx-lpc@4 has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
Warning (avoid_default_addr_size): Relying on default #address-cells value for /adf4351-rx-lpc@4
Warning (avoid_default_addr_size): Relying on default #size-cells value for /adf4351-rx-lpc@4

Copying the dtb file to

/lib/firmware

and executing

echo adf4350 > /sys/devices/platform/bone_capemgr/slots

it returns the error

bash: echo: write error: No such file or directory

Of course the file slots exists.

After this large post (I tried to explain the situation the best I can), I am stuck on how to make the driver works.

Do you have any suggestion about how to solve it ?

Thank you in advance.

Regards,

Simon

#arm #linux

[ - ]
Reply by March 3, 2017

Hi Simon,

It looks that it is trying to initialise twice

redefinition of '__inittest'
static inline initcall_t __inittest(void)  \

The driver can only initialise once.

The second error is related may be relate with file access permissions or unexisting folder.

Check if the file exists in the specified location :

\$ls /sys/devices/platform/bone_capemgr/

And if exists try to execute the command again but logged in as root.

"and executing

echo adf4350 > /sys/devices/platform/bone_capemgr/slots

it returns the error

bash: echo: write error: No such file or directory

Of course the file slots exists."

Hope that helps,

Pedro.

[ - ]
Reply by March 3, 2017

Hi Pedro,

Regarding the devicetree modification (2nd error), I did all with root permissions.

So I think the problem is strictly related with the dts code.

Regarding the compilation error (1st error), I understand that the driver cannot be loaded twice.

Also, inserting the code

#define GPIO_PF10 10
#define MAX_CTRL_CS 8

static struct spi_board_info board_spi_board_info[] __initdata =
{
#if defined(CONFIG_ADF4350) || defined(CONFIG_ADF4350_MODULE)
{
.modalias = "adf4351",
.max_speed_hz = 1000000,
.bus_num = 0,
.chip_select = GPIO_PF10 + MAX_CTRL_CS,
.platform_data = NULL,
.mode = SPI_MODE_0,
},
#endif
};

static int __init board_init(void)
{
spi_register_board_info(board_spi_board_info, ARRAY_SIZE(board_spi_board_info));
return 0;
}
arch_initcall(board_init);


into the adf4350.c file is not the correct way to do use it.

I think this code should be included in a board dedicated C file.

Simon

[ - ]
Reply by March 3, 2017

Hi Simon,

Great that your sort out the second problem. Regarding the first problem, I think the problem is related with this:

"Unlike PCI or USB devices, SPI devices are not enumerated at the hardware level. Instead, the software must know which devices are connected on each SPI bus segment, and what slave selects these devices are using. For this reason, the kernel code must instantiate SPI devices explicitly. The most common method is to declare the SPI devices by bus number.

This method is appropriate when the SPI bus is a system bus, as in many embedded systems, wherein each SPI bus has a number which is known in advance. It is thus possible to pre-declare the SPI devices that inhabit this bus. This is done with an array of struct spi_board_info, which is registered by calling spi_register_board_info().

For more information see: Documentation/spi/spi-summary

# Adding Linux driver support

Configure kernel with “make menuconfig” (alternatively use “make xconfig” or “make qconfig”)

"

Basically you will have to recompile the Kernel.

Good luck,

Pedro

[ - ]
Reply by March 4, 2017

Yes, I did not pay attention to the SPI documentation (my bad).

Thank you Pedro.

[ - ]
Reply by March 4, 2017

Hi Simon,

Let me know if you managed to sort it.

Take care,

Pedro