1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <ztest.h>
8 #include <devicetree.h>
9 #include <device.h>
10 #include <drivers/gpio.h>
11 
12 #define TEST_GPIO DT_NODELABEL(test_gpio_0)
13 #define TEST_I2C DT_NODELABEL(test_i2c)
14 #define TEST_DEVA DT_NODELABEL(test_dev_a)
15 #define TEST_GPIOX DT_NODELABEL(test_gpiox)
16 #define TEST_DEVB DT_NODELABEL(test_dev_b)
17 
18 static const struct device *devlist;
19 static const struct device *devlist_end;
20 
21 static device_handle_t init_order[10];
22 
dev_init(const struct device * dev)23 static int dev_init(const struct device *dev)
24 {
25 	static uint8_t init_idx;
26 
27 	__ASSERT_NO_MSG(init_idx < ARRAY_SIZE(init_order));
28 	init_order[init_idx++] = device_handle_get(dev);
29 
30 	return 0;
31 }
32 
33 DEVICE_DT_DEFINE(TEST_GPIO, dev_init, NULL,
34 		 NULL, NULL, PRE_KERNEL_1, 90, NULL);
35 DEVICE_DT_DEFINE(TEST_I2C, dev_init, NULL,
36 		 NULL, NULL, POST_KERNEL, 10, NULL);
37 DEVICE_DT_DEFINE(TEST_DEVA, dev_init, NULL,
38 		 NULL, NULL, POST_KERNEL, 20, NULL);
39 /* NB: Intentional init devb before required gpiox */
40 DEVICE_DT_DEFINE(TEST_DEVB, dev_init, NULL,
41 		 NULL, NULL, POST_KERNEL, 30, NULL);
42 DEVICE_DT_DEFINE(TEST_GPIOX, dev_init, NULL,
43 		 NULL, NULL, POST_KERNEL, 40, NULL);
44 
45 #define DEV_HDL(node_id) device_handle_get(DEVICE_DT_GET(node_id))
46 
test_init_order(void)47 static void test_init_order(void)
48 {
49 	zassert_equal(init_order[0], DEV_HDL(TEST_GPIO),
50 		      NULL);
51 	zassert_equal(init_order[1], DEV_HDL(TEST_I2C),
52 		      NULL);
53 	zassert_equal(init_order[2], DEV_HDL(TEST_DEVA),
54 		      NULL);
55 	zassert_equal(init_order[3], DEV_HDL(TEST_DEVB),
56 		      NULL);
57 	zassert_equal(init_order[4], DEV_HDL(TEST_GPIOX),
58 		      NULL);
59 }
60 
check_handle(device_handle_t hdl,const device_handle_t * hdls,size_t nhdls)61 static bool check_handle(device_handle_t hdl,
62 			 const device_handle_t *hdls,
63 			 size_t nhdls)
64 {
65 	const device_handle_t *hdle = hdls + nhdls;
66 
67 	while (hdls < hdle) {
68 		if (*hdls == hdl) {
69 			return true;
70 		}
71 		++hdls;
72 	}
73 
74 	return false;
75 }
76 
77 struct requires_context {
78 	uint8_t ndevs;
79 	const struct device *rdevs[2];
80 };
81 
requires_visitor(const struct device * dev,void * context)82 static int requires_visitor(const struct device *dev,
83 			    void *context)
84 {
85 	struct requires_context *ctx = context;
86 	const struct device **rdp = ctx->rdevs;
87 
88 	while (rdp < (ctx->rdevs + ctx->ndevs)) {
89 		if (*rdp == NULL) {
90 			*rdp = dev;
91 			return 0;
92 		}
93 
94 		++rdp;
95 	}
96 
97 	return -ENOSPC;
98 }
99 
test_requires(void)100 static void test_requires(void)
101 {
102 	size_t nhdls = 0;
103 	const device_handle_t *hdls;
104 	const struct device *dev;
105 	struct requires_context ctx = { 0 };
106 
107 	/* TEST_GPIO: no req */
108 	dev = device_get_binding(DT_LABEL(TEST_GPIO));
109 	zassert_equal(dev, DEVICE_DT_GET(TEST_GPIO), NULL);
110 	hdls = device_required_handles_get(dev, &nhdls);
111 	zassert_equal(nhdls, 0, NULL);
112 	zassert_equal(0, device_required_foreach(dev, requires_visitor, &ctx),
113 		      NULL);
114 
115 	/* TEST_I2C: no req */
116 	dev = device_get_binding(DT_LABEL(TEST_I2C));
117 	zassert_equal(dev, DEVICE_DT_GET(TEST_I2C), NULL);
118 	hdls = device_required_handles_get(dev, &nhdls);
119 	zassert_equal(nhdls, 0, NULL);
120 	zassert_equal(0, device_required_foreach(dev, requires_visitor, &ctx),
121 		      NULL);
122 
123 	/* TEST_DEVA: TEST_I2C GPIO */
124 	dev = device_get_binding(DT_LABEL(TEST_DEVA));
125 	zassert_equal(dev, DEVICE_DT_GET(TEST_DEVA), NULL);
126 	hdls = device_required_handles_get(dev, &nhdls);
127 	zassert_equal(nhdls, 2, NULL);
128 	zassert_true(check_handle(DEV_HDL(TEST_I2C), hdls, nhdls), NULL);
129 	zassert_true(check_handle(DEV_HDL(TEST_GPIO), hdls, nhdls), NULL);
130 
131 	/* Visit fails if not enough space */
132 	ctx = (struct requires_context){
133 		.ndevs = 1,
134 	};
135 	zassert_equal(-ENOSPC, device_required_foreach(dev, requires_visitor, &ctx),
136 		      NULL);
137 
138 	/* Visit succeeds if enough space. */
139 	ctx = (struct requires_context){
140 		.ndevs = 2,
141 	};
142 	zassert_equal(2, device_required_foreach(dev, requires_visitor, &ctx),
143 		      NULL);
144 	zassert_true((ctx.rdevs[0] == device_from_handle(DEV_HDL(TEST_I2C)))
145 		      || (ctx.rdevs[1] == device_from_handle(DEV_HDL(TEST_I2C))),
146 		     NULL);
147 	zassert_true((ctx.rdevs[0] == device_from_handle(DEV_HDL(TEST_GPIO)))
148 		      || (ctx.rdevs[1] == device_from_handle(DEV_HDL(TEST_GPIO))),
149 		     NULL);
150 
151 	/* TEST_GPIOX: TEST_I2C */
152 	dev = device_get_binding(DT_LABEL(TEST_GPIOX));
153 	zassert_equal(dev, DEVICE_DT_GET(TEST_GPIOX), NULL);
154 	hdls = device_required_handles_get(dev, &nhdls);
155 	zassert_equal(nhdls, 1, NULL);
156 	zassert_true(check_handle(DEV_HDL(TEST_I2C), hdls, nhdls), NULL);
157 	ctx = (struct requires_context){
158 		.ndevs = 3,
159 	};
160 	zassert_equal(1, device_required_foreach(dev, requires_visitor, &ctx),
161 		      NULL);
162 	zassert_true(ctx.rdevs[0] == device_from_handle(DEV_HDL(TEST_I2C)),
163 		     NULL);
164 
165 	/* TEST_DEVB: TEST_I2C TEST_GPIOX */
166 	dev = device_get_binding(DT_LABEL(TEST_DEVB));
167 	zassert_equal(dev, DEVICE_DT_GET(TEST_DEVB), NULL);
168 	hdls = device_required_handles_get(dev, &nhdls);
169 	zassert_equal(nhdls, 2, NULL);
170 	zassert_true(check_handle(DEV_HDL(TEST_I2C), hdls, nhdls), NULL);
171 	zassert_true(check_handle(DEV_HDL(TEST_GPIOX), hdls, nhdls), NULL);
172 }
173 
174 
test_main(void)175 void test_main(void)
176 {
177 	size_t ndevs;
178 
179 	ndevs = z_device_get_all_static(&devlist);
180 	devlist_end = devlist + ndevs;
181 
182 	ztest_test_suite(devicetree_driver,
183 			 ztest_unit_test(test_init_order),
184 			 ztest_unit_test(test_requires)
185 			 );
186 	ztest_run_test_suite(devicetree_driver);
187 }
188