1 /***************************************************************************//**
2 * \file cyhal_analog_common.c
3 *
4 * \brief
5 * Provides common functionality that needs to be shared among all drivers that
6 * interact with the Programmable Analog Subsystem.
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 "cy_pdl.h"
29 #include "cyhal_hw_types.h"
30 #include "cyhal_hwmgr.h"
31 #include "cyhal_pin_package.h"
32 #include "cyhal_gpio.h"
33 #include "cyhal_system_impl.h"
34 #include "cyhal_analog_common.h"
35 
36 #if (_CYHAL_DRIVER_AVAILABLE_PASS)
37 
38 #if defined(__cplusplus)
39 extern "C"
40 {
41 #endif
42 
43 #if defined(CY_IP_MXS40PASS_INSTANCES)
44 static uint16_t cyhal_analog_ref_count = 0;
45 #endif
46 
47 #if (_CYHAL_DRIVER_AVAILABLE_COMP_CTB)
48 static uint16_t cyhal_analog_ctb_ref_count = 0;
49 
50 CTBM_Type *const _cyhal_ctb_base[] =
51 {
52 /* All current CAT1/CAT2 devices have only one CTB block per PASS */
53 #if ((PASS_NR_CTBS == 1) || (PASS0_NR_CTBS == 1))
54     CTBM0,
55 #else
56     #error "Unhandled CTB instance count"
57 #endif
58 #if (PASS1_NR_CTBS == 1)
59     CTBM1,
60 #elif (PASS1_NR_CTBS > 1)
61     #error "Unhandled CTB instance count"
62 #endif
63 };
64 
65 
66 #endif
67 
_cyhal_analog_init(void)68 void _cyhal_analog_init(void)
69 {
70 #if defined(CY_IP_MXS40PASS_INSTANCES)
71     uint32_t saved_intr = cyhal_system_critical_section_enter();
72     if(cyhal_analog_ref_count == 0)
73     {
74         Cy_SysAnalog_Init(&Cy_SysAnalog_Fast_Local);
75         Cy_SysAnalog_Enable();
76     }
77 
78     ++cyhal_analog_ref_count;
79     cyhal_system_critical_section_exit(saved_intr);
80 #endif
81 }
82 
_cyhal_analog_free(void)83 void _cyhal_analog_free(void)
84 {
85 #if defined(CY_IP_MXS40PASS_INSTANCES)
86     uint32_t saved_intr = cyhal_system_critical_section_enter();
87     CY_ASSERT(cyhal_analog_ref_count > 0);
88     --cyhal_analog_ref_count;
89     if(cyhal_analog_ref_count == 0)
90     {
91         Cy_SysAnalog_Disable();
92         Cy_SysAnalog_DeInit();
93     }
94     cyhal_system_critical_section_exit(saved_intr);
95 #endif
96 }
97 
98 #if (_CYHAL_DRIVER_AVAILABLE_COMP_CTB)
cyhal_analog_ctb_init(CTBM_Type * base)99 void cyhal_analog_ctb_init(CTBM_Type *base)
100 {
101     uint32_t saved_intr = cyhal_system_critical_section_enter();
102     _cyhal_analog_init();
103     if(cyhal_analog_ctb_ref_count == 0)
104     {
105         Cy_CTB_Enable(base);
106     }
107     ++cyhal_analog_ctb_ref_count;
108     cyhal_system_critical_section_exit(saved_intr);
109 }
110 
cyhal_analog_ctb_free(CTBM_Type * base)111 void cyhal_analog_ctb_free(CTBM_Type *base)
112 {
113     uint32_t saved_intr = cyhal_system_critical_section_enter();
114     CY_ASSERT(cyhal_analog_ctb_ref_count > 0);
115     --cyhal_analog_ctb_ref_count;
116     if(cyhal_analog_ctb_ref_count == 0)
117     {
118         Cy_CTB_Disable(base);
119         Cy_CTB_DeInit(base, true);
120     }
121     _cyhal_analog_free();
122     cyhal_system_critical_section_exit(saved_intr);
123 }
124 
_cyhal_opamp_pin_to_mask(uint8_t opamp_num,cyhal_gpio_t vin_p,cyhal_gpio_t vin_m,cyhal_gpio_t vout)125 uint32_t _cyhal_opamp_pin_to_mask(uint8_t opamp_num, cyhal_gpio_t vin_p, cyhal_gpio_t vin_m, cyhal_gpio_t vout)
126 {
127     /* Follower mode require close switch from vin_p to OAP+, from OAP- to OPAMP_OUT, from OPAMP_OUT to vout */
128     /* Non follower mode require close switch from vin_p to OAP+, from vin_m to OAP- */
129 
130     const cyhal_resource_pin_mapping_t *vin_p0_map = _CYHAL_UTILS_GET_RESOURCE(vin_p, cyhal_pin_map_opamp_vin_p0);
131     // If we have a valid vplus pin, it must be in either vin_p0 or vin_p1
132 #ifdef CYHAL_PIN_MAP_DRIVE_MODE_OPAMP_VIN_P1
133     CY_ASSERT((NULL != vin_p0_map) || (NULL != _CYHAL_UTILS_GET_RESOURCE(vin_p, cyhal_pin_map_opamp_vin_p1)));
134 #else
135     CY_ASSERT(NULL != vin_p0_map);
136 #endif
137     uint32_t switch_mask = (0u == opamp_num)
138                             ? ((NULL != vin_p0_map) ? CTBM_OA0_SW_OA0P_A20_Msk /* OA0_POS_PIN0 */ : CTBM_OA0_SW_OA0P_A30_Msk /* OA0_POS_PIN6 */)
139                             : ((NULL != vin_p0_map) ? CTBM_OA1_SW_OA1P_A13_Msk /* OA1_POS_PIN5 */ : CTBM_OA1_SW_OA1P_A43_Msk /* OA1_POS_PIN7 */);
140 
141     if (NC == vin_m)
142     {
143         if(NC != vout)
144         {
145             // Set switches for internal feedback
146             switch_mask |= (0u == opamp_num) ? CTBM_OA0_SW_OA0O_D81_Msk /* OA0_OUT_SHORT_1X_10X */ : CTBM_OA1_SW_OA1O_D82_Msk /* OA1_OUT_SHORT_1X_10X */;
147             switch_mask |= (0u == opamp_num) ? CTBM_OA0_SW_OA0M_A81_Msk : CTBM_OA1_SW_OA1M_A82_Msk;
148         }
149     }
150     else
151     {
152         switch_mask |= (0u == opamp_num) ? CTBM_OA0_SW_OA0M_A11_Msk /* OA0_NEG_PIN1 */ :  CTBM_OA1_SW_OA1M_A22_Msk /* OA1_NEG_PIN4 */;
153     }
154 
155     return switch_mask;
156 }
157 
_cyhal_opamp_init_common(cyhal_resource_inst_t * rsc,cy_rslt_t bad_arg_error,cyhal_gpio_t vin_p,cyhal_gpio_t vin_m,cyhal_gpio_t vout,cyhal_gpio_t comp_out)158 cy_rslt_t _cyhal_opamp_init_common(cyhal_resource_inst_t* rsc, cy_rslt_t bad_arg_error, cyhal_gpio_t vin_p, cyhal_gpio_t vin_m, cyhal_gpio_t vout, cyhal_gpio_t comp_out)
159 {
160     cy_rslt_t result = CY_RSLT_SUCCESS;
161     rsc->type = CYHAL_RSC_INVALID;
162     cyhal_gpio_t reserved_vin_p = NC;
163     cyhal_gpio_t reserved_vin_m = NC;
164     cyhal_gpio_t reserved_vout = NC;
165     cyhal_gpio_t reserved_comp_out = NC;
166 
167     const cyhal_resource_pin_mapping_t *vin_p_map = _CYHAL_UTILS_GET_RESOURCE(vin_p, cyhal_pin_map_opamp_vin_p0);
168 #ifdef CYHAL_PIN_MAP_DRIVE_MODE_OPAMP_VIN_P1
169     if(NULL == vin_p_map)
170     {
171         vin_p_map = _CYHAL_UTILS_GET_RESOURCE(vin_p, cyhal_pin_map_opamp_vin_p1);
172     }
173 #endif
174 
175     // In at least one use case, everything except for vin_p is optional. Leave it to the calling driver to
176     // validate which combinations are allowed in its particular use case.
177     const cyhal_resource_pin_mapping_t *vin_m_map = (NC != vin_m)    ? _CYHAL_UTILS_GET_RESOURCE(vin_m, cyhal_pin_map_opamp_vin_m)      : NULL;
178     const cyhal_resource_pin_mapping_t *vout_map  = (NC != vout)     ? _CYHAL_UTILS_GET_RESOURCE(vout, cyhal_pin_map_opamp_out_10x)     : NULL;
179     const cyhal_resource_pin_mapping_t *comp_map  = (NC != comp_out) ? _CYHAL_UTILS_GET_RESOURCE(comp_out, cyhal_pin_map_opamp_dsi_ctb_cmp) : NULL;
180 
181 
182     if((NULL == vin_p_map) || ((NC != vin_m) && (NULL == vin_m_map)) || ((NC != vout) && (NULL == vout_map)) || ((NC != comp_out) && (NULL == comp_map)))
183     {
184         result = bad_arg_error;
185     }
186 
187     if((CY_RSLT_SUCCESS == result) && (NULL != vin_p_map) &&
188         ((NULL != vin_m_map && (false == _cyhal_utils_map_resources_equal(vin_p_map, vin_m_map)))
189         || (NULL != vout_map && (false == _cyhal_utils_map_resources_equal(vin_p_map, vout_map)))
190         || (NULL != comp_map && (false == _cyhal_utils_map_resources_equal(vin_p_map, comp_map)))))
191     {
192         result = bad_arg_error;
193     }
194 
195     if (NULL != vin_p_map)
196     {
197         cyhal_resource_inst_t rsc2 = { CYHAL_RSC_OPAMP, vin_p_map->block_num, vin_p_map->channel_num };
198         if(CY_RSLT_SUCCESS == result)
199         {
200             result = cyhal_hwmgr_reserve(&rsc2);
201         }
202 
203         if(CY_RSLT_SUCCESS == result)
204         {
205             *rsc = rsc2;
206 
207             /* If we fail to reserve any of the pins, clear it out so that free doesn't try to release it */
208             result = _cyhal_utils_reserve_and_connect(vin_p_map, CYHAL_PIN_MAP_DRIVE_MODE_OPAMP_VIN_P0);
209         }
210 
211         if(CY_RSLT_SUCCESS == result)
212         {
213             reserved_vin_p = vin_p;
214             if(NC != vin_m)
215             {
216                 result = _cyhal_utils_reserve_and_connect(vin_m_map, CYHAL_PIN_MAP_DRIVE_MODE_OPAMP_VIN_M);
217             }
218         }
219 
220         if(CY_RSLT_SUCCESS == result)
221         {
222             reserved_vin_m = vin_m;
223             if(NC != vout)
224             {
225                 result = _cyhal_utils_reserve_and_connect(vout_map, CYHAL_PIN_MAP_DRIVE_MODE_OPAMP_OUT_10X);
226             }
227         }
228 
229         if(CY_RSLT_SUCCESS == result)
230         {
231             reserved_vout = vout;
232             if(NC != comp_out)
233             {
234                 result = _cyhal_utils_reserve_and_connect(comp_map, CYHAL_PIN_MAP_DRIVE_MODE_OPAMP_DSI_CTB_CMP);
235             }
236         }
237 
238         if(CY_RSLT_SUCCESS == result)
239         {
240             reserved_comp_out = comp_out;
241         }
242 
243         if(CY_RSLT_SUCCESS != result)
244         {
245             _cyhal_utils_release_if_used(&reserved_vin_p);
246             _cyhal_utils_release_if_used(&reserved_vin_m);
247             _cyhal_utils_release_if_used(&reserved_vout);
248             _cyhal_utils_release_if_used(&reserved_comp_out);
249 
250             if(CYHAL_RSC_INVALID != rsc->type)
251             {
252                 cyhal_hwmgr_free(rsc);
253             }
254         }
255     }
256 
257     return result;
258 }
259 
_cyhal_opamp_convert_power(cyhal_power_level_t hal_power)260 uint32_t _cyhal_opamp_convert_power(cyhal_power_level_t hal_power)
261 {
262     switch(hal_power)
263     {
264         case CYHAL_POWER_LEVEL_OFF:
265             return (uint32_t)CY_CTB_POWER_OFF;
266         case CYHAL_POWER_LEVEL_LOW:
267             return (uint32_t)CY_CTB_POWER_LOW;
268         case CYHAL_POWER_LEVEL_MEDIUM:
269             return (uint32_t)CY_CTB_POWER_MEDIUM;
270         case CYHAL_POWER_LEVEL_HIGH:
271             return (uint32_t)CY_CTB_POWER_HIGH;
272         case CYHAL_POWER_LEVEL_DEFAULT:
273             return (uint32_t)CY_CTB_POWER_MEDIUM;
274         default:
275             CY_ASSERT(false);
276             return CYHAL_POWER_LEVEL_OFF;
277     }
278 }
279 
280 #endif // _CYHAL_DRIVER_AVAILABLE_COMP_CTB
281 
282 #if defined(__cplusplus)
283 }
284 #endif
285 
286 #endif /* (_CYHAL_DRIVER_AVAILABLE_PASS) */
287