/**************************************************************************** * * Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED. * * This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT * be copied by any method or incorporated into another program without * the express written consent of Aerospace C.Power. This Information or any portion * thereof remains the property of Aerospace C.Power. The Information contained herein * is believed to be accurate and Aerospace C.Power assumes no responsibility or * liability for its use in any way and conveys no license or title under * any patent or copyright and makes no representation or warranty that this * Information is free from patent or copyright infringement. * * ****************************************************************************/ #include "os_types.h" #include "iot_errno.h" #include "iot_i2c_api.h" #include "iot_gpio_api.h" #include "gpio.h" #include "gpio_mtx.h" #include "i2c_hw.h" #include "os_utils.h" #include "iot_io_api.h" #include "iot_board_api.h" #include "os_lock.h" #include "iot_gpio_ex.h" /* The iic config of tpt29555. */ #define TPT29555_IIC_PHY_ADDR (0x24) #define TPT29555_INIT_COMPLETED (1) #define TPT29555_INIT_UNCOMPLETED (0) #define TPT29555_IIC_DEF_PORT (0) /* Port#0. */ #define TPT29555_IIC_DEF_SPEED (100) /* 100K. */ #define TPT29555_IIC_DEF_NACK_NUM (1) /* N-ACK number. */ /* TPT29555 reg op cmd. */ #define TPT29555_INPUT_PORT_REGA (0x00) //read data from gpio. #define TPT29555_INPUT_PORT_REGB (0x01) #define TPT29555_OUTPUT_PORT_REGA (0x02) //output data to gpio. #define TPT29555_OUTPUT_PORT_REGB (0x03) #define TPT29555_INVER_PORT_REGA (0x04) //polarity inversion to gpio. #define TPT29555_INVER_PORT_REGB (0x05) #define TPT29555_CONFIG_PORT_REGA (0x06) //set the directions of gpio. #define TPT29555_CONFIG_PORT_REGB (0x07) #define TPT29555_REGISTER_RESPONSE_TM (10) // tpt29555 response time: ms /* each port has 8 gpios, gpio7 ~ gpio0. */ #define GPIO_EX_PORT_NUMBER (8) #define TPT29555_GPIO_EX_PORTA (0x00) #define TPT29555_GPIO_EX_PORTB (0x01) #define GPIO_EX_GET_GPIO(gpio) ((gpio) % GPIO_EX_PORT_NUMBER) #define GPIO_EX_GET_PORT(gpio) ((gpio) / GPIO_EX_PORT_NUMBER) #define GPIO_EX_VALID(gpio) (((gpio) >= 0) && \ ((gpio) < GPIO_EX_PORT_NUMBER)) #define GPIO_PORT_VALID(port) ((port) == TPT29555_GPIO_EX_PORTA || \ (port) == TPT29555_GPIO_EX_PORTB) typedef struct _tpt29555_iic_cfg { uint8_t inited; /* IIC initialization done. 0-not yet, 1-done.*/ uint8_t port; /* IIC port number. */ uint32_t baud; /* IIC baudrate, unit is Kb. */ uint8_t nack_wait_num; /* wait nack number. */ uint16_t gpio_scl; /* SCL gpio pin. */ uint16_t gpio_sda; /* SDA gpio pin. */ } tpt29555_iic_cfg_t; static tpt29555_iic_cfg_t tpt29555_iic_cfg = { TPT29555_INIT_UNCOMPLETED, /* IIC initialization uncompleted. */ TPT29555_IIC_DEF_PORT, /* IIC device port number. */ TPT29555_IIC_DEF_SPEED, /* Baudrate, unit is Kb. */ TPT29555_IIC_DEF_NACK_NUM, /* Wait nack number. */ 0, /* SCL gpio pin. */ 0 /* SDA gpio pin. */ }; static os_mutex_h gpio_ext_mutex = NULL; static uint32_t register_opt_tm = 0; /* operate register timestamp: 1ms */ static uint8_t tpt29555_i2c_write_reg(uint8_t reg_addr, uint8_t val) { uint8_t ret = ERR_FAIL; char buf[2] = {0}; uint32_t cur_opt_tm = os_boot_time32(); uint32_t delay_tm; buf[0] = reg_addr; buf[1] = val; gpio_debug_printf("[%s][info] arg1:%d, arg2:%d\n", __FUNCTION__, reg_addr, val); delay_tm = (uint32_t)(cur_opt_tm - register_opt_tm); if (delay_tm < TPT29555_REGISTER_RESPONSE_TM) { os_delay(TPT29555_REGISTER_RESPONSE_TM - delay_tm); } ret = iot_i2c_write(tpt29555_iic_cfg.port, TPT29555_IIC_PHY_ADDR, buf, 2); if (ret != ERR_OK) { iot_printf("[%s][err] i2c write data error\n", __FUNCTION__); goto out; } out: register_opt_tm = os_boot_time32(); return ret; } static uint8_t tpt29555_i2c_read_reg(uint8_t reg_addr, uint8_t *data, uint8_t len) { uint8_t ret = ERR_FAIL; char buf[2] = {0}; buf[0] = reg_addr; uint32_t cur_opt_tm = os_boot_time32(); uint32_t delay_tm; gpio_debug_printf("[%s][info] arg1:%d, arg2:%d, arg3:%d\n", __FUNCTION__, reg_addr, *data, len); if ((data == NULL) || (len == 0)) { return ERR_FAIL; } delay_tm = (uint32_t)(cur_opt_tm - register_opt_tm); if (delay_tm < TPT29555_REGISTER_RESPONSE_TM) { os_delay(TPT29555_REGISTER_RESPONSE_TM - delay_tm); } ret = iot_i2c_write(tpt29555_iic_cfg.port, TPT29555_IIC_PHY_ADDR, buf, 1); if (ret != ERR_OK) { iot_printf("[%s][err] i2c write data error\n", __FUNCTION__); goto out; } os_delay(TPT29555_REGISTER_RESPONSE_TM); ret = iot_i2c_read(tpt29555_iic_cfg.port, TPT29555_IIC_PHY_ADDR, (char *)data, len); if (ret != ERR_OK) { iot_printf("[%s][err] i2c read data error\n", __FUNCTION__); goto out; } out: register_opt_tm = os_boot_time32(); return ret; } static uint8_t tpt29555_gpio_ex_open_as_out(uint8_t gpio_num, uint8_t gpio_port) { uint8_t ret = ERR_FAIL; uint8_t data; uint8_t reg_addr; gpio_debug_printf("[%s][info] arg1:%d, arg2:%d\n", __FUNCTION__, gpio_num, gpio_port); if ((!GPIO_EX_VALID(gpio_num)) ||!GPIO_PORT_VALID(gpio_port)) { return ERR_FAIL; } os_acquire_mutex(gpio_ext_mutex); if (gpio_port == TPT29555_GPIO_EX_PORTA) { reg_addr = TPT29555_CONFIG_PORT_REGA; } else if (gpio_port == TPT29555_GPIO_EX_PORTB) { reg_addr = TPT29555_CONFIG_PORT_REGB; } else { IOT_ASSERT(0); } ret = tpt29555_i2c_read_reg(reg_addr, &data, 1); if (ret != ERR_OK) { iot_printf("[%s][err] open gpio ext as output mode error!\n", __FUNCTION__); goto out; } data &= ~(1 << gpio_num); ret = tpt29555_i2c_write_reg(reg_addr, data); if (ret != ERR_OK) { iot_printf("[%s][err] open gpio ext as output mode error!\n", __FUNCTION__); } out: os_release_mutex(gpio_ext_mutex); return ret; } static uint8_t tpt29555_gpio_ex_open_as_in(uint8_t gpio_num, uint8_t gpio_port) { uint8_t ret = ERR_FAIL; uint8_t data; uint8_t reg_addr; gpio_debug_printf("[%s][info] arg1:%d, arg2:%d\n", __FUNCTION__, gpio_num, gpio_port); if ((!GPIO_EX_VALID(gpio_num)) ||!GPIO_PORT_VALID(gpio_port)) { return ERR_FAIL; } os_acquire_mutex(gpio_ext_mutex); if (gpio_port == TPT29555_GPIO_EX_PORTA) { reg_addr = TPT29555_CONFIG_PORT_REGA; } else if (gpio_port == TPT29555_GPIO_EX_PORTB) { reg_addr = TPT29555_CONFIG_PORT_REGB; } else { IOT_ASSERT(0); } ret = tpt29555_i2c_read_reg(reg_addr, &data, 1); if (ret != ERR_OK) { iot_printf("[%s][err] open gpio ext as input mode error!\n", __FUNCTION__); goto out; } data |= 1 << gpio_num; ret = tpt29555_i2c_write_reg(reg_addr, data); if (ret != ERR_OK) { iot_printf("[%s][err] open gpio ext as input mode error!\n", __FUNCTION__); } out: os_release_mutex(gpio_ext_mutex); return ret; } static int iot_gpio_ext_hw_set_mode(int gpio, int mode) { uint8_t ret = ERR_FAIL; uint8_t gpio_num = GPIO_EX_GET_GPIO(gpio); uint8_t gpio_port = GPIO_EX_GET_PORT(gpio); gpio_debug_printf("[%s][info] arg1:%d, arg2:%d, arg3:%d\n", __FUNCTION__, gpio_num, gpio_port, mode); if (TPT29555_INIT_COMPLETED != tpt29555_iic_cfg.inited) { iot_printf("[%s][err] The chip is not initialized!\n", __FUNCTION__); return ERR_FAIL; } if ((!GPIO_EX_VALID(gpio_num)) ||!GPIO_PORT_VALID(gpio_port)) { return ERR_FAIL; } os_acquire_mutex(gpio_ext_mutex); if (GPIO_INPUT == mode) { ret = tpt29555_gpio_ex_open_as_in(gpio_num, gpio_port); } else if (GPIO_OUTPUT == mode) { ret = tpt29555_gpio_ex_open_as_out(gpio_num, gpio_port); } else { /* not support */ IOT_ASSERT(0); } if (ret != ERR_OK) { iot_printf("[%s][err] gpio ext set mode error!\n", __FUNCTION__); } os_release_mutex(gpio_ext_mutex); return ret; } static int iot_tpt29555_gpio_ex_value_get(int gpio) { uint8_t reg_addr, ret = ERR_FAIL; uint8_t value; uint8_t gpio_num = GPIO_EX_GET_GPIO(gpio); uint8_t gpio_port = GPIO_EX_GET_PORT(gpio); gpio_debug_printf("[%s][info] arg1:%d, arg2:%d\n", __FUNCTION__, gpio_num, gpio_port); if (TPT29555_INIT_COMPLETED != tpt29555_iic_cfg.inited) { iot_printf("[%s][err] The chip is not initialized!\n", __FUNCTION__); return ERR_FAIL; } if ((!GPIO_EX_VALID(gpio_num)) ||!GPIO_PORT_VALID(gpio_port)) { return ERR_FAIL; } os_acquire_mutex(gpio_ext_mutex); if (gpio_port == TPT29555_GPIO_EX_PORTA) { reg_addr = TPT29555_INPUT_PORT_REGA; } else if (gpio_port == TPT29555_GPIO_EX_PORTB) { reg_addr = TPT29555_INPUT_PORT_REGB; } ret = tpt29555_i2c_read_reg(reg_addr, &value, 1); if (ERR_OK != ret) { iot_printf("[%s][err] get gpio ext value error!\n", __FUNCTION__); goto out; } os_release_mutex(gpio_ext_mutex); return (value >> gpio_num) & 0x01; out: os_release_mutex(gpio_ext_mutex); return ret; } static int iot_tpt29555_gpio_ex_value_set(int gpio, int value) { uint8_t ret = ERR_FAIL; uint8_t data = 0; uint8_t reg_addr, gpio_num, gpio_port; gpio_num = GPIO_EX_GET_GPIO(gpio); gpio_port = GPIO_EX_GET_PORT(gpio); gpio_debug_printf("[%s][info] arg1:%d, arg2:%d, arg3:%d\n", __FUNCTION__, gpio_num, gpio_port, value); if (TPT29555_INIT_COMPLETED != tpt29555_iic_cfg.inited) { iot_printf("[%s][err] The chip is not initialized!\n", __FUNCTION__); return ERR_FAIL; } if ((!GPIO_EX_VALID(gpio_num)) ||!GPIO_PORT_VALID(gpio_port)) { return ERR_FAIL; } os_acquire_mutex(gpio_ext_mutex); if (gpio_port == TPT29555_GPIO_EX_PORTA) { reg_addr = TPT29555_OUTPUT_PORT_REGA; } else if (gpio_port == TPT29555_GPIO_EX_PORTB) { reg_addr = TPT29555_OUTPUT_PORT_REGB; } ret = tpt29555_i2c_read_reg(reg_addr, &data, 1); if (ERR_OK != ret) { iot_printf("[%s][err] get gpio ext value error!\n", __FUNCTION__); goto out; } if (0 == value) { data &= ~(1 << gpio_num); } else { data |= 1 << gpio_num; } ret = tpt29555_i2c_write_reg(reg_addr, data); if (ret != ERR_OK) { iot_printf("[%s][err] set gpio ext value error!\n", __FUNCTION__); } out: os_release_mutex(gpio_ext_mutex); return ret; } static int iot_tpt29555_gpio_ex_init(void) { iot_i2c_module_cfg_t iic_cfg; uint8_t value; if (gpio_ext_mutex == NULL) { gpio_ext_mutex = os_create_mutex(IOT_DRIVER_MID); } if (gpio_ext_mutex == NULL) { IOT_ASSERT(0); goto err; } if (tpt29555_iic_cfg.inited == TPT29555_INIT_COMPLETED) { return ERR_OK; } tpt29555_iic_cfg.gpio_scl = iot_board_get_gpio(GPIO_EX_IO_I2C_SCL); tpt29555_iic_cfg.gpio_sda = iot_board_get_gpio(GPIO_EX_IO_I2C_SDA); if ((tpt29555_iic_cfg.gpio_scl == GPIO_NO_VALID) || (tpt29555_iic_cfg.gpio_sda == GPIO_NO_VALID)) { iot_printf("[%s] init gpio ext chip TPT29555 invalid!\n", __FUNCTION__); goto err; } iic_cfg.baud = tpt29555_iic_cfg.baud; iic_cfg.gpio.scl = tpt29555_iic_cfg.gpio_scl; iic_cfg.gpio.sda = tpt29555_iic_cfg.gpio_sda; iic_cfg.nack_wait_num = tpt29555_iic_cfg.nack_wait_num; iic_cfg.port = tpt29555_iic_cfg.port; if (ERR_OK != iot_i2c_module_init(&iic_cfg)) { iot_printf("[%s][err] init err!\n", __FUNCTION__); goto err; } /* check device ACK or NACK */ if (ERR_OK != tpt29555_i2c_read_reg(TPT29555_INPUT_PORT_REGA, &value, 1)) { iot_printf("[%s][info] read register failed, reg:0x%x, value:0x%x\n", __FUNCTION__, TPT29555_INPUT_PORT_REGA, value); goto err; } iot_printf("[%s][info] init gpio ext chip TPT29555 successfully!\n", __FUNCTION__); tpt29555_iic_cfg.inited = TPT29555_INIT_COMPLETED; return ERR_OK; err: return ERR_FAIL; } static int iot_gpio_ext_hw_set_interrupt_mode(int gpio, int mode) { (void)gpio; (void)mode; return 0; } static int iot_gpio_ext_hw_get_int_status(int gpio) { (void)gpio; return 0; } static int iot_gpio_ext_hw_clear_int_status(int gpio) { (void)gpio; return 0; } static int iot_gpio_ext_hw_set_drain_mode(int gpio, int mode) { (void)gpio; (void)mode; return 0; } iot_gpio_op_t hw_gpio_api_table_ext_tpt29555 = { .gpio_init = iot_tpt29555_gpio_ex_init, .set_gpio_mode = iot_gpio_ext_hw_set_mode, .set_interrupt_mode = iot_gpio_ext_hw_set_interrupt_mode, .set_value = iot_tpt29555_gpio_ex_value_set, .get_value = iot_tpt29555_gpio_ex_value_get, .get_interrupt_status = iot_gpio_ext_hw_get_int_status, .clear_interrupt_status = iot_gpio_ext_hw_clear_int_status, .set_gpio_open_drain = iot_gpio_ext_hw_set_drain_mode, };