1 /***************************************************************************/ /**
2 * \file cyhal_opamp.c
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon Continuous
6 * Time Block. This interface abstracts out the chip specific details. If any chip
7 * specific functionality is necessary, or performance is critical the low level
8 * functions can be used directly.
9 *
10 ********************************************************************************
11 * \copyright
12 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
13 * an affiliate of Cypress Semiconductor Corporation
14 *
15 * SPDX-License-Identifier: Apache-2.0
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 *     http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 *******************************************************************************/
29 
30 #include <string.h>
31 #include "cyhal_opamp.h"
32 #include "cyhal_gpio.h"
33 #include "cyhal_analog_common.h"
34 #include "cyhal_hwmgr.h"
35 #include "cy_ctb.h"
36 
37 /**
38 * \addtogroup group_hal_impl_opamp Opamp (Operational Amplifier)
39 * \ingroup group_hal_impl
40 *
41 * \section group_hal_impl_opamp_power Power Level Mapping
42 * The following table shows how the HAL-defined power levels map to the hardware-specific power levels
43 * | HAL Power Level                | Opamp Power Level   |
44 * | ------------------------------ | ------------------- |
45 * | @ref CYHAL_POWER_LEVEL_HIGH    | CY_CTB_POWER_HIGH   |
46 * | @ref CYHAL_POWER_LEVEL_MEDIUM  | CY_CTB_POWER_MEDIUM |
47 * | @ref CYHAL_POWER_LEVEL_LOW     | CY_CTB_POWER_LOW    |
48 * | @ref CYHAL_POWER_LEVEL_DEFAULT | CY_CTB_POWER_MEDIUM |
49 *
50 */
51 
52 #if (CYHAL_DRIVER_AVAILABLE_OPAMP)
53 
54 static const cy_stc_ctb_opamp_config_t _cyhal_opamp_default_config =
55 {
56 #if defined(CY_IP_MXS40PASS_CTB_INSTANCES)
57     .deepSleep    = CY_CTB_DEEPSLEEP_ENABLE,
58     .oaPower      = CY_CTB_POWER_OFF,
59     .oaMode       = CY_CTB_MODE_OPAMP10X,
60     .oaPump       = _CYHAL_CTB_PUMP_ENABLE,
61     .oaCompEdge   = CY_CTB_COMP_EDGE_DISABLE,
62     .oaCompLevel  = CY_CTB_COMP_DSI_TRIGGER_OUT_LEVEL,
63     .oaCompBypass = CY_CTB_COMP_BYPASS_SYNC,
64     .oaCompHyst   = CY_CTB_COMP_HYST_DISABLE,
65     .oaCompIntrEn = true,
66 #else
67     .power      = CY_CTB_POWER_OFF,
68     .outputMode = CY_CTB_MODE_OPAMP_EXTERNAL,
69     .pump       = _CYHAL_CTB_PUMP_ENABLE,
70     .compEdge   = CY_CTB_COMP_EDGE_DISABLE,
71     .compLevel  = CY_CTB_COMP_TRIGGER_OUT_LEVEL,
72     .compBypass = false,
73     .compHyst   = false,
74     .compIntrEn = true,
75 #endif
76 };
77 
78 #if defined(__cplusplus)
79 extern "C"
80 {
81 #endif
82 
_cyhal_opamp_init_hw(cyhal_opamp_t * obj,const cy_stc_ctb_opamp_config_t * cfg)83 cy_rslt_t _cyhal_opamp_init_hw(cyhal_opamp_t *obj, const cy_stc_ctb_opamp_config_t* cfg)
84 {
85     obj->base = _cyhal_ctb_base[obj->resource.block_num];
86     cy_rslt_t result = Cy_CTB_OpampInit(obj->base, _cyhal_opamp_convert_sel(obj->resource.channel_num), cfg);
87     if(CY_RSLT_SUCCESS == result)
88     {
89         obj->is_init_success = true;
90         /* Initialize the programmable analog */
91         cyhal_analog_ctb_init(obj->base);
92     }
93     return result;
94 }
95 
cyhal_opamp_init(cyhal_opamp_t * obj,cyhal_gpio_t vin_p,cyhal_gpio_t vin_m,cyhal_gpio_t vout)96 cy_rslt_t cyhal_opamp_init(cyhal_opamp_t *obj, cyhal_gpio_t vin_p, cyhal_gpio_t vin_m, cyhal_gpio_t vout)
97 {
98     /* Check if obj is free */
99     CY_ASSERT(NULL != obj);
100 
101     /* Initial values */
102     cy_rslt_t result = CY_RSLT_SUCCESS;
103     memset(obj, 0, sizeof(cyhal_opamp_t));
104     obj->base = NULL;
105     obj->resource.type = CYHAL_RSC_INVALID;
106     obj->is_init_success = false;
107 
108     /* Validate input pins. vin_p and vout are mandatory pins, vin_m is optional. */
109     if ((NC == vin_p) || (NC == vout))
110     {
111         result = CYHAL_OPAMP_RSLT_ERR_INVALID_PIN;
112     }
113 
114     /* Allocate resources */
115     if(CY_RSLT_SUCCESS == result)
116     {
117         result = _cyhal_opamp_init_common(&(obj->resource), CYHAL_OPAMP_RSLT_BAD_ARGUMENT, vin_p, vin_m, vout, NC /* comp_out unused by opamp */);
118     }
119 
120 
121     /* Configure the opamp */
122     if (result == CY_RSLT_SUCCESS)
123     {
124         obj->pin_vin_p = vin_p;
125         obj->pin_vin_m = vin_m;
126         obj->pin_vout = vout;
127 
128         result = _cyhal_opamp_init_hw(obj, &_cyhal_opamp_default_config);
129     }
130 
131     if (result == CY_RSLT_SUCCESS)
132     {
133         /* OPAMP Routing. Close input switches for OA0 or OA1. */
134         Cy_CTB_SetAnalogSwitch(obj->base, _cyhal_opamp_convert_switch(obj->resource.channel_num), _cyhal_opamp_pin_to_mask(obj->resource.channel_num, vin_p, vin_m, vout), _CYHAL_CTB_SW_CLOSE);
135         _cyhal_opamp_set_isolation_switch(obj->resource.channel_num, obj->base, true);
136     }
137 
138     /* Free OPAMP in case of failure */
139     if (result != CY_RSLT_SUCCESS)
140     {
141         cyhal_opamp_free(obj);
142     }
143     return result;
144 }
145 
cyhal_opamp_init_cfg(cyhal_opamp_t * obj,const cyhal_opamp_configurator_t * cfg)146 cy_rslt_t cyhal_opamp_init_cfg(cyhal_opamp_t *obj, const cyhal_opamp_configurator_t *cfg)
147 {
148     memset(obj, 0, sizeof(cyhal_opamp_t));
149     obj->owned_by_configurator = true;
150     obj->resource = *cfg->resource;
151     obj->is_init_success = false;
152     obj->pin_vin_p = NC;
153     obj->pin_vin_m = NC;
154     obj->pin_vout  = NC;
155     cy_rslt_t result = _cyhal_opamp_init_hw(obj, cfg->config);
156     if(CY_RSLT_SUCCESS != result)
157     {
158         cyhal_opamp_free(obj);
159     }
160 
161     return result;
162 }
163 
cyhal_opamp_set_power(cyhal_opamp_t * obj,cyhal_power_level_t power)164 cy_rslt_t cyhal_opamp_set_power(cyhal_opamp_t *obj, cyhal_power_level_t power)
165 {
166     /* Safe convert power level from HAL (cyhal_power_level_t) to PDL (cy_en_ctb_power_t) */
167     cy_en_ctb_power_t power_level = (cy_en_ctb_power_t)_cyhal_opamp_convert_power(power);
168 
169     Cy_CTB_SetPower(obj->base, _cyhal_opamp_convert_sel(obj->resource.channel_num), power_level, _CYHAL_CTB_PUMP_ENABLE);
170 
171     return CY_RSLT_SUCCESS;
172 }
173 
cyhal_opamp_free(cyhal_opamp_t * obj)174 void cyhal_opamp_free(cyhal_opamp_t *obj)
175 {
176     if (NULL != obj && NULL != obj->base)
177     {
178         if (obj->is_init_success)
179         {
180             cyhal_opamp_set_power(obj, CYHAL_POWER_LEVEL_OFF);
181             if(false == obj->owned_by_configurator)
182             {
183                 Cy_CTB_SetAnalogSwitch(obj->base, _cyhal_opamp_convert_switch(obj->resource.channel_num), _cyhal_opamp_pin_to_mask(obj->resource.channel_num, obj->pin_vin_p, obj->pin_vin_m, obj->pin_vout), _CYHAL_CTB_SW_OPEN);
184                 _cyhal_opamp_set_isolation_switch(obj->resource.channel_num, obj->base, false);
185             }
186             cyhal_analog_ctb_free(obj->base);
187         }
188     }
189 
190     if((NULL != obj) && (CYHAL_RSC_INVALID != obj->resource.type))
191     {
192         if(false == obj->owned_by_configurator)
193         {
194             cyhal_hwmgr_free(&obj->resource);
195         }
196         obj->base = NULL;
197         obj->resource.type = CYHAL_RSC_INVALID;
198     }
199 
200     if(NULL != obj)
201     {
202         _cyhal_utils_release_if_used(&(obj->pin_vin_p));
203         _cyhal_utils_release_if_used(&(obj->pin_vout));
204         _cyhal_utils_release_if_used(&(obj->pin_vin_m));
205     }
206 }
207 
208 #if defined(__cplusplus)
209 }
210 #endif
211 
212 #endif /* CYHAL_DRIVER_AVAILABLE_OPAMP */
213