summaryrefslogtreecommitdiff
path: root/documentation/6.components/device-driver/core/bus.md
blob: 6169d1424932baee709500c76e245ed5b073dbef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
@page page_device_bus Bus and driver binding (core)

# Device model: bus and driver

RT-Thread **DM** binds **drivers** to **devices** through **`struct rt_bus`**: each bus keeps linked lists of devices and drivers, runs **`match`**, then **`probe`** / **`remove`** / **`shutdown`**. Most SoC drivers use the built-in **`platform`** bus; other stacks (e.g. **RPMsg**) register their own bus type on the same core.

Headers: `components/drivers/include/drivers/core/bus.h`, `driver.h`. Core: `components/drivers/core/bus.c`. Reference bus: `components/drivers/core/platform.c`.

Device-side helpers (`rt_dm_dev_iomap`, properties, IRQ): @ref page_device_dm.

---

## Kconfig

| Option | Role |
| --- | --- |
| **`RT_USING_DM`** | Enables **`bus.c`**, **`driver.c`**, platform bus, and DM helpers |
| **`RT_USING_DEV_BUS`** | Optional **`rt_device_bus_create`** — bus as **`RT_Device_Class_Bus`** device |
| **`RT_USING_OFW`** | Platform **`match`** uses **`compatible`**; devices carry **`dev->ofw_node`** |
| **`RT_USING_PINCTRL`** | Platform **`probe`** applies **`pinctrl-*`** before driver **`probe`** |
| **`RT_USING_CLK`** | Platform **`probe`** runs **`rt_ofw_clk_set_defaults`** |

---

## Architecture

```
  rt_bus_register(bus)
         |
         v
  struct rt_bus (platform, rpmsg, ...)
    dev_list --> rt_device
    drv_list --> rt_driver
    match / probe / remove / shutdown
```

**Binding** (`bus.c`): **`rt_bus_add_device`** walks **`drv_list`**; **`rt_bus_add_driver`** walks **`dev_list`**. **`match`** must succeed before **`dev->drv`** is set and **`bus->probe(dev)`** runs. Failed probe clears **`dev->drv`**.

| Object | Role |
| --- | --- |
| **`struct rt_bus`** | Bus type and lifecycle hooks |
| **`struct rt_driver`** | Driver on a bus; **`ref_count`** = bound devices |
| **`struct rt_platform_device`** | Platform device embedding **`rt_device`** |

---

## `struct rt_bus` callbacks

| Callback | Contract |
| --- | --- |
| **`match`** | **Pure** — no HW access; return **`RT_TRUE`** to bind |
| **`probe`** | Bus-level setup (platform: pinctrl, clocks, power domain) then driver **`probe`** |
| **`remove`** | Teardown; platform calls **`pdrv->remove`** and **`rt_platform_ofw_free`** |
| **`shutdown`** | Invoked from **`rt_bus_shutdown()`** on system off |

---

## Bus and driver API

| API | Role |
| --- | --- |
| **`rt_bus_register`** | Register bus on global **`bus_nodes`** |
| **`rt_bus_add_device` / `rt_bus_add_driver`** | Add node and run matching |
| **`rt_bus_remove_device` / `rt_bus_remove_driver`** | Remove; driver busy if **`ref_count > 0`** |
| **`rt_bus_for_each_dev` / `rt_bus_for_each_drv`** | Iterate under spinlock |
| **`rt_bus_find_by_name`** | Find **`"platform"`** etc. |
| **`rt_bus_reload_driver_device`** | Move device to another bus |
| **`rt_bus_shutdown`** | Shutdown all devices on all buses |
| **`rt_driver_register` / `unregister`** | Driver attach/detach |

---

## `RT_DRIVER_EXPORT` / platform

```c
#define RT_DRIVER_EXPORT(driver, bus_name, mode)  /* INIT_DEVICE_EXPORT */
#define RT_PLATFORM_DRIVER_EXPORT(driver) \
    RT_DRIVER_EXPORT(driver, platform, BUILIN)
```

Example:

```c
static const struct rt_ofw_node_id my_ids[] = {
    { .compatible = "vendor,my-ip" },
    { /* sentinel */ },
};

static struct rt_platform_driver my_drv = {
    .name = "my-ip",
    .ids  = my_ids,
    .probe  = my_probe,
    .remove = my_remove,
};
RT_PLATFORM_DRIVER_EXPORT(my_drv);
```

---

## Platform bus

**`INIT_CORE_EXPORT(platform_bus_init)`** registers **`name = "platform"`**.

### `platform_match`

1. **`rt_ofw_node_match(np, pdrv->ids)`** when **`dev->ofw_node`** is set.
2. Else compare **`pdev->name`** and **`pdrv->name`**.

### `platform_probe` (before `pdrv->probe`)

1. Pinctrl default / index 0 — @ref page_device_pinctrl
2. **`rt_ofw_clk_set_defaults`** — @ref page_device_clk
3. **`rt_dm_power_domain_attach(dev, RT_TRUE)`** — **`-RT_EEMPTY`** OK — @ref page_device_power_domain
4. **`pdrv->probe(pdev)`** — map MMIO, clocks, register **`rt_device`**

| OFW API | Role |
| --- | --- |
| **`rt_platform_ofw_request`** | Instantiate from DT node |
| **`rt_platform_ofw_device_probe_child`** | Probe children |
| **`rt_platform_ofw_free`** | Free OFW state on remove |

See @ref page_device_platform, @ref page_device_ofw.

---

## Custom `rt_bus`

| New bus when… | Use **platform** when… |
| --- | --- |
| Non-OFW enumeration (RPMsg, internal stack bus) | **`/soc`** MMIO + **`compatible`** |

Implement **`match`/`probe`/`remove`**, **`rt_bus_register`** at init, then **`rt_bus_add_driver`** / **`rt_bus_add_device`**.

---

## SDIO vs core

MMC-specific DM: @ref page_device_sdio_dm. This page covers **`rt_bus` / `rt_driver`** only.

---

## Power and probe order

| Topic | Document |
| --- | --- |
| System shutdown | @ref page_device_dm_power |
| Power domains | @ref page_device_power_domain |
| Regulators | @ref page_device_regulator |

Typical order: **regulator → power domain → clock/reset → `rt_dm_dev_iomap`**.

---

## Engineer checklist

1. Export driver with **`RT_PLATFORM_DRIVER_EXPORT`** (or subsystem **`RT_DRIVER_EXPORT`**).
2. Request device via **`rt_platform_ofw_request`** or manual register.
3. In **`probe`**: resources → HW → register functional device; unwind on error.
4. In **`remove`**: reverse order; disable IRQ before free.

---

## Pitfalls

- **`match` with side effects** breaks re-probe.
- **Double `rt_bus_add_device`** without remove.
- **`rt_driver_unregister` while devices bound** — **`-RT_EBUSY`**.
- **Link order is not probe order** — defer on missing phandles.

---

## See also

- @ref page_device_dm
- @ref page_device_dm_power
- @ref page_device_platform
- @ref page_device_ofw, @ref page_device_dtc
- @ref page_device_sdio_dm
- `components/drivers/core/bus.c`, `platform.c`