/*
 * @file mcp23008_gpio_expander.c
 *
 * @brief This file contains driver function of GPIO expander MCP23008
 *
 * @copyright Copyright 2024 Antaris, Inc.
 *
 * 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 "mcp23008_gpio_expander.h"
#include "main.h"

s_mcp23008 hgpio_exp_nic_u2 = {0};
s_mcp23008 hgpio_exp_nic_u4 = {0};
s_mcp23008 hgpio_exp_nic_u5 = {0};

s_mcp23008 hgpio_exp_es_16 = {0};
s_mcp23008 hgpio_exp_es_37 = {0};
s_mcp23008 hgpio_exp_es_38 = {0};
s_mcp23008 hgpio_exp_es_40 = {0};

s_mcp23008 hgpio_exp_ssd_16 = {0};
s_mcp23008 hgpio_exp_ssd_18 = {0};

s_mcp23008 hgpio_exp_bp_28 = {0};

s_mcp23008 hgpio_exp_pwr_u3 = {0};
s_mcp23008 hgpio_exp_pwr_u19 = {0};
s_mcp23008 hgpio_exp_pwr_u20 = {0};

extern I2C_HandleTypeDef hi2c1;

/*!
 *  @brief I2C read hook function for MCP23008 module
 */
int8_t mcp23008_i2c_read(void* intf_hdl, uint16_t slv_addr, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
    I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef*)intf_hdl;
    int8_t sts = MCP23008_ERR;
    if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)(slv_addr), &reg_addr, 1, 500) == HAL_OK)
    {
        if(HAL_I2C_Master_Receive(hi2c, (uint16_t)(slv_addr), data, len, 500) == HAL_OK)
        {
            sts = MCP23008_SCS;
        }
        else
        {
            sts = MCP23008_COM_ERR;
        }
    }
    else
    {
        sts = MCP23008_COM_ERR;
    }
    return sts;
}

/*!
 *  @brief I2C write hook function for MCP23008 module
 */
int8_t mcp23008_i2c_write(void* intf_hdl, uint16_t slv_addr, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
    I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef*)intf_hdl;
    uint8_t data_array[2] = {0};
    int8_t sts = MCP23008_ERR;
    data_array[0]=reg_addr;
    data_array[1]=data[0];
    if(HAL_I2C_Master_Transmit(hi2c,slv_addr,data_array,2,500) == HAL_OK)
    {
        sts = MCP23008_SCS;
    }
    return sts;
}

/*!
 *  @brief init io board gpio expander function for MCP23008 module
 */
void nic_1_brd_gpio_exp_test_init(uint8_t ahw_id)
{
    switch(ahw_id)
    {
    case GPIO_EXP_MCP23008_U4:
    {
        hgpio_exp_nic_u4.intf_hdl = &hi2c1;
        hgpio_exp_nic_u4.slv_addr = 0x46;
        hgpio_exp_nic_u4.write = mcp23008_i2c_write;
        hgpio_exp_nic_u4.read =  mcp23008_i2c_read;
    }
        break;

    case GPIO_EXP_MCP23008_U5:
    {
        hgpio_exp_nic_u5.intf_hdl = &hi2c1;
        hgpio_exp_nic_u5.slv_addr = 0x42;
        hgpio_exp_nic_u5.write = mcp23008_i2c_write;
        hgpio_exp_nic_u5.read =  mcp23008_i2c_read;
    }
        break;

    case GPIO_EXP_MCP23008_U2:
    {
        hgpio_exp_nic_u2.intf_hdl = &hi2c1;
        hgpio_exp_nic_u2.slv_addr = 0x4E;
        hgpio_exp_nic_u2.write = mcp23008_i2c_write;
        hgpio_exp_nic_u2.read = mcp23008_i2c_read;
    }
        break;
    default:
        break;
    }
}

/*!
 *  @brief init es board gpio expander function for MCP23008 module
 */
void es_brd_gpio_exp_test_init(uint8_t ahw_id)
{
    switch(ahw_id)
    {
    case GPIO_EXP_MCP23008_U16:
    {
        hgpio_exp_es_16.intf_hdl = &hi2c1;
        hgpio_exp_es_16.slv_addr = 0x48;
        hgpio_exp_es_16.write = mcp23008_i2c_write;
        hgpio_exp_es_16.read = mcp23008_i2c_read;
    }
    break;

    case GPIO_EXP_MCP23008_U37:
    {
        hgpio_exp_es_37.intf_hdl = &hi2c1;
        hgpio_exp_es_37.slv_addr = 0x4A;
        hgpio_exp_es_37.write = mcp23008_i2c_write;
        hgpio_exp_es_37.read = mcp23008_i2c_read;
    }
    break;

    case GPIO_EXP_MCP23008_U38:
    {
        hgpio_exp_es_38.intf_hdl = &hi2c1;
        hgpio_exp_es_38.slv_addr = 0x4C;
        hgpio_exp_es_38.write = mcp23008_i2c_write;
        hgpio_exp_es_38.read = mcp23008_i2c_read;
    }
    break;

    case GPIO_EXP_MCP23008_U40:
    {
        hgpio_exp_es_40.intf_hdl = &hi2c1;
        hgpio_exp_es_40.slv_addr = 0x4E;
        hgpio_exp_es_40.write = mcp23008_i2c_write;
        hgpio_exp_es_40.read = mcp23008_i2c_read;
    }
    break;
    default:
        break;
    }
}

/*!
 *  @brief init ssd board gpio expander function for MCP23008 module
 */
void ssd_brd_gpio_exp_test_init(uint8_t ahw_id)
{
    switch(ahw_id)
    {
    case GPIO_EXP_MCP23008_SSD_U16:
    {
        hgpio_exp_ssd_16.intf_hdl = &hi2c1;
        hgpio_exp_ssd_16.slv_addr = 0x4E;
        hgpio_exp_ssd_16.write = mcp23008_i2c_write;
        hgpio_exp_ssd_16.read = mcp23008_i2c_read;
    }
    break;

    case GPIO_EXP_MCP23008_SSD_U18:
    {
        hgpio_exp_ssd_18.intf_hdl = &hi2c1;
        hgpio_exp_ssd_18.slv_addr = 0x40;
        hgpio_exp_ssd_18.write = mcp23008_i2c_write;
        hgpio_exp_ssd_18.read = mcp23008_i2c_read;
    }
        break;
    default:
        break;

    }
}

/*!
 *  @brief init bp board gpio expander function for MCP23008 module
 */
void bp_brd_gpio_exp_test_init(uint8_t ahw_id)
{
    switch(ahw_id)
    {
    case GPIO_EXP_MCP23008_BP_U28:
    {
        hgpio_exp_bp_28.intf_hdl = &hi2c1;
        hgpio_exp_bp_28.slv_addr = 0x40;
        hgpio_exp_bp_28.write = mcp23008_i2c_write;
        hgpio_exp_bp_28.read = mcp23008_i2c_read;
    }
        break;
    default:
        break;

    }
}

/*!
 *  @brief init power board gpio expander function for MCP23008 module
 */
void pwr_brd_gpio_exp_test_init(uint8_t ahw_id)
{
    switch(ahw_id)
    {
    case GPIO_EXP_MCP23008_PWR_BRD_1:
    {
        hgpio_exp_pwr_u3.intf_hdl = &hi2c1;
        hgpio_exp_pwr_u3.slv_addr = 0x40;
        hgpio_exp_pwr_u3.write = mcp23008_i2c_write;
        hgpio_exp_pwr_u3.read = mcp23008_i2c_read;
    }
        break;

    case GPIO_EXP_MCP23008_PWR_BRD_2:
    {
        hgpio_exp_pwr_u19.intf_hdl = &hi2c1;
        hgpio_exp_pwr_u19.slv_addr = 0x4E;
        hgpio_exp_pwr_u19.write = mcp23008_i2c_write;
        hgpio_exp_pwr_u19.read = mcp23008_i2c_read;
    }
        break;

    case GPIO_EXP_MCP23008_PWR_BRD_3:
    {
        hgpio_exp_pwr_u20.intf_hdl = &hi2c1;
        hgpio_exp_pwr_u20.slv_addr = 0x4C;
        hgpio_exp_pwr_u20.write = mcp23008_i2c_write;
        hgpio_exp_pwr_u20.read = mcp23008_i2c_read;
    }
    break;
    default:
        break;

    }
}

/*!
 * @brief This API is used to check null pointer
 */
static e_mcp23008_err mcp23008_null_ptr_check(const s_mcp23008* dev)
{
    e_mcp23008_err sts = MCP23008_ERR;
    if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL))
    {
        sts = MCP23008_NULL_PTR;
    }
    else
    {

        sts = MCP23008_SCS;
    }
    return sts;
}

/*!
 * @brief This function is used to set the GPIO direction
 */
e_mcp23008_err mcp23008_set_direction(s_mcp23008* mcp23008_hdl, uint8_t gpio_pin, e_gpio_dir gpio_dir)
{
    e_mcp23008_err sts= MCP23008_ERR;
    uint8_t data = 0;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(gpio_pin <= MCP23008_GPIO_MAX && gpio_dir < MCP23008_GPIO_DIR_MAX)
        {
            if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,IODIR,&data,1)==MCP23008_SCS)
            {
                if(gpio_dir==MCP23008_GPIO_INPUT)
                {
                    data = data | gpio_pin;
                }
                else
                {
                    data= data & (~gpio_pin);
                }
                sts = mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,IODIR,&data,1);
            }
            else
            {
                sts = MCP23008_COM_ERR;
            }
        }
        else
        {
            sts = MCP23008_INVLD_ARG;
        }
    }
    else
    {
        sts = MCP23008_NULL_PTR;
    }
    return sts;
}

/*!
 * @brief This function is used to read the GPIO
 */
e_gpio_pin_ste mcp23008_read_pin(s_mcp23008* mcp23008_hdl, e_gpio_num gpio_pin)
{
    e_gpio_pin_ste gpio_ste = MCP23008_GPIO_STE_MAX;
    uint8_t data = 0;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPIO_PORT,&data,1) == MCP23008_SCS)
        {
            data = (data & gpio_pin);
            if(data>0)
            {
                gpio_ste = MCP23008_GPIO_HIGH;
            }
            else
            {
                gpio_ste = MCP23008_GPIO_LOW;
            }
        }
    }
    return gpio_ste;
}

/*!
 * @brief This function self validates the GPIO expander by  writing and reading back the data from register through i2c
 */
e_mcp23008_err mcp23008_self_test(s_mcp23008* mcp23008_hdl)
{
    e_mcp23008_err sts = MCP23008_ERR ;
    uint8_t data = 0;
    uint8_t write_data = 0x41;
    uint8_t read_data = 0;
    sts =  mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,DEFVAL,&data,1);
    if(sts == MCP23008_SCS)
    {
        mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,DEFVAL,&write_data,1);
        mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,DEFVAL,&read_data,1);
    }
    if(write_data == read_data)
    {
        sts = MCP23008_SCS;
    }
    else
    {
        sts = MCP23008_ERR;
    }
    mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,DEFVAL,&data,1);
    return sts;
}

/*!
 * @brief This function is used to write the GPIO with specified state
 */
e_mcp23008_err mcp23008_write_pin(s_mcp23008* mcp23008_hdl, uint8_t gpio_pin, e_gpio_pin_ste gpio_ste)
{
    e_mcp23008_err sts= MCP23008_ERR;
    uint8_t data = 0;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(gpio_pin <= MCP23008_GPIO_MAX && gpio_ste < MCP23008_GPIO_STE_MAX)
        {
            if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPIO_PORT,&data,1)==MCP23008_SCS)
            {
                if(gpio_ste==MCP23008_GPIO_HIGH)
                {
                    data = data | gpio_pin;
                }
                else
                {
                    data= data & (~gpio_pin);
                }
                sts= mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPIO_PORT,&data,1);
            }
            else
            {
                sts = MCP23008_COM_ERR;
            }
        }
        else
        {
            sts = MCP23008_INVLD_ARG;
        }
    }
    else
    {
        sts = MCP23008_NULL_PTR;
    }
    return sts;
}

/*!
 * @brief This function is used to toggle the GPIO
 */
e_mcp23008_err mcp23008_toggle_pin(s_mcp23008* mcp23008_hdl, uint8_t gpio_pin)
{
    e_mcp23008_err sts= MCP23008_ERR;
    uint8_t data = 0;
    uint8_t mask = 0x01;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(gpio_pin <= MCP23008_GPIO_MAX)
        {
            if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPIO_PORT,&data,1) == MCP23008_SCS)
            {
                data = data >> gpio_pin;
                data = data & 0x01;
                data = !data;
                if(data == MCP23008_GPIO_HIGH)
                {
                    mask = mask << gpio_pin;
                    data = data | mask;
                }
                else
                {
                    mask = mask << gpio_pin;
                    mask = ~mask;
                    data= data & mask;
                }
                sts= mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPIO_PORT,&data,1);
            }
            else
            {
                sts=MCP23008_COM_ERR ;
            }
        }
        else
        {
            sts=MCP23008_INVLD_ARG;
        }
    }
    else
    {
        sts=MCP23008_NULL_PTR;
    }
    return sts;
}

/*!
 * @brief This function is used to configure the pin
 */
e_mcp23008_err mcp23008_config_pin(s_mcp23008* mcp23008_hdl, s_gpio_config* gpio_pin)
{
    e_mcp23008_err sts= MCP23008_ERR;
    uint8_t gpio_bit_msk = 0;
    uint8_t pin = 0;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS && gpio_pin != NULL)
    {
        switch(gpio_pin->mode)
        {
        case MCP23008_GPIO_MODE_INPUT:
        {
            sts = mcp23008_set_direction (mcp23008_hdl,gpio_pin->gpio_bit_msk,MCP23008_GPIO_INPUT);
            break;
        }
        case MCP23008_GPIO_MODE_OUTPUT:
        {
            sts = mcp23008_set_direction (mcp23008_hdl,gpio_pin->gpio_bit_msk,MCP23008_GPIO_OUTPUT);
            //		sts = mcp23008_write_pin(mcp23008_hdl,gpio_pin->gpio_bit_msk,gpio_pin->gpio_state);
            break;
        }
        case MCP23008_GPIO_MODE_IT_RISING:
        {
            sts = mcp23008_set_direction (mcp23008_hdl,gpio_pin->gpio_bit_msk,MCP23008_GPIO_INPUT);
            sts |= mcp23008_interrupt_cfg(mcp23008_hdl,gpio_pin->gpio_bit_msk, MCP23008_GPIO_INTR_RISING);
            break;
        }
        case MCP23008_GPIO_MODE_IT_FALLING:
        {
            sts = mcp23008_set_direction (mcp23008_hdl,gpio_pin->gpio_bit_msk,MCP23008_GPIO_INPUT);
            sts |= mcp23008_interrupt_cfg(mcp23008_hdl,gpio_pin->gpio_bit_msk, MCP23008_GPIO_INTR_FALLING);
            break;

        }
        case MCP23008_GPIO_MODE_IT_RISING_FALLING:
        {
            sts = mcp23008_set_direction (mcp23008_hdl,gpio_pin->gpio_bit_msk,MCP23008_GPIO_INPUT);
            sts |= mcp23008_interrupt_cfg(mcp23008_hdl,gpio_pin->gpio_bit_msk, MCP23008_GPIO_INTR_RISING_FALLING);
            break;
        }
        }
        if(sts == MCP23008_SCS)
        {
            if(gpio_pin->pull_up_sts==MCP23008_PULLUP_ENABLE)
            {
                sts = mcp23008_pullup_enable (mcp23008_hdl,gpio_pin->gpio_bit_msk);
            }
            else
            {
                sts = mcp23008_pullup_disable (mcp23008_hdl,gpio_pin->gpio_bit_msk);
            }
        }
        if(sts == MCP23008_SCS)
        {
            gpio_bit_msk=gpio_pin->gpio_bit_msk;
            while(gpio_bit_msk)
            {
                if((gpio_bit_msk & 0x01) == 0x01)
                {
                    mcp23008_hdl->callback_func_info[pin].callback_func=gpio_pin->cb_func;
                    mcp23008_hdl->callback_func_info[pin].cb_func_args=gpio_pin->cb_func_args;
                }
                gpio_bit_msk=gpio_bit_msk>>1;
                pin++;
            }
        }
    }
    else
    {
        sts = MCP23008_NULL_PTR;
    }
    return sts;
}

/*!
 * @brief This function is used for enable pullup configuration
 */
e_mcp23008_err mcp23008_pullup_enable(s_mcp23008* mcp23008_hdl, uint8_t gpio_pin)
{
    e_mcp23008_err sts= MCP23008_ERR;
    uint8_t data = 0;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(gpio_pin <= MCP23008_GPIO_MAX )
        {
            if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPPU,&data,1) == MCP23008_SCS)
            {
                data = data | gpio_pin;
            }
            else
            {
                sts=MCP23008_COM_ERR;
            }
            sts=mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPPU,&data,1);
        }
        else
        {
            sts=MCP23008_INVLD_ARG;
        }
    }
    else
    {
        sts=MCP23008_NULL_PTR;
    }
    return sts;
}

/*!
 * @brief This function is used for disable pullup configuration
 */
e_mcp23008_err mcp23008_pullup_disable(s_mcp23008* mcp23008_hdl, uint8_t gpio_pin)
{
    e_mcp23008_err sts= MCP23008_ERR;
    uint8_t data = 0;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(gpio_pin <= MCP23008_GPIO_MAX)
        {
            if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPPU,&data,1) == MCP23008_SCS)
            {
                data= data & (~gpio_pin);
            }
            else
            {
                sts=MCP23008_COM_ERR;
            }
            sts=mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPPU,&data,1);
        }
        else
        {
            sts=MCP23008_INVLD_ARG;
        }
    }
    else
    {
        sts=MCP23008_NULL_PTR;
    }
    return sts;
}

/*!
 * @brief This function configure the interrupt
 */
e_mcp23008_err mcp23008_interrupt_cfg(s_mcp23008* mcp23008_hdl, uint8_t gpio_pin, e_gpio_intr_typ intr_typ)
{
    e_mcp23008_err sts= MCP23008_COM_ERR;
    uint8_t data;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(gpio_pin <= MCP23008_GPIO_MAX && intr_typ < MCP23008_GPIO_INTR_MAX)
        {
            if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPINTEN,&data,1) == MCP23008_SCS)
            {
                switch(intr_typ)
                {
                case MCP23008_GPIO_INTR_DISABLE:
                    data= data & (~gpio_pin);
                    sts=mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPINTEN,&data,1);
                    break;

                case MCP23008_GPIO_INTR_RISING_FALLING:
                    data = data | gpio_pin;
                    if(mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPINTEN,&data,1) == MCP23008_SCS)
                    {
                        if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,INTCON,&data,1) == MCP23008_SCS)
                        {
                            data= data & (~gpio_pin);
                            sts=mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,INTCON,&data,1);
                        }
                    }
                    break;

                case MCP23008_GPIO_INTR_RISING:
                    data = data | gpio_pin;
                    if(mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPINTEN,&data,1) == MCP23008_SCS)
                    {
                        if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,INTCON,&data,1) == MCP23008_SCS)
                        {
                            data = data | gpio_pin;
                            if(mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,INTCON,&data,1) == MCP23008_SCS)
                            {
                                if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,DEFVAL,&data,1) == MCP23008_SCS)
                                {
                                    data = data & (~gpio_pin);
                                    sts=mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,DEFVAL,&data,1);
                                }
                            }
                        }
                    }
                    break;

                case MCP23008_GPIO_INTR_FALLING:
                    data = data | gpio_pin;
                    if(mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,GPINTEN,&data,1) == MCP23008_SCS)
                    {
                        if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,INTCON,&data,1) == MCP23008_SCS)
                        {
                            data = data | gpio_pin;
                            if(mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,INTCON,&data,1) == MCP23008_SCS)
                            {
                                if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,DEFVAL,&data,1) == MCP23008_SCS)
                                {
                                    data = data | gpio_pin;
                                    sts=mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,DEFVAL,&data,1);
                                }
                            }
                        }
                    }
                    break;

                default:
                    break;
                }
            }
            else
            {
                sts=MCP23008_INVLD_ARG;
            }
        }
    }
    else
    {
        sts=MCP23008_NULL_PTR;
    }
    return sts;
}

/*!
 *   @brief This function is used to check the interrupt status
 */
e_mcp23008_err mcp23008_check_intr_sts(s_mcp23008* mcp23008_hdl, uint8_t* intr_sts)
{
    e_mcp23008_err sts= MCP23008_ERR;
    uint8_t data = 0;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,INTF,&data,1) == MCP23008_SCS)
        {
            *intr_sts = data;
            sts =  MCP23008_SCS;
        }
        else
        {
            sts = MCP23008_COM_ERR;
        }
    }
    else
    {
        sts = MCP23008_NULL_PTR;
    }
    return sts;
}

/*!
 *   @brief This function is used to check the interrupt status
 */
e_mcp23008_err mcp23008_clear_interrupt(s_mcp23008* mcp23008_hdl)
{
    e_mcp23008_err sts= MCP23008_ERR;
    uint8_t data = 0;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,INTCAP,&data,1) == MCP23008_SCS)
        {
            sts =  MCP23008_SCS;
        }
        else
        {
            sts = MCP23008_COM_ERR;
        }
    }
    else
    {
        sts = MCP23008_NULL_PTR;
    }
    return sts;
}

/*!
 * @brief This function is used to set the interrupt polarity
 */
e_mcp23008_err mcp23008_int_pin_polarity_cfg(s_mcp23008* mcp23008_hdl,e_int_pin_plrty polarity)
{
    e_mcp23008_err sts= MCP23008_ERR;
    uint8_t data = 0;
    if(mcp23008_null_ptr_check(mcp23008_hdl)==MCP23008_SCS)
    {
        if(polarity<MCP23008_INT_PLRTY_MAX)
        {
            if(mcp23008_hdl->read(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,IOCON,&data,1) == MCP23008_SCS)
            {
                if(polarity == MCP23008_INT_HIGH_IMPEDANCE)
                {
                    data = (data & 0xFB) | 0x04 ;
                }
                else if (polarity == MCP23008_INT_ACT_HIGH)
                {
                    data = (data & 0xF9) | 0x02 ;
                }
                else
                {
                    data = (data & 0xF9);
                }
                sts= mcp23008_hdl->write(mcp23008_hdl->intf_hdl, mcp23008_hdl->slv_addr,IOCON,&data,1);
            }
        }
        else
        {
            sts = MCP23008_INVLD_ARG;
        }
    }
    else
    {
        sts=MCP23008_NULL_PTR;
    }
    return sts;
}

