Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-hal-cat1 / source / cyhal_analog_common.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 8 KB Fix file modes.
/***************************************************************************//**
* \file cyhal_analog_common.c
*
* \brief
* Provides common functionality that needs to be shared among all drivers that
* interact with the Programmable Analog Subsystem.
*
********************************************************************************
* \copyright
* Copyright 2018-2021 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include "cy_pdl.h"
#include "cyhal_hw_types.h"
#include "cyhal_hwmgr.h"
#include "cyhal_pin_package.h"
#include "cyhal_gpio.h"
#include "cyhal_system_impl.h"

#if defined(CY_IP_MXS40PASS_INSTANCES)
#include "cy_ctb.h"
#endif

#if defined(CY_IP_MXS40PASS_INSTANCES) || defined(CY_IP_M0S8PASS4A_INSTANCES)

#if defined(__cplusplus)
extern "C"
{
#endif

#if defined(CY_IP_MXS40PASS_INSTANCES)
static uint16_t cyhal_analog_ref_count = 0;
#endif

#ifdef CY_IP_MXS40PASS_CTB_INSTANCES
static uint16_t cyhal_analog_ctb_ref_count = 0;

CTBM_Type *const _cyhal_ctb_base[] =
{
#if (CY_IP_MXS40PASS_CTB_INSTANCES == 1)
    CTBM0,
#endif

/* All current CAT1/CAT2 devices have only one CTB block */
#if (CY_IP_MXS40PASS_CTB_INSTANCES > 1)
    #error "Unhandled CTB instance count"
#endif
};


#endif

void _cyhal_analog_init(void)
{
#if defined(CY_IP_MXS40PASS_INSTANCES)
    uint32_t saved_intr = cyhal_system_critical_section_enter();
    if(cyhal_analog_ref_count == 0)
    {
        Cy_SysAnalog_Init(&Cy_SysAnalog_Fast_Local);
        Cy_SysAnalog_Enable();
    }

    ++cyhal_analog_ref_count;
    cyhal_system_critical_section_exit(saved_intr);
#endif
}

void _cyhal_analog_free(void)
{
#if defined(CY_IP_MXS40PASS_INSTANCES)
    uint32_t saved_intr = cyhal_system_critical_section_enter();
    CY_ASSERT(cyhal_analog_ref_count > 0);
    --cyhal_analog_ref_count;
    if(cyhal_analog_ref_count == 0)
    {
        Cy_SysAnalog_Disable();
        Cy_SysAnalog_DeInit();
    }
    cyhal_system_critical_section_exit(saved_intr);
#endif
}

#ifdef CY_IP_MXS40PASS_CTB_INSTANCES
void cyhal_analog_ctb_init(CTBM_Type *base)
{
    uint32_t saved_intr = cyhal_system_critical_section_enter();
    _cyhal_analog_init();
    if(cyhal_analog_ctb_ref_count == 0)
    {
        Cy_CTB_Enable(base);
    }
    ++cyhal_analog_ctb_ref_count;
    cyhal_system_critical_section_exit(saved_intr);
}

void cyhal_analog_ctb_free(CTBM_Type *base)
{
    uint32_t saved_intr = cyhal_system_critical_section_enter();
    CY_ASSERT(cyhal_analog_ctb_ref_count > 0);
    --cyhal_analog_ctb_ref_count;
    if(cyhal_analog_ctb_ref_count == 0)
    {
        Cy_CTB_Disable(base);
        Cy_CTB_DeInit(base, true);
    }
    _cyhal_analog_free();
    cyhal_system_critical_section_exit(saved_intr);
}

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)
{
    /* Follower mode require close switch from vin_p to OAP+, from OAP- to OPAMP_OUT, from OPAMP_OUT to vout */
    /* Non follower mode require close switch from vin_p to OAP+, from vin_m to OAP- */

    const cyhal_resource_pin_mapping_t *vin_p0_map = CY_UTILS_GET_RESOURCE(vin_p, cyhal_pin_map_opamp_vin_p0);
    // If we have a valid vplus pin, it must be in either vin_p0 or vin_p1
#ifdef CYHAL_PIN_MAP_OPAMP_VIN_P1
    CY_ASSERT(NULL != vin_p0_map || NULL != CY_UTILS_GET_RESOURCE(vin_p, cyhal_pin_map_opamp_vin_p1));
#else
    CY_ASSERT(NULL != vin_p0_map);
#endif
    uint32_t switch_mask = (0u == opamp_num)
                            ? ((NULL != vin_p0_map) ? CY_CTB_SW_OA0_POS_PIN0_MASK : CY_CTB_SW_OA0_POS_PIN6_MASK)
                            : ((NULL != vin_p0_map) ? CY_CTB_SW_OA1_POS_PIN5_MASK : CY_CTB_SW_OA1_POS_PIN7_MASK);

    if (NC == vin_m)
    {
        if(NC != vout)
        {
            // Set switches for internal feedback
            switch_mask |= (0u == opamp_num) ? CY_CTB_SW_OA0_OUT_SHORT_1X_10X_MASK : CY_CTB_SW_OA1_OUT_SHORT_1X_10X_MASK ;
            switch_mask |= (0u == opamp_num) ? CY_CTB_SW_OA0_NEG_OUT_MASK          : CY_CTB_SW_OA1_NEG_OUT_MASK;
        }
    }
    else
    {
        switch_mask |= (0u == opamp_num) ? CY_CTB_SW_OA0_NEG_PIN1_MASK :  CY_CTB_SW_OA1_NEG_PIN4_MASK;
    }

    return switch_mask;
}

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)
{
    cy_rslt_t result = CY_RSLT_SUCCESS;
    rsc->type = CYHAL_RSC_INVALID;
    cyhal_gpio_t reserved_vin_p = NC;
    cyhal_gpio_t reserved_vin_m = NC;
    cyhal_gpio_t reserved_vout = NC;
    cyhal_gpio_t reserved_comp_out = NC;

    const cyhal_resource_pin_mapping_t *vin_p_map = CY_UTILS_GET_RESOURCE(vin_p, cyhal_pin_map_opamp_vin_p0);
#ifdef CYHAL_PIN_MAP_OPAMP_VIN_P1
    if(NULL == vin_p_map)
    {
        vin_p_map = CY_UTILS_GET_RESOURCE(vin_p, cyhal_pin_map_opamp_vin_p1);
    }
#endif

    // In at least one use case, everything except for vin_p is optional. Leave it to the calling driver to
    // validate which combinations are allowed in its particular use case.
    const cyhal_resource_pin_mapping_t *vin_m_map = (NC != vin_m)    ? CY_UTILS_GET_RESOURCE(vin_m, cyhal_pin_map_opamp_vin_m)      : NULL;
    const cyhal_resource_pin_mapping_t *vout_map  = (NC != vout)     ? CY_UTILS_GET_RESOURCE(vout, cyhal_pin_map_opamp_out_10x)     : NULL;
    const cyhal_resource_pin_mapping_t *comp_map  = (NC != comp_out) ? CY_UTILS_GET_RESOURCE(comp_out, cyhal_pin_map_opamp_dsi_ctb_cmp) : NULL;


    if(NULL == vin_p_map || (NC != vin_m && NULL == vin_m_map) || (NC != vout && NULL == vout_map) || (NC != comp_out && NULL == comp_map))
    {
        result = bad_arg_error;
    }

    if(CY_RSLT_SUCCESS == result &&
        ((NULL != vin_m_map && false == _cyhal_utils_resources_equal(vin_p_map->inst, vin_m_map->inst))
        || (NULL != vout_map && false == _cyhal_utils_resources_equal(vin_p_map->inst, vout_map->inst))
        || (NULL != comp_map && false == _cyhal_utils_resources_equal(vin_p_map->inst, comp_map->inst))))
    {
        result = bad_arg_error;
    }

    if(CY_RSLT_SUCCESS == result)
    {
        result = cyhal_hwmgr_reserve(vin_p_map->inst);
    }

    if(CY_RSLT_SUCCESS == result)
    {
        *rsc = *(vin_p_map->inst);

        /* If we fail to reserve any of the pins, clear it out so that free doesn't try to release it */
        result = _cyhal_utils_reserve_and_connect(vin_p, vin_p_map);
    }

    if(CY_RSLT_SUCCESS == result)
    {
        reserved_vin_p = vin_p;
        if(NC != vin_m)
        {
            result = _cyhal_utils_reserve_and_connect(vin_m, vin_m_map);
        }
    }

    if(CY_RSLT_SUCCESS == result)
    {
        reserved_vin_m = vin_m;
        if(NC != vout)
        {
            result = _cyhal_utils_reserve_and_connect(vout, vout_map);
        }
    }

    if(CY_RSLT_SUCCESS == result)
    {
        reserved_vout = vout;
        if(NC != comp_out)
        {
            result = _cyhal_utils_reserve_and_connect(comp_out, comp_map);
        }
    }

    if(CY_RSLT_SUCCESS == result)
    {
        reserved_comp_out = comp_out;
    }

    if(CY_RSLT_SUCCESS != result)
    {
        _cyhal_utils_release_if_used(&reserved_vin_p);
        _cyhal_utils_release_if_used(&reserved_vin_m);
        _cyhal_utils_release_if_used(&reserved_vout);
        _cyhal_utils_release_if_used(&reserved_comp_out);

        if(CYHAL_RSC_INVALID != rsc->type)
        {
            cyhal_hwmgr_free(rsc);
        }
    }

    return result;
}

uint32 _cyhal_opamp_convert_power(cyhal_power_level_t hal_power)
{
    switch(hal_power)
    {
        case CYHAL_POWER_LEVEL_OFF:
            return (uint32_t)CY_CTB_POWER_OFF;
        case CYHAL_POWER_LEVEL_LOW:
            return (uint32_t)CY_CTB_POWER_LOW;
        case CYHAL_POWER_LEVEL_MEDIUM:
            return (uint32_t)CY_CTB_POWER_MEDIUM;
        case CYHAL_POWER_LEVEL_HIGH:
            return (uint32_t)CY_CTB_POWER_HIGH;
        case CYHAL_POWER_LEVEL_DEFAULT:
            return (uint32_t)CY_CTB_POWER_MEDIUM;
        default:
            CY_ASSERT(false);
            return CYHAL_POWER_LEVEL_OFF;
    }
}
#endif

#if defined(__cplusplus)
}
#endif

#endif /* defined(CY_IP_MXS40PASS_INSTANCES || defined(CY_IP_M0S8PASS4A_INSTANCES) */