Multiple SPI Kernel Drivers on the Same SPI Bus?

Background

I have a Beagle Bone Black cape with both a Nordic nRF51822 and TI CC2520. Both of these devices are on the SPI0 bus. I have kernel drivers that work for each separately on Debian 3.8.13.

Goal

I would like to be able to load both kernel drivers at the same time and have them share the SPI bus.

Issue

While I have figured out how to make each kernel driver take control of the SPI0 bus when loaded separately, I can’t seem to get them to each have access when loaded together. I’m far from an expert on device tree overlays and am not sure how to glue everything together so that the kernel drives are successfully loaded.

Here is my code so far in the kernel driver that pertains to creating the SPI device for the nRF51822. I create a struct spi_driver with config information and then call module_spi_driver() to init, etc. (copied from /linux/drivers/net/ieee802154/cc2520.c). The probe() function callback sets up a character device and configures some GPIOs (that code needs to be updated to work with device tree, but for now it should be fine).

`
static int nrf51822_spi_probe(struct spi_device *spi_device)
{
ERR(KERN_INFO, “Inserting SPI protocol driver.\n”);
nrf51822_spi_device = spi_device;

//
// Create a buffer to move data over the character device
//

//
// Setup the interrupt from the nRF51822
//

//
// Configure the character device in /dev
//

return 0;
}

static int nrf51822_spi_remove(struct spi_device *spi_device)
{
ERR(KERN_INFO, “Removing SPI protocol driver.”);
nrf51822_spi_device = NULL;

// Free memory and close things
}

static const struct spi_device_id nrf51822_ids = {
{“nrf51822”, },
{},
};
MODULE_DEVICE_TABLE(spi, nrf51822_ids);

static const struct of_device_id nrf51822_of_ids = {
{.compatible = “brad,nrf51822”, },
{},
};
MODULE_DEVICE_TABLE(of, nrf51822_of_ids);

// Configure SPI
static struct spi_driver nrf51822_spi_driver = {
.driver = {
.name = nrf51822_name,
.owner = THIS_MODULE,
.bus = &spi_bus_type,
.of_match_table = of_match_ptr(nrf51822_of_ids),
},
.id_table = nrf51822_ids,
.probe = nrf51822_spi_probe,
.remove = nrf51822_spi_remove,
};

// This I believe will load this driver correctly
// and cause it to be probed when it is needed.
module_spi_driver(nrf51822_spi_driver);

MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

`

And here is my attempt at a device overlay. I’m only claiming a single GPIO which I use as an interrupt from the nRF51822 back to the beagle bone.

`
/dts-v1/;
/plugin/;

/ {
compatible = “ti,beaglebone”, “ti,beaglebone-black”;

/* identification */
part-number = “BB-BONE-NRF51822”;
version = “00A0”;

/* state the resources this cape uses /
exclusive-use =
/
the pin header uses */

/* GPIO /
“P9.16”, /
Interrupt from NRF51822 */

/* the hardware ip uses */
“gpio1_19”;

fragment@0 {
target = <&am33xx_pinmux>;
overlay {
bb_cc2520_gpio_pins: pinmux_bb_2520_gpio_pins {
compatible = “nrf51822”;
pinctrl-single,pins = <
/* GPIO /
0x04C 0x2F /
ehrpwm1b.gpio1_19, INPUT | MODE7 */

;
};
};
};

fragment@1 {
target = <&ocp>;
overlay {
nrf51822 {
compatible = “brad,nrf51822”;

/* the power control gpio */
interrupt-gpio = <&gpio1 19 0x0>;

/* the muxing */
pinctrl-names = “default”;
pinctrl-0 = <&nrf51822_pins>;
};
};
};
};
`

The end effect is that my probe() function in the kernel driver is never called, even after loading the overlay and kernel module.

How do I set things up so that two kernel modules can both use SPI0? Has anyone tried this? Everything I’ve looked at appears to assume only one device is attached to the SPI bus so it can specify the SPI pins in its .dts file (but I could be wrong about that).

Thanks for any help or direction.

You don’t say where your got the drivers, I couldn’t find either in linux-3.16.1.
Under normal use spi0 will be controlled by spi/spi-omap2-mcspi.c, as indicated by its inclusion of the compatible entry “ti,omap4-mcspi”. See am33xx.dtsi for the definition of this term.
By using modprobe, etc. you are bypassing this logic.
I believe you may need a master driver that will control the bus, and slave drivers that can manage each device. They could communicate using some kind of message passing.

I think you are making this much more difficult than it needs to be. The standard linux SPI device works fine for talking to any slave device. What you need to do is to connect one device to CS0 and the other device to CS1, and then tell the (one) driver to use one or the other chip select when you open() the slave. If you had two drivers controlling the same SPI hardware, then you could interleave register accesses! You don’t want to do that. You want each SPI read, write, or ioctl to access one of your devices in an atomic manner.

If the standard SPI driver you are using does not support anything but CS0, then you need to add support for the other chip select.

use GPIO as slave selects
http://www.nagavenkat.adurthi.com/2014/02/spi-communication-beaglebone-black-as-master-to-arduino-as-slave/

There is always a tradeoff between the more direct path and a modular one. Having a single driver for multiple ICs would work, but makes it harder to compose different combinations of those ICs in the future. But if that is the most feasible path for now, so be it.

As for issues with multiple SPI drivers using the same bus as the same time, I think the underlying SPI driver in Linux should handle this. Per include/linux/spi/spi.h:

`

<b><i>* A @spi_message is used to execute an atomic sequence of data transfers,</i></b>
<b><i>* each represented by a struct spi_transfer.  The sequence is "atomic"</i></b>
<b><i>* in the sense that no other spi_message may use that SPI bus until that</i></b>
<b>_* sequence completes._</b>

`

It’s possible that having one control SPI driver is the solution. However, that absolutely feels like something the OS should do, given what a shared bus is.