blob: ec3515ccad287a0a6cb67dae3706b7c010cf162b [file] [log] [blame]
Kumar Galad12d8af2016-10-05 12:01:54 -05001/*
2 * Copyright (c) 2015-2016 Intel Corporation.
3 *
David B. Kinderac74d8b2017-01-18 17:01:01 -08004 * SPDX-License-Identifier: Apache-2.0
Kumar Galad12d8af2016-10-05 12:01:54 -05005 */
6
7#include <errno.h>
8#include <string.h>
9#include <device.h>
10#include <misc/util.h>
11#include <atomic.h>
12
13extern struct device __device_init_start[];
Andrew Boie0b474ee2016-11-08 11:06:55 -080014extern struct device __device_PRE_KERNEL_1_start[];
15extern struct device __device_PRE_KERNEL_2_start[];
16extern struct device __device_POST_KERNEL_start[];
17extern struct device __device_APPLICATION_start[];
Kumar Galad12d8af2016-10-05 12:01:54 -050018extern struct device __device_init_end[];
19
Kumar Galad12d8af2016-10-05 12:01:54 -050020
21#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
Kumar Galacc334c72017-04-21 10:55:34 -050022extern u32_t __device_busy_start[];
23extern u32_t __device_busy_end[];
Kumar Galad12d8af2016-10-05 12:01:54 -050024#define DEVICE_BUSY_SIZE (__device_busy_end - __device_busy_start)
25#endif
26
27/**
28 * @brief Execute all the device initialization functions at a given level
29 *
30 * @details Invokes the initialization routine for each device object
31 * created by the DEVICE_INIT() macro using the specified level.
32 * The linker script places the device objects in memory in the order
33 * they need to be invoked, with symbols indicating where one level leaves
34 * off and the next one begins.
35 *
36 * @param level init level to run.
37 */
Adithya Baglody8feda922018-10-25 12:04:25 +053038void _sys_device_do_config_level(s32_t level)
Kumar Galad12d8af2016-10-05 12:01:54 -050039{
40 struct device *info;
Flavio Ceolinac146852018-11-01 17:42:07 -070041 static struct device *config_levels[] = {
42 __device_PRE_KERNEL_1_start,
43 __device_PRE_KERNEL_2_start,
44 __device_POST_KERNEL_start,
45 __device_APPLICATION_start,
46 /* End marker */
47 __device_init_end,
48 };
Kumar Galad12d8af2016-10-05 12:01:54 -050049
Amir Kaplan61b6f5a2017-03-22 14:49:34 +020050 for (info = config_levels[level]; info < config_levels[level+1];
51 info++) {
Adithya Baglody8feda922018-10-25 12:04:25 +053052 struct device_config *device_conf = info->config;
Kumar Galad12d8af2016-10-05 12:01:54 -050053
Adithya Baglody8feda922018-10-25 12:04:25 +053054 (void)device_conf->init(info);
Andrew Boie5bd891d2017-09-27 12:59:28 -070055 _k_object_init(info);
Kumar Galad12d8af2016-10-05 12:01:54 -050056 }
57}
58
59struct device *device_get_binding(const char *name)
60{
61 struct device *info;
62
Leandro Pereirab55eb032018-02-14 14:47:11 -080063 /* Split the search into two loops: in the common scenario, where
64 * device names are stored in ROM (and are referenced by the user
65 * with CONFIG_* macros), only cheap pointer comparisons will be
66 * performed. Reserve string comparisons for a fallback.
67 */
68 for (info = __device_init_start; info != __device_init_end; info++) {
Adithya Baglody8feda922018-10-25 12:04:25 +053069 if ((info->driver_api != NULL) &&
70 (info->config->name == name)) {
Leandro Pereirab55eb032018-02-14 14:47:11 -080071 return info;
72 }
73 }
74
Kumar Galad12d8af2016-10-05 12:01:54 -050075 for (info = __device_init_start; info != __device_init_end; info++) {
Adithya Baglody8feda922018-10-25 12:04:25 +053076 if (info->driver_api == NULL) {
Leandro Pereirad24daa42017-10-19 14:17:37 -070077 continue;
78 }
79
Adithya Baglody8feda922018-10-25 12:04:25 +053080 if (strcmp(name, info->config->name) == 0) {
Kumar Galad12d8af2016-10-05 12:01:54 -050081 return info;
82 }
83 }
84
85 return NULL;
86}
87
88#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
Ramesh Thomas6249c562016-10-07 17:07:04 -070089int device_pm_control_nop(struct device *unused_device,
Kumar Galacc334c72017-04-21 10:55:34 -050090 u32_t unused_ctrl_command, void *unused_context)
Kumar Galad12d8af2016-10-05 12:01:54 -050091{
92 return 0;
93}
Ramesh Thomas6249c562016-10-07 17:07:04 -070094
Kumar Galad12d8af2016-10-05 12:01:54 -050095void device_list_get(struct device **device_list, int *device_count)
96{
97
98 *device_list = __device_init_start;
99 *device_count = __device_init_end - __device_init_start;
100}
101
102
103int device_any_busy_check(void)
104{
105 int i = 0;
106
107 for (i = 0; i < DEVICE_BUSY_SIZE; i++) {
108 if (__device_busy_start[i] != 0) {
109 return -EBUSY;
110 }
111 }
112 return 0;
113}
114
115int device_busy_check(struct device *chk_dev)
116{
117 if (atomic_test_bit((const atomic_t *)__device_busy_start,
118 (chk_dev - __device_init_start))) {
119 return -EBUSY;
120 }
121 return 0;
122}
123
124#endif
125
126void device_busy_set(struct device *busy_dev)
127{
128#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
129 atomic_set_bit((atomic_t *) __device_busy_start,
130 (busy_dev - __device_init_start));
Flavio Santesb80db0a2016-12-11 00:19:26 -0600131#else
132 ARG_UNUSED(busy_dev);
Kumar Galad12d8af2016-10-05 12:01:54 -0500133#endif
134}
135
136void device_busy_clear(struct device *busy_dev)
137{
138#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
139 atomic_clear_bit((atomic_t *) __device_busy_start,
140 (busy_dev - __device_init_start));
Flavio Santesb80db0a2016-12-11 00:19:26 -0600141#else
142 ARG_UNUSED(busy_dev);
Kumar Galad12d8af2016-10-05 12:01:54 -0500143#endif
144}