1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /* The macros in this file are not public, applications should not use them.
8  * The macros are used to translate devicetree zephyr,uac2 compatible nodes
9  * into uint8_t array initializer. The output should be treated as a binary blob
10  * for the USB host to use (and parse).
11  */
12 
13 #include <zephyr/sys/util.h>
14 #include <zephyr/usb/usb_ch9.h>
15 
16 #ifndef ZEPHYR_INCLUDE_USBD_UAC2_MACROS_H_
17 #define ZEPHYR_INCLUDE_USBD_UAC2_MACROS_H_
18 
19 #define ARRAY_BIT(idx, value) (value##ull << idx)
20 
21 #define U16_LE(value) ((value) & 0xFF), (((value) & 0xFF00) >> 8)
22 #define U32_LE(value)								\
23 	((value) & 0xFF),							\
24 	(((value) & 0xFF00) >> 8),						\
25 	(((value) & 0xFF0000) >> 16),						\
26 	(((value) & 0xFF000000) >> 24)
27 
28 #define ARRAY_ELEMENT_LESS_THAN_NEXT(node, prop, idx)				\
29 	COND_CODE_1(IS_EQ(idx, UTIL_DEC(DT_PROP_LEN(node, prop))),		\
30 		(1 /* nothing to compare the last element against */),		\
31 		((DT_PROP_BY_IDX(node, prop, idx) <				\
32 		  DT_PROP_BY_IDX(node, prop, UTIL_INC(idx)))))
33 #define IS_ARRAY_SORTED(node, prop)						\
34 	DT_FOREACH_PROP_ELEM_SEP(node, prop, ARRAY_ELEMENT_LESS_THAN_NEXT, (&&))
35 
36 #define FIRST_INTERFACE_NUMBER			0x00
37 #define FIRST_IN_EP_ADDR			0x81
38 #define FIRST_OUT_EP_ADDR			0x01
39 
40 /* A.1 Audio Function Class Code */
41 #define AUDIO_FUNCTION				AUDIO
42 
43 /* A.2 Audio Function Subclass Codes */
44 #define FUNCTION_SUBCLASS_UNDEFINED		0x00
45 
46 /* A.3 Audio Function Protocol Codes */
47 #define FUNCTION_PROTOCOL_UNDEFINED		0x00
48 #define AF_VERSION_02_00			IP_VERSION_02_00
49 
50 /* A.4 Audio Interface Class Code */
51 #define AUDIO					0x01
52 
53 /* A.5 Audio Interface Subclass Codes */
54 #define INTERFACE_SUBCLASS_UNDEFINED		0x00
55 #define AUDIOCONTROL				0x01
56 #define AUDIOSTREAMING				0x02
57 #define MIDISTREAMING				0x03
58 
59 /* A.6 Audio Interface Protocol Codes */
60 #define INTERFACE_PROTOCOL_UNDEFINED		0x00
61 #define IP_VERSION_02_00			0x20
62 
63 /* A.8 Audio Class-Specific Descriptor Types */
64 #define CS_UNDEFINED		0x20
65 #define CS_DEVICE		0x21
66 #define CS_CONFIGURATION	0x22
67 #define CS_STRING		0x23
68 #define CS_INTERFACE		0x24
69 #define CS_ENDPOINT		0x25
70 
71 /* A.9 Audio Class-Specific AC Interface Descriptor Subtypes */
72 #define AC_DESCRIPTOR_UNDEFINED			0x00
73 #define AC_DESCRIPTOR_HEADER			0x01
74 #define AC_DESCRIPTOR_INPUT_TERMINAL		0x02
75 #define AC_DESCRIPTOR_OUTPUT_TERMINAL		0x03
76 #define AC_DESCRIPTOR_MIXER_UNIT		0x04
77 #define AC_DESCRIPTOR_SELECTOR_UNIT		0x05
78 #define AC_DESCRIPTOR_FEATURE_UNIT		0x06
79 #define AC_DESCRIPTOR_EFFECT_UNIT		0x07
80 #define AC_DESCRIPTOR_PROCESSING_UNIT		0x08
81 #define AC_DESCRIPTOR_EXTENSION_UNIT		0x09
82 #define AC_DESCRIPTOR_CLOCK_SOURCE		0x0A
83 #define AC_DESCRIPTOR_CLOCK_SELECTOR		0x0B
84 #define AC_DESCRIPTOR_CLOCK_MULTIPLIER		0x0C
85 #define AC_DESCRIPTOR_SAMPLE_RATE_CONVERTER	0x0D
86 
87 /* A.10 Audio Class-Specific AS Interface Descriptor Subtypes */
88 #define AS_DESCRIPTOR_UNDEFINED			0x00
89 #define AS_DESCRIPTOR_GENERAL			0x01
90 #define AS_DESCRIPTOR_FORMAT_TYPE		0x02
91 #define AS_DESCRIPTOR_ENCODER			0x03
92 #define AS_DESCRIPTOR_DECODER			0x04
93 
94 /* A.13 Audio Class-Specific Endpoint Descriptor Subtypes */
95 #define DESCRIPTOR_UNDEFINED			0x00
96 #define EP_GENERAL				0x01
97 
98 /* Universal Serial Bus Device Class Definition for Audio Data Formats
99  * Release 2.0, May 31, 2006. A.1 Format Type Codes
100  * Values are in decimal to facilitate use with IS_EQ() macro.
101  */
102 #define FORMAT_TYPE_UNDEFINED			0
103 #define FORMAT_TYPE_I				1
104 #define FORMAT_TYPE_II				2
105 #define FORMAT_TYPE_III				3
106 #define FORMAT_TYPE_IV				4
107 #define EXT_FORMAT_TYPE_I			129
108 #define EXT_FORMAT_TYPE_II			130
109 #define EXT_FORMAT_TYPE_III			131
110 
111 /* Automatically assign Entity IDs based on entities order in devicetree */
112 #define ENTITY_ID(e) UTIL_INC(DT_NODE_CHILD_IDX(e))
113 
114 /* Name of uint8_t array holding descriptor data */
115 #define DESCRIPTOR_NAME(prefix, node) uac2_## prefix ## _ ## node
116 
117 /* Connected Entity ID or 0 if property is not defined. Rely on devicetree
118  * "required: true" to fail compilation if mandatory handle (e.g. clock source)
119  * is absent.
120  */
121 #define CONNECTED_ENTITY_ID(entity, phandle)					\
122 	COND_CODE_1(DT_NODE_HAS_PROP(entity, phandle),				\
123 		(ENTITY_ID(DT_PHANDLE_BY_IDX(entity, phandle, 0))), (0))
124 
125 #define ID_IF_TERMINAL_ASSOCIATES_WITH_TARGET(entity, target_id)		\
126 	IF_ENABLED(UTIL_AND(IS_EQ(						\
127 		CONNECTED_ENTITY_ID(entity, assoc_terminal), target_id),	\
128 		UTIL_OR(							\
129 			DT_NODE_HAS_COMPAT(entity, zephyr_uac2_input_terminal),	\
130 			DT_NODE_HAS_COMPAT(entity, zephyr_uac2_output_terminal)	\
131 		)), (ENTITY_ID(entity)))
132 
133 /* Find ID of terminal entity associated with given terminal entity. This macro
134  * evaluates to "+ 0" if there isn't any terminal entity associated. If there
135  * are terminal entities associated with given terminal, then the macro evalues
136  * to "IDs + 0" where IDs are the terminal entities ID separated by spaces.
137  *
138  * If there is exactly one ID then compiler will compute correct value.
139  * If there is more than one associated entity, then it will fail at build time
140  * (as it should) because the caller expects single integer.
141  */
142 #define FIND_ASSOCIATED_TERMINAL(entity)					\
143 	DT_FOREACH_CHILD_VARGS(DT_PARENT(entity),				\
144 		ID_IF_TERMINAL_ASSOCIATES_WITH_TARGET, ENTITY_ID(entity)) + 0
145 
146 /* If entity has assoc_terminal property, return the entity ID of associated
147  * terminal. Otherwise, search if any other terminal entity points to us and
148  * use its ID. If search yields no results then this evaluates to "+ 0" which
149  * matches the value USB Audio Class expects in bAssocTerminal if no association
150  * exists.
151  *
152  * This is a workaround for lack of cyclic dependencies support in devicetree.
153  */
154 #define ASSOCIATED_TERMINAL_ID(entity)						\
155 	COND_CODE_1(DT_NODE_HAS_PROP(entity, assoc_terminal),			\
156 		(CONNECTED_ENTITY_ID(entity, assoc_terminal)),			\
157 		(FIND_ASSOCIATED_TERMINAL(entity)))
158 
159 
160 #define CLOCK_SOURCE_ATTRIBUTES(entity)						\
161 	(DT_ENUM_IDX(entity, clock_type)) |					\
162 	(DT_PROP(entity, sof_synchronized) << 2)
163 
164 /* Control properties are optional enums in devicetree that can either be
165  * "read-only" or "host-programmable". If the property is missing, then it means
166  * that control is not present. Convert the control property into actual values
167  * used by USB Audio Class, i.e. 0b00 when control is not present, 0b01 when
168  * control is present but read-only and 0b11 when control can be programmed by
169  * host. Value 0b10 is not allowed by the specification.
170  */
171 #define CONTROL_BITS(entity, control_name, bitshift)				\
172 	COND_CODE_1(DT_NODE_HAS_PROP(entity, control_name),			\
173 		(COND_CODE_0(DT_ENUM_IDX(entity, control_name),			\
174 			((0x1 << bitshift)) /* read-only */,			\
175 			((0x3 << bitshift)) /* host-programmable */)),		\
176 		((0x0 << bitshift)) /* control not present */)
177 
178 #define CLOCK_SOURCE_CONTROLS(entity)						\
179 	CONTROL_BITS(entity, frequency_control, 0)	|			\
180 	CONTROL_BITS(entity, validity_control, 2)
181 
182 #define INPUT_TERMINAL_CONTROLS(entity)						\
183 	CONTROL_BITS(entity, copy_protect_control, 0)	|			\
184 	CONTROL_BITS(entity, connector_control, 2)	|			\
185 	CONTROL_BITS(entity, overload_control, 4)	|			\
186 	CONTROL_BITS(entity, cluster_control, 6)	|			\
187 	CONTROL_BITS(entity, underflow_control, 8)	|			\
188 	CONTROL_BITS(entity, overflow_control, 10)
189 
190 #define OUTPUT_TERMINAL_CONTROLS(entity)					\
191 	CONTROL_BITS(entity, copy_protect_control, 0)	|			\
192 	CONTROL_BITS(entity, connector_control, 2)	|			\
193 	CONTROL_BITS(entity, overload_control, 4)	|			\
194 	CONTROL_BITS(entity, underflow_control, 6)	|			\
195 	CONTROL_BITS(entity, overflow_control, 8)
196 
197 #define AUDIO_STREAMING_DATA_ENDPOINT_CONTROLS(node)				\
198 	CONTROL_BITS(node, pitch_control, 0)		|			\
199 	CONTROL_BITS(node, data_overrun_control, 2)	|			\
200 	CONTROL_BITS(node, data_underrun_control, 4)
201 
202 /* 4.1 Audio Channel Cluster Descriptor */
203 #define SPATIAL_LOCATIONS_ARRAY(cluster)					\
204 	DT_PROP(cluster, front_left),						\
205 	DT_PROP(cluster, front_right),						\
206 	DT_PROP(cluster, front_center),						\
207 	DT_PROP(cluster, low_frequency_effects),				\
208 	DT_PROP(cluster, back_left),						\
209 	DT_PROP(cluster, back_right),						\
210 	DT_PROP(cluster, front_left_of_center),					\
211 	DT_PROP(cluster, front_right_of_center),				\
212 	DT_PROP(cluster, back_center),						\
213 	DT_PROP(cluster, side_left),						\
214 	DT_PROP(cluster, side_right),						\
215 	DT_PROP(cluster, top_center),						\
216 	DT_PROP(cluster, top_front_left),					\
217 	DT_PROP(cluster, top_front_center),					\
218 	DT_PROP(cluster, top_front_right),					\
219 	DT_PROP(cluster, top_back_left),					\
220 	DT_PROP(cluster, top_back_center),					\
221 	DT_PROP(cluster, top_back_right),					\
222 	DT_PROP(cluster, top_front_left_of_center),				\
223 	DT_PROP(cluster, top_front_right_of_center),				\
224 	DT_PROP(cluster, left_low_frequency_effects),				\
225 	DT_PROP(cluster, right_low_frequency_effects),				\
226 	DT_PROP(cluster, top_side_left),					\
227 	DT_PROP(cluster, top_side_right),					\
228 	DT_PROP(cluster, bottom_center),					\
229 	DT_PROP(cluster, back_left_of_center),					\
230 	DT_PROP(cluster, back_right_of_center),					\
231 	0, 0, 0, 0, /* D27..D30: Reserved */					\
232 	DT_PROP(cluster, raw_data)
233 
234 #define SPATIAL_LOCATIONS_U32(entity) \
235 	(FOR_EACH_IDX(ARRAY_BIT, (|), SPATIAL_LOCATIONS_ARRAY(entity)))
236 #define NUM_SPATIAL_LOCATIONS(entity) \
237 	(FOR_EACH(IDENTITY, (+), SPATIAL_LOCATIONS_ARRAY(entity)))
238 #define SPATIAL_LOCATIONS(entity) U32_LE(SPATIAL_LOCATIONS_U32(entity))
239 
240 
241 /* 4.7.2.1 Clock Source Descriptor */
242 #define CLOCK_SOURCE_DESCRIPTOR(entity)						\
243 	0x08,						/* bLength */		\
244 	CS_INTERFACE,					/* bDescriptorType */	\
245 	AC_DESCRIPTOR_CLOCK_SOURCE,			/* bDescriptorSubtype */\
246 	ENTITY_ID(entity),				/* bClockID */		\
247 	CLOCK_SOURCE_ATTRIBUTES(entity),		/* bmAttributes */	\
248 	CLOCK_SOURCE_CONTROLS(entity),			/* bmControls */	\
249 	CONNECTED_ENTITY_ID(entity, assoc_terminal),	/* bAssocTerminal */	\
250 	0x00,						/* iClockSource */
251 
252 /* 4.7.2.4 Input Terminal Descriptor */
253 #define INPUT_TERMINAL_DESCRIPTOR(entity)					\
254 	0x11,						/* bLength */		\
255 	CS_INTERFACE,					/* bDescriptorType */	\
256 	AC_DESCRIPTOR_INPUT_TERMINAL,			/* bDescriptorSubtype */\
257 	ENTITY_ID(entity),				/* bTerminalID */	\
258 	U16_LE(DT_PROP(entity, terminal_type)),		/* wTerminalType */	\
259 	ASSOCIATED_TERMINAL_ID(entity),			/* bAssocTerminal */	\
260 	CONNECTED_ENTITY_ID(entity, clock_source),	/* bCSourceID */	\
261 	NUM_SPATIAL_LOCATIONS(entity),			/* bNrChannels */	\
262 	SPATIAL_LOCATIONS(entity),			/* bmChannelConfig */	\
263 	0x00,						/* iChannelNames */	\
264 	U16_LE(INPUT_TERMINAL_CONTROLS(entity)),	/* bmControls */	\
265 	0x00,						/* iTerminal */
266 
267 /* 4.7.2.5 Output Terminal Descriptor */
268 #define OUTPUT_TERMINAL_DESCRIPTOR(entity)					\
269 	0x0C,						/* bLength */		\
270 	CS_INTERFACE,					/* bDescriptorType */	\
271 	AC_DESCRIPTOR_OUTPUT_TERMINAL,			/* bDescriptorSubtype */\
272 	ENTITY_ID(entity),				/* bTerminalID */	\
273 	U16_LE(DT_PROP(entity, terminal_type)),		/* wTerminalType */	\
274 	ASSOCIATED_TERMINAL_ID(entity),			/* bAssocTerminal */	\
275 	CONNECTED_ENTITY_ID(entity, data_source),	/* bSourceID */		\
276 	CONNECTED_ENTITY_ID(entity, clock_source),	/* bCSourceID */	\
277 	U16_LE(OUTPUT_TERMINAL_CONTROLS(entity)),	/* bmControls */	\
278 	0x00,						/* iTerminal */
279 
280 #define ENTITY_HEADER(entity)							\
281 	IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_clock_source), (	\
282 		CLOCK_SOURCE_DESCRIPTOR(entity)					\
283 	))									\
284 	IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_input_terminal), (	\
285 		INPUT_TERMINAL_DESCRIPTOR(entity)				\
286 	))									\
287 	IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_output_terminal), (	\
288 		OUTPUT_TERMINAL_DESCRIPTOR(entity)				\
289 	))
290 
291 #define ENTITY_HEADER_ARRAYS(entity)						\
292 	IF_ENABLED(UTIL_NOT(IS_EMPTY(ENTITY_HEADER(entity))), (			\
293 		static uint8_t DESCRIPTOR_NAME(ac_entity, entity)[] = {		\
294 			ENTITY_HEADER(entity)					\
295 		};								\
296 	))
297 
298 #define ENTITY_HEADER_PTRS(entity)						\
299 	IF_ENABLED(UTIL_NOT(IS_EMPTY(ENTITY_HEADER(entity))), (			\
300 		(struct usb_desc_header *) &DESCRIPTOR_NAME(ac_entity, entity),	\
301 	))
302 
303 #define ENTITY_HEADERS(node) DT_FOREACH_CHILD(node, ENTITY_HEADER)
304 #define ENTITY_HEADERS_ARRAYS(node) DT_FOREACH_CHILD(node, ENTITY_HEADER_ARRAYS)
305 #define ENTITY_HEADERS_PTRS(node) DT_FOREACH_CHILD(node, ENTITY_HEADER_PTRS)
306 #define ENTITY_HEADERS_LENGTH(node) sizeof((uint8_t []){ENTITY_HEADERS(node)})
307 
308 #define AUDIO_STREAMING_CONTROLS(node)						\
309 	CONTROL_BITS(entity, active_alternate_setting_control, 0)	|	\
310 	CONTROL_BITS(entity, valid_alternate_settings_control, 2)
311 
312 /* TODO: Support other format types. Currently the PCM format (0x00000001) is
313  * hardcoded and format type is either I or IV depending on whether the
314  * interface has isochronous endpoint or not.
315  */
316 #define AUDIO_STREAMING_FORMAT_TYPE(node)					\
317 	COND_CODE_0(DT_PROP(node, external_interface),				\
318 		(FORMAT_TYPE_I), (FORMAT_TYPE_IV))
319 #define AUDIO_STREAMING_FORMATS(node) U32_LE(0x00000001)
320 
321 /* If AudioStreaming is linked to input terminal, obtain the channel cluster
322  * configuration from the linked terminal. Otherwise (it has to be connected
323  * to output terminal) obtain the channel cluster configuration from data source
324  * entity.
325  */
326 #define AUDIO_STREAMING_CHANNEL_CLUSTER(node)					\
327 	IF_ENABLED(DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal),		\
328 		zephyr_uac2_input_terminal), (					\
329 			DT_PROP(node, linked_terminal)				\
330 	))									\
331 	IF_ENABLED(DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal),		\
332 		zephyr_uac2_output_terminal), (					\
333 			DT_PROP(DT_PROP(node, linked_terminal), data_source)	\
334 	))
335 
336 #define AUDIO_STREAMING_NUM_SPATIAL_LOCATIONS(node)				\
337 	NUM_SPATIAL_LOCATIONS(AUDIO_STREAMING_CHANNEL_CLUSTER(node))
338 #define AUDIO_STREAMING_SPATIAL_LOCATIONS(node)					\
339 	SPATIAL_LOCATIONS(AUDIO_STREAMING_CHANNEL_CLUSTER(node))
340 
341 /* 4.9.2 Class-Specific AS Interface Descriptor */
342 #define AUDIO_STREAMING_GENERAL_DESCRIPTOR(node)				\
343 	0x10,						/* bLength */		\
344 	CS_INTERFACE,					/* bDescriptorType */	\
345 	AS_DESCRIPTOR_GENERAL,				/* bDescriptorSubtype */\
346 	CONNECTED_ENTITY_ID(node, linked_terminal),	/* bTerminalLink */	\
347 	AUDIO_STREAMING_CONTROLS(node),			/* bmControls*/		\
348 	AUDIO_STREAMING_FORMAT_TYPE(node),		/* bFormatType */	\
349 	AUDIO_STREAMING_FORMATS(node),			/* bmFormats */		\
350 	AUDIO_STREAMING_NUM_SPATIAL_LOCATIONS(node),    /* bNrChannels */	\
351 	AUDIO_STREAMING_SPATIAL_LOCATIONS(node),	/* bmChannelConfig */	\
352 	0x00,						/* iChannelNames */
353 
354 /* Universal Serial Bus Device Class Definition for Audio Data Formats
355  * Release 2.0, May 31, 2006. 2.3.1.6 Type I Format Type Descriptor
356  */
357 #define AUDIO_STREAMING_FORMAT_I_TYPE_DESCRIPTOR(node)				\
358 	0x06,						/* bLength */		\
359 	CS_INTERFACE,					/* bDescriptorType */	\
360 	AS_DESCRIPTOR_FORMAT_TYPE,			/* bDescriptorSubtype */\
361 	FORMAT_TYPE_I,					/* bFormatType */	\
362 	DT_PROP(node, subslot_size),			/* bSubslotSize */	\
363 	DT_PROP(node, bit_resolution),			/* bBitResolution */
364 
365 /* Universal Serial Bus Device Class Definition for Audio Data Formats
366  * Release 2.0, May 31, 2006. 2.3.4.1 Type IV Format Type Descriptor
367  */
368 #define AUDIO_STREAMING_FORMAT_IV_TYPE_DESCRIPTOR(node)				\
369 	0x04,						/* bLength */		\
370 	CS_INTERFACE,					/* bDescriptorType */	\
371 	AS_DESCRIPTOR_FORMAT_TYPE,			/* bDescriptorSubtype */\
372 	FORMAT_TYPE_IV,					/* bFormatType */
373 
374 /* 4.9.3 Class-Specific AS Format Type Descriptor */
375 #define AUDIO_STREAMING_FORMAT_TYPE_DESCRIPTOR(node)				\
376 	IF_ENABLED(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_I), (	\
377 		AUDIO_STREAMING_FORMAT_I_TYPE_DESCRIPTOR(node)))		\
378 	IF_ENABLED(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_IV), (	\
379 		AUDIO_STREAMING_FORMAT_IV_TYPE_DESCRIPTOR(node)))
380 
381 #define AUDIO_STREAMING_INTERFACE_DESCRIPTORS(node)				\
382 	AUDIO_STREAMING_GENERAL_DESCRIPTOR(node)				\
383 	AUDIO_STREAMING_FORMAT_TYPE_DESCRIPTOR(node)
384 
385 #define AUDIO_STREAMING_INTERFACE_DESCRIPTORS_ARRAYS(node)			\
386 	static uint8_t DESCRIPTOR_NAME(as_general_desc, node)[] = {		\
387 		AUDIO_STREAMING_GENERAL_DESCRIPTOR(node)			\
388 	};									\
389 	static uint8_t DESCRIPTOR_NAME(as_format_desc, node)[] = {		\
390 		AUDIO_STREAMING_FORMAT_TYPE_DESCRIPTOR(node)			\
391 	};
392 
393 #define AUDIO_STREAMING_INTERFACE_DESCRIPTORS_PTRS(node)			\
394 	(struct usb_desc_header *) &DESCRIPTOR_NAME(as_general_desc, node),	\
395 	(struct usb_desc_header *) &DESCRIPTOR_NAME(as_format_desc, node),
396 
397 /* 4.7.2 Class-Specific AC Interface Descriptor */
398 #define AC_INTERFACE_HEADER_DESCRIPTOR(node)					\
399 	0x09,						/* bLength */		\
400 	CS_INTERFACE,					/* bDescriptorType */	\
401 	AC_DESCRIPTOR_HEADER,				/* bDescriptorSubtype */\
402 	U16_LE(0x0200),					/* bcdADC */		\
403 	DT_PROP(node, audio_function),			/* bCategory */		\
404 	U16_LE(9 + ENTITY_HEADERS_LENGTH(node)),	/* wTotalLength */	\
405 	0x00,						/* bmControls */	\
406 
407 #define AC_INTERFACE_HEADER_DESCRIPTOR_ARRAY(node)				\
408 	static uint8_t DESCRIPTOR_NAME(ac_header, node)[] = {			\
409 		AC_INTERFACE_HEADER_DESCRIPTOR(node)				\
410 	};
411 
412 #define AC_INTERFACE_HEADER_DESCRIPTOR_PTR(node)				\
413 	(struct usb_desc_header *) &DESCRIPTOR_NAME(ac_header, node),
414 
415 #define IS_AUDIOSTREAMING_INTERFACE(node)					\
416 	DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming)
417 
418 #define UAC2_NUM_INTERFACES(node)						\
419 	1 /* AudioControl interface */ +					\
420 	DT_FOREACH_CHILD_SEP(node, IS_AUDIOSTREAMING_INTERFACE, (+))
421 
422 /* 4.6 Interface Association Descriptor */
423 #define UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR(node)				\
424 	0x08,						/* bLength */		\
425 	USB_DESC_INTERFACE_ASSOC,			/* bDescriptorType */	\
426 	FIRST_INTERFACE_NUMBER,				/* bFirstInterface */	\
427 	UAC2_NUM_INTERFACES(node),			/* bInterfaceCount */	\
428 	AUDIO_FUNCTION,					/* bFunctionClass */	\
429 	FUNCTION_SUBCLASS_UNDEFINED,			/* bFunctionSubclass */ \
430 	AF_VERSION_02_00,				/* bFunctionProtocol */	\
431 	0x00,						/* iFunction */
432 
433 #define UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_ARRAY(node)			\
434 	static uint8_t DESCRIPTOR_NAME(iad, node)[] = {				\
435 		UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR(node)					\
436 	};
437 
438 #define UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_PTR(node)				\
439 	(struct usb_desc_header *) &DESCRIPTOR_NAME(iad, node),
440 
441 /* 4.7.1 Standard AC Interface Descriptor */
442 #define AC_INTERFACE_DESCRIPTOR(node)						\
443 	0x09,						/* bLength */		\
444 	USB_DESC_INTERFACE,				/* bDescriptorType */	\
445 	FIRST_INTERFACE_NUMBER,				/* bInterfaceNumber */	\
446 	0x00,						/* bAlternateSetting */ \
447 	DT_PROP(node, interrupt_endpoint),		/* bNumEndpoints */	\
448 	AUDIO,						/* bInterfaceClass */	\
449 	AUDIOCONTROL,					/* bInterfaceSubClass */\
450 	IP_VERSION_02_00,				/* bInterfaceProtocol */\
451 	0x00,						/* iInterface */
452 
453 #define AC_INTERFACE_DESCRIPTOR_ARRAY(node)					\
454 	static uint8_t DESCRIPTOR_NAME(ac_interface, node)[] = {		\
455 		AC_INTERFACE_DESCRIPTOR(node)					\
456 	};
457 
458 #define AC_INTERFACE_DESCRIPTOR_PTR(node)					\
459 	(struct usb_desc_header *) &DESCRIPTOR_NAME(ac_interface, node),
460 
461 /* 4.8.2.1 Standard AC Interrupt Endpoint Descriptor */
462 #define AC_ENDPOINT_DESCRIPTOR(node)						\
463 	0x07,						/* bLength */		\
464 	USB_DESC_ENDPOINT,				/* bDescriptorType */	\
465 	FIRST_IN_EP_ADDR,				/* bEndpointAddress */	\
466 	USB_EP_TYPE_INTERRUPT,				/* bmAttributes */	\
467 	0x06,						/* wMaxPacketSize */	\
468 	0x01,						/* bInterval */		\
469 
470 #define AC_ENDPOINT_DESCRIPTOR_ARRAY(node)					\
471 	static uint8_t DESCRIPTOR_NAME(ac_endpoint, node)[] = {			\
472 		AC_ENDPOINT_DESCRIPTOR(node)					\
473 	};
474 
475 #define AC_ENDPOINT_DESCRIPTOR_PTR(node)					\
476 	(struct usb_desc_header *) &DESCRIPTOR_NAME(ac_endpoint, node),
477 
478 #define FIND_AUDIOSTREAMING(node, fn, ...)					\
479 	IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), (	\
480 		fn(node, __VA_ARGS__)))
481 
482 #define FOR_EACH_AUDIOSTREAMING_INTERFACE(node, fn, ...)			\
483 	DT_FOREACH_CHILD_VARGS(node, FIND_AUDIOSTREAMING, fn, __VA_ARGS__)
484 
485 #define COUNT_AS_INTERFACES_BEFORE_IDX(node, idx)				\
486 	+ 1 * (DT_NODE_CHILD_IDX(node) < idx)
487 
488 #define AS_INTERFACE_NUMBER(node)						\
489 	FIRST_INTERFACE_NUMBER + 1 /* AudioControl interface */	+		\
490 	FOR_EACH_AUDIOSTREAMING_INTERFACE(DT_PARENT(node),			\
491 		COUNT_AS_INTERFACES_BEFORE_IDX, DT_NODE_CHILD_IDX(node))
492 
493 #define AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node)					\
494 	UTIL_NOT(DT_PROP(node, external_interface))
495 
496 #define AS_IS_USB_ISO_IN(node)							\
497 	UTIL_AND(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node),			\
498 		DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal),		\
499 			zephyr_uac2_output_terminal))
500 
501 #define AS_IS_USB_ISO_OUT(node)							\
502 	UTIL_AND(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node),			\
503 		DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal),		\
504 			zephyr_uac2_input_terminal))
505 
506 #define CLK_IS_SOF_SYNCHRONIZED(entity)						\
507 	IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_clock_source), (	\
508 		DT_PROP(entity, sof_synchronized)				\
509 	))
510 
511 /* Sampling frequencies are sorted (asserted at compile time), so just grab
512  * last sampling frequency.
513  */
514 #define CLK_MAX_FREQUENCY(entity)						\
515 	IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_clock_source), (	\
516 		DT_PROP_BY_IDX(entity, sampling_frequencies,			\
517 			UTIL_DEC(DT_PROP_LEN(entity, sampling_frequencies)))	\
518 	))
519 
520 #define AS_CLK_SOURCE(node)							\
521 	DT_PROP(DT_PROP(node, linked_terminal), clock_source)
522 
523 #define AS_CLK_MAX_FREQUENCY(node)						\
524 	CLK_MAX_FREQUENCY(AS_CLK_SOURCE(node))
525 
526 #define AS_IS_SOF_SYNCHRONIZED(node)						\
527 	CLK_IS_SOF_SYNCHRONIZED(AS_CLK_SOURCE(node))
528 
529 #define AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node)					\
530 	UTIL_AND(UTIL_AND(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node),		\
531 			UTIL_NOT(DT_PROP(node, implicit_feedback))),		\
532 		UTIL_AND(UTIL_NOT(AS_IS_SOF_SYNCHRONIZED(node)),		\
533 			AS_IS_USB_ISO_OUT(node)))
534 
535 #define AS_INTERFACE_NUM_ENDPOINTS(node)					\
536 	(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node) +				\
537 	AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node))
538 
539 /* 4.9.1 Standard AS Interface Descriptor */
540 #define AS_INTERFACE_DESCRIPTOR(node, alternate, numendpoints)			\
541 	0x09,						/* bLength */		\
542 	USB_DESC_INTERFACE,				/* bDescriptorType */	\
543 	AS_INTERFACE_NUMBER(node),			/* bInterfaceNumber */	\
544 	alternate,					/* bAlternateSetting */	\
545 	numendpoints,					/* bNumEndpoints */	\
546 	AUDIO,						/* bInterfaceClass */	\
547 	AUDIOSTREAMING,					/* bInterfaceSubClass */\
548 	IP_VERSION_02_00,				/* bInterfaceProtocol */\
549 	0x00,						/* iInterface */
550 
551 #define AS_INTERFACE_DESCRIPTOR_ARRAY(node, alternate, numendpoints)		\
552 	static uint8_t DESCRIPTOR_NAME(as_if_alt##alternate, node)[] = {	\
553 		AS_INTERFACE_DESCRIPTOR(node, alternate, numendpoints)		\
554 	};
555 
556 #define AS_INTERFACE_DESCRIPTOR_PTR(node, alternate)				\
557 	(struct usb_desc_header *) &DESCRIPTOR_NAME(as_if_alt##alternate, node),
558 
559 #define COUNT_AS_OUT_ENDPOINTS_BEFORE_IDX(node, idx)				\
560 	+ AS_IS_USB_ISO_OUT(node) * (DT_NODE_CHILD_IDX(node) < idx)
561 
562 #define COUNT_AS_IN_ENDPOINTS_BEFORE_IDX(node, idx)				\
563 	+ (AS_IS_USB_ISO_IN(node) + AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node))	\
564 		* (DT_NODE_CHILD_IDX(node) < idx)
565 
566 /* FIXME: Ensure that the explicit feedback endpoints assignments match
567  * numbering requirements from Universal Serial Bus Specification Revision 2.0
568  * 9.6.6 Endpoint. This FIXME is not limited to the macros here but also to
569  * actual USB stack endpoint fixup (so the fixup does not break the numbering).
570  *
571  * This FIXME does not affect nRF52 and nRF53 when implicit feedback is used
572  * because the endpoints after fixup will be 0x08 and 0x88 because there are
573  * only two isochronous endpoints on these devices (one IN, one OUT).
574  */
575 #define AS_NEXT_OUT_EP_ADDR(node)						\
576 	FIRST_OUT_EP_ADDR +							\
577 	FOR_EACH_AUDIOSTREAMING_INTERFACE(DT_PARENT(node),			\
578 		COUNT_AS_OUT_ENDPOINTS_BEFORE_IDX, DT_NODE_CHILD_IDX(node))
579 
580 #define AS_NEXT_IN_EP_ADDR(node)						\
581 	FIRST_IN_EP_ADDR + DT_PROP(DT_PARENT(node), interrupt_endpoint) +	\
582 	FOR_EACH_AUDIOSTREAMING_INTERFACE(DT_PARENT(node),			\
583 		COUNT_AS_IN_ENDPOINTS_BEFORE_IDX, DT_NODE_CHILD_IDX(node))
584 
585 #define AS_DATA_EP_ADDR(node)							\
586 	COND_CODE_1(AS_IS_USB_ISO_OUT(node),					\
587 		(AS_NEXT_OUT_EP_ADDR(node)),					\
588 		(AS_NEXT_IN_EP_ADDR(node)))
589 
590 #define AS_BYTES_PER_SAMPLE(node)						\
591 	DT_PROP(node, subslot_size)
592 
593 /* Asynchronous endpoints needs space for 1 extra sample */
594 #define AS_SAMPLES_PER_PACKET(node)						\
595 	((ROUND_UP(AS_CLK_MAX_FREQUENCY(node), 1000) / 1000) +			\
596 	  UTIL_NOT(AS_IS_SOF_SYNCHRONIZED(node)))
597 
598 #define AS_DATA_EP_SYNC_TYPE(node)						\
599 	COND_CODE_1(AS_IS_SOF_SYNCHRONIZED(node), (0x3 << 2), (0x1 << 2))
600 
601 #define AS_DATA_EP_USAGE_TYPE(node)						\
602 	COND_CODE_1(UTIL_AND(DT_PROP(node, implicit_feedback),			\
603 		UTIL_NOT(AS_IS_USB_ISO_OUT(node))), (0x2 << 4), (0x0 << 4))
604 
605 #define AS_DATA_EP_ATTR(node)							\
606 	USB_EP_TYPE_ISO | AS_DATA_EP_SYNC_TYPE(node) |				\
607 	AS_DATA_EP_USAGE_TYPE(node)
608 
609 #define AS_DATA_EP_MAX_PACKET_SIZE(node)					\
610 	AUDIO_STREAMING_NUM_SPATIAL_LOCATIONS(node) *				\
611 	AS_BYTES_PER_SAMPLE(node) * AS_SAMPLES_PER_PACKET(node)
612 
613 /* 4.10.1.1 Standard AS Isochronous Audio Data Endpoint Descriptor */
614 #define STANDARD_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node)			\
615 	0x07,						/* bLength */		\
616 	USB_DESC_ENDPOINT,				/* bDescriptorType */	\
617 	AS_DATA_EP_ADDR(node),				/* bEndpointAddress */	\
618 	AS_DATA_EP_ATTR(node),				/* bmAttributes */	\
619 	U16_LE(AS_DATA_EP_MAX_PACKET_SIZE(node)),	/* wMaxPacketSize */	\
620 	0x01,						/* bInterval */
621 
622 #define LOCK_DELAY_UNITS(node)							\
623 	COND_CODE_1(DT_NODE_HAS_PROP(node, lock_delay_units),			\
624 		(1 + DT_ENUM_IDX(node, lock_delay_units)),			\
625 		(0 /* Undefined */))
626 
627 /* 4.10.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor */
628 #define CLASS_SPECIFIC_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node)		\
629 	0x08,						/* bLength */		\
630 	CS_ENDPOINT,					/* bDescriptorType */	\
631 	EP_GENERAL,					/* bDescriptorSubtype */\
632 	0x00,						/* bmAttributes */	\
633 	AUDIO_STREAMING_DATA_ENDPOINT_CONTROLS(node),	/* bmControls */	\
634 	LOCK_DELAY_UNITS(node),				/* bLockDelayUnits */	\
635 	U16_LE(DT_PROP_OR(node, lock_delay, 0)),	/* wLockDelay */
636 
637 #define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS(node)				\
638 	STANDARD_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node)			\
639 	CLASS_SPECIFIC_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node)
640 
641 #define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_ARRAYS(node)			\
642 	static uint8_t DESCRIPTOR_NAME(std_data_ep, node)[] = {			\
643 		STANDARD_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node)		\
644 	};									\
645 	static uint8_t DESCRIPTOR_NAME(cs_data_ep, node)[] = {			\
646 		CLASS_SPECIFIC_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node)	\
647 	};
648 
649 #define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_PTRS(node)			\
650 	(struct usb_desc_header *) &DESCRIPTOR_NAME(std_data_ep, node),		\
651 	(struct usb_desc_header *) &DESCRIPTOR_NAME(cs_data_ep, node),
652 
653 #define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node)				\
654 	0x07,						/* bLength */		\
655 	USB_DESC_ENDPOINT,				/* bDescriptorType */	\
656 	AS_NEXT_IN_EP_ADDR(node),			/* bEndpointAddress */	\
657 	0x11,						/* bmAttributes */	\
658 	U16_LE(0x03), /* FIXME: 4 on High-Speed*/	/* wMaxPacketSize */	\
659 	0x01, /* TODO: adjust to P 5.12.4.2 Feedback */	/* bInterval */
660 
661 #define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_ARRAY(node)			\
662 	static uint8_t DESCRIPTOR_NAME(feedback_ep, node)[] = {			\
663 		AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node)			\
664 	};
665 
666 #define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_PTR(node)			\
667 	(struct usb_desc_header *) &DESCRIPTOR_NAME(feedback_ep, node),
668 
669 #define AS_DESCRIPTORS(node)							\
670 	AS_INTERFACE_DESCRIPTOR(node, 0, 0)					\
671 	IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), (			\
672 		AS_INTERFACE_DESCRIPTOR(node, 1,				\
673 			AS_INTERFACE_NUM_ENDPOINTS(node))))			\
674 	AUDIO_STREAMING_INTERFACE_DESCRIPTORS(node)				\
675 	IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), (			\
676 		AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS(node)			\
677 		IF_ENABLED(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), (		\
678 			AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node)))	\
679 	))
680 
681 #define AS_DESCRIPTORS_ARRAYS(node)						\
682 	AS_INTERFACE_DESCRIPTOR_ARRAY(node, 0, 0)				\
683 	IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), (			\
684 		AS_INTERFACE_DESCRIPTOR_ARRAY(node, 1,				\
685 			AS_INTERFACE_NUM_ENDPOINTS(node))))			\
686 	AUDIO_STREAMING_INTERFACE_DESCRIPTORS_ARRAYS(node)			\
687 	IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), (			\
688 		AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_ARRAYS(node)		\
689 		IF_ENABLED(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), (		\
690 			AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_ARRAY(node)))	\
691 	))
692 
693 #define AS_DESCRIPTORS_PTRS(node)						\
694 	AS_INTERFACE_DESCRIPTOR_PTR(node, 0)					\
695 	IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), (			\
696 		AS_INTERFACE_DESCRIPTOR_PTR(node, 1)))				\
697 	AUDIO_STREAMING_INTERFACE_DESCRIPTORS_PTRS(node)			\
698 	IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), (			\
699 		AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_PTRS(node)		\
700 		IF_ENABLED(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), (		\
701 			AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_PTR(node)))	\
702 	))
703 
704 #define AS_DESCRIPTORS_IF_AUDIOSTREAMING(node)					\
705 	IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), (	\
706 		AS_DESCRIPTORS(node)))
707 
708 #define AS_DESCRIPTORS_ARRAYS_IF_AUDIOSTREAMING(node)				\
709 	IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), (	\
710 		AS_DESCRIPTORS_ARRAYS(node)))
711 
712 #define AS_DESCRIPTORS_PTRS_IF_AUDIOSTREAMING(node)				\
713 	IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), (	\
714 		AS_DESCRIPTORS_PTRS(node)))
715 
716 #define UAC2_AUDIO_CONTROL_DESCRIPTORS(node)					\
717 	AC_INTERFACE_DESCRIPTOR(node)						\
718 	AC_INTERFACE_HEADER_DESCRIPTOR(node)					\
719 	ENTITY_HEADERS(node)							\
720 	IF_ENABLED(DT_PROP(node, interrupt_endpoint), (				\
721 		AC_ENDPOINT_DESCRIPTOR(node)))
722 
723 #define UAC2_AUDIO_CONTROL_DESCRIPTOR_ARRAYS(node)				\
724 	AC_INTERFACE_DESCRIPTOR_ARRAY(node)					\
725 	AC_INTERFACE_HEADER_DESCRIPTOR_ARRAY(node)				\
726 	ENTITY_HEADERS_ARRAYS(node)						\
727 	IF_ENABLED(DT_PROP(node, interrupt_endpoint), (				\
728 		AC_ENDPOINT_DESCRIPTOR_ARRAY(node)))
729 
730 #define UAC2_AUDIO_CONTROL_DESCRIPTOR_PTRS(node)				\
731 	AC_INTERFACE_DESCRIPTOR_PTR(node)					\
732 	AC_INTERFACE_HEADER_DESCRIPTOR_PTR(node)				\
733 	ENTITY_HEADERS_PTRS(node)						\
734 	IF_ENABLED(DT_PROP(node, interrupt_endpoint), (				\
735 		AC_ENDPOINT_DESCRIPTOR_PTR(node)))
736 
737 #define UAC2_DESCRIPTOR_ARRAYS(node)						\
738 	UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_ARRAY(node)			\
739 	UAC2_AUDIO_CONTROL_DESCRIPTOR_ARRAYS(node)				\
740 	DT_FOREACH_CHILD(node, AS_DESCRIPTORS_ARRAYS_IF_AUDIOSTREAMING)
741 
742 #define UAC2_DESCRIPTOR_PTRS(node)						\
743 	UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_PTR(node)				\
744 	UAC2_AUDIO_CONTROL_DESCRIPTOR_PTRS(node)				\
745 	DT_FOREACH_CHILD(node, AS_DESCRIPTORS_PTRS_IF_AUDIOSTREAMING)		\
746 	NULL
747 
748 #define UAC2_DESCRIPTORS(node)							\
749 	UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR(node)				\
750 	UAC2_AUDIO_CONTROL_DESCRIPTORS(node)					\
751 	DT_FOREACH_CHILD(node, AS_DESCRIPTORS_IF_AUDIOSTREAMING)
752 
753 
754 /* Helper macros to determine endpoint offset within complete UAC2 blob */
755 #define COUNT_AS_DESCRIPTORS_BYTES_UP_TO_IDX(node, idx)				\
756 	(sizeof((uint8_t []){AS_DESCRIPTORS_IF_AUDIOSTREAMING(node)}) *		\
757 	(DT_NODE_CHILD_IDX(node) <= idx))
758 
759 #define UAC2_DESCRIPTOR_AS_DESC_END_OFFSET(node)				\
760 	(sizeof((uint8_t []){							\
761 		UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR(DT_PARENT(node))		\
762 		UAC2_AUDIO_CONTROL_DESCRIPTORS(DT_PARENT(node))			\
763 	})) + DT_FOREACH_CHILD_SEP_VARGS(DT_PARENT(node),			\
764 		COUNT_AS_DESCRIPTORS_BYTES_UP_TO_IDX, (+),			\
765 		DT_NODE_CHILD_IDX(node))
766 
767 #define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_SIZE(node)			\
768 	(sizeof((uint8_t []) {AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS(node)}))
769 
770 #define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_SIZE(node)			\
771 	COND_CODE_1(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node),			\
772 		(sizeof((uint8_t []) {						\
773 			AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node)		\
774 		})), (0))
775 
776 /* Return offset inside UAC2_DESCRIPTORS(DT_PARENT(node)) poiting to data
777  * endpoint address belonging to given AudioStreaming interface node.
778  *
779  * It is programmer error to call this macro with node other than AudioStreaming
780  * or when AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node) is 0.
781  */
782 #define UAC2_DESCRIPTOR_AS_DATA_EP_OFFSET(node)					\
783 	UAC2_DESCRIPTOR_AS_DESC_END_OFFSET(node)				\
784 	- AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_SIZE(node)			\
785 	- AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_SIZE(node)			\
786 	+ offsetof(struct usb_ep_descriptor, bEndpointAddress)
787 
788 /* Return offset inside UAC2_DESCRIPTORS(DT_PARENT(node)) poiting to feedback
789  * endpoint address belonging to given AudioStreaming interface node.
790  *
791  * It is programmer error to call this macro with node other than AudioStreaming
792  * or when AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node) is 0.
793  */
794 #define UAC2_DESCRIPTOR_AS_FEEDBACK_EP_OFFSET(node)				\
795 	UAC2_DESCRIPTOR_AS_DESC_END_OFFSET(node)				\
796 	- AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_SIZE(node)			\
797 	+ offsetof(struct usb_ep_descriptor, bEndpointAddress)
798 
799 /* Helper macros to determine endpoint descriptor offset within descriptor set */
800 #define COUNT_PTRS(...) sizeof((struct usb_desc_header *[]){__VA_ARGS__})	\
801 	/ sizeof(struct usb_desc_header *)
802 
803 #define COUNT_AS_DESCRIPTORS_UP_TO_IDX(node, idx)				\
804 	(COUNT_PTRS(AS_DESCRIPTORS_PTRS_IF_AUDIOSTREAMING(node))) *		\
805 	(DT_NODE_CHILD_IDX(node) <= idx)
806 
807 #define UAC2_DESCRIPTOR_AS_DESC_END_COUNT(node)					\
808 	(COUNT_PTRS(								\
809 		UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_PTR(DT_PARENT(node))	\
810 		UAC2_AUDIO_CONTROL_DESCRIPTOR_PTRS(DT_PARENT(node))		\
811 	)) + DT_FOREACH_CHILD_SEP_VARGS(DT_PARENT(node),			\
812 		COUNT_AS_DESCRIPTORS_UP_TO_IDX, (+),				\
813 		DT_NODE_CHILD_IDX(node))
814 
815 #define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_COUNT(node)			\
816 	COUNT_PTRS(AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_PTRS(node))
817 
818 #define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_COUNT(node)			\
819 	COND_CODE_1(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node),			\
820 		(COUNT_PTRS(							\
821 			AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_PTR(node)	\
822 		)), (0))
823 
824 /* Return index inside UAC2_DESCRIPTOR_PTRS(DT_PARENT(node)) poiting to data
825  * endpoint descriptor belonging to given AudioStreaming interface node.
826  *
827  * It is programmer error to call this macro with node other than AudioStreaming
828  * or when AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node) is 0.
829  */
830 #define UAC2_DESCRIPTOR_AS_DATA_EP_INDEX(node)					\
831 	UAC2_DESCRIPTOR_AS_DESC_END_COUNT(node)					\
832 	- AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_COUNT(node)			\
833 	- AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_COUNT(node)
834 
835 /* Return index inside UAC2_DESCRIPTOR_PTRS(DT_PARENT(node)) poiting to feedback
836  * endpoint descriptor belonging to given AudioStreaming interface node.
837  *
838  * It is programmer error to call this macro with node other than AudioStreaming
839  * or when AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node) is 0.
840  */
841 #define UAC2_DESCRIPTOR_AS_FEEDBACK_EP_INDEX(node)				\
842 	UAC2_DESCRIPTOR_AS_DESC_END_COUNT(node)					\
843 	- AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_COUNT(node)
844 
845 /* Helper macros to validate USB Audio Class 2 devicetree entries.
846  * Macros above do rely on the assumptions checked below.
847  */
848 #define VALIDATE_INPUT_TERMINAL_ASSOCIATION(entity)				\
849 	UTIL_OR(UTIL_NOT(DT_NODE_HAS_PROP(entity, assoc_terminal)),		\
850 		DT_NODE_HAS_COMPAT(DT_PROP(entity, assoc_terminal),		\
851 			zephyr_uac2_output_terminal))
852 
853 #define VALIDATE_OUTPUT_TERMINAL_ASSOCIATION(entity)				\
854 	UTIL_OR(UTIL_NOT(DT_NODE_HAS_PROP(entity, assoc_terminal)),		\
855 		DT_NODE_HAS_COMPAT(DT_PROP(entity, assoc_terminal),		\
856 			zephyr_uac2_input_terminal))
857 
858 #define NEEDS_SUBSLOT_SIZE_AND_BIT_RESOLUTION(node) UTIL_OR(			\
859 	UTIL_OR(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_I),	\
860 		IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_III)),	\
861 	UTIL_OR(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), EXT_FORMAT_TYPE_I),	\
862 		IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), EXT_FORMAT_TYPE_III)))
863 
864 #define VALIDATE_SUBSLOT_SIZE(node)						\
865 	(DT_PROP(node, subslot_size) >= 1 && DT_PROP(node, subslot_size) <= 4)
866 
867 #define VALIDATE_BIT_RESOLUTION(node)						\
868 	(DT_PROP(node, bit_resolution) <= (DT_PROP(node, subslot_size) * 8))
869 
870 #define VALIDATE_LINKED_TERMINAL(node)						\
871 	UTIL_OR(DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal),		\
872 		zephyr_uac2_input_terminal),					\
873 		DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal),		\
874 		zephyr_uac2_output_terminal))
875 
876 #define VALIDATE_NODE(node)							\
877 	IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_clock_source), (	\
878 		BUILD_ASSERT(DT_PROP_LEN(node, sampling_frequencies),		\
879 			"Sampling frequencies array must not be empty");	\
880 		BUILD_ASSERT(IS_ARRAY_SORTED(node, sampling_frequencies),	\
881 			"Sampling frequencies array must be sorted ascending");	\
882 	))									\
883 	IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_input_terminal), (	\
884 		BUILD_ASSERT(!((SPATIAL_LOCATIONS_U32(node) & BIT(31))) ||	\
885 			SPATIAL_LOCATIONS_U32(node) == BIT(31),			\
886 			"Raw Data set alongside other spatial locations");	\
887 		BUILD_ASSERT(VALIDATE_INPUT_TERMINAL_ASSOCIATION(node),		\
888 			"Terminals associations must be Input<->Output");	\
889 	))									\
890 	IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_output_terminal), (	\
891 		BUILD_ASSERT(VALIDATE_OUTPUT_TERMINAL_ASSOCIATION(node),	\
892 			"Terminals associations must be Input<->Output");	\
893 	))									\
894 	IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), (	\
895 		BUILD_ASSERT(VALIDATE_LINKED_TERMINAL(node),			\
896 			"Linked Terminal must be Input or Output Terminal");	\
897 		BUILD_ASSERT(!NEEDS_SUBSLOT_SIZE_AND_BIT_RESOLUTION(node) ||	\
898 			VALIDATE_SUBSLOT_SIZE(node),				\
899 			"Subslot Size can only be 1, 2, 3 or 4");		\
900 		BUILD_ASSERT(!NEEDS_SUBSLOT_SIZE_AND_BIT_RESOLUTION(node) ||	\
901 			VALIDATE_BIT_RESOLUTION(node),				\
902 			"Bit Resolution must fit inside Subslot Size");		\
903 		BUILD_ASSERT(!DT_PROP(node, implicit_feedback) ||		\
904 			!AS_IS_SOF_SYNCHRONIZED(node),				\
905 			"Implicit feedback on SOF synchronized clock");		\
906 	))
907 
908 #endif /* ZEPHYR_INCLUDE_USBD_UAC2_MACROS_H_ */
909