1 /***************************************************************************//**
2 * \file cyhal_interconnect.c
3 *
4 * \brief
5 * Provides a high level interface for interacting with the internal digital
6 * routing on the chip. This is a wrapper around the lower level PDL API.
7 *
8 ********************************************************************************
9 * \copyright
10 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
11 * an affiliate of Cypress Semiconductor Corporation
12 *
13 * SPDX-License-Identifier: Apache-2.0
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 *     http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 *******************************************************************************/
27 
28 #include "cyhal_interconnect.h"
29 #include "cyhal_gpio_impl.h"
30 
31 #if defined(__cplusplus)
32 extern "C"
33 {
34 #endif
35 
36 #if (CYHAL_DRIVER_AVAILABLE_INTERCONNECT)
37 
38 typedef enum
39 {
40     CYHAL_CONNECT_TYPE_VALIDATE,
41     CYHAL_CONNECT_TYPE_CONNECT,
42     CYHAL_CONNECT_TYPE_DISCONNECT,
43 } cyhal_connect_type_t;
44 
45 // Only define if there are actual trigger signals
46 #if defined(CY_IP_M0S8PERI_TR) || defined(CY_IP_MXPERI_TR) || defined(CY_IP_MXSPERI)
47 //Need to take peri #
48 #ifdef CY_IP_M0S8PERI_INSTANCES
49 #define _CYHAL_PERI_INSTANCES (CY_IP_M0S8PERI_INSTANCES)
50 #elif defined(CY_IP_MXSPERI_INSTANCES)
51 #define _CYHAL_PERI_INSTANCES (CY_IP_MXSPERI_INSTANCES)
52 #elif defined(CY_IP_MXPERI_TR_INSTANCES)
53 #define _CYHAL_PERI_INSTANCES (CY_IP_MXPERI_TR_INSTANCES)
54 #endif
55 #ifdef _CYHAL_PERI_INSTANCES
56 static uint8_t _CYHAL_INTERCONNECT_BASE_IDX[_CYHAL_PERI_INSTANCES] = {
57     0,
58 #if (_CYHAL_PERI_INSTANCES == 2)
59     PERI0_TR_GROUP_NR,
60 #elif (_CYHAL_PERI_INSTANCES > 2)
61 #error "Max amount of PERI instances is 2"
62 //For current devices there is a maximum of 2 PERI instances possible
63 #endif
64 };
65 
get_peri_block_from_trigger(uint8_t mux_group)66 static uint32_t get_peri_block_from_trigger(uint8_t mux_group)
67 {
68     uint32_t blk_idx = 0;
69     for(uint8_t i = 0; i < _CYHAL_PERI_INSTANCES;i++)
70     {
71         if(mux_group > _CYHAL_INTERCONNECT_BASE_IDX[i])
72         {
73             blk_idx=i;
74         }
75     }
76     return blk_idx;
77 }
78 
get_local_peri_group_num_from_trigger(uint8_t mux_group)79 static uint32_t get_local_peri_group_num_from_trigger(uint8_t mux_group)
80 {
81     return ((uint32_t)(mux_group - _CYHAL_INTERCONNECT_BASE_IDX[get_peri_block_from_trigger(mux_group)]));
82 }
83 // Helpers for creating Cy_TrigMux_* inputs                                //helper for local peri based group
84 #define CY_TRIGMUX_INPUT_LINE(mux_group, source_idx) (uint32_t)(((get_local_peri_group_num_from_trigger(mux_group))) << 8 | (source_idx) | (get_peri_block_from_trigger(mux_group) << 16u))
85 #define CY_TRIGMUX_OUTPUT_LINE(mux_group, dest_idx) (uint32_t)(0x40000000 |  ((get_local_peri_group_num_from_trigger(mux_group))) << 8 | (dest_idx) | (get_peri_block_from_trigger(mux_group) << 16u))
86 #define CY_SELECT_OUTPUT_LINE(mux_group, dest_idx) (uint32_t)(0x40001000 | ((get_local_peri_group_num_from_trigger(mux_group))) << 8 | (dest_idx) | (get_peri_block_from_trigger(mux_group) << 16u))
87 #else
88 #error "No PERI Instances"
89 #endif
90 #if (CY_IP_MXPERI_VERSION >= 2u) || (CY_IP_M0S8PERI_VERSION >= 1u) || (CY_IP_MXSPERI >= 1u)
_cyhal_get_first_1to1_mux_idx(void)91 static int8_t _cyhal_get_first_1to1_mux_idx(void)
92 {
93     for(uint8_t idx = 0; idx < (sizeof(cyhal_is_mux_1to1)/sizeof(cyhal_is_mux_1to1[0])); idx++)
94     {
95         if(cyhal_is_mux_1to1[idx])
96             return idx;
97     }
98 
99     return -1;
100 }
101 #endif
102 
103 // Reads peri trigmux register and returns the selected input line (0 is
104 // default if no line has been selected)
_cyhal_read_mux_input_idx(uint8_t mux_group,uint8_t mux_output_idx)105 static uint8_t _cyhal_read_mux_input_idx(uint8_t mux_group, uint8_t mux_output_idx)
106 {
107 #if (CY_IP_MXPERI_VERSION >= 2u) || (CY_IP_M0S8PERI_VERSION >= 1u) || (CY_IP_MXSPERI >= 1u)
108     const int8_t MUX_GROUP_1TO1_OFFSET = _cyhal_get_first_1to1_mux_idx();
109     const uint8_t FIRST_1TO1_MUX_GROUP_IDX = 16;
110 #endif
111 
112     uint32_t mux_reg = 0;
113 #if (CY_IP_MXPERI_VERSION >= 2u) || (CY_IP_M0S8PERI_VERSION == 1u) || (CY_IP_MXSPERI >= 1u)
114     // M0S8 has no 1to1 muxes but the table is still valid
115     if(cyhal_is_mux_1to1[mux_group])
116     {
117         // There are up to 16 regular mux groups and up to 16 1to1 mux groups
118         // (in PSoC™ 6).  PERI_TR_GR_TR_CTL starts at the first regular mux so
119         // offset by 16 if reading a 1to1 mux.
120         mux_reg = PERI_TR_GR_TR_CTL(mux_group - MUX_GROUP_1TO1_OFFSET + FIRST_1TO1_MUX_GROUP_IDX, mux_output_idx);
121     }
122     else
123     {
124         mux_reg = PERI_TR_GR_TR_CTL(mux_group, mux_output_idx);
125     }
126 #else // CY_IP_MXPERI_VERSION == 1
127     mux_reg = PERI_TR_GR_TR_CTL(mux_group, mux_output_idx);
128 #endif
129 
130 
131 #if (CY_IP_MXPERI_VERSION >= 1u) || (CY_IP_MXSPERI >= 1u)
132     return _FLD2VAL(PERI_TR_GR_TR_OUT_CTL_TR_SEL, mux_reg);
133 #elif CY_IP_M0S8PERI_VERSION == 1u
134     return _FLD2VAL(PERI_TR_CTL_TR_SEL, mux_reg);
135 #endif
136 }
137 
138 #if (CY_IP_MXPERI_VERSION >= 2u) || (CY_IP_M0S8PERI_VERSION == 1u) || (CY_IP_MXSPERI >= 1u)
_cyhal_interconnect_change_connection_direct(uint8_t mux_group,uint8_t mux_group_1to1_offset,uint8_t source_idx,uint8_t dest_idx,cyhal_signal_type_t type,bool connect)139 static cy_rslt_t _cyhal_interconnect_change_connection_direct(
140     uint8_t mux_group, uint8_t mux_group_1to1_offset, uint8_t source_idx, uint8_t dest_idx, cyhal_signal_type_t type, bool connect)
141 {
142 #if CY_IP_M0S8PERI_VERSION == 1u
143     CY_UNUSED_PARAMETER(type);
144     CY_UNUSED_PARAMETER(mux_group_1to1_offset);
145 #endif
146 
147     if(cyhal_is_mux_1to1[mux_group])
148     {
149 #if (CY_IP_MXPERI_VERSION >= 2u) || (CY_IP_MXSPERI >= 1u)
150         // Cy_TrigMux_Select assumes the mux_group idx param starts from the
151         // first 1to1 mux (so first 1to1 mux is 0)
152         uint32_t out_trig = CY_SELECT_OUTPUT_LINE(mux_group - mux_group_1to1_offset, dest_idx);
153 
154         if(connect)
155             return Cy_TrigMux_Select(out_trig, false, (en_trig_type_t)type);
156         else
157             return Cy_TrigMux_Deselect(out_trig);
158 #else
159         return (connect)
160             ? CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION
161             : CYHAL_INTERCONNECT_RSLT_CANNOT_DISCONNECT;
162 #endif
163     }
164     else
165     {
166         uint32_t in_trig = CY_TRIGMUX_INPUT_LINE(mux_group, source_idx);
167         uint32_t out_trig = CY_TRIGMUX_OUTPUT_LINE(mux_group, dest_idx);
168 
169         if(connect)
170         {
171 #if (CY_IP_MXPERI_VERSION >= 2u) || (CY_IP_MXSPERI >= 1u)
172             return Cy_TrigMux_Connect(in_trig, out_trig, false, (en_trig_type_t)type);
173 #else
174             return Cy_TrigMux_Connect(in_trig, out_trig);
175 #endif
176         }
177         else
178         {
179             // No Cy_TrigMux_Disconnect so just clear register of found
180             // mux input line.
181             PERI_TR_GR_TR_CTL(mux_group, dest_idx) = 0;
182             return CY_RSLT_SUCCESS;
183         }
184     }
185 }
186 #elif CY_IP_MXPERI_VERSION == 1u
187 /* Change a HAL trigger connection where a mux is involved */
_cyhal_interconnect_change_connection_direct(uint8_t mux,uint8_t input_idx,uint8_t output_idx,cyhal_signal_type_t type,bool connect)188 static cy_rslt_t _cyhal_interconnect_change_connection_direct(uint8_t mux, uint8_t input_idx, uint8_t output_idx, cyhal_signal_type_t type, bool connect)
189 {
190     if (connect)
191     {
192         uint32_t in_trig = CY_TRIGMUX_INPUT_LINE(mux, input_idx);
193         uint32_t out_trig = CY_TRIGMUX_OUTPUT_LINE(mux, output_idx);
194 
195         return Cy_TrigMux_Connect(in_trig, out_trig, false, (en_trig_type_t)type);
196     }
197     else
198     {
199         PERI_TR_GR_TR_CTL(mux, output_idx) = 0;
200         return CY_RSLT_SUCCESS;
201     }
202 }
203 
204 /* Change a HAL trigger connection where 2 muxes are involved */
_cyhal_interconnect_change_connection_indirect(uint8_t source_mux_group,uint8_t source_mux_input_idx,uint8_t source_mux_output_idx,uint8_t dest_mux_group,uint8_t dest_mux_input_idx,uint8_t dest_mux_output_idx,cyhal_signal_type_t type,bool connect)205 static cy_rslt_t _cyhal_interconnect_change_connection_indirect(uint8_t source_mux_group, uint8_t source_mux_input_idx, uint8_t source_mux_output_idx,
206     uint8_t dest_mux_group, uint8_t dest_mux_input_idx, uint8_t dest_mux_output_idx, cyhal_signal_type_t type, bool connect)
207 {
208     if(connect)
209     {
210         // Construct Cy_TrigMux_Connect trigger inputs for both source and dest muxes
211         uint32_t source_mux_in_trig = CY_TRIGMUX_INPUT_LINE(source_mux_group, source_mux_input_idx);
212         uint32_t source_mux_out_trig = CY_TRIGMUX_OUTPUT_LINE(source_mux_group, source_mux_output_idx);
213 
214         uint32_t dest_mux_in_trig = CY_TRIGMUX_INPUT_LINE(dest_mux_group, dest_mux_input_idx);
215         uint32_t dest_mux_out_trig = CY_TRIGMUX_OUTPUT_LINE(dest_mux_group, dest_mux_output_idx);
216 
217         if(_cyhal_read_mux_input_idx(dest_mux_group, dest_mux_output_idx) != 0)
218         {
219             return CYHAL_INTERCONNECT_RSLT_ALREADY_CONNECTED;
220         }
221 
222         cy_rslt_t result = Cy_TrigMux_Connect(source_mux_in_trig, source_mux_out_trig, false, (en_trig_type_t)type);
223         if (CY_RSLT_SUCCESS == result)
224             result = Cy_TrigMux_Connect(dest_mux_in_trig, dest_mux_out_trig, false, (en_trig_type_t)type);
225         return result;
226     }
227     else
228     {
229         // No Cy_TrigMux_Disconnect so just clear registers of found muxes
230         PERI_TR_GR_TR_CTL(source_mux_group, source_mux_output_idx) = 0;
231         PERI_TR_GR_TR_CTL(dest_mux_group, dest_mux_output_idx) = 0;
232         return CY_RSLT_SUCCESS;
233     }
234 }
235 #endif /* #if CY_IP_MXPERI_VERSION >= 2u || CY_IP_M0S8PERI_VERSION == 1u */
236 
237 // Since both connect and disconnect need to derive mux group(s) and trigger
238 // indices, use this func to avoid duplicate code.
_cyhal_interconnect_check_connection(cyhal_source_t source,cyhal_dest_t dest,cyhal_connect_type_t connect)239 static cy_rslt_t _cyhal_interconnect_check_connection(cyhal_source_t source, cyhal_dest_t dest, cyhal_connect_type_t connect)
240 {
241     cyhal_internal_source_t internal_src = _CYHAL_TRIGGER_GET_SOURCE_SIGNAL(source);
242     cyhal_signal_type_t type = _CYHAL_TRIGGER_GET_SOURCE_TYPE(source);
243 #if CY_IP_MXPERI_VERSION >= 2u || CY_IP_M0S8PERI_VERSION >= 1u || CY_IP_MXSPERI >= 1u
244     const int8_t mux_group_1to1_offset = _cyhal_get_first_1to1_mux_idx();
245 
246     // cyhal_dest_to_mux stores 1to1 triggers with bit 8 set and the lower 7
247     // bits as the offset into the 1to1 triggers (so 128 is 1to1 mux index 0)
248     // but here we need the actual group offset for all the triggers.
249     uint8_t mux_group = cyhal_dest_to_mux[dest];
250     if(mux_group & 0x80)
251         mux_group = mux_group_1to1_offset + (mux_group & ~0x80);
252     // Ensure mux_group is within the range of cyhal_mux_to_sources to avoid
253     // out-of-bounds indexing
254     if (mux_group >= (sizeof(cyhal_mux_to_sources) / sizeof(cyhal_mux_to_sources[0])))
255     {
256         return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
257     }
258 
259     uint8_t dest_idx = cyhal_mux_dest_index[dest];
260 
261     // Search through table of mux input trigger lines
262     for (uint16_t source_idx = 0; source_idx < cyhal_sources_per_mux[mux_group]; source_idx++)
263     {
264         if(cyhal_mux_to_sources[mux_group][source_idx] == internal_src)
265         {
266             // 1to1 triggers muxes source and dest indices must match
267             if(cyhal_is_mux_1to1[mux_group] && (source_idx != dest_idx))
268             {
269                 return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
270             }
271 
272             // Check if the mux is already configured (possibly from a
273             // different source)
274             if(CYHAL_CONNECT_TYPE_DISCONNECT != connect
275                 && _cyhal_read_mux_input_idx(mux_group, dest_idx) != 0)
276             {
277                 return CYHAL_INTERCONNECT_RSLT_ALREADY_CONNECTED;
278             }
279 
280             return (connect == CYHAL_CONNECT_TYPE_VALIDATE)
281                 ? CY_RSLT_SUCCESS
282                 : _cyhal_interconnect_change_connection_direct(mux_group, mux_group_1to1_offset, source_idx, dest_idx, type, connect == CYHAL_CONNECT_TYPE_CONNECT);
283         }
284     }
285     return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
286 #elif CY_IP_MXPERI_VERSION == 1u
287     uint8_t dest_mux_group = cyhal_dest_to_mux[dest];
288     uint8_t dest_mux_output_idx = cyhal_mux_dest_index[dest];
289 
290     // Special case 1: DW sources connect to USB_DMA_BURSTEND destinations directly
291     // through mux 9 so handle here.
292     if(dest_mux_group == 9)
293     {
294         if((internal_src < _CYHAL_TRIGGER_CPUSS_DW0_TR_OUT0) || (internal_src > _CYHAL_TRIGGER_CPUSS_DW1_TR_OUT15))
295             return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
296 
297         if((dest < CYHAL_TRIGGER_USB_DMA_BURSTEND0) || (dest > CYHAL_TRIGGER_USB_DMA_BURSTEND7))
298             return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
299 
300         uint16_t mux9_input_idx = (uint16_t)(internal_src - _CYHAL_TRIGGER_CPUSS_DW0_TR_OUT0) + 1;
301         uint16_t mux9_output_idx = (uint16_t)(dest - CYHAL_TRIGGER_USB_DMA_BURSTEND0);
302 
303         uint8_t set_input_idx = _cyhal_read_mux_input_idx(9, mux9_output_idx);
304         if ((CYHAL_CONNECT_TYPE_DISCONNECT != connect) && (set_input_idx != 0))
305             return CYHAL_INTERCONNECT_RSLT_ALREADY_CONNECTED;
306         else if ((CYHAL_CONNECT_TYPE_DISCONNECT == connect) && (set_input_idx == 0))
307             return CYHAL_INTERCONNECT_RSLT_CANNOT_DISCONNECT;
308         else
309         {
310             return (connect == CYHAL_CONNECT_TYPE_VALIDATE)
311                 ? CY_RSLT_SUCCESS
312                 : _cyhal_interconnect_change_connection_direct(9, mux9_input_idx, mux9_output_idx, type, connect == CYHAL_CONNECT_TYPE_CONNECT);
313         }
314     }
315 
316     // Special case 2: UDB_TR_DW_ACK destinations have no destinations side mux
317     // and are instead only connected through mux 10. Handle those connections
318     // here (while handling all other connections through mux 10 later).
319     if((dest_mux_group == 10) && (dest >= CYHAL_TRIGGER_UDB_TR_DW_ACK0) && (dest <= CYHAL_TRIGGER_UDB_TR_DW_ACK7))
320     {
321         if((internal_src < _CYHAL_TRIGGER_CPUSS_DW0_TR_OUT0) || (internal_src > _CYHAL_TRIGGER_CPUSS_DW1_TR_OUT15))
322             return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
323 
324         uint16_t mux10_input_idx = (uint16_t)(internal_src - _CYHAL_TRIGGER_CPUSS_DW0_TR_OUT0) + 1;
325         uint16_t mux10_output_idx = (uint16_t)(dest - CYHAL_TRIGGER_UDB_TR_DW_ACK0);
326 
327         uint8_t set_input_idx = _cyhal_read_mux_input_idx(10, mux10_output_idx);
328         if ((CYHAL_CONNECT_TYPE_DISCONNECT != connect) && (set_input_idx != 0))
329             return CYHAL_INTERCONNECT_RSLT_ALREADY_CONNECTED;
330         else if ((CYHAL_CONNECT_TYPE_DISCONNECT == connect) && (set_input_idx == 0))
331             return CYHAL_INTERCONNECT_RSLT_CANNOT_DISCONNECT;
332         else
333         {
334             return (connect == CYHAL_CONNECT_TYPE_VALIDATE)
335                 ? CY_RSLT_SUCCESS
336                 : _cyhal_interconnect_change_connection_direct(10, mux10_input_idx, mux10_output_idx, type, connect == CYHAL_CONNECT_TYPE_CONNECT);
337         }
338     }
339 
340     // Since PSoC™ 6 BLE devices w/ trigmux vers1 have a 1to1 relationship
341     // between peripheral sources and reduction trigger muxes (besides DW which
342     // connects to trig mux 9 and 10, handled above) it is possible to search
343     // through source mux tables to find the idx required.
344     uint16_t source_mux_group = 0;
345     uint16_t source_mux_input_idx = 0;
346     bool found_source_mux_info = false;
347     for(source_mux_group = 10; source_mux_group < 15; source_mux_group++)
348     {
349         for(source_mux_input_idx = 0; source_mux_input_idx < cyhal_sources_per_mux[source_mux_group]; source_mux_input_idx++)
350         {
351             if(cyhal_mux_to_sources[source_mux_group][source_mux_input_idx] == internal_src)
352             {
353                 found_source_mux_info = true;
354                 break;
355             }
356         }
357         if(found_source_mux_info)
358             break;
359     }
360 
361     if(!found_source_mux_info)
362         return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
363 
364     // Construct the cyhal_internal_source_t range that contains all possible inputs
365     // from the source mux to the dest mux. Not every cyhal_internal_source_t in this
366     // range will go to the dest mux but dest_mux_input_line_low and
367     // dest_mux_input_line_high will be used in the next step to find which inputs can.
368     cyhal_internal_source_t dest_mux_input_line_low;
369     cyhal_internal_source_t dest_mux_input_line_high;
370     switch (source_mux_group)
371     {
372         case 10:
373             dest_mux_input_line_low = _CYHAL_TRIGGER_TR_GROUP10_OUTPUT0;
374             dest_mux_input_line_high = _CYHAL_TRIGGER_TR_GROUP10_OUTPUT7;
375             break;
376         case 11:
377             dest_mux_input_line_low = _CYHAL_TRIGGER_TR_GROUP11_OUTPUT0;
378             dest_mux_input_line_high = _CYHAL_TRIGGER_TR_GROUP11_OUTPUT15;
379             break;
380         case 12:
381             dest_mux_input_line_low = _CYHAL_TRIGGER_TR_GROUP12_OUTPUT0;
382             dest_mux_input_line_high = _CYHAL_TRIGGER_TR_GROUP12_OUTPUT9;
383             break;
384         case 13:
385             dest_mux_input_line_low = _CYHAL_TRIGGER_TR_GROUP13_OUTPUT0;
386             dest_mux_input_line_high = _CYHAL_TRIGGER_TR_GROUP13_OUTPUT17;
387             break;
388         case 14:
389             dest_mux_input_line_low = _CYHAL_TRIGGER_TR_GROUP14_OUTPUT0;
390             dest_mux_input_line_high = _CYHAL_TRIGGER_TR_GROUP14_OUTPUT15;
391             break;
392         default:
393             return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
394     }
395 
396     // Search through the dest mux source table to find the low and high
397     // indices of the valid inputs from the source mux to the dest mux. These
398     // indices will correspond to, and be between, dest_mux_input_line_low and
399     // dest_mux_input_line_high (but not necessarily the whole range). If e.g
400     // only source mux output lines 8-9 go to the dest mux this will be
401     // reflected by setting source_mux_start_idx to 8
402     uint16_t dest_mux_input_line_low_idx = 10000;
403     uint16_t dest_mux_input_line_high_idx = 0;
404     uint16_t source_mux_start_idx = 0;
405     for(uint16_t i = 0; i < cyhal_sources_per_mux[dest_mux_group]; i++)
406     {
407         if((cyhal_mux_to_sources[dest_mux_group][i] >= dest_mux_input_line_low) &&
408                 (cyhal_mux_to_sources[dest_mux_group][i] <= dest_mux_input_line_high))
409         {
410             if(dest_mux_input_line_low_idx > i)
411             {
412                 dest_mux_input_line_low_idx = i;
413                 source_mux_start_idx = (uint16_t)(cyhal_mux_to_sources[dest_mux_group][i] - dest_mux_input_line_low);
414             }
415 
416             if(dest_mux_input_line_high_idx < i)
417                 dest_mux_input_line_high_idx = i;
418         }
419     }
420 
421     // Construct possible output trigger lines from the source mux starting at
422     // the first input line found in the previous step. Since source mux output
423     // lines can be arbitrarily selected and may already be in use, read the
424     // source mux register to check if an output is free.
425     uint8_t source_mux_output_idx = 0;
426     uint8_t dest_mux_input_idx = 0;
427     bool found_connection = false;
428     for(source_mux_output_idx = source_mux_start_idx; source_mux_output_idx < (source_mux_start_idx + (dest_mux_input_line_high_idx - dest_mux_input_line_low_idx + 1)); source_mux_output_idx++)
429     {
430         // If connecting: Check if possible output trigger is free.
431         if((connect != CYHAL_CONNECT_TYPE_DISCONNECT) && _cyhal_read_mux_input_idx(source_mux_group, source_mux_output_idx) == 0)
432         {
433             dest_mux_input_idx = dest_mux_input_line_low_idx + source_mux_output_idx - source_mux_start_idx;
434 
435             found_connection = true;
436             break;
437         }
438         // If disconnecting: We have already used this source mux output line
439         // and it matches the inputted source. Since disconnecting only
440         // requires output idx info (for both muxes) nothing needs to be
441         // calculated here.
442         else if((connect == CYHAL_CONNECT_TYPE_DISCONNECT) && _cyhal_read_mux_input_idx(source_mux_group, source_mux_output_idx) == source_mux_input_idx)
443         {
444             found_connection = true;
445             break;
446         }
447     }
448 
449     if(!found_connection)
450     {
451         return (connect == CYHAL_CONNECT_TYPE_DISCONNECT)
452             ? CYHAL_INTERCONNECT_RSLT_CANNOT_DISCONNECT
453             : CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
454     }
455 
456     return (connect == CYHAL_CONNECT_TYPE_VALIDATE)
457         ? CY_RSLT_SUCCESS
458         : _cyhal_interconnect_change_connection_indirect(source_mux_group, source_mux_input_idx, source_mux_output_idx,
459             dest_mux_group, dest_mux_input_idx, dest_mux_output_idx, type, connect == CYHAL_CONNECT_TYPE_CONNECT);
460 #else
461 #error Unrecognized PERI version
462 #endif
463 }
464 
465 #endif /* defined(CY_IP_M0S8PERI_TR) || defined(CY_IP_MXPERI_TR) || defined(CY_IP_MXSPERI) */
466 
_cyhal_connect_signal(cyhal_source_t source,cyhal_dest_t dest)467 cy_rslt_t _cyhal_connect_signal(cyhal_source_t source, cyhal_dest_t dest)
468 {
469 #if defined(CY_IP_M0S8PERI_TR) || defined(CY_IP_MXPERI_TR) || defined(CY_IP_MXSPERI)
470     return _cyhal_interconnect_check_connection(source, dest, CYHAL_CONNECT_TYPE_CONNECT);
471 #else
472     CY_UNUSED_PARAMETER(source);
473     CY_UNUSED_PARAMETER(dest);
474     return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
475 #endif /* defined(CY_IP_M0S8PERI_TR) || defined(CY_IP_MXPERI_TR) || defined(CY_IP_MXSPERI) */
476 }
477 
_cyhal_disconnect_signal(cyhal_source_t source,cyhal_dest_t dest)478 cy_rslt_t _cyhal_disconnect_signal(cyhal_source_t source, cyhal_dest_t dest)
479 {
480 #if defined(CY_IP_M0S8PERI_TR) || defined(CY_IP_MXPERI_TR) || defined(CY_IP_MXSPERI)
481     return _cyhal_interconnect_check_connection(source, dest, CYHAL_CONNECT_TYPE_DISCONNECT);
482 #else
483     CY_UNUSED_PARAMETER(source);
484     CY_UNUSED_PARAMETER(dest);
485     return CYHAL_INTERCONNECT_RSLT_INVALID_CONNECTION;
486 #endif /* defined(CY_IP_M0S8PERI_TR) || defined(CY_IP_MXPERI_TR) || defined(CY_IP_MXSPERI) */
487 }
488 
_cyhal_can_connect_signal(cyhal_source_t source,cyhal_dest_t dest)489 bool _cyhal_can_connect_signal(cyhal_source_t source, cyhal_dest_t dest)
490 {
491 #if defined(CY_IP_M0S8PERI_TR) || defined(CY_IP_MXPERI_TR) || defined(CY_IP_MXSPERI)
492     return (CY_RSLT_SUCCESS == _cyhal_interconnect_check_connection(source, dest, CYHAL_CONNECT_TYPE_VALIDATE));
493 #else
494     CY_UNUSED_PARAMETER(source);
495     CY_UNUSED_PARAMETER(dest);
496     return false;
497 #endif /* defined(CY_IP_M0S8PERI_TR) || defined(CY_IP_MXPERI_TR) || defined(CY_IP_MXSPERI) */
498 }
499 
500 #endif /* CYHAL_DRIVER_AVAILABLE_INTERCONNECT */
501 
cyhal_connect_pin(const cyhal_resource_pin_mapping_t * pin_connection,uint8_t drive_mode)502 cy_rslt_t cyhal_connect_pin(const cyhal_resource_pin_mapping_t *pin_connection, uint8_t drive_mode)
503 {
504     cyhal_gpio_t pin = pin_connection->pin;
505     GPIO_PRT_Type *port = Cy_GPIO_PortToAddr(CYHAL_GET_PORT(pin));
506     en_hsiom_sel_t hsiom = pin_connection->hsiom;
507 
508     Cy_GPIO_Pin_FastInit(port, CYHAL_GET_PIN(pin), drive_mode, 1, hsiom);
509     // Force output to enable pulls.
510     switch (drive_mode)
511     {
512         case CY_GPIO_DM_PULLUP:
513             Cy_GPIO_Write(port, CYHAL_GET_PIN(pin), 1);
514             break;
515         case CY_GPIO_DM_PULLDOWN:
516             Cy_GPIO_Write(port, CYHAL_GET_PIN(pin), 0);
517             break;
518         default:
519             /* do nothing */
520             break;
521     }
522 
523     return CY_RSLT_SUCCESS;
524 }
525 
cyhal_disconnect_pin(cyhal_gpio_t pin)526 cy_rslt_t cyhal_disconnect_pin(cyhal_gpio_t pin)
527 {
528     GPIO_PRT_Type *port = Cy_GPIO_PortToAddr(CYHAL_GET_PORT(pin));
529 
530     Cy_GPIO_Pin_FastInit(port, CYHAL_GET_PIN(pin), CY_GPIO_DM_HIGHZ, 1, HSIOM_SEL_GPIO);
531 
532     return CY_RSLT_SUCCESS;
533 }
534 
535 #if defined(__cplusplus)
536 }
537 #endif
538