Skip to content

Commit 8e59d4c

Browse files
gmarullhenrikbrixandersen
authored andcommitted
device: add new device_deinit API
Add a new API to de-initialize a device. When a device is de-initialized, it will release any resources it has acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will be left as in its reset state. It is the responsability of the caller to ensure that the device is ready to be de-initialized. For now, deinit call always initializes to NULL. New macros will be introduced to not break existing device APIs. Signed-off-by: Gerard Marull-Paretas <[email protected]>
1 parent 766bfe7 commit 8e59d4c

File tree

8 files changed

+80
-24
lines changed

8 files changed

+80
-24
lines changed

include/zephyr/device.h

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ typedef int16_t device_handle_t;
167167
#define DEVICE_DEFINE(dev_id, name, init_fn, pm, data, config, level, prio, \
168168
api) \
169169
Z_DEVICE_STATE_DEFINE(dev_id); \
170-
Z_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, name, init_fn, 0U, pm, data, \
171-
config, level, prio, api, \
170+
Z_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, name, init_fn, NULL, 0U, pm, \
171+
data, config, level, prio, api, \
172172
&Z_DEVICE_STATE_NAME(dev_id))
173173

174174
/**
@@ -220,7 +220,7 @@ typedef int16_t device_handle_t;
220220
...) \
221221
Z_DEVICE_STATE_DEFINE(Z_DEVICE_DT_DEV_ID(node_id)); \
222222
Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \
223-
DEVICE_DT_NAME(node_id), init_fn, \
223+
DEVICE_DT_NAME(node_id), init_fn, NULL, \
224224
Z_DEVICE_DT_FLAGS(node_id), pm, data, config, level, \
225225
prio, api, \
226226
&Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_ID(node_id)), \
@@ -455,6 +455,8 @@ typedef uint8_t device_flags_t;
455455
struct device_ops {
456456
/** Initialization function */
457457
int (*init)(const struct device *dev);
458+
/** De-initialization function */
459+
int (*deinit)(const struct device *dev);
458460
};
459461

460462
/**
@@ -834,6 +836,25 @@ __syscall bool device_is_ready(const struct device *dev);
834836
*/
835837
__syscall int device_init(const struct device *dev);
836838

839+
/**
840+
* @brief De-initialize a device.
841+
*
842+
* When a device is de-initialized, it will release any resources it has
843+
* acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will
844+
* be left as in its reset state.
845+
*
846+
* @warning It is the responsability of the caller to ensure that the device is
847+
* ready to be de-initialized.
848+
*
849+
* @param dev device to be de-initialized.
850+
*
851+
* @retval 0 If successful
852+
* @retval -EPERM If device has not been initialized.
853+
* @retval -ENOTSUP If device does not support de-initialization.
854+
* @retval -errno For any other errors.
855+
*/
856+
__syscall int device_deinit(const struct device *dev);
857+
837858
/**
838859
* @}
839860
*/
@@ -1078,6 +1099,7 @@ device_get_dt_nodelabels(const struct device *dev)
10781099
*
10791100
* @param name_ Name of the device.
10801101
* @param init_fn_ Init function (optional).
1102+
* @param deinit_fn_ De-init function (optional).
10811103
* @param flags_ Device flags.
10821104
* @param pm_ Reference to @ref pm_device_base (optional).
10831105
* @param data_ Reference to device data.
@@ -1088,15 +1110,15 @@ device_get_dt_nodelabels(const struct device *dev)
10881110
* @param node_id_ Devicetree node identifier
10891111
* @param dev_id_ Device identifier token, as passed to Z_DEVICE_BASE_DEFINE
10901112
*/
1091-
#define Z_DEVICE_INIT(name_, init_fn_, flags_, pm_, data_, config_, api_, state_, \
1092-
deps_, node_id_, dev_id_) \
1113+
#define Z_DEVICE_INIT(name_, init_fn_, deinit_fn_, flags_, pm_, data_, config_, api_, \
1114+
state_, deps_, node_id_, dev_id_) \
10931115
{ \
10941116
.name = name_, \
10951117
.config = (config_), \
10961118
.api = (api_), \
10971119
.state = (state_), \
10981120
.data = (data_), \
1099-
.ops = { .init = (init_fn_) }, \
1121+
.ops = { .init = (init_fn_), .deinit = (deinit_fn_) }, \
11001122
.flags = (flags_), \
11011123
IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \
11021124
IF_ENABLED(CONFIG_PM_DEVICE, Z_DEVICE_INIT_PM_BASE(pm_)) /**/ \
@@ -1134,6 +1156,7 @@ device_get_dt_nodelabels(const struct device *dev)
11341156
* @param dev_id Device identifier (used to name the defined @ref device).
11351157
* @param name Name of the device.
11361158
* @param init_fn Init function.
1159+
* @param deinit_fn De-init function.
11371160
* @param flags Device flags.
11381161
* @param pm Reference to @ref pm_device_base associated with the device.
11391162
* (optional).
@@ -1144,15 +1167,15 @@ device_get_dt_nodelabels(const struct device *dev)
11441167
* @param api Reference to device API.
11451168
* @param ... Optional dependencies, manually specified.
11461169
*/
1147-
#define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, init_fn, flags, pm, data, config, level, prio, \
1148-
api, state, deps) \
1170+
#define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, init_fn, deinit_fn, flags, pm, data, config, \
1171+
level, prio, api, state, deps) \
11491172
COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static)) \
11501173
COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (), (const)) \
11511174
STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE( \
11521175
device, COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (device_mutable), (device)), \
11531176
Z_DEVICE_SECTION_NAME(level, prio), DEVICE_NAME_GET(dev_id)) = \
1154-
Z_DEVICE_INIT(name, init_fn, flags, pm, data, config, api, state, deps, node_id, \
1155-
dev_id)
1177+
Z_DEVICE_INIT(name, init_fn, deinit_fn, flags, pm, data, config, api, state, deps, \
1178+
node_id, dev_id)
11561179

11571180
/**
11581181
* @brief Issue an error if the given init level is not supported.
@@ -1205,8 +1228,8 @@ device_get_dt_nodelabels(const struct device *dev)
12051228
* @param state Reference to device state.
12061229
* @param ... Optional dependencies, manually specified.
12071230
*/
1208-
#define Z_DEVICE_DEFINE(node_id, dev_id, name, init_fn, flags, pm, data, config,\
1209-
level, prio, api, state, ...) \
1231+
#define Z_DEVICE_DEFINE(node_id, dev_id, name, init_fn, deinit_fn, flags, pm, \
1232+
data, config, level, prio, api, state, ...) \
12101233
Z_DEVICE_NAME_CHECK(name); \
12111234
\
12121235
IF_ENABLED(CONFIG_DEVICE_DEPS, \
@@ -1216,8 +1239,8 @@ device_get_dt_nodelabels(const struct device *dev)
12161239
(IF_ENABLED(DT_NODE_EXISTS(node_id), \
12171240
(Z_DEVICE_DT_METADATA_DEFINE(node_id, dev_id);))))\
12181241
\
1219-
Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, init_fn, flags, pm, data, \
1220-
config, level, prio, api, state, \
1242+
Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, init_fn, deinit_fn, flags, \
1243+
pm, data, config, level, prio, api, state, \
12211244
Z_DEVICE_DEPS_NAME(dev_id)); \
12221245
\
12231246
Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, level, prio); \

include/zephyr/drivers/can.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,8 +761,8 @@ struct can_device_state {
761761
Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \
762762
DEVICE_DT_NAME(node_id), \
763763
&UTIL_CAT(Z_DEVICE_DT_DEV_ID(node_id), _init), \
764-
Z_DEVICE_DT_FLAGS(node_id), pm, data, config, \
765-
level, prio, api, \
764+
NULL, Z_DEVICE_DT_FLAGS(node_id), pm, data, \
765+
config, level, prio, api, \
766766
&(Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_ID(node_id)).devstate), \
767767
__VA_ARGS__)
768768

include/zephyr/drivers/i2c.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -668,8 +668,8 @@ static inline void i2c_xfer_stats(const struct device *dev, struct i2c_msg *msgs
668668
Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \
669669
DEVICE_DT_NAME(node_id), \
670670
&UTIL_CAT(Z_DEVICE_DT_DEV_ID(node_id), _init), \
671-
Z_DEVICE_DT_FLAGS(node_id), pm, data, config, \
672-
level, prio, api, \
671+
NULL, Z_DEVICE_DT_FLAGS(node_id), pm, data, \
672+
config, level, prio, api, \
673673
&(Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_ID(node_id)).devstate), \
674674
__VA_ARGS__)
675675

include/zephyr/drivers/smbus.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ static inline void smbus_xfer_stats(const struct device *dev, uint8_t sent,
510510
Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_NAME(node_id), \
511511
DEVICE_DT_NAME(node_id), \
512512
&UTIL_CAT(Z_DEVICE_DT_DEV_NAME(node_id), _init),\
513-
Z_DEVICE_DT_FLAGS(node_id), pm_device, \
513+
NULL, Z_DEVICE_DT_FLAGS(node_id), pm_device, \
514514
data_ptr, cfg_ptr, level, prio, \
515515
api_ptr, \
516516
&(Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_NAME \

include/zephyr/drivers/spi.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ struct spi_device_state {
579579
Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \
580580
DEVICE_DT_NAME(node_id), \
581581
&UTIL_CAT(Z_DEVICE_DT_DEV_ID(node_id), _init), \
582-
Z_DEVICE_DT_FLAGS(node_id), pm_device, \
582+
NULL, Z_DEVICE_DT_FLAGS(node_id), pm_device, \
583583
data_ptr, cfg_ptr, level, prio, \
584584
api_ptr, \
585585
&(Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_ID(node_id)).devstate), \
@@ -614,7 +614,7 @@ static inline void spi_transceive_stats(const struct device *dev, int error,
614614
api, ...) \
615615
Z_DEVICE_STATE_DEFINE(Z_DEVICE_DT_DEV_ID(node_id)); \
616616
Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \
617-
DEVICE_DT_NAME(node_id), init_fn, \
617+
DEVICE_DT_NAME(node_id), init_fn, NULL, \
618618
Z_DEVICE_DT_FLAGS(node_id), pm, data, config, \
619619
level, prio, api, \
620620
&Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_ID(node_id)), \

include/zephyr/net/ethernet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,7 @@ static inline bool net_eth_is_vlan_interface(struct net_if *iface)
11711171
init_fn, pm, data, config, prio, \
11721172
api, mtu) \
11731173
Z_DEVICE_STATE_DEFINE(dev_id); \
1174-
Z_DEVICE_DEFINE(node_id, dev_id, name, init_fn, \
1174+
Z_DEVICE_DEFINE(node_id, dev_id, name, init_fn, NULL, \
11751175
Z_DEVICE_DT_FLAGS(node_id), pm, data, \
11761176
config, POST_KERNEL, prio, api, \
11771177
&Z_DEVICE_STATE_NAME(dev_id));

include/zephyr/net/net_if.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3378,7 +3378,7 @@ extern int net_stats_prometheus_scrape(struct prometheus_collector *collector,
33783378
init_fn, pm, data, config, prio, \
33793379
api, l2, l2_ctx_type, mtu) \
33803380
Z_DEVICE_STATE_DEFINE(dev_id); \
3381-
Z_DEVICE_DEFINE(node_id, dev_id, name, init_fn, \
3381+
Z_DEVICE_DEFINE(node_id, dev_id, name, init_fn, NULL, \
33823382
Z_DEVICE_DT_FLAGS(node_id), pm, data, \
33833383
config, POST_KERNEL, prio, api, \
33843384
&Z_DEVICE_STATE_NAME(dev_id)); \
@@ -3526,7 +3526,7 @@ extern int net_stats_prometheus_scrape(struct prometheus_collector *collector,
35263526
#define Z_NET_DEVICE_OFFLOAD_INIT(node_id, dev_id, name, init_fn, pm, \
35273527
data, config, prio, api, mtu) \
35283528
Z_DEVICE_STATE_DEFINE(dev_id); \
3529-
Z_DEVICE_DEFINE(node_id, dev_id, name, init_fn, \
3529+
Z_DEVICE_DEFINE(node_id, dev_id, name, init_fn, NULL, \
35303530
Z_DEVICE_DT_FLAGS(node_id), pm, data, \
35313531
config, POST_KERNEL, prio, api, \
35323532
&Z_DEVICE_STATE_NAME(dev_id)); \

kernel/device.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#include <errno.h>
78
#include <stddef.h>
89
#include <string.h>
910
#include <zephyr/device.h>
@@ -142,6 +143,38 @@ bool z_impl_device_is_ready(const struct device *dev)
142143
return dev->state->initialized && (dev->state->init_res == 0U);
143144
}
144145

146+
int z_impl_device_deinit(const struct device *dev)
147+
{
148+
int ret;
149+
150+
if (!dev->state->initialized) {
151+
return -EPERM;
152+
}
153+
154+
if (dev->ops.deinit == NULL) {
155+
return -ENOTSUP;
156+
}
157+
158+
ret = dev->ops.deinit(dev);
159+
if (ret < 0) {
160+
return ret;
161+
}
162+
163+
dev->state->initialized = false;
164+
165+
return 0;
166+
}
167+
168+
#ifdef CONFIG_USERSPACE
169+
static inline int z_vrfy_device_deinit(const struct device *dev)
170+
{
171+
K_OOPS(K_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY));
172+
173+
return z_impl_device_deinit(dev);
174+
}
175+
#include <zephyr/syscalls/device_deinit_mrsh.c>
176+
#endif
177+
145178
#ifdef CONFIG_DEVICE_DEPS
146179

147180
static int device_visitor(const device_handle_t *handles,

0 commit comments

Comments
 (0)