3
votes

I'm new with Android developpemnent but I want to write a SPI driver to connect a SPI IC and then an Android application to send and receive data from and to the IC.

From there, I don't really know where to create the driver (and what it should contain) and how to link an application in top of that. I have a customisable Android kernel (9.0 Pie, APQ8096_LA.UM.7.5.r1-03100-8x96.0_P_v5.0) with all its .dts, .dtsi, .c, and so on. I also got an eval board and the adequate documentation for the mapping.

I googled for a week and didn't found what I was looking for. I learned a bit about the device tree system. Since I have a Snapdragon 820 msm8996, I modified "msm8996-blsp.dtsi" and "msm8996-pinctrl.dtsi". I had this bit of code:

msm8996-pinctrl.dtsi

&soc {
...
    spi_0 {
        spi_0_active: spi_0_active {
            spi_0 {
                pins = "gpio0", "gpio1", "gpio2", "gpio3";
                function = "blsp_spi1";
                drive-strength = <6>;
                bias-disable;
            };

        };

        spi_0_sleep: spi_0_sleep {
            spi_0 {
                pins = "gpio0", "gpio1", "gpio2", "gpio3";
                function = "blsp_spi1";
                drive-strength = <6>;
                bias-disable;
            };
        };
    };
...          

msm8996-blsp.dtsi

&soc {
...
    spi_0: spi@7575000 { //QUP Base address for BLSP1_QUP0
        compatible = "qcom,spi-qup-v2"; //Manufacturer and Model
        #address-cells = <1>;
        #size-cells = <0>;
        reg-names = "spi_physical", "spi_bam_physical";
        reg = <0x07575000 0x600>,
        <0x07544000 0x2b000>;
        interrupt-names = "spi_irq", "spi_bam_irq";
        interrupts = <0 95 0>, <0 238 0>;
        spi-max-frequency = <5000000>; //Maximum supported frequency in HZ
        qcom,infinite-mode = <0>;
        qcom,use-bam; // Enable BAM mode
        /* Add BAM pipes */
        qcom,bam-consumer-pipe-index = <12>;
        qcom,bam-producer-pipe-index = <13>;
        qcom,ver-reg-exists;
        qcom,master-id = <86>;
        qcom,use-pinctrl;
        pinctrl-names = "spi_default", "spi_sleep";
        pinctrl-0 = <&spi_0_active>;
        pinctrl-1 = <&spi_0_sleep>;
        clock-names = "iface_clk", "core_clk";
        clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
        <&clock_gcc clk_gcc_blsp1_qup1_spi_apps_clk>;
        status = "enabled";
    }
...

I build this kernel with

$ ./build.sh msm8996 -j $(nproc)

I flashed my eval board with fastboot and then I went in adb.

$ adb root
$ adb wait-for-device
$ adb shell
# cd /sys/class/spi_master
# ls
// Nothing here

Considering my spi adress is defined at @7575000, I expected the output to be

# spi_0

Is my code correct to enable it (I'm not good with device tree yet)? If so, why isn't visible with adb and how should I make it visible? What should be the next steps to access this SPI with an Android application?

I searched stackoverflow and so many places, but writing device drivers for Android doesn't seem to be common...

1
@Fantômas Why did you edit out the "Android" in the title?fleclerc
Because there's absolutely no need of repeating a TAG in the TITLE.Phantômaxx
Meta references for title editing: this one and also this, and probably a few others. Although I don't mind leaving in product/software names if it flows as part of an ordinary English sentence, the <title> of this page is prefixed with android already, as that is the question's primary tag.halfer
So this is about SPI controller driver (vs. SPI device driver). Device tree files "tell" Linux device driver subsystem which values to pass to which driver (spi controller base address to which spi controller driver). Driver will still have a _probe() function to check the peripheral is responding as expected and initialise it - if that fails, you won't have an spi_master in sysfs. How confident are you with C and kernel compilation? Could you add printk's to driver's probe()? Or before that, check that spi master driver actually knows your device tree strings (I believe "compatible" is used).domen
@domen If I understand, there are 2 layers of "kernel" drivers: drivers (call it custom driver) which communicate with device/peripheral drivers (i.e. SPI, data bus, memory, etc). So, I would need to write a custom driver to communicate in a structured way with my device by passing through android SPI device driver? For the C language, I'm completely confident with it, but not at all with kernel compilation, it's my first time with it.fleclerc

1 Answers

0
votes

There is no need for you to write a SPI driver for snapdragon it is already in the kernel. Maybe you need to write something to connect it to your device.

The easiest way to expose a spi controller to userspace is by mapping spidev to your device

There must be support for this in your kernel (which is added with the CONFIG_SPI_SPIDEV=y config flag) and in the device tree under the bus

Something like this:

&spi_0 {
   spidev@1 {
      #address-cells = <1>;
      #size-cells = <1>;
      compatible = "linux, spidev";
      spi-max-frequency = <20000000>;
      reg = <1>;   
   };
};

The device tree is compiled together with the kernel and contains among other things your gpio mappings and DMA configurations so the same kernel can serve multiple boards. Make sure android is using your newly compiled kernel and device tree, sometimes it accidentally builds with one of the prebuilt kernels.

After those steps you should have a /dev/spidev0.0 (or some other number) in /dev With ioctl complex operations can be used.

To verify if your software have full connection to your SPI bus connect a wire from MOSI to MISO the SPI writeread command will echo the same data it receives - remove the wire and verify there is nothing.

At this point should you start communicate with your sensor, and develop its control software.

In above case I would have started to check the log prints from kernel booting to verify it identifies the hardware correctly and the driver is loaded.