123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632 |
- /*
- * Copyright (c) 2024 Wingcool Technology Co., Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * @file
- * @brief SD8563 Timer driver for Actions SoC
- */
- #include <errno.h>
- #include <kernel.h>
- #include <string.h>
- //#include <stdbool.h>
- #include <init.h>
- #include <irq.h>
- #include <drivers/adc.h>
- #include <drivers/input/input_dev.h>
- #include <sys/util.h>
- #include <sys/byteorder.h>
- #include <board.h>
- #include <soc_pmu.h>
- #include <logging/log.h>
- #include <device.h>
- #include <drivers/gpio.h>
- #include <soc.h>
- #include <string.h>
- #include <drivers/i2c.h>
- //#include <board_cfg.h>
- #include <drivers/uart.h>
- 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;
- extern uint8_t bySetTimeStep;
- #include <drivers/hrtimer.h>
- #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))
- && ((bySetTimeStep == 0) || (bySetTimeStep == 2))
- )
- {
- 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;
- if (bySetTimeStep)
- {
- bySetTimeStep = 3; //设置完成
- }
- 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.
- }
- 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
|