Skip to content

Adding support for multi-functional-devices #48934

Open
@bjarki-andreasen

Description

@bjarki-andreasen

Introduction

Currently, only one API can be mapped to each instance of a struct device. This proposal provides two solutions which together allow for multiple APIs pr device instance, and the creation of devices which consist of multiple sub devices.

Problem description

Some devices provide multiple functions, which require multiple APIs pr single device instance. Some devices consist of multiple internal devices, which all require their own handles and APIs. There is no general design guideline for creating such devices, and creating devices with multiple APIs pr instance is not currently possible. This is preventing the creation of proper drivers for cellular and GNSS modems which do provide many varying features which can not be efficiently covered by a single API, since the functionalities are ever expanding and vary highly between devices.

Proposed change

The first solution is simply a design guideline for devices which consist of multiple sub devices. The change includes adding a documentation page describing this guideline, and adding some macros to help keep the driver design consistent. The specific docs and macros are contained in this PR #48932

   bus {
       parent {
          child1 {
          }; 
          child2 {
          };
          child3 {
          };
       };
   };

The second solution creates one struct device for each API implemented by a single device instance. The struct devices share all data except for the API pointer. Their names reflect the API they implement, and they are referenced using a function similar to DEVICE_DT_GET(node_id), called DEVICE_DT_API_GET(node_id, api_type), which returns the struct device which implements the specified API type if it has been defined by a driver, using DEVICE_DT_API_DEFINE(api_type, node_id, api_ptr)

struct api_foo;
struct api_bar;

DEVICE_DT_DEFINE(node_id, ... NULL)
DEVICE_DT_API_DEFINE(foo, node_id, &api_foo)
DEVICE_DT_API_DEFINE(bar, node_id, &api_bar)
struct device *foo_dev = DEVICE_DT_API_GET(foo, node_id);
struct device *bar_dev = DEVICE_DT_API_GET(bar, node_id);

The API struct devices are stored in ROM, grouped by API type, allowing for iterating through all devices which support a specific API type, which is handy for the shell for example.

Solution 2 requires no changes to the existing API headers, adds no overhead to the usage of API wrappers, while allowing for multiple APIs pr device instance

int ret = foo_var_get(&foo_dev);
ret = bar_dev_set(&bar_dev);

Detailed RFC

The first solution requires little extra explaining, since it is literally a docs page :)

The second solution requires updating the linker files to add sections for the API struct devices, and an update to the device.h file to include the new macros for defining and getting struct devices. Adding convenience macros to the driver API headers like LOCATION_DEVICE_DT_API_DEFINE(node_id, api_ptr) should also be done, but is not required.

struct api_loc;

DEVICE_DT_DEFINE(node_id, ... NULL)
LOCATION_DEVICE_DT_API_DEFINE(node_id, &api_loc)

Proposed change (Detailed)

See #48817 for example implementation of an API using solution 2

  1. Add documentation and macros for solution 1
  2. Add linker file which will contain API iterable sections
  3. Update device.h to include new macros for solution 2
  4. Add convenience macros to driver API headers
  5. Start transition period from old solution to these solutions
  6. Update in-tree drivers to use DEVICE_DT_API_DEFINE for APIs, and set DEVICE_DT_DEFINE api_ptr to NULL
  7. Transition period ends
  8. Remove api_ptr from DEVICE_DT_DEFINE
  9. Use api ptr in struct device from DEVICE_DT_DEFINE as init function
  10. update linker and device.c to use struct devices with init instead of an additional list as is does now
  11. Success

Dependencies

The only dependency which we can not control is the out-of-tree drivers which must be updated in the transition period.

Concerns and Unresolved Questions

Alternatives

Come forth with your alternatives here :)

Metadata

Metadata

Labels

RFCRequest For Comments: want input from the communityarea: Device Model

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions