MFD Device Tree Binding Guide- Free Linux Device Drivers Tutorial

MFD Device Tree Binding Guide
Free Linux Kernel Development Course · Free Linux Device Drivers Course · Free Embedded Linux Course
Lecture 2 of 3
Kernel 6.x
Original DT + Code Demo
linux mfd device tree binding
free linux kernel development course
free linux device drivers course
of_compatible mfd_cell
free embedded systems course

This lecture on MFD device tree binding continues the free linux kernel development course by connecting the mfd_cell array from the previous lecture to real device tree nodes. You will learn how a single MFD parent node in the device tree describes child nodes for each sub-function, and how the kernel automatically matches those child nodes to the right cell using of_compatible and the child node’s reg property.

What You Will Learn

  • How an MFD parent device tree node and its children are structured
  • How #address-cells/#size-cells and reg apply inside an MFD node
  • Two ways the kernel matches DT child nodes to mfd_cell entries
  • How to extend the original ep_mfd_demo driver with a matching device tree overlay

Prerequisites

  • Completed Lecture 1: Linux MFD Subsystem Explained
  • Comfortable reading and writing basic device tree source (.dts) syntax from this course’s device tree chapter

Why MFD Nodes Need Child Nodes

A device tree describes physical hardware, and an MFD chip is physically one device on the bus. So the device tree represents it as one parent node — matching the MFD core driver’s of_device_id table — with one child node per sub-function. Each child node’s compatible string is what the MFD core compares against each cell’s of_compatible field to decide which platform device belongs to which node.

Device Tree Structure for an MFD Node
i2c-bus node
mfd-demo@50  compatible = “ep,mfd-demo”
led  compatible = “ep,mfd-led”
status  compatible = “ep,mfd-status”

Two Matching Strategies Used by the MFD Core

Strategy How it works When to use it
Compatible-string matching MFD core walks the parent node’s children looking for a node whose compatible equals cell->of_compatible Sub-functions with no numeric address, e.g. an LED or status cell
Reg-based matching MFD core compares the child node’s reg property against cell->of_reg when cell->use_of_reg is set Sub-functions that live at a specific offset inside a shared register map, such as syscon-backed cells

Original Device Tree Example

The following overlay matches the ep_mfd_demo driver built in Lecture 1. It is written for an I2C-attached MFD chip; adapt the bus node to your board.

/* ep-mfd-demo.dtsi — original EmbeddedPathashala teaching overlay */
&i2c1 {
	status = "okay";

	mfd_demo: mfd-demo@50 {
		compatible = "ep,mfd-demo";
		reg = <0x50>;
		#address-cells = <1>;
		#size-cells = <0>;

		mfd_led: led {
			compatible = "ep,mfd-led";
		};

		mfd_status: status {
			compatible = "ep,mfd-status";
		};
	};
};

Notice that #address-cells and #size-cells are declared on the parent node even though this example does not use numeric reg matching for its children — it is good practice to declare them whenever a node has children, so the binding stays consistent if a reg-based cell is added later.

Extending the Cell Table for of_compatible Matching

// unchanged from Lecture 1 — of_compatible strings must match the DTS exactly
static const struct mfd_cell ep_mfd_cells[] = {
	{ .name = "ep-mfd-led",    .of_compatible = "ep,mfd-led" },
	{ .name = "ep-mfd-status", .of_compatible = "ep,mfd-status" },
};

Build and Test Steps

# Compile the overlay (adjust paths to your board's dts include tree)
dtc -@ -I dts -O dtb -o ep-mfd-demo.dtbo ep-mfd-demo.dtsi

# On boards using U-Boot overlays, copy the dtbo to the overlays directory
sudo cp ep-mfd-demo.dtbo /boot/overlays/

# After reboot, confirm the parent and child nodes are visible
ls /proc/device-tree/i2c@*/mfd-demo@50/
# expect: led  status  compatible  reg  name  ...

# Load the core driver from Lecture 1
sudo insmod ep_mfd_demo.ko

# Confirm both child platform devices exist
ls /sys/bus/platform/devices/ | grep -i ep-mfd

Expected Output

ep-mfd-led.0.auto
ep-mfd-status.1.auto

Each name ends in .auto because the driver used PLATFORM_DEVID_AUTO; the MFD core assigned the numeric suffix automatically when it created the platform devices from the matched device tree children.

Common Mistakes

  • Compatible string typos between the DTS child node and the driver’s of_compatible field — matching is exact and case-sensitive
  • Leaving out #address-cells/#size-cells on the parent when children later need numeric reg values
  • Disabling a child node with status = "disabled" and expecting the cell to still register — it will be skipped
  • Confusing the MFD parent’s own reg (its I2C/SPI address) with a child cell’s of_reg offset

Best Practices

  • Give every sub-function node a clear, documented compatible string in your binding documentation
  • Prefer compatible-string matching for functionally distinct cells, and reg-based matching only for register-offset-defined sub-blocks
  • Keep the DT binding and the mfd_cell array in the same commit/patch so they never drift out of sync

Real-World Use Cases

Vendor PMIC bindings such as those for axp20x and tps65086 place regulator, RTC, and power-key child nodes directly under the PMIC’s I2C node, exactly following the pattern shown here. Understanding this binding style is essential before writing or reviewing any PMIC, audio-codec, or system-controller driver in mainline Linux.

Summary / Key Takeaways

  • The MFD parent DT node matches the core driver; child nodes represent each sub-function
  • Compatible-string matching is the common case; reg-based matching is used for register-offset cells
  • The cell table and the DT binding must be kept in sync string-for-string

Conclusion

With the device tree binding in place, the ep_mfd_demo driver from Lecture 1 now creates real, DT-backed platform devices for each sub-function. The final lecture in this mini-series introduces syscon and the simple-mfd binding, which lets you skip writing a core driver entirely for the simplest register-sharing use case.

Frequently Asked Questions

Can an MFD child node be disabled independently of the parent?

Yes. Setting status = "disabled" on a child node prevents that specific cell from being registered, while the parent and other children are unaffected.

Does every MFD cell need a reg property?

No. Only cells matched by of_reg/use_of_reg need a numeric reg; compatible-string-matched cells typically omit it.

What happens if a compatible string in the DTS has no matching cell?

The MFD core simply does not create a platform device for that node; no error is raised for an unmatched child by default.

Can I mix compatible-string and reg-based matching in the same driver?

Yes, different cells in the same array can use either matching strategy independently.

Where should I document a new MFD device tree binding?

New bindings should be documented as YAML schema files under Documentation/devicetree/bindings/mfd/ in the kernel source tree.

Do overlay-based systems like Raspberry Pi support MFD bindings?

Yes, MFD parent/child bindings work the same way whether compiled into the base DTB or loaded as a .dtbo overlay.

Continue the Free Linux Kernel Development Course

Next up: Syscon and the simple-mfd Driver

 

Leave a Reply

Your email address will not be published. Required fields are marked *