/**************************************************************************** * * 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. * * ****************************************************************************/ /* os_ship header files */ #include "os_utils_api.h" /* iot common header files */ #include "iot_config_api.h" #include "iot_utils_api.h" #include "iot_i2c_api.h" #include "iot_gpio_api.h" #include "iot_board_api.h" #include "iot_io_api.h" #include "iot_errno_api.h" #include "iot_config.h" /* iot common header files */ #include "iot_rtc_api.h" #include "iot_rtc_ext.h" #if IOT_EXT_RTC_BL8025T_ENABLE #define BL8025T_TRANS_BUF_CNT 16 /* the iic config of bl8025t. */ #define BL8025T_IIC_PHY_ADDR 0x32 /* shift as (0x32 << 1) in driver. */ #define BL8025T_IIC_DEF_PORT 0 /* Port#0. */ #define BL8025T_IIC_DEF_SPEED 100 /* 100K. */ #define BL8025T_IIC_DEF_NACK_NUM 1 /* N-ACK number. */ /* bl8025t fOUT frequency selection, frequency is 32768HZ */ #define BL8025T_FOUT_FRE_32768HZ 0 /* bl8025t fOUT frequency selection, frequency is 1024HZ */ #define BL8025T_FOUT_FRE_1024HZ 1 /* bl8025t fOUT frequency selection, frequency is 1HZ */ #define BL8025T_FOUT_FRE_1HZ 2 /* bl8025t fOUT frequency selection, frequency is 32768HZ */ #define BL8025T_FOUT_FRE_32768HZ2 3 /* bl8025t register internal address definition */ #define BL8025T_SEC_REG_ADDR 0x00 #define BL8025T_MIN_REG_ADDR 0x01 #define BL8025T_HOUR_REG_ADDR 0x02 #define BL8025T_WEEK_REG_ADDR 0x03 #define BL8025T_DAY_REG_ADDR 0x04 #define BL8025T_MON_REG_ADDR 0x05 #define BL8025T_YAER_REG_ADDR 0x06 #define BL8025T_EXTEND_REG_ADDR 0x0D #define BL8025T_FLAG_REG_ADDR 0x0E #define BL8025T_CTRL_REG_ADDR 0x0F /* bl8025t sec register layout definition */ typedef struct { /* calendar time - seconds, BCD format */ uint8_t sec :7, /* flag to mark if oscillator fail */ rsvd :1; } bl8025t_sec_reg_t; /* bl8025t min register layout definition */ typedef struct { /* calendar time - min, BCD format */ uint8_t min :7, /* flag to mark if oscillator fail */ rsvd :1; } bl8025t_min_reg_t; /* bl8025t hour register layout definition */ typedef struct { /* calendar time - hour, BCD format */ uint8_t hour :6, /* don't care */ rsvd :2; } bl8025t_hour_reg_t; /* bl8025t week register layout definition */ typedef struct { /* calendar time - week */ uint8_t week :6, /* don't care */ rsvd :2; } bl8025t_week_reg_t; /* bl8025t day register layout definition */ typedef struct { /* calendar time - day, BCD format */ uint8_t day :6, /* don't care */ rsvd :2; } bl8025t_day_reg_t; /* bl8025t mon register layout definition */ typedef struct { /* calendar time - mon, BCD format */ uint8_t mon :5, /* don't care */ rsvd :3; } bl8025t_mon_reg_t; /* bl8025t year register layout definition */ typedef struct { /* calendar time - year, BCD format */ uint8_t year; } bl8025t_year_reg_t; /* bl8025t flag register layout definition */ typedef struct { /* don't care */ uint8_t rsvd :2, /* Alarm interrupt flag */ uf :1, /* Timing interrupt flag */ tf :1, /* update interrupt flag */ af :1, /* don't care */ rsvd1 :1, /* electric low flag */ vlf :1, /* voltage detection mark */ vdet :1; } bl8025t_flag_reg_t; /* bl8025t ctrl register layout definition */ typedef struct { /* temperature compensation time select */ uint8_t csel :2, /* alarm interrupt enable */ uie :1, /* timing interrupt enable */ tie :1, /* update interrupt enable */ aie :1, /* don't care */ rsvd :2, /* reset */ reset :1; } bl8025t_ctrl_reg_t; /* bl8025t calendar layout */ typedef struct { /* sec register */ bl8025t_sec_reg_t sec_reg; /* min register */ bl8025t_min_reg_t min_reg; /* hour register */ bl8025t_hour_reg_t hour_reg; /* week register */ bl8025t_week_reg_t week_reg; /* day register */ bl8025t_day_reg_t day_reg; /* mon register */ bl8025t_mon_reg_t mon_reg; /* year register */ bl8025t_year_reg_t year_reg; } bl8025t_calendar_reg_t; /* bl8025t calendar layout */ typedef struct { /* flag register */ bl8025t_flag_reg_t flag_reg; /* ctrl register */ bl8025t_ctrl_reg_t ctrl_reg; } bl8025t_check_reg_t; /* bl8025t extend register layout definition */ typedef struct { /* countdown cycle selector bit */ uint8_t tsel :2, /* FOUT frequency selector bit */ fsel :2, /* Timing function enable bit */ te :1, /* Periodic updates interrupt the selection bit */ usel :1, /* day and calendar alarm options */ wada :1, /* factory test bit */ test :1; } bl8025t_extend_reg_t; /* check the validity of the calendar register */ #define bl8025t_sec_is_valid(x) \ (iot_bcd_check(x) && (x) <= 0x59) #define bl8025t_min_is_valid(x) \ (iot_bcd_check(x) && (x) <= 0x59) #define bl8025t_hour_is_valid(x) \ (iot_bcd_check(x) && (x) <= 0x23) #define bl8025t_day_is_valid(x) \ (iot_bcd_check(x) && (x) <= 0x31 && (x) >= 1) #define bl8025t_mon_is_valid(x) \ (iot_bcd_check(x) && (x) <= 0x12 && (x) >= 1) #define bl8025t_year_is_valid(x) \ (iot_bcd_check(x) && (x) <= 0x99) static uint8_t buf[BL8025T_TRANS_BUF_CNT]; static uint8_t bl8025t_regs_is_valid(bl8025t_calendar_reg_t *cal_regs) { uint8_t reason = 0; if (!cal_regs) { reason = 1; IOT_ASSERT(0); goto err; } if (!bl8025t_sec_is_valid(cal_regs->sec_reg.sec)) { reason = 2; goto err; } if (!bl8025t_min_is_valid(cal_regs->min_reg.min)) { reason = 3; goto err; } if (!bl8025t_hour_is_valid(cal_regs->hour_reg.hour)) { reason = 4; goto err; } if (!bl8025t_day_is_valid(cal_regs->day_reg.day)) { reason = 5; goto err; } if (!bl8025t_mon_is_valid(cal_regs->mon_reg.mon)) { reason = 6; goto err; } if (!bl8025t_year_is_valid(cal_regs->year_reg.year)) { reason = 7; goto err; } return ERR_OK; err: iot_printf("%s err, reason %lu\n", __FUNCTION__, reason); return ERR_FAIL; } static uint32_t bl8025t_read_regs(uint8_t addr, uint8_t *data, uint8_t cnt) { uint8_t reason = 0; if(ERR_OK != iot_i2c_write(BL8025T_IIC_DEF_PORT, BL8025T_IIC_PHY_ADDR, (char *)&addr, 1)) { reason = 1; goto out; } os_delay(10); if(ERR_OK != iot_i2c_read(BL8025T_IIC_DEF_PORT, BL8025T_IIC_PHY_ADDR, (char *)data, cnt)) { reason = 1; goto out; } os_delay(5); out: if (reason) { iot_printf("%s fail, reason %lu\n", __FUNCTION__, reason); return ERR_FAIL; } return ERR_OK; } static uint32_t bl8025t_write_regs(uint8_t addr, uint8_t *data, uint8_t cnt) { buf[0] = addr; os_mem_cpy(buf + 1, data, cnt); if (cnt > (IOT_ARRAY_CNT(buf) - 1)) { return ERR_NOMEM; } iot_i2c_write(BL8025T_IIC_DEF_PORT, BL8025T_IIC_PHY_ADDR, (char *)buf, cnt + 1); os_delay(10); return ERR_OK; } static void arx8025t_software_reset () { buf[0] = BL8025T_CTRL_REG_ADDR; bl8025t_ctrl_reg_t ctrl_reg; ctrl_reg.reset = 1; os_mem_cpy(buf + 1, &ctrl_reg, 1); iot_i2c_write(BL8025T_IIC_DEF_PORT, BL8025T_IIC_PHY_ADDR, (char *)buf, 2); os_delay(10); } static uint32_t bl8025t_get_time(iot_time_tm_t *tm) { uint32_t ret; iot_time_tm_t in_tm; uint8_t reason = 0; bl8025t_calendar_reg_t cal_regs = { 0 }; bl8025t_check_reg_t check_regs = { 0 }; ret = bl8025t_read_regs(BL8025T_SEC_REG_ADDR, (uint8_t *)&cal_regs, sizeof(cal_regs)); if (ret != ERR_OK) { reason = 1; goto err; } ret = bl8025t_read_regs(BL8025T_FLAG_REG_ADDR, (uint8_t *)&check_regs, sizeof(check_regs)); if (ret != ERR_OK) { reason = 2; goto err; } if (check_regs.flag_reg.vdet || check_regs.flag_reg.vlf) { check_regs.flag_reg.vdet = 0; check_regs.flag_reg.vlf = 0; if (iot_rtc_data_is_revised()) { iot_rtc_get(&in_tm); cal_regs.sec_reg.sec = iot_byte_to_bcd(in_tm.tm_sec); cal_regs.min_reg.min = iot_byte_to_bcd(in_tm.tm_min); cal_regs.hour_reg.hour = iot_byte_to_bcd(in_tm.tm_hour); cal_regs.day_reg.day = iot_byte_to_bcd(in_tm.tm_mday); cal_regs.mon_reg.mon = iot_byte_to_bcd(in_tm.tm_mon); if (in_tm.tm_year < 2000) { in_tm.tm_year = 2000; } cal_regs.year_reg.year = iot_byte_to_bcd(in_tm.tm_year - 2000); } ret = bl8025t_write_regs(BL8025T_SEC_REG_ADDR, (uint8_t*)&cal_regs, sizeof(cal_regs)); if (ret) { reason = 2; goto err; } ret = bl8025t_write_regs(BL8025T_FLAG_REG_ADDR, (uint8_t*)&cal_regs, sizeof(cal_regs)); reason = 3; goto err; } if (bl8025t_regs_is_valid(&cal_regs) != ERR_OK) { reason = 4; goto err; } tm->tm_sec = iot_bcd_to_byte(cal_regs.sec_reg.sec); tm->tm_min = iot_bcd_to_byte(cal_regs.min_reg.min); tm->tm_hour = iot_bcd_to_byte(cal_regs.hour_reg.hour); tm->tm_mday = iot_bcd_to_byte(cal_regs.day_reg.day); tm->tm_mon = iot_bcd_to_byte(cal_regs.mon_reg.mon); tm->tm_year = iot_bcd_to_byte(cal_regs.year_reg.year) + 2000; iot_printf("%s %lu-%lu-%lu %lu:%lu:%lu\n", __FUNCTION__, tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return ERR_OK; err: iot_printf("%s err, reason %lu\n", __FUNCTION__, reason); return ERR_FAIL; } static uint32_t bl8025t_set_time(iot_time_tm_t *tm, uint8_t week) { uint32_t ret; bl8025t_calendar_reg_t cal_regs = { 0 }; bl8025t_check_reg_t check_regs = { 0 }; ret = bl8025t_read_regs(BL8025T_FLAG_REG_ADDR, (uint8_t *)&check_regs, sizeof(check_regs)); if (ret) { goto err; } if (check_regs.flag_reg.vdet || check_regs.flag_reg.vlf) { goto err; } ret = bl8025t_read_regs(BL8025T_SEC_REG_ADDR, (uint8_t *)&cal_regs, sizeof(cal_regs)); if (ret) { goto err; } cal_regs.sec_reg.sec = iot_byte_to_bcd(tm->tm_sec); cal_regs.min_reg.min = iot_byte_to_bcd(tm->tm_min); cal_regs.hour_reg.hour = iot_byte_to_bcd(tm->tm_hour); cal_regs.day_reg.day = iot_byte_to_bcd(tm->tm_mday); cal_regs.week_reg.week = 1 << week; cal_regs.mon_reg.mon = iot_byte_to_bcd(tm->tm_mon); cal_regs.year_reg.year = iot_byte_to_bcd(tm->tm_year - 2000); iot_printf("%s %02x-%02x-%02x %02x:%02x:%02x week %lu\n", __FUNCTION__, cal_regs.year_reg.year, cal_regs.mon_reg.mon, cal_regs.day_reg.day, cal_regs.hour_reg.hour, cal_regs.min_reg.min, cal_regs.sec_reg.sec, week); ret = bl8025t_write_regs(BL8025T_SEC_REG_ADDR, (uint8_t *)&cal_regs, sizeof(cal_regs)); if (ret) { IOT_ASSERT(0); goto err; } return ERR_OK; err: IOT_ASSERT(0); return ERR_FAIL; } static uint32_t bl8025t_is_startup(iot_time_tm_t *tm) { uint32_t ret; bl8025t_calendar_reg_t cal_regs = { 0 }; bl8025t_check_reg_t check_regs = { 0 }; ret = bl8025t_read_regs(BL8025T_FLAG_REG_ADDR, (uint8_t *)&check_regs, sizeof(check_regs)); IOT_ASSERT(ret == ERR_OK); if (!check_regs.flag_reg.vlf) { ret = bl8025t_read_regs(BL8025T_SEC_REG_ADDR, (uint8_t *)&cal_regs, sizeof(cal_regs)); tm->tm_sec = iot_bcd_to_byte(cal_regs.sec_reg.sec); tm->tm_min = iot_bcd_to_byte(cal_regs.min_reg.min); tm->tm_hour = iot_bcd_to_byte(cal_regs.hour_reg.hour); tm->tm_mday = iot_bcd_to_byte(cal_regs.day_reg.day); tm->tm_mon = iot_bcd_to_byte(cal_regs.mon_reg.mon); tm->tm_year = iot_bcd_to_byte(cal_regs.year_reg.year) + 2000; return 1; } return 0; } static uint32_t bl8025t_init(iot_time_tm_t *tm, uint32_t *done) { uint32_t ret; uint8_t reg_is_valid = 1; bl8025t_calendar_reg_t cal_regs = { 0 }; bl8025t_check_reg_t check_regs = {0}; bl8025t_extend_reg_t extend_reg = {0}; *done = 0; ret = bl8025t_read_regs(BL8025T_SEC_REG_ADDR, (uint8_t*)&cal_regs, sizeof(cal_regs)); if (ret) { IOT_ASSERT(0); ret = ERR_FAIL; goto err; } ret = bl8025t_read_regs(BL8025T_FLAG_REG_ADDR, (uint8_t*)&check_regs, sizeof(check_regs)); if (ret) { IOT_ASSERT(0); ret = ERR_FAIL; goto err; } if (bl8025t_regs_is_valid(&cal_regs) != ERR_OK) { reg_is_valid = 0; } if (check_regs.flag_reg.vlf || check_regs.flag_reg.vdet || !reg_is_valid) { /* if the electric low flag, initialize external RTC */ iot_printf("%s waring - electric low flag vlf %lu, vdet %lu\n", __FUNCTION__, check_regs.flag_reg.vlf, check_regs.flag_reg.vdet); iot_printf("%s bl8025t register time value, sec = %lu, min = %lu," "hour = %lu, week =%lu, day = %lu, mon = %lu, year = %lu\n", __FUNCTION__, cal_regs.sec_reg.sec, cal_regs.min_reg.min, cal_regs.hour_reg.hour, cal_regs.week_reg.week, cal_regs.day_reg.day, cal_regs.year_reg.year); arx8025t_software_reset(); os_delay(1000); /* write logic 0 and start the oscillator */ check_regs.flag_reg.vlf = 0; check_regs.flag_reg.vdet = 0; if (!reg_is_valid) { cal_regs.sec_reg.sec = iot_byte_to_bcd(tm->tm_sec); cal_regs.min_reg.min = iot_byte_to_bcd(tm->tm_min); cal_regs.hour_reg.hour = iot_byte_to_bcd(tm->tm_hour); cal_regs.day_reg.day = iot_byte_to_bcd(tm->tm_mday); cal_regs.mon_reg.mon = iot_byte_to_bcd(tm->tm_mon); if (tm->tm_year < 2000) { tm->tm_year = 2000; } cal_regs.year_reg.year = iot_byte_to_bcd(tm->tm_year - 2000); } ret = bl8025t_write_regs(BL8025T_SEC_REG_ADDR, (uint8_t*)&cal_regs, sizeof(cal_regs)); if (ret) { ret = ERR_BUSY; goto err; } ret = bl8025t_write_regs(BL8025T_FLAG_REG_ADDR, (uint8_t*)&check_regs, sizeof(check_regs)); if (ret) { ret = ERR_BUSY; goto err; } if (!reg_is_valid) { goto out; } } /* set fout pin output 1ZH frequency */ ret = bl8025t_read_regs(BL8025T_EXTEND_REG_ADDR, (uint8_t*)&extend_reg, sizeof(extend_reg)); if (ret) { IOT_ASSERT(0); ret = ERR_FAIL; goto err; } iot_printf("%s fout = %d!\n", __FUNCTION__, extend_reg.fsel); if (extend_reg.fsel != BL8025T_FOUT_FRE_1HZ) { extend_reg.fsel = BL8025T_FOUT_FRE_1HZ; ret = bl8025t_write_regs(BL8025T_EXTEND_REG_ADDR, (uint8_t*)&extend_reg, sizeof(extend_reg)); if (ret) { IOT_ASSERT(0); ret = ERR_FAIL; goto err; } iot_printf("%s set fout %d!\n", __FUNCTION__, extend_reg.fsel); } tm->tm_sec = iot_bcd_to_byte(cal_regs.sec_reg.sec); tm->tm_min = iot_bcd_to_byte(cal_regs.min_reg.min); tm->tm_hour = iot_bcd_to_byte(cal_regs.hour_reg.hour); tm->tm_mday = iot_bcd_to_byte(cal_regs.day_reg.day); tm->tm_mon = iot_bcd_to_byte(cal_regs.mon_reg.mon); tm->tm_year = iot_bcd_to_byte(cal_regs.year_reg.year) + 2000; *done = 1; goto out; err: iot_printf("%s fail\n", __FUNCTION__); out: return ret; } static void bl8025t_deinit(void) { } static uint32_t bl8025t_probe(void) { uint8_t addr; uint32_t ret = ERR_OK; iot_i2c_module_cfg_t iic_cfg = { 0 }; /* I2C configuration */ iic_cfg.baud = BL8025T_IIC_DEF_SPEED; iic_cfg.gpio.scl = iot_board_get_gpio(GPIO_EXT_RTC_I2C_SCL); iic_cfg.gpio.sda = iot_board_get_gpio(GPIO_EXT_RTC_I2C_SDA); iic_cfg.nack_wait_num = BL8025T_IIC_DEF_NACK_NUM; iic_cfg.port = BL8025T_IIC_DEF_PORT; if ((GPIO_NO_VALID == iic_cfg.gpio.scl) || (GPIO_NO_VALID == iic_cfg.gpio.sda)) { ret = ERR_NOSUPP; return ret; } /* iot_gpio_open_as_output can cancel the function bound on the GPIO. * This is not necessary if those GPIOs are not multiplex. */ if ((ERR_OK != iot_gpio_open_as_output(iic_cfg.gpio.scl)) || (ERR_OK != iot_gpio_open_as_output(iic_cfg.gpio.sda))) { iot_printf("%s open iic gpio fail!\n", __FUNCTION__); } if (ERR_OK != iot_i2c_module_init(&iic_cfg)) { iot_printf("%s init i2c module fail!\n", __FUNCTION__); ret = ERR_NOSUPP; return ret; } if (ERR_OK != bl8025t_read_regs(BL8025T_SEC_REG_ADDR, (uint8_t*)&addr, 1)) { ret = ERR_NOSUPP; return ret; } iot_printf("%s rtc chip is BL8025! \n", __FUNCTION__); return ret; } /* define bl8025t device */ const iot_ext_rtc_drv_t g_bl8025t_drv = { .drv_prode = bl8025t_probe, .drv_init = bl8025t_init, .drv_deinit = bl8025t_deinit, .drv_get_time = bl8025t_get_time, .drv_set_time = bl8025t_set_time, .drv_is_startup = bl8025t_is_startup, }; #endif /* IOT_EXT_RTC_BL8025T_ENABLE */