/** * @file gpio.c * @author chipsea * @brief Contains all functions support for gpio and iomux driver * @version 0.1 * @date 2020-11-30 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd. * @note */ #include "sdk_config.h" #include "log.h" #include "mcu.h" #include "gpio.h" #include "types.h" #include "clock.h" #include "error.h" #include "string.h" #include "pwrmgr.h" #include "jump_function.h" extern uint32_t s_gpio_wakeup_src_group1, s_gpio_wakeup_src_group2; enum { GPIO_PIN_ASSI_NONE = 0, GPIO_PIN_ASSI_OUT, GPIO_PIN_ASSI_IN, }; typedef struct { bool enable; uint8_t pin_state; gpioin_Hdl_t posedgeHdl; gpioin_Hdl_t negedgeHdl; }gpioin_Ctx_t; typedef struct { bool state; uint8_t pin_assignments[NUMBER_OF_PINS]; gpioin_Ctx_t irq_ctx[NUMBER_OF_PINS]; }gpio_Ctx_t; typedef struct{ uint8_t reg_i; uint8_t bit_h; uint8_t bit_l; }PULL_TypeDef; static gpio_Ctx_t m_gpioCtx = { .state = FALSE, .pin_assignments = {0,}, }; const uint8_t c_gpio_index[GPIO_NUM] = {0,1,2,3,7,9,10,11,14,15,16,17,18,20,23,24,25,26,27,31,32,33,34}; const PULL_TypeDef c_gpio_pull[GPIO_NUM]= { {0,2,1}, //p0 {0,5,4}, //p1 {0,8,7}, //p2 {0,11,10},//p3 {0,23,22},//p7 {0,29,28},//p9 {1,2,1}, //p10 {1,5,4}, //p11 {1,14,13},//p14 {1,17,16},//p15 {1,20,19},//p16 {1,23,22},//p17 {1,26,25},//p18 {2,2,1}, //p20 {2,11,10},//p23 {2,14,13},//p24 {2,17,16},//p25 {2,20,19},//p26 {2,23,22},//p27 {3,5,4}, //p31 {3,8,7}, //p32 {3,11,10},//p33 {3,14,13},//p34 }; const signed char retention_reg[GPIO_NUM][2]={ {0,13},//p0 {0,14},//p1 {0,16},//p2 {0,17},//p3 {0,19},//p7 {0,20},//p9 {1,7},//p10 {1,8},//p11 {1,10},//p14 {1,11},//p15 {1,28},//p16 {1,29},//p17 {2,4},//p18 {2,5},//p20 {2,7},//p23 {2,8},//p24 {2,25},//p25 {2,26},//p26 {2,28},//p27 {2,29},//p31 {3,1},//p32 {3,2},//p33 {3,23},//p34 }; static int hal_gpio_interrupt_disable(GpioPin_t pin) { subWriteReg(&(AP_GPIO->intmask),pin,pin,1); subWriteReg(&(AP_GPIO->inten),pin,pin,0); return ERR_NONE; } static void hal_gpio_wakeup_control(GpioPin_t pin, bit_action_e value) { if(pin < P32) { if (value) AP_AON->REG_S9 |= BIT(c_gpio_index[pin]); else AP_AON->REG_S9 &= ~BIT(c_gpio_index[pin]); } else { if (value) AP_AON->REG_S10 |= BIT(c_gpio_index[pin] - 32); else AP_AON->REG_S10 &= ~BIT(c_gpio_index[pin] - 32); } } void HalGpioDsControl(GpioPin_t pin, bit_action_e value) { if(value) AP_IOMUX->pad_ps0 |= BIT(pin); else AP_IOMUX->pad_ps0 &= ~BIT(pin); } ErrCode_t HalGpioAnalogConfig(GpioPin_t pin, bit_action_e value) { if((pin < P11) || (pin > P25)) return ERR_INVALID_PARAM; if(value > Bit_ENABLE) { return ERR_INVALID_DATA; } if(value) { HalGpioPupdConfig(pin,GPIO_FLOATING); AP_IOMUX->Analog_IO_en |= BIT(pin - P11); } else { AP_IOMUX->Analog_IO_en &= ~BIT(pin - P11); } return ERR_NONE; } void HalGpioPin2Pin3Control(GpioPin_t pin, uint8_t en)//0:sw,1:other func { if(en) AP_IOMUX->gpio_pad_en |= BIT(pin-2); else AP_IOMUX->gpio_pad_en &= ~BIT(pin-2); } static void hal_gpio_retention_enable(GpioPin_t pin,uint8_t en) { if(en) { if((pin == P32)||(pin == P33)||(pin == P34)) { AP_AON->PMCTL0 |= BIT(retention_reg[pin][1]); } else { AP_AON->IOCTL[retention_reg[pin][0]] |= BIT(retention_reg[pin][1]); } } else { if((pin == P32)||(pin == P33)||(pin == P34)) { AP_AON->PMCTL0 &= ~BIT(retention_reg[pin][1]); } else { AP_AON->IOCTL[retention_reg[pin][0]] &= ~BIT(retention_reg[pin][1]); } } } int hal_gpioin_disable(GpioPin_t pin) { gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); if (pin > (NUMBER_OF_PINS - 1)) return ERR_NOT_SUPPORTED; p_irq_ctx[pin].enable = FALSE; m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_NONE; HalGpioPinInit(pin, GPIO_INPUT); return hal_gpio_interrupt_disable(pin); } __ATTR_SECTION_SRAM__ static int hal_gpio_interrupt_enable(GpioPin_t pin, gpio_polarity_e type) { uint32_t gpio_tmp; if (pin >= NUMBER_OF_PINS) return ERR_NOT_SUPPORTED; gpio_tmp = AP_GPIO->inttype_level; gpio_tmp |= (1 << pin); //edge sensitive AP_GPIO->inttype_level = gpio_tmp; gpio_tmp = AP_GPIO->intmask; gpio_tmp &= ~(1 << pin); //unmask interrupt AP_GPIO->intmask = gpio_tmp; gpio_tmp = AP_GPIO->int_polarity; if (type == POL_RISING ) gpio_tmp |= (1 << pin); else gpio_tmp &= ~(1 << pin); AP_GPIO->int_polarity = gpio_tmp; gpio_tmp = AP_GPIO->inten; gpio_tmp |= (1 << pin); //enable interrupt AP_GPIO->inten = gpio_tmp; return ERR_NONE; } __ATTR_SECTION_SRAM__ static void hal_gpioin_event_pin(GpioPin_t pin, gpio_polarity_e type) { gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); if (p_irq_ctx[pin].posedgeHdl && (type == POL_RISING )) { p_irq_ctx[pin].posedgeHdl(pin,POL_RISING );//LOG("POS\n"); } else if (p_irq_ctx[pin].negedgeHdl && (type == POL_FALLING)) { p_irq_ctx[pin].negedgeHdl(pin,POL_FALLING);//LOG("NEG\n"); } } static void hal_gpioin_wakeup_trigger(GpioPin_t pin) { uint8_t pin_state = (uint8_t)HalGpioGet(pin); gpio_polarity_e type = pin_state ? POL_RISING : POL_FALLING; if (m_gpioCtx.irq_ctx[pin].pin_state != pin_state) hal_gpioin_event_pin(pin, type); } __ATTR_SECTION_SRAM__ static void hal_gpioin_event(uint32 int_status, uint32 polarity) { int i; gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); // LOG("GI:%x,%x\n",int_status,polarity); for (i = 0; i < NUMBER_OF_PINS; i++) { if (int_status & (1ul << i)) { gpio_polarity_e type = (polarity & BIT(i)) ? POL_RISING : POL_FALLING; hal_gpioin_event_pin((GpioPin_t)i, type); //reconfig interrupt if (p_irq_ctx[i].posedgeHdl && p_irq_ctx[i].negedgeHdl) //both raise and fall { type = (type == POL_RISING) ? POL_FALLING : POL_RISING ; hal_gpio_interrupt_enable((GpioPin_t)i, type); } else if (p_irq_ctx[i].posedgeHdl) //raise { hal_gpio_interrupt_enable((GpioPin_t)i, POL_RISING ); } else if (p_irq_ctx[i].negedgeHdl) //fall { hal_gpio_interrupt_enable((GpioPin_t)i, POL_FALLING); } } } } ErrCode_t hal_gpioin_enable(GpioPin_t pin) { gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); gpio_polarity_e type = POL_FALLING; uint32 pinVal = 0; if (p_irq_ctx[pin].posedgeHdl == NULL && p_irq_ctx[pin].negedgeHdl == NULL) return ERR_NOT_REGISTED; m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_IN; p_irq_ctx[pin].enable = TRUE; HalGpioPinInit(pin, GPIO_INPUT); //HalGpioPupdConfig(pin, PULL_DOWN); //??need disccuss if (p_irq_ctx[pin].posedgeHdl && p_irq_ctx[pin].negedgeHdl) //both raise and fall { pinVal = HalGpioGet(pin); type = pinVal ? POL_FALLING : POL_RISING ; } else if (p_irq_ctx[pin].posedgeHdl) //raise { type = POL_RISING ; } else if (p_irq_ctx[pin].negedgeHdl) //fall { type = POL_FALLING; } hal_gpio_interrupt_enable(pin, type); return ERR_NONE; } void GpioSleepHandler(void) { int i; gpio_polarity_e pol; uint8_t ic_ver = get_ic_version(); for (i = 0; i < NUMBER_OF_PINS; i++) { //config wakeup if (m_gpioCtx.pin_assignments[i] == GPIO_PIN_ASSI_OUT) { hal_gpio_retention_enable((GpioPin_t)i,Bit_ENABLE); } if (m_gpioCtx.pin_assignments[i] == GPIO_PIN_ASSI_IN) { if(ic_ver != VERSION_0100 && ((i==P16)||(i==P17))) { HalGpioAnalogConfig((GpioPin_t)i,Bit_DISABLE); subWriteReg(&(AP_AON->PMCTL2_0),6,6,0x01); WaitUs(50); pol = HalGpioGet((GpioPin_t)i) ? POL_FALLING : POL_RISING ; subWriteReg(&(AP_AON->PMCTL2_0),6,6,0x00); } else { pol = HalGpioGet((GpioPin_t)i) ? POL_FALLING : POL_RISING ; } HalGpioWkupConfig((GpioPin_t)i, pol); m_gpioCtx.irq_ctx[i].pin_state = HalGpioGet((GpioPin_t)i); } } } void GpioWakeupHandler(void) { int i; uint8_t ic_ver = get_ic_version(); NVIC_SetPriority(GPIO_IRQn, IRQ_PRIO_HAL); NVIC_EnableIRQ(GPIO_IRQn); for (i = 0; i < NUMBER_OF_PINS; i++) { if( ((i == GPIO_P02) || (i == GPIO_P03)) && (m_gpioCtx.pin_assignments[i] != GPIO_PIN_ASSI_NONE) ) { HalGpioPin2Pin3Control((GpioPin_t)i,1); } if(ic_ver != VERSION_0100 && ((i==P16)||(i==P17))) { HalGpioAnalogConfig((GpioPin_t)i,Bit_DISABLE); } if (m_gpioCtx.pin_assignments[i] == GPIO_PIN_ASSI_OUT) { bool pol = HalGpioGet((GpioPin_t)i); HalGpioSet((GpioPin_t)i, (bit_action_e)pol); HalGpioPinInit((GpioPin_t)i, GPIO_OUTPUT); hal_gpio_retention_enable((GpioPin_t)i, Bit_DISABLE); } } for (i = 0; i < NUMBER_OF_PINS; i++) { if (m_gpioCtx.irq_ctx[i].enable) { hal_gpioin_enable((GpioPin_t)i); //resume gpio irq hal_gpioin_wakeup_trigger((GpioPin_t)i);//trigger gpio irq manually } } } __ATTR_SECTION_SRAM__ void HalGpioIRQHandler(void) { uint32 polarity = AP_GPIO->int_polarity; uint32 st = AP_GPIO->int_status; AP_GPIO->porta_eoi = st;//clear interrupt hal_gpioin_event(st, polarity); } bool HalBootPinStatusGet(void) { bool status; uint32_t config; config = *(volatile unsigned int *)0x4000f058; status = (config & 0x40)>> 6; return status; } void HalGpioSet(GpioPin_t pin, bit_action_e bitVal) { if(bitVal) AP_GPIO->swporta_dr |= BIT(pin); else AP_GPIO->swporta_dr &= ~BIT(pin); } bool HalGpioGet(GpioPin_t pin) { uint32_t r; if(pin >= GPIO_NUM ) { return ERR_NOT_SUPPORTED; } if(AP_GPIO->swporta_ddr & BIT(pin)) { r = AP_GPIO->swporta_dr; } else { r = AP_GPIO->ext_porta; } return (int)((r>> pin) &1); } ErrCode_t HalGpioPupdConfig(GpioPin_t pin, gpio_pupd_e type) { if(pin >= GPIO_NUM || type > GPIO_PULL_DOWN) { return ERR_NOT_SUPPORTED; } uint8_t i = c_gpio_pull[pin].reg_i; uint8_t h = c_gpio_pull[pin].bit_h; uint8_t l = c_gpio_pull[pin].bit_l; if(pin < P31) subWriteReg(&(AP_AON->IOCTL[i]),h,l,type); else subWriteReg(&(AP_AON->PMCTL0),h,l,type); return ERR_NONE; } ErrCode_t HalGpioFmuxEnable(GpioPin_t pin, bit_action_e value) { if(pin >= GPIO_NUM || value > Bit_ENABLE) { return ERR_NOT_SUPPORTED; } if(value) { AP_IOMUX->full_mux0_en |= BIT(pin); } else { AP_IOMUX->full_mux0_en &= ~BIT(pin); } return ERR_NONE; } ErrCode_t HalGpioFmuxConfig(GpioPin_t pin, gpio_fmux_e type) { uint8_t h = 0, l = 0; uint32_t reg_index; uint32_t bit_index; if( (pin >= GPIO_NUM) || (type > FMUX_ANT_SEL_2) ) { return ERR_NOT_SUPPORTED; } reg_index = pin / 4; bit_index = pin % 4; l = 8 * bit_index; h = l + 5; subWriteReg(&(AP_IOMUX->gpio_sel[reg_index]),h,l,type); HalGpioFmuxEnable(pin, Bit_ENABLE); return ERR_NONE; } ErrCode_t HalGpioWkupConfig(GpioPin_t pin, gpio_polarity_e type) { if(pin >= GPIO_NUM || type > POL_RISING) { return ERR_NOT_SUPPORTED; } uint8_t i = c_gpio_pull[pin].reg_i; uint8_t p = c_gpio_pull[pin].bit_l-1; if (m_gpioCtx.pin_assignments[pin] != GPIO_PIN_ASSI_IN) return ERR_INVALID_STATE; AP_GPIO->inttype_level |= BIT(pin);//edge sensitive if(pin < P31) { if(POL_FALLING == type) AP_AON->IOCTL[i] |= BIT(p); else AP_AON->IOCTL[i] &= ~BIT(p); } else { if(POL_FALLING == type) AP_AON->PMCTL0 |= BIT(p); else AP_AON->PMCTL0 &= ~BIT(p); } hal_gpio_wakeup_control(pin,Bit_ENABLE);//enable wakeup function return ERR_NONE; } ErrCode_t HalGpioRegister(GpioPin_t pin, gpioin_Hdl_t posedgeHdl, gpioin_Hdl_t negedgeHdl) { ErrCode_t ret; gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); if(pin >= GPIO_NUM ) { return ERR_NOT_SUPPORTED; } hal_gpioin_disable(pin); p_irq_ctx[pin].posedgeHdl = posedgeHdl; p_irq_ctx[pin].negedgeHdl = negedgeHdl; ret = hal_gpioin_enable(pin); JUMP_FUNCTION(V16_IRQ_HANDLER) = (uint32_t)&HalGpioIRQHandler; if (ret != ERR_NONE) hal_gpioin_disable(pin); return ret; } ErrCode_t HalGpioUnregister(GpioPin_t pin) { gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); if (pin >= GPIO_NUM) return ERR_NOT_SUPPORTED; hal_gpioin_disable(pin); p_irq_ctx[pin].negedgeHdl = NULL; p_irq_ctx[pin].posedgeHdl = NULL; return ERR_NONE; } ErrCode_t HalGpioInit(void) { if (m_gpioCtx.state) return ERR_INVALID_STATE; memset(&m_gpioCtx, 0, sizeof(m_gpioCtx)); m_gpioCtx.state = TRUE; //disable all channel irq,unmask all channel AP_GPIO->inten = 0; AP_GPIO->intmask = 0; //disable all wakeup pin AP_WAKEUP->io_wu_mask_31_0 = 0; AP_WAKEUP->io_wu_mask_34_32 = 0; NVIC_SetPriority(GPIO_IRQn, IRQ_PRIO_HAL); NVIC_EnableIRQ(GPIO_IRQn); hal_pwrmgr_register(MOD_GPIO, GpioSleepHandler, GpioWakeupHandler); return ERR_NONE; } ErrCode_t HalGpioPinInit(GpioPin_t pin, gpio_dir_t type) { if(pin >= GPIO_NUM || type > GPIO_OUTPUT) { return ERR_NOT_SUPPORTED; } HalGpioFmuxEnable(pin,Bit_DISABLE); if((pin == P2) || (pin == P3)) HalGpioPin2Pin3Control(pin,1); HalGpioAnalogConfig(pin,Bit_DISABLE); if(type == GPIO_OUTPUT) { AP_GPIO->swporta_ddr |= BIT(pin); m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_OUT; } else { AP_GPIO->swporta_ddr &= ~BIT(pin); m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_IN; } return ERR_NONE; }