1 /*
2  * Copyright (c) 2020, Linaro Ltd.
3  * Copyright (c) 2021-2024, Gerson Fernando Budke <nandojve@gmail.com>
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /** @file
9  * @brief Atmel SAM0 MCU family devicetree helper macros
10  */
11 
12 #ifndef _ATMEL_SAM0_DT_H_
13 #define _ATMEL_SAM0_DT_H_
14 
15 /* clang-format off */
16 
17 #define ATMEL_SAM0_DT_INST_CELL_REG_ADDR_OFFSET(n, cell)		\
18 	(volatile uint32_t *)						\
19 	(DT_REG_ADDR(DT_INST_PHANDLE_BY_NAME(n, clocks, cell)) +	\
20 	 DT_INST_CLOCKS_CELL_BY_NAME(n, cell, offset))
21 
22 #define ATMEL_SAM0_DT_INST_CELL_PERIPH_MASK(n, name, cell)		\
23 	BIT(DT_INST_CLOCKS_CELL_BY_NAME(n, name, cell))
24 
25 /* Helper macro to get register address that control peripheral clock
26  * enable bit.
27  */
28 #define ATMEL_SAM0_DT_INST_MCLK_PM_REG_ADDR_OFFSET(n)			\
29 	COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(mclk)),	\
30 		(ATMEL_SAM0_DT_INST_CELL_REG_ADDR_OFFSET(n, mclk)),	\
31 		(ATMEL_SAM0_DT_INST_CELL_REG_ADDR_OFFSET(n, pm)))
32 
33 /* Helper macro to get peripheral clock bit mask.
34  */
35 #define ATMEL_SAM0_DT_INST_MCLK_PM_PERIPH_MASK(n, cell)			\
36 	COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(mclk)),	\
37 		(ATMEL_SAM0_DT_INST_CELL_PERIPH_MASK(n, mclk, cell)),	\
38 		(ATMEL_SAM0_DT_INST_CELL_PERIPH_MASK(n, pm, cell)))
39 
40 /* Helper macros for use with ATMEL SAM0 DMAC controller
41  * return 0xff as default value if there is no 'dmas' property
42  */
43 #define ATMEL_SAM0_DT_INST_DMA_CELL(n, name, cell)		\
44 	COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas),		\
45 		    (DT_INST_DMAS_CELL_BY_NAME(n, name, cell)),	\
46 		    (0xff))
47 #define ATMEL_SAM0_DT_INST_DMA_TRIGSRC(n, name) \
48 	ATMEL_SAM0_DT_INST_DMA_CELL(n, name, trigsrc)
49 #define ATMEL_SAM0_DT_INST_DMA_CHANNEL(n, name) \
50 	ATMEL_SAM0_DT_INST_DMA_CELL(n, name, channel)
51 #define ATMEL_SAM0_DT_INST_DMA_CTLR(n, name)			\
52 	COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas),		\
53 		    (DT_INST_DMAS_CTLR_BY_NAME(n, name)),	\
54 		    (DT_INVALID_NODE))
55 
56 
57 /* Use to check if a sercom 'n' is enabled for a given 'compat' */
58 #define ATMEL_SAM0_DT_SERCOM_CHECK(n, compat) \
59 	DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(sercom##n), compat, okay)
60 
61 /* Use to check if TCC 'n' is enabled for a given 'compat' */
62 #define ATMEL_SAM0_DT_TCC_CHECK(n, compat) \
63 	DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(tcc##n), compat, okay)
64 
65 /* Common macro for use to set HCLK_FREQ_HZ */
66 #define ATMEL_SAM0_DT_CPU_CLK_FREQ_HZ \
67 	DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency)
68 
69 /**
70  * @brief Test if a node has a atmel,assigned-clocks phandle-array property at
71  * a given index.
72  *
73  * This expands to 1 if the given index is valid atmel,assigned-clocks property
74  * phandle-array index. Otherwise, it expands to 0.
75  *
76  * Example devicetree fragment:
77  *
78  *     n1: node-1 {
79  *             atmel,assigned-clocks = <...>, <...>;
80  *     };
81  *
82  *     n2: node-2 {
83  *             atmel,assigned-clocks = <...>;
84  *     };
85  *
86  * Example usage:
87  *
88  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_IDX(DT_NODELABEL(n1), 0) // 1
89  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_IDX(DT_NODELABEL(n1), 1) // 1
90  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_IDX(DT_NODELABEL(n1), 2) // 0
91  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_IDX(DT_NODELABEL(n2), 1) // 0
92  *
93  * @param node_id node identifier; may or may not have any atmel,assigned-clocks
94  *		  property
95  * @param idx index of a atmel,assigned-clocks property phandle-array whose
96  *            existence to check
97  * @return 1 if the index exists, 0 otherwise
98  */
99 #define ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_IDX(node_id, idx) \
100 	DT_PROP_HAS_IDX(node_id, atmel_assigned_clocks, idx)
101 
102 /**
103  * @brief Test if a node has a clock-names array property holds a given name
104  *
105  * This expands to 1 if the name is available as atmel,assigned-clocks-name array
106  * property cell. Otherwise, it expands to 0.
107  *
108  * Example devicetree fragment:
109  *
110  *     n1: node-1 {
111  *             atmel,assigned-clocks = <...>, <...>;
112  *             atmel,assigned-clock-names = "alpha", "beta";
113  *     };
114  *
115  *     n2: node-2 {
116  *             atmel,assigned-clocks = <...>;
117  *             atmel,assigned-clock-names = "alpha";
118  *     };
119  *
120  * Example usage:
121  *
122  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_NAME(DT_NODELABEL(n1), alpha) // 1
123  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_NAME(DT_NODELABEL(n1), beta)  // 1
124  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_NAME(DT_NODELABEL(n2), beta)  // 0
125  *
126  * @param node_id node identifier; may or may not have any clock-names property.
127  * @param name lowercase-and-underscores clock-names cell value name to check
128  * @return 1 if the atmel,assigned-clock name exists, 0 otherwise
129  */
130 #define ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_NAME(node_id, name) \
131 	DT_PROP_HAS_NAME(node_id, atmel_assigned_clocks, name)
132 
133 /**
134  * @brief Get the number of elements in a atmel,assigned-clocks property
135  *
136  * Example devicetree fragment:
137  *
138  *     n1: node-1 {
139  *             atmel,assigned-clocks = <&foo>, <&bar>;
140  *     };
141  *
142  *     n2: node-2 {
143  *             atmel,assigned-clocks = <&foo>;
144  *     };
145  *
146  * Example usage:
147  *
148  *     ATMEL_SAM0_DT_NUM_ASSIGNED_CLOCKS(DT_NODELABEL(n1)) // 2
149  *     ATMEL_SAM0_DT_NUM_ASSIGNED_CLOCKS(DT_NODELABEL(n2)) // 1
150  *
151  * @param node_id node identifier with a atmel,assigned-clocks property
152  * @return number of elements in the property
153  */
154 #define ATMEL_SAM0_DT_NUM_ASSIGNED_CLOCKS(node_id) \
155 	DT_PROP_LEN(node_id, atmel_assigned_clocks)
156 
157 
158 /**
159  * @brief Get the node identifier for the controller phandle from a
160  *        "atmel,assigned-clocks" phandle-array property at an index
161  *
162  * Example devicetree fragment:
163  *
164  *     clk1: clock-controller@... { ... };
165  *
166  *     clk2: clock-controller@... { ... };
167  *
168  *     n: node {
169  *             atmel,assigned-clocks = <&clk1 10 20>, <&clk2 30 40>;
170  *     };
171  *
172  * Example usage:
173  *
174  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_IDX(DT_NODELABEL(n), 0)) // DT_NODELABEL(clk1)
175  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_IDX(DT_NODELABEL(n), 1)) // DT_NODELABEL(clk2)
176  *
177  * @param node_id node identifier
178  * @param idx logical index into "atmel,assigned-clocks"
179  * @return the node identifier for the clock controller referenced at index "idx"
180  * @see DT_PHANDLE_BY_IDX()
181  */
182 #define ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_IDX(node_id, idx) \
183 	DT_PHANDLE_BY_IDX(node_id, atmel_assigned_clocks, idx)
184 
185 /**
186  * @brief Equivalent to ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_IDX(node_id, 0)
187  * @param node_id node identifier
188  * @return a node identifier for the atmel,assigned-clocks controller at index 0
189  *         in "atmel,assigned-clocks"
190  * @see ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_IDX()
191  */
192 #define ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR(node_id) \
193 	ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_IDX(node_id, 0)
194 
195 /**
196  * @brief Get the node identifier for the controller phandle from a
197  *        atmel,assigned-clocks phandle-array property by name
198  *
199  * Example devicetree fragment:
200  *
201  *     clk1: clock-controller@... { ... };
202  *
203  *     clk2: clock-controller@... { ... };
204  *
205  *     n: node {
206  *             atmel,assigned-clocks = <&clk1 10 20>, <&clk2 30 40>;
207  *             atmel,assigned-clock-names = "alpha", "beta";
208  *     };
209  *
210  * Example usage:
211  *
212  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_NAME(DT_NODELABEL(n), beta) // DT_NODELABEL(clk2)
213  *
214  * @param node_id node identifier
215  * @param name lowercase-and-underscores name of a atmel,assigned-clocks element
216  *             as defined by the node's clock-names property
217  * @return the node identifier for the clock controller referenced by name
218  * @see DT_PHANDLE_BY_NAME()
219  */
220 #define ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_NAME(node_id, name) \
221 	DT_PHANDLE_BY_NAME(node_id, atmel_assigned_clocks, name)
222 
223 /**
224  * @brief Get a atmel,assigned-clock specifier's cell value at an index
225  *
226  * Example devicetree fragment:
227  *
228  *     clk1: clock-controller@... {
229  *             compatible = "vnd,clock";
230  *             #atmel,assigned-clock-cells = < 2 >;
231  *     };
232  *
233  *     n: node {
234  *             atmel,assigned-clocks = < &clk1 10 20 >, < &clk1 30 40 >;
235  *     };
236  *
237  * Bindings fragment for the vnd,clock compatible:
238  *
239  *     atmel,assigned-clock-cells:
240  *       - bus
241  *       - bits
242  *
243  * Example usage:
244  *
245  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_IDX(DT_NODELABEL(n), 0, bus) // 10
246  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_IDX(DT_NODELABEL(n), 1, bits) // 40
247  *
248  * @param node_id node identifier for a node with a atmel,assigned-clocks property
249  * @param idx logical index into atmel,assigned-clocks property
250  * @param cell lowercase-and-underscores cell name
251  * @return the cell value at index "idx"
252  * @see DT_PHA_BY_IDX()
253  */
254 #define ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_IDX(node_id, idx, cell) \
255 	DT_PHA_BY_IDX(node_id, atmel_assigned_clocks, idx, cell)
256 
257 /**
258  * @brief Get a atmel,assigned-clock specifier's cell value by name
259  *
260  * Example devicetree fragment:
261  *
262  *     clk1: clock-controller@... {
263  *             compatible = "vnd,clock";
264  *             #atmel,assigned-clock-cells = < 2 >;
265  *     };
266  *
267  *     n: node {
268  *             atmel,assigned-clocks = < &clk1 10 20 >, < &clk1 30 40 >;
269  *             clock-names = "alpha", "beta";
270  *     };
271  *
272  * Bindings fragment for the vnd,clock compatible:
273  *
274  *     atmel,assigned-clock-cells:
275  *       - bus
276  *       - bits
277  *
278  * Example usage:
279  *
280  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_NAME(DT_NODELABEL(n), alpha, bus) // 10
281  *     ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_NAME(DT_NODELABEL(n), beta, bits) // 40
282  *
283  * @param node_id node identifier for a node with a atmel,assigned-clocks property
284  * @param name lowercase-and-underscores name of a atmel,assigned-clocks element
285  *             as defined by the node's clock-names property
286  * @param cell lowercase-and-underscores cell name
287  * @return the cell value in the specifier at the named element
288  * @see DT_PHA_BY_NAME()
289  */
290 #define ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_NAME(node_id, name, cell) \
291 	DT_PHA_BY_NAME(node_id, atmel_assigned_clocks, name, cell)
292 
293 /**
294  * @brief Equivalent to ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_IDX(node_id, 0, cell)
295  * @param node_id node identifier for a node with a atmel,assigned-clocks property
296  * @param cell lowercase-and-underscores cell name
297  * @return the cell value at index 0
298  * @see ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_IDX()
299  */
300 #define ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL(node_id, cell) \
301 	ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_IDX(node_id, 0, cell)
302 
303 /**
304  * @brief Equivalent to ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_IDX(DT_DRV_INST(inst), idx)
305  * @param inst DT_DRV_COMPAT instance number; may or may not have any
306  *             atmel,assigned-clocks property
307  * @param idx index of a atmel,assigned-clocks property phandle-array whose existence
308  *            to check
309  * @return 1 if the index exists, 0 otherwise
310  */
311 #define ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_HAS_IDX(inst, idx) \
312 	DT_ASSIGNED_CLOCKS_HAS_IDX(DT_DRV_INST(inst), idx)
313 
314 /**
315  * @brief Equivalent to DT_CLOCK_HAS_NAME(DT_DRV_INST(inst), name)
316  * @param inst DT_DRV_COMPAT instance number; may or may not have any
317  *             atmel,clock-names property.
318  * @param name lowercase-and-underscores clock-names cell value name to check
319  * @return 1 if the atmel,assigned-clock name exists, 0 otherwise
320  */
321 #define ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_HAS_NAME(inst, name) \
322 	ATMEL_SAM0_DT_ASSIGNED_CLOCKS_HAS_NAME(DT_DRV_INST(inst), name)
323 
324 /**
325  * @brief Equivalent to ATMEL_SAM0_DT_NUM_ASSIGNED_CLOCKS(DT_DRV_INST(inst))
326  * @param inst instance number
327  * @return number of elements in the atmel,assigned-clocks property
328  */
329 #define ATMEL_SAM0_DT_INST_NUM_ASSIGNED_CLOCKS(inst) \
330 	ATMEL_SAM0_DT_NUM_ASSIGNED_CLOCKS(DT_DRV_INST(inst))
331 
332 /**
333  * @brief Get the node identifier for the controller phandle from a
334  *        "atmel,assigned-clocks" phandle-array property at an index
335  *
336  * @param inst instance number
337  * @param idx logical index into "atmel,assigned-clocks"
338  * @return the node identifier for the clock controller referenced at
339  *         index "idx"
340  * @see ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_IDX()
341  */
342 #define ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CTLR_BY_IDX(inst, idx) \
343 	ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_IDX(DT_DRV_INST(inst), idx)
344 
345 /**
346  * @brief Equivalent to ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CTLR_BY_IDX(inst, 0)
347  * @param inst instance number
348  * @return a node identifier for the atmel,assigned-clocks controller at index 0
349  *         in "atmel,assigned-clocks"
350  * @see ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR()
351  */
352 #define ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CTLR(inst) \
353 	ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CTLR_BY_IDX(inst, 0)
354 
355 /**
356  * @brief Get the node identifier for the controller phandle from a
357  *        atmel,assigned-clocks phandle-array property by name
358  *
359  * @param inst instance number
360  * @param name lowercase-and-underscores name of a atmel,assigned-clocks element
361  *             as defined by the node's atmel,assigned-clock-names property
362  * @return the node identifier for the clock controller referenced by
363  *         the named element
364  * @see ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_NAME()
365  */
366 #define ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CTLR_BY_NAME(inst, name) \
367 	ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CTLR_BY_NAME(DT_DRV_INST(inst), name)
368 
369 /**
370  * @brief Get a DT_DRV_COMPAT instance's atmel,assigned-clock specifier's cell
371  *        value at an index
372  * @param inst DT_DRV_COMPAT instance number
373  * @param idx logical index into atmel,assigned-clocks property
374  * @param cell lowercase-and-underscores cell name
375  * @return the cell value at index "idx"
376  * @see ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_IDX()
377  */
378 #define ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CELL_BY_IDX(inst, idx, cell) \
379 	ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_IDX(DT_DRV_INST(inst), idx, cell)
380 
381 /**
382  * @brief Get a DT_DRV_COMPAT instance's atmel,assigned-clock specifier's cell
383  *        value by name
384  * @param inst DT_DRV_COMPAT instance number
385  * @param name lowercase-and-underscores name of a atmel,assigned-clocks element
386  *             as defined by the node's atmel,assigned-clock-names property
387  * @param cell lowercase-and-underscores cell name
388  * @return the cell value in the specifier at the named element
389  * @see ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_NAME()
390  */
391 #define ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CELL_BY_NAME(inst, name, cell) \
392 	ATMEL_SAM0_DT_ASSIGNED_CLOCKS_CELL_BY_NAME(DT_DRV_INST(inst), name, cell)
393 
394 /**
395  * @brief Equivalent to ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CELL_BY_IDX(inst, 0, cell)
396  * @param inst DT_DRV_COMPAT instance number
397  * @param cell lowercase-and-underscores cell name
398  * @return the value of the cell inside the specifier at index 0
399  */
400 #define ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CELL(inst, cell) \
401 	ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CELL_BY_IDX(inst, 0, cell)
402 
403 /* clang-format on */
404 
405 #endif /* _ATMEL_SAM0_SOC_DT_H_ */
406