Component Helper for Aggregate Drivers

The component helper allows drivers to collect a pile of sub-devices, including their bound drivers, into an aggregate driver. Various subsystems already provide functions to get hold of such components, e.g. of_clk_get_by_name(). The component helper can be used when such a subsystem-specific way to find a device is not available: The component helper fills the niche of aggregate drivers for specific hardware, where further standardization into a subsystem would not be practical. The common example is when a logical device (e.g. a DRM display driver) is spread around the SoC on various components (scanout engines, blending blocks, transcoders for various outputs and so on).

The component helper also doesn’t solve runtime dependencies, e.g. for system suspend and resume operations. See also device links.

Components are registered using component_add() and unregistered with component_del(), usually from the driver’s probe and disconnect functions.

Aggregate drivers first assemble a component match list of what they need using component_match_add(). This is then registered as an aggregate driver using component_master_add_with_match(), and unregistered using component_master_del().

API

struct component_ops

callbacks for component drivers

Definition

struct component_ops {
  int (*bind)(struct device *comp, struct device *master, void *master_data);
  void (*unbind)(struct device *comp, struct device *master, void *master_data);
};

Members

bind
Called through component_bind_all() when the aggregate driver is ready to bind the overall driver.
unbind
Called through component_unbind_all() when the aggregate driver is ready to bind the overall driver, or when component_bind_all() fails part-ways through and needs to unbind some already bound components.

Description

Components are registered with component_add() and unregistered with component_del().

struct component_master_ops

callback for the aggregate driver

Definition

struct component_master_ops {
  int (*bind)(struct device *master);
  void (*unbind)(struct device *master);
};

Members

bind

Called when all components or the aggregate driver, as specified in the match list passed to component_master_add_with_match(), are ready. Usually there are 3 steps to bind an aggregate driver:

  1. Allocate a structure for the aggregate driver.
  2. Bind all components to the aggregate driver by calling component_bind_all() with the aggregate driver structure as opaque pointer data.
  3. Register the aggregate driver with the subsystem to publish its interfaces.

Note that the lifetime of the aggregate driver does not align with any of the underlying struct device instances. Therefore devm cannot be used and all resources acquired or allocated in this callback must be explicitly released in the unbind callback.

unbind
Called when either the aggregate driver, using component_master_del(), or one of its components, using component_del(), is unregistered.

Description

Aggregate drivers are registered with component_master_add_with_match() and unregistered with component_master_del().

void component_match_add(struct device * master, struct component_match ** matchptr, int (*compare) (struct device *, void *, void * compare_data)

add a component match entry

Parameters

struct device * master
device with the aggregate driver
struct component_match ** matchptr
pointer to the list of component matches
int (*)(struct device *, void *) compare
compare function to match against all components
void * compare_data
opaque pointer passed to the compare function

Description

Adds a new component match to the list stored in matchptr, which the master aggregate driver needs to function. The list of component matches pointed to by matchptr must be initialized to NULL before adding the first match. This only matches against components added with component_add().

The allocated match list in matchptr is automatically released using devm actions.

See also component_match_add_release() and component_match_add_typed().

void component_match_add_release(struct device * master, struct component_match ** matchptr, void (*release) (struct device *, void *, int (*compare) (struct device *, void *, void * compare_data)

add a component match entry with release callback

Parameters

struct device * master
device with the aggregate driver
struct component_match ** matchptr
pointer to the list of component matches
void (*)(struct device *, void *) release
release function for compare_data
int (*)(struct device *, void *) compare
compare function to match against all components
void * compare_data
opaque pointer passed to the compare function

Description

Adds a new component match to the list stored in matchptr, which the master aggregate driver needs to function. The list of component matches pointed to by matchptr must be initialized to NULL before adding the first match. This only matches against components added with component_add().

The allocated match list in matchptr is automatically released using devm actions, where upon release will be called to free any references held by compare_data, e.g. when compare_data is a device_node that must be released with of_node_put().

See also component_match_add() and component_match_add_typed().

void component_match_add_typed(struct device * master, struct component_match ** matchptr, int (*compare_typed) (struct device *, int, void *, void * compare_data)

add a component match entry for a typed component

Parameters

struct device * master
device with the aggregate driver
struct component_match ** matchptr
pointer to the list of component matches
int (*)(struct device *, int, void *) compare_typed
compare function to match against all typed components
void * compare_data
opaque pointer passed to the compare function

Description

Adds a new component match to the list stored in matchptr, which the master aggregate driver needs to function. The list of component matches pointed to by matchptr must be initialized to NULL before adding the first match. This only matches against components added with component_add_typed().

The allocated match list in matchptr is automatically released using devm actions.

See also component_match_add_release() and component_match_add_typed().

int component_master_add_with_match(struct device * dev, const struct component_master_ops * ops, struct component_match * match)

register an aggregate driver

Parameters

struct device * dev
device with the aggregate driver
const struct component_master_ops * ops
callbacks for the aggregate driver
struct component_match * match
component match list for the aggregate driver

Description

Registers a new aggregate driver consisting of the components added to match by calling one of the component_match_add() functions. Once all components in match are available, it will be assembled by calling component_master_ops.bind from ops. Must be unregistered by calling component_master_del().

void component_master_del(struct device * dev, const struct component_master_ops * ops)

unregister an aggregate driver

Parameters

struct device * dev
device with the aggregate driver
const struct component_master_ops * ops
callbacks for the aggregate driver

Description

Unregisters an aggregate driver registered with component_master_add_with_match(). If necessary the aggregate driver is first disassembled by calling component_master_ops.unbind from ops.

void component_unbind_all(struct device * master_dev, void * data)

unbind all components of an aggregate driver

Parameters

struct device * master_dev
device with the aggregate driver
void * data
opaque pointer, passed to all components

Description

Unbinds all components of the aggregate dev by passing data to their component_ops.unbind functions. Should be called from component_master_ops.unbind.

int component_bind_all(struct device * master_dev, void * data)

bind all components of an aggregate driver

Parameters

struct device * master_dev
device with the aggregate driver
void * data
opaque pointer, passed to all components

Description

Binds all components of the aggregate dev by passing data to their component_ops.bind functions. Should be called from component_master_ops.bind.

int component_add_typed(struct device * dev, const struct component_ops * ops, int subcomponent)

register a component

Parameters

struct device * dev
component device
const struct component_ops * ops
component callbacks
int subcomponent
nonzero identifier for subcomponents

Description

Register a new component for dev. Functions in ops will be call when the aggregate driver is ready to bind the overall driver by calling component_bind_all(). See also struct component_ops.

subcomponent must be nonzero and is used to differentiate between multiple components registerd on the same device dev. These components are match using component_match_add_typed().

The component needs to be unregistered at driver unload/disconnect by calling component_del().

See also component_add().

int component_add(struct device * dev, const struct component_ops * ops)

register a component

Parameters

struct device * dev
component device
const struct component_ops * ops
component callbacks

Description

Register a new component for dev. Functions in ops will be called when the aggregate driver is ready to bind the overall driver by calling component_bind_all(). See also struct component_ops.

The component needs to be unregistered at driver unload/disconnect by calling component_del().

See also component_add_typed() for a variant that allows multipled different components on the same device.

void component_del(struct device * dev, const struct component_ops * ops)

unregister a component

Parameters

struct device * dev
component device
const struct component_ops * ops
component callbacks

Description

Unregister a component added with component_add(). If the component is bound into an aggregate driver, this will force the entire aggregate driver, including all its components, to be unbound.