Files
kunlun/driver/extern/rtc/src/bl8025t_driver.c

583 lines
19 KiB
C
Raw Normal View History

2024-09-28 14:24:04 +08:00
/****************************************************************************
*
* 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 */