How to enable SPI on Hikey 620 and get the corresponding module loaded?

I am using BMC150 magnetometer sensor on Hikey 620. I had success through I2C, but having difficulty with SPI (Driver located here : bmc150_magn_spi.c - drivers/iio/magnetometer/bmc150_magn_spi.c - Linux source code (v5.15.12) - Bootlin) .

I have enabled

CONFIG_SPI=y
CONFIG_sPI_MASTER=y
CONFIG_SPI_DESIGNWARE=y
CONFIG_SPI_DW_PCI=y
CONFIG_SPI_DW_MMIO=y
CONFIG_SPI_PL022=y
CONFIG_SPI_SPIDEV=y

and

CONFIG_BMC150_MAGN=m
CONFIG_BMC150_MAGN_SPI=m

in the kernel config.

and did the following change in device tree

                spi0: spi@f7106000 {
                        status = "ok";
+
+                       magn@0 {
+                               compatible = "spidev";
+                               spi-max-frequency = <500000>;
+                               reg=<0>;
+                               status = "ok";
+                       };
                };

But still I do not see the sensor modules getting loaded (even when I set compatible string as “bmc150”). I though see the following (when compatible string is set to “spidev”).

/ # ls /dev/spidev0.0 -la
crw-------    1 0        0         153,   0 Jan  1 00:00 /dev/spidev0.0

Please guide. I am using kernel 4.15.3 forked from https://github.com/suihkulokki/linux

Hi @insanecoder,

Couple of things:

  1. SPIDEV is an userspace utility used for testing the SPI slave devices attached to the bus. It is more like i2c-tools package (i2cdetect, i2cget…).
  2. For using a SPI kernel module, you need to use the corresponding devicetree binding. For this sensor, here is the devicetree binding:
    https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt
  3. The latest kernel source for Hikey boards are hosted here:
    manivannan.sadhasivam/linux.git - Linux kernel tree for personal upstream work

Hope this helps!

Thanks,
Mani

  1. Yes, I knew this.
  2. That binding example is mainly for I2C and it indeed worked for me as I stated. I tried taking the compatible string for SPI as “bmc150” (as defined in driver as of_device_node), but it didn’t help. Since this is the first time I am trying SPI, so to be honest I might be making some mistake in device tree definition (or maybe missing some kernel config) and hence would be very thankful if you can give an example on Hikey620.
  3. I tried the kernel pointed by you 4.19, but still the same behaviour.

This is my dmeg log :

/sys/bus/iio/devices # dmesg | grep spi
[    0.610463] ssp-pl022 f7106000.spi: ARM PL022 driver, device ID: 0x00041022
[    0.624236] ssp-pl022 f7106000.spi: BUSNO: -1
[    0.636790] ssp-pl022 f7106000.spi: mapped registers from 0x00000000f7106000 to (____ptrval____)
[    2.167869] ssp-pl022 f7106000.spi: setup for DMA on RX dma0chan0, TX dma0chan1
[    2.175332] ssp-pl022 f7106000.spi: registered master spi0
[    2.176652] spi spi0.0: allocated memory for controller's runtime state
[    2.176689] ssp-pl022 f7106000.spi: SSP Target Frequency is: 500000, Effective Frequency is 499328
[    2.176698] ssp-pl022 f7106000.spi: SSP cpsdvsr = 2, scr = 148
[    2.176706] spi spi0.0: 4 <= n <=8 bits per word
[    2.176714] spi spi0.0: DMA mode NOT set in controller state
[    2.176731] spi spi0.0: setup mode 0, 8 bits/w, 500000 Hz max --> 0
[    2.176991] ssp-pl022 f7106000.spi: registered child spi0.0
[    2.177001] ssp-pl022 f7106000.spi: probe succeeded

Something like below should help:

        soc {
                spi0: spi@f7106000 {
                        status = "ok";
                        magn@0 {
                                compatible = "bosch,bmc150b";
                                reg = <0>;
                                spi-max-frequency = <500000>;
                                cs-gpios = <>;
                        };
                };

Make sure to fill cs-gpios property as per the connection.

Additionally, you also need to patch below diff for the of_match_table based lookup:

diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c
index ed9be0490d77..a7ca9fba9489 100644
--- a/drivers/iio/magnetometer/bmc150_magn_spi.c
+++ b/drivers/iio/magnetometer/bmc150_magn_spi.c
@@ -52,12 +52,19 @@ static const struct acpi_device_id bmc150_magn_acpi_match[] = {
 };
 MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match);
 
+static const struct of_device_id bmc150_magn_of_match[] = {
+       { .compatible = "bosch,bmc150b" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, bmc150_magn_of_match);
+
 static struct spi_driver bmc150_magn_spi_driver = {
        .probe          = bmc150_magn_spi_probe,
        .remove         = bmc150_magn_spi_remove,
        .id_table       = bmc150_magn_spi_id,
        .driver = {
                .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
+               .of_match_table = bmc150_magn_of_match,
                .name   = "bmc150_magn_spi",
        },
 };

I added the of_device_id already in the driver but that didn’t work out. But cs-gpios, that’s definitely something I didn’t define in the device tree.

I have connected to pins 8,10,12 and 14 as per the pinout : 96Boards GPIO Pinout
PIN8 - Sensor clock pin
PIN10 - Sensor DIN pin
PIN12 - Sensor CSB pin
PIN14 - Sensor DOUT pin

so what should be the cs-gpio in this case. I assumed that there was only one Chip Select pin and hence I need not define it. Looks like I was wrong. Please help. I noticed that spi0 in hi6220.dtsi file defines

cs-gpios = <&gpio6 2 0>;

Do I need to define the same again in the spi device definition?

PS : reg=<0> gives compiler warning /soc/spi@f7106000/magn@0:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1), so I was using reg=<0 0 0>.

So you are using the default CS pin. Then there is no need to add cs-gpios property since it got already added in spi node.

That warning from DTC shows that the default address and size cells (2,1) are used for this node. You should define proper length as below:


        soc {
                spi0: spi@f7106000 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";
                        magn@0 {
                                compatible = "bosch,bmc150b";
                                reg = <0>;
                                spi-max-frequency = <500000>;
                        };
                };

Even with above settings, if the module is not loaded then you need to debug the driver to see what is going wrong.

I found out the real problem and it turned out to be my own stupidity. Out of nowhere, I got an idea to build the driver statically into the kernel and the probe got called. Till now I was making it as a module.

So the problem now boils down to automatic module loading which I can figure out easily. But thanks to Mani for such a great support. I and future visitors will definitely find this post helpful.

Addendum for future makers to the page:
Checkout /sys/bus/*/drivers/ to ensure that the driver is registered with the kernel or not. Best way to begin with is build the driver statically.

If building as a module :-
Manually do modprobe
or
put into init.rc to load at startup
or
use systemd to pick modules defined in /etc/modules-load.d/my_modules.conf