/* * Copyright (c) 2024 Wingcool Technology Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief SD8563 Timer driver for Actions SoC */ #include #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include LOG_MODULE_REGISTER(sd8563, CONFIG_SYS_LOG_INPUT_DEV_LEVEL); #define rtc_slaver_addr (0xA2 >> 1)// 0x51 //#ifndef CONFIG_MERGE_WORK_Q //#define CONFIG_USED_TP_WORK_QUEUE 0 //#endif #ifdef CONFIG_USED_TP_WORK_QUEUE #define CONFIG_TIMER_WORK_Q_STACK_SIZE 1280 struct k_work_q timer_drv_q; K_THREAD_STACK_DEFINE(timer_work_q_stack, CONFIG_TIMER_WORK_Q_STACK_SIZE); #endif struct acts_timer_data { input_notify_t notify; const struct device *i2c_dev; const struct device *gpio_dev; const struct device *this_dev; struct gpio_callback key_gpio_cb; struct k_work init_timer; bool inited; #ifdef CONFIG_PM_DEVICE uint32_t pm_state; #endif }; uint16_t timer_crc[2] __attribute((used)) = {0}; uint8_t read_time_data[7] = {0}; static struct acts_timer_data timer_acts_ddata; static int _sd8563_close_write_protection(const struct device *i2c_dev); static void _sd8563_open_write_protection(const struct device *i2c_dev); static void _sd8563_read_time(const struct device *i2c_dev, bool is_uart_send); static void _sd8563_set_time(const struct device *i2c_dev, uint8_t set_hour, uint8_t set_minute, uint8_t set_week, uint16_t set_year, uint8_t set_month, uint8_t set_day); extern void uart2_poll_out_ch(int c); extern uint8_t bySetHour; extern uint8_t bySetMinute; extern uint8_t bySetWeekday; extern uint16_t wSetYear; extern uint8_t bySetMonth; extern uint8_t bySetDay; #include #if 1 static struct hrtimer g_rtc_ht_read; static void timer_acts_handler(struct k_work *work) { static struct acts_timer_data *external_rtc = &timer_acts_ddata; if ((bySetHour != 0xff) || (wSetYear != 0xff)) { hrtimer_stop(&g_rtc_ht_read); if (_sd8563_close_write_protection(external_rtc->i2c_dev) == 1) { _sd8563_set_time(external_rtc->i2c_dev, bySetHour, bySetMinute, bySetWeekday, wSetYear, bySetMonth, bySetDay); _sd8563_open_write_protection(external_rtc->i2c_dev); } k_msleep(100); _sd8563_read_time(external_rtc->i2c_dev, false); //读一次,避免用户在设置后再次快速进入设置界面时数据不正确 hrtimer_restart(&g_rtc_ht_read); bySetHour = 0xff; bySetMinute = 0xff; bySetWeekday = 0xff; wSetYear = 0xff; bySetMonth = 0xff; bySetDay = 0xff; return; } _sd8563_read_time(external_rtc->i2c_dev, true); //不在ISR中完成,防止中断嵌套 } K_WORK_DEFINE(timer_acts, timer_acts_handler); static void htimer_fun(struct hrtimer *ttimer, void *expiry_fn_arg) { //static int t; //static struct acts_timer_data *external_rtc = &timer_acts_ddata; //printk("%d ---htimer--\n", t++); //_sd8563_read_time(external_rtc->i2c_dev, true); //不在ISR中完成,防止中断嵌套 k_work_submit(&timer_acts); //向系统工作队列提交一个工作项,让工作队列的线程将执行该工作 } static void htimer_read(unsigned int ms) { hrtimer_init(&g_rtc_ht_read, htimer_fun, NULL); hrtimer_start(&g_rtc_ht_read, 1000*ms, 1000*ms); } #endif static void _sd8563_open_write_protection(const struct device *i2c_dev) { #if 1 uint8_t write_cmd[2] = {0}; uint8_t read_cmd[7] = {0}; int ret = 0; printk("_sd8563_read_write_protection\n"); ret = i2c_write_read(i2c_dev, rtc_slaver_addr, write_cmd, 1, read_cmd, 1); if (ret != 0) { printk("i2c_write_read ERR\n"); } printk("CTR1 = %d\n", read_cmd[0]); if (read_cmd[0] & 0x40) //bit6:WRTC=1,write_protection has been opened { printk("write_protection has been opened\n"); return; } //open_write_protection: 0E寄存器的bit6~bit2依次写入b0000、b10101、b01010、b10111 write_cmd[0] = 0x0E; ret = i2c_write_read(i2c_dev, rtc_slaver_addr, write_cmd, 1, read_cmd, 1); if (ret != 0) { printk("i2c_write_read ERR\n"); } read_cmd[0] = (read_cmd[0] & 0x83); //bit6~bit2 write b0000 write_cmd[1] = read_cmd[0]; ret = i2c_write(i2c_dev, write_cmd, 2, rtc_slaver_addr); if (ret != 0) { printk("step1 i2c write ERR\n"); return; } //bit6~bit2 write b10101 write_cmd[1] = read_cmd[0] | 0x54; ret = i2c_write(i2c_dev, write_cmd, 2, rtc_slaver_addr); if (ret != 0) { printk("step2 i2c write ERR\n"); return; } //bit6~bit2 write b01010 write_cmd[1] = read_cmd[0] | 0x28; ret = i2c_write(i2c_dev, write_cmd, 2, rtc_slaver_addr); if (ret != 0) { printk("step3 i2c write ERR\n"); return; } //bit6~bit2 write b10111 write_cmd[1] = read_cmd[0] | 0x5C; ret = i2c_write(i2c_dev, write_cmd, 2, rtc_slaver_addr); if (ret != 0) { printk("step4 i2c write ERR\n"); return; } k_msleep(1); write_cmd[0] = 0; //CTR1 ret = i2c_write_read(i2c_dev, rtc_slaver_addr, write_cmd, 1, read_cmd, 1); if (ret != 0) { printk("i2c_write_read ERR\n"); } printk("CTR1 = %d\n", read_cmd[0]); if (read_cmd[0] & 0x40) //bit6:WRTC=1,write_protection has been opened { printk("write_protection has been opened\n"); } printk("_sd8563_open_write_protection exit\n"); #endif } static int _sd8563_close_write_protection(const struct device *i2c_dev) { #if 1 uint8_t write_cmd[2] = {0}; uint8_t read_cmd[7] = {0}; int ret = 0; printk("_sd8563_read_write_protection\n"); ret = i2c_write_read(i2c_dev, rtc_slaver_addr, write_cmd, 1, read_cmd, 1); if (ret != 0) { printk("i2c_write_read ERR\n"); return 0; } printk("CTR1 = %d\n", read_cmd[0]); if ((read_cmd[0] & 0x40) == 0) //bit6:WRTC = 0,write_protection has been closed { printk("write_protection has been closed\n"); return 1; } //close_write_protection: 0E寄存器的bit6~bit2依次写入b0000、b11100、b00011、b01110 write_cmd[0] = 0x0E; ret = i2c_write_read(i2c_dev, rtc_slaver_addr, write_cmd, 1, read_cmd, 1); if (ret != 0) { printk("i2c_write_read ERR\n"); return 0; } read_cmd[0] = (read_cmd[0] & 0x83); //bit6~bit2 write b0000 write_cmd[1] = read_cmd[0]; ret = i2c_write(i2c_dev, write_cmd, 2, rtc_slaver_addr); if (ret != 0) { printk("step1 i2c write ERR\n"); return 0; } //bit6~bit2 write b11100 write_cmd[1] = read_cmd[0] | 0x70; ret = i2c_write(i2c_dev, write_cmd, 2, rtc_slaver_addr); if (ret != 0) { printk("step2 i2c write ERR\n"); return 0; } //bit6~bit2 write b00011 write_cmd[1] = read_cmd[0] | 0x0C; ret = i2c_write(i2c_dev, write_cmd, 2, rtc_slaver_addr); if (ret != 0) { printk("step3 i2c write ERR\n"); return 0; } //bit6~bit2 write b01110 write_cmd[1] = read_cmd[0] | 0x38; ret = i2c_write(i2c_dev, write_cmd, 2, rtc_slaver_addr); if (ret != 0) { printk("step4 i2c write ERR\n"); return 0; } k_msleep(1); write_cmd[0] = 0; //CTR1 ret = i2c_write_read(i2c_dev, rtc_slaver_addr, write_cmd, 1, read_cmd, 1); if (ret != 0) { printk("i2c_write_read ERR\n"); return 0; } printk("CTR1 = %d\n", read_cmd[0]); if ((read_cmd[0] & 0x40) == 0) //bit6:WRTC = 0,write_protection has been closed { printk("write_protection has been closed\n"); return 1; } printk("_sd8563_close_write_protection exit\n"); return 0; #else return 1; #endif } static void _sd8563_set_time(const struct device *i2c_dev, uint8_t set_hour, uint8_t set_minute, uint8_t set_week, uint16_t set_year, uint8_t set_month, uint8_t set_day) { #if 1 uint8_t write_cmd[8] = {0}; uint8_t read_cmd[7] = {0}; bool power_on_set_time_data = false; int ret = 0; printk("_sd8563_set_time start\n"); write_cmd[0] = 0x02; //sec ret = i2c_write_read(i2c_dev, rtc_slaver_addr, write_cmd, 1, read_cmd, 1); if (ret != 0) { printk("i2c_write_read ERR\n"); return; } if ((set_hour == 0xFF) && (set_year == 0xFF)) //power on { printk("read_cmd[0] = %d\n", read_cmd[0]); if ((read_cmd[0] & 0x80) == 0) //bit7:0SF/ { printk("bit7:0SF is 0,The time has been set\n"); return; } power_on_set_time_data = true; } _sd8563_read_time(i2c_dev, false); //read time //printk("y:%x, mon:%x, week:%x, d:%x, h:%x, min:%x, sec:%x\n", // read_time_data[6], read_time_data[5], read_time_data[4], read_time_data[3], read_time_data[2], read_time_data[1], read_time_data[0]); if(set_hour != 0xFF) { read_time_data[0] = 0; set_minute = (set_minute / 10) * 16 + set_minute % 10; //DEC TO BCD CODE set_hour = (set_hour / 10) * 16 + set_hour % 10; //DEC TO BCD CODE read_time_data[1] = set_minute;//(set_minute / 10) * 16 + set_minute % 10; //DEC TO BCD CODE read_time_data[2] = set_hour;//(set_hour / 10) * 16 + set_hour % 10; //DEC TO BCD CODE read_time_data[4] = set_week % 7;//0:Sun. 1:Mon. 2:Tue. 3:Wed. 4:Thu. 5:Fri. 6:Sat. } else if (set_year != 0xFF) { if (set_year >= 2000) { set_year = set_year - 2000; } set_day = (set_day / 10) * 16 + set_day % 10; //DEC TO BCD CODE set_month = (set_month / 10) * 16 + set_month % 10; //DEC TO BCD CODE set_year = (set_year / 10) * 16 + set_year % 10; //DEC TO BCD CODE read_time_data[3] = set_day;//(set_day / 10) * 16 + set_day % 10; //DEC TO BCD CODE read_time_data[5] = set_month;//(set_month / 10) * 16 + set_month % 10; //DEC TO BCD CODE read_time_data[6] = set_year;//(set_year / 10) * 16 + set_year % 10; //DEC TO BCD CODE } if (power_on_set_time_data == true) { //BCD code write_cmd[1] = 0; //sec write_cmd[2] = 0x35; //min write_cmd[3] = 0x11; //hour write_cmd[4] = 0x12; //day write_cmd[5] = 0x06; //week write_cmd[6] = 0x10; //mon write_cmd[7] = 0x24; //year printk("power on set time and date\n"); } else { //BCD code for (uint8_t i = 0; i < 7; i++) { write_cmd[i + 1] = read_time_data[i];//(read_time_data[i] / 10) * 16 + read_time_data[i] % 10; //DEC TO BCD CODE } //write_cmd[1] = read_time_data[0]; //sec //write_cmd[2] = read_time_data[1]; //min //write_cmd[3] = read_time_data[2]; //hour //write_cmd[4] = read_time_data[3]; //day //write_cmd[5] = read_time_data[4]; //week //write_cmd[6] = read_time_data[5]; //mon //write_cmd[7] = read_time_data[6]; //year } ret = i2c_write(i2c_dev, write_cmd, 8, rtc_slaver_addr); if (ret != 0) { printk("i2c write ERR\n"); return; } k_msleep(1); ret = i2c_write_read(i2c_dev, rtc_slaver_addr, write_cmd, 1, read_cmd, 7); if (ret != 0) { printk("i2c_write_read ERR\n"); return; } printk("y:%x, mon:%x, week:%x, d:%x, h:%x, min:%x, sec:%x\n", read_cmd[6], read_cmd[5], read_cmd[4], read_cmd[3], read_cmd[2], read_cmd[1], read_cmd[0]); printk("_sd8563_set_time exit\n"); #endif } static void _sd8563_read_time(const struct device *i2c_dev, bool is_uart_send) { #if 1 uint8_t i, check_sum = 0x52; uint8_t write_cmd[1] = {0x02}; //static uint8_t read_time_data[7] = {0}; int ret = 0; //printk("_sd8563_read_time\n"); ret = i2c_write_read(i2c_dev, rtc_slaver_addr, write_cmd, 1, read_time_data, 7); //ret = i2c_burst_read(i2c_dev, rtc_slaver_addr, 0x02, read_cmd, 3); //ret = i2c_read(i2c_dev, read_time_data, 7, rtc_slaver_addr); if (ret != 0) { printk("i2c_write_read ERR\n"); } read_time_data[0] = read_time_data[0] & 0x7F; //bit7:0SF/ read_time_data[5] = read_time_data[5] & 0x7F; //bit7:C/century if (is_uart_send == false) { return; } //uart2 send data start ==============================================// uart2_poll_out_ch(0x5A); //报文表头 uart2_poll_out_ch(0x54); for (i = 0; i < 7; i++) { read_time_data[i] = (read_time_data[i] / 16) * 10 + read_time_data[i] % 16; //DEC TO BCD CODE check_sum += read_time_data[i]; uart2_poll_out_ch(read_time_data[i]); } uart2_poll_out_ch(check_sum); //checksum //uart2 send data end ==============================================// //printk("y:20%d, mon:%d, week:%d, d:%d, h:%d, min:%d, sec:%d\n", // read_time_data[6], read_time_data[5], read_time_data[4], read_time_data[3], read_time_data[2], read_time_data[1], read_time_data[0]); #endif } static void _sd8563_init_work(struct k_work *work) { struct acts_timer_data *external_rtc = &timer_acts_ddata; printk("sd8563 init work\n"); external_rtc->inited = true; if (_sd8563_close_write_protection(external_rtc->i2c_dev) == 1) { //k_msleep(2); _sd8563_set_time(external_rtc->i2c_dev, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); //k_msleep(2); _sd8563_open_write_protection(external_rtc->i2c_dev); } #if 0 uint8_t i; for (i=0; i < 20; i++) { k_msleep(1000); _sd8563_read_time(external_rtc->i2c_dev, 0); } #endif htimer_read(1000); //1000ms = 1s printk("sd8563 init work exit\n"); } static int _sd8563_acts_init(const struct device *dev) { struct acts_timer_data *external_rtc = dev->data; printk("sd8563 acts init\n"); #if 1 external_rtc->this_dev = (struct device *)dev; external_rtc->i2c_dev = (struct device *)device_get_binding(CONFIG_SD8563_I2C_NAME); if (!external_rtc->i2c_dev) { printk("can not access right i2c device\n"); return -1; } external_rtc->inited = false; k_work_init(&external_rtc->init_timer, _sd8563_init_work); #ifdef CONFIG_USED_TP_WORK_QUEUE k_work_queue_start(&timer_drv_q, timer_work_q_stack, K_THREAD_STACK_SIZEOF(timer_work_q_stack), 7, NULL); k_work_submit_to_queue(&timer_drv_q, &external_rtc->init_timer); #else k_work_submit(&external_rtc->init_timer); #endif #endif printk("sd8563 acts init exit\n"); return 0; } #ifdef CONFIG_PM_DEVICE static void _sd8563_suspend(const struct device *dev) { //struct acts_timer_data *external_rtc = (struct acts_timer_data *)dev->data; printk("sd8563 suspend\n"); hrtimer_stop(&g_rtc_ht_read); } static void _sd8563_resume(const struct device *dev) { struct acts_timer_data *external_rtc = (struct acts_timer_data *)dev->data; external_rtc->i2c_dev = (struct device *)device_get_binding(CONFIG_SD8563_I2C_NAME); if (!external_rtc->i2c_dev) { printk("can not access right i2c device\n"); return; } external_rtc->inited = false; k_work_init(&external_rtc->init_timer, _sd8563_init_work); printk("sd8563 resume\n"); #ifdef CONFIG_USED_TP_WORK_QUEUE k_work_submit_to_queue(&tp_drv_q, &external_rtc->init_timer); #else k_work_submit(&external_rtc->init_timer); #endif } static int _sd8563_pm_control(const struct device *dev, enum pm_device_action action) { int ret = 0; //printk("sd8563 pm control\n"); switch (action) { case PM_DEVICE_ACTION_SUSPEND: break; case PM_DEVICE_ACTION_RESUME: break; case PM_DEVICE_ACTION_EARLY_SUSPEND: _sd8563_suspend(dev); break; case PM_DEVICE_ACTION_LATE_RESUME: _sd8563_resume(dev); break; default: break; } return ret; } #else /* CONFIG_PM_DEVICE */ static int _sd8563_pm_control(const struct device *dev, uint32_t ctrl_command, void *context, device_pm_cb cb, void *arg) { } #endif #if IS_ENABLED(CONFIG_SD8563) DEVICE_DEFINE(sd8563, CONFIG_SD8563_DEV_NAME, _sd8563_acts_init, _sd8563_pm_control, &timer_acts_ddata, NULL, POST_KERNEL, 50, NULL); #endif