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