Mikrobus

mikroBUS is a standard specification by MikroElektronika that can be freely used by anyone following the guidelines. It includes SPI, I2C, UART, PWM, ADC, reset, interrupt, and power (3.3V and 5V) connections to common embedded peripherals.

This page is meant to foster discussion within the embedded Linux community on usage of mikroBUS compatible add-on boards, adding mikroBUS sockets to embedded Linux systems, and ways to improve both Linux support for mikroBUS and the mikroBUS standard.

Usage of mikroBUS compatible add-on boards today
Many drivers for mikroBUS add-on boards already exist in the kernel, but using them can be a challenge. The most straight-forward method for loading existing drivers is to provide device tree overlay fragments at boot time, which is reasonably supported by mainline Linux. There are some out-of-tree efforts to load device tree overlay fragments at run time or to use the Greybus simulator to generate new instances of the embedded buses used on a mikroBUS socket.

Device tree overlays loaded at boot time
Today, there is no mainline solution for enabling mikroBUS add-on boards at run-time, so they must all be configured at boot-time with device trees.

Instructions for PocketBeagle: https://github.com/beagleboard/pocketbeagle/wiki/Click-boards%E2%84%A2

Example overlay: https://github.com/beagleboard/bb.org-overlays/blob/master/src/arm/PB-I2C2-MPU-9DOF-CLICK.dts

This is the primary mechanism for enumerating device drivers for mikroBUS add-on boards today. It suffers from the need to maintain a large out-of-tree database for which you'd need an overlay for every mikroBUS add-on board for every Linux system for every mikroBUS socket on that system. Multiplying 1,000 Click boards by the number of BeagleBoard.org boards by the number of sockets supported on each of those boards ends up being a LOT of device tree overlay fragments.

Further, the application of those fragments is rather error-prone and can even result in preventing a system from booting.

Run-time device tree overlays
There are some out-of-tree mechanisms for loading device-tree overlay fragments via ConfigFS.

This patch doesn't apply after 4.14 and is not likely to be accepted in mainline. Mainline doesn't want arbitrary device-tree fragments, but there is a chance that this could be considered a "development-only" patch if this is rebased. The solution would allow run-time loading, but would not be automatic and requires authoring of overlay fragments specific to every add-on board, every Linux platform and every mikroBUS socket.

Using Greybus simulator to enable software hotplug support
It is possible to enumerate some device drivers for mikroBUS add-on boards by running the Greybus simulator, gbsim. Instructions for setting up gbsim and more information can be found in a wiki write-up on a GSoC project. This method uses Greybus simulator to load a manifest blob to the kernel greybus driver where the virtual interfaces(SPI/I2C/other) are created.

gbsim manages the transfers between the physical bus/gpio/interrupt and the virtual Greybus interface. Having a userspace application, gbsim, in the middle of the transactions has a performance and security impact.

This approach requires additional platform data for instantiating device drivers for mikroBUS add-on boards with platform data requirements like reset, interrupt-gpio, and other named-gpio, thus the approach needs more refinements to tackle the issues of instantiating devices with additional platform data requirements. A few approaches to solve this problem are discussed here.

Using Greybus to enumerate drivers for mikroBUS add-on boards has an added advantage of using different transports which makes it ideal for IoT applications. A transport could be a wired or wireless network, in addition to more flexible embedded busses like Unipro.

Motivation for supporting software hotplug
By supporting hotplug, the time to develop and debug support for various mikroBUS add-on boards can be greatly reduced. Further, it opens up the possibility for support under dynamically instantiated buses such as with Greybus.

Creation of a mikroBUS bus driver in the Linux kernel
This approach does not involve the use of greybus directly but uses the greybus manifests for providing the platform data, it is actually a combination of the Greybus manifest parsing logic combined with the working of Bone Cape Manager used in the previous BB kernels, the Cape Manager used to load the data for a cape from the Device Tree whereas this bus driver takes the data from the manifest blob passed via the SysFS interface.The Mikrobus port information for the device is parsed from the Device Tree(this information only account for the port information and does not have any click specific information).

Identifier
Adding an identifier would provide a way to load the device drivers for a mikroBUS add-on board without the need for manual configuration. By fetching the identifier in the mikroBUS bus driver probe function, would enable that function to call the probe function in the various device drivers.

Proposal #1: Use Greybus Manifest binaries

 * Module vendor specified separately from driver usage
 * Possibility of using existing driver names for invocation

Proposal #2: Use simple string identifiers

 * Requires table to be kept in kernel
 * Fix-ups would be very direct and not "fix-ups" at all, since no driver specific information would be encoded

Proposal #3: mikroBUS Specific Manifest Binaries

 * Provides a way to encode all the device information in click, uses mikrobus specific manifest
 * Driver specific platform data passed to the drivers through the Unified Device Properties Interface for ACPI and Device Trees
 * Drivers must use the device_get_* calls to read the properties instead of the of_get_* calls.
 * Manifest will be able to encode all the properties under linux/property.h

Specifics on power function
The direction and accommodations related to the power pins aren't as specific in the mikroBus standard as with Feather.

Usage of improved mikroBUS support in Linux and mikroBUS standard
Assuming all of the suggestions above are implemented, what would the resulting usage be?

Adding a mikroBUS socket to your Linux system
Once the mikroBUS driver is implemented, the device tree fragment for a particular mikroBUS socket will have a basic structure like this:

mikrobus@f00 { #address-cells = <1>; #size-cells   = <0>; compatible    = "mikroe,mikrobus"; pinctrl-0     = <&mikrobus0_pins>; /*contains the pin information of the SPI/I2C/UART ports, for pinmux configuration*/ eeprom        = <&eeprom_phandle>; i2c-port      = <&i2cN>; spi-port      = <&spiN>; uart-port     = <&uartN>; int-gpio      = <&gpioN M 0>; pwm-gpio      = <&gpioN M 0>; rst-gpio      = <&gpioN M 0>; status        = "okay"; };

mikroBUS add-on board device tree fragment
Assuming we are using a MPU9DOF Click, the device tree fragment would look something like this:

/dts-v1/; /plugin/;

/ {	&mikrobus_i2c { status = "okay"; #address-cells = <1>; #size-cells = <0>; mpu9150@69 { compatible = "invensense,mpu9150"; reg = ; interrupt-parent = <&mikrobus_int>; interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; /* 0 is the first interrupt signal, next is the type */ i2c-gate { #address-cells = <1>; #size-cells = <0>; ax8975@c { compatible = "ak,ak8975"; reg = ; };			};		};	}; };

Because we have a mikroBUS socket defined, the references to bus drivers and gpio drivers are no longer board or socket dependent, so this can be universal for all consumption of this mikroBUS add-on board. Symbols will need help being resolved against the individual mikroBUS instance as they are left generic.

The mikroBUS driver will need to know to make any adjustments to pinmux settings to satisfy the interface needs. Those cannot be handled generically across platforms.

Greybus Manifest
If you are using Greybus to instantiate the embedded buses used for your mikroBUS socket, you'll need to create a Greybus manifest to enumerate those buses to Linux. The Greybus manifest format for a MPU9DOF Click would be a structure like this:

[manifest-header] version-major = 0 version-minor = 1

[module-descriptor] vendor = 0xffff product = 0x0001 version = 1 vendor-string-id = 1 product-string-id = 2 unique-id = 0

[string-descriptor 1] string = "MikroElektronika"
 * Vendor string (id can't be 0)

[string-descriptor 2] string = "MPU 9DOF Click"
 * Product string (id can't be 0)

[bundle-descriptor 1] class = 0x0a device-driver-descriptor-id = 1
 * Bundle 1

[cport-descriptor 1] bundle = 1 protocol = 0x03
 * I2C protocol on CPort 1

[cport-descriptor 2] bundle = 1 protocol = 0x02
 * GPIO protocol on CPort 2

[string-descriptor 3] string = "mpu9150"
 * Device driver name

[device-driver-descriptor 1] class = 0x3 ; I2C address = 0x68 ; Only used for applicable busses irq = 1 ; Used, IRQ_RISING reset = 0 ; Not used device-driver-string-id = 3
 * Device driver descriptor
 * -- operates on a platform consuming all of the interfaces provided for this bundle
 * -- assumes things like IRQ and RESET aligned with Mikrobus specification

If you are using Greybus to instantiate the embedded buses used for your mikroBUS socket, you'll need to create a Greybus manifest to enumerate those buses to Linux. Another example for a manifest in which the mikroBUS driver will replace/substitute a mikroBUS port specific resource is shown below for the OLEDC Click :

[manifest-header] version-major = 0 version-minor = 1

[module-descriptor] vendor = 0xffff product = 0x0001 version = 1 vendor-string-id = 1 product-string-id = 2 unique-id = 0

[string-descriptor 1] string = "MikroElektronika"
 * Vendor string (id can't be 0)

[string-descriptor 2] string = "OLEDC Click"
 * Product string (id can't be 0)

[bundle-descriptor 1] class = 0x0a device-driver-descriptor-id = 1
 * Bundle 1

[cport-descriptor 1] bundle = 1 protocol = 0x0b
 * SPI protocol on CPort 1

[string-descriptor 3] string = "RESET"
 * GPIO string

[cport-descriptor 2] bundle = 1 protocol = 0x02 gpio-string-id = 3
 * GPIO protocol on CPort 2

[string-descriptor 4] string = "PWM"
 * GPIO string

[cport-descriptor 3] bundle = 1 protocol = 0x02 gpio-string-id = 4
 * GPIO protocol on CPort 3

[string-descriptor 5] string = "ssd1351"
 * Device driver name

[device-display-driver-descriptor 1] width=128 height=128 fps=40 regwidth=8 buswidth=8 backlight=2 debug=3
 * Device display driver properties
 * -- For a given class of device driver needing extra properties, the manifest needs to be extended to support
 * a data structure for those properties. This provides me with serious concerns regarding the need to align
 * with kernel version as this isn't part of an standard interface today to the best of my knowledge.

[device-driver-descriptor 1] class = 0xb ; SPI -- QUESTION -- should this be a fbtft or drmtiny driver SPI? Which subsystem is called to load the driver? address = 0 ; Not used irq = 1 ; Used, IRQ_RISING reset = 0 ; Not used device-driver-string-id = 5 device-display-driver-descriptor-id = 1
 * Device driver descriptor
 * -- operates on a platform consuming all of the interfaces provided for this bundle
 * -- assumes things like IRQ and RESET aligned with mikroBUS specification
 * . we need some kind of indexing and substitution when these assumptions aren't enough see %GPIO=RESET%
 * . the GPIO string names can be defined by us for mikroBUS and stored as part of the GPIO line namessfa

Classes
I think the only relevant class for us is "BRIDGED_PHY" as we are just connecting the buses that are defined. We might need to come up with a new class though.

Protocols
Here are the relavent prototols:

Mikrobus Manifest
The mikroBUS click manifest can be used to describe the devices in a Click Board, the manifest creation tool will be able to read a JSON/YAML manifest source and create the manifest binary blob, the mikroBUS manifest source for MPU9DOF Click would have a structure like this:

JSON Format
{	"Version": "1.0", "Type" : "click", "Name" : "mpu9dof", "GPIOConfig" : { "INT" : "IRQ_RISING" },	"Devices" : [ {				"compatible" : "mpu9150", "class" : "I2C", "address" : "0x68", "IRQ" : "INT" }		] }

YAML Format
--- Version: '1.0' Type: click Name: mpu9dof GPIOConfig: INT: IRQ_RISING Devices: - compatible: mpu9150 class: I2C address: '0x68' IRQ: INT

Another example for a manifest in which the mikroBUS driver will replace/substitute a mikroBUS port specific resource is shown below for the OLEDC Click :

OLEDC Click JSON Format
{	"Version": "1.0", "Type" : "click", "Name" : "oledc", "GPIOConfig" : { "INT" : "HIGH" }, 	"Devices" : [		{			"Compatible" : "ssd1351", "Class" : "SPI", "Properties" : [				{					"Name" : "width", "Value" : 128 },				{					"Name" : "height", "Value" : 128 },       	                {					"Name" : "fps", "Value" : 40 },       	                {					"Name" : "regwidth", "Value" : 8 },       	                {					"Name" : "buswidth", "Value" : 8 },                               {					"Name" : "backlight", "Value" : 2 },                               {					"Name" : "backlight", "Value" : 2 },                               {					"Name" : "debug", "Value" : 3 },                               {					"Name" : "reset-gpios", "Replace" : "RST" },                               {					"Name" : "dc-gpios", "Replace" : "PWM" }               ]		}     ] }
 * Currently only the GPIO descriptors will need to be replaced by the driver for different ports
 * A name:value interface for the properties will be enabled with the following assumptions (numbers are u32 values, an array of numbers are considered u32 arrays, replace will be modified to name:&reference)
 * Currently manifest supports only inline properties, non-inline properties can be implemented in future to support more clicks if required.
 * Devices field is an array because a single click may have multiple devices in it, say for example the Waveform Click.
 * GPIOConfig field sets up the mikroBUS port so as to take care of GPIO signals (like Enable,Reset on the device) that won't be taken care of by the corresponding device driver.
 * TODO: Manifest Binary Description

mikroBUS Driver Sysfs Entries
The mikroBUS driver provides a few SysFS entries, a few of them are just debug interfaces for loading manifest binaries, adding a mikrobus port dynamically .etc, the sysfs directory structure of the mikroBUS driver is as below:




 * The add_port and del_port under the mikroBUS base directory can be used to supply config for adding/deleting a mikroBUS port dynamically.
 * The new_device entry under the mikrobus adapter is the debug interface for supplying the click manifest to the driver.

The mikroBUS driver also creates necessary symlinks to bring all the devices in a single click together under the same directory under the port(MPU9DOF Click shown as example):



Comparisons to other popular embedded add-on form-factors
The purpose of this page is to advance the development of mikroBUS support in Linux. Some distractions may be introduced to either illustrate the effort cannot be sufficiently limited in scope to tackle or that focus should be elsewhere. I'm not assuming these would be introduced with any ill-will, they are just natural concerns that need to be addressed up-front.

Why should mikroBUS be a bus in the kernel even if these other interfaces aren't?

 * mikroBUS is simple, not requiring the need to overlay arbitrary device trees like Capes or other excessively flexible interfaces defined arbitrary collections of microcontroller pins.
 * mikroBUS a free standard and not an ad-hoc one.
 * Over 750+ Click add-on boards ranging from wireless connectivity clicks to Human Machine Interface clicks, of which more than 100+ clicks already have support in the Linux kernel.
 * Over 140+ Development boards supported.

Definitions
