/*
 * 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);
static void _sd8563_set_time(const struct device *i2c_dev, 
							 uint8_t set_hour, 
							 uint8_t set_minute,
							 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 bySetMonth;
extern uint8_t bySetDay;

#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) || (bySetMonth != 0))
	{
		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, bySetMonth, bySetDay);

			_sd8563_open_write_protection(external_rtc->i2c_dev);
		}

		bySetHour = 0xff;
		bySetMinute = 0xff;
		bySetMonth = 0;
		bySetDay = 0;

		hrtimer_restart(&g_rtc_ht_read);

		return;
	}

    _sd8563_read_time(external_rtc->i2c_dev);  //不在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);
	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	
	static uint8_t write_cmd[2] = {0};
	static 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	
	static uint8_t write_cmd[2] = {0};
	static 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_month,
							 uint8_t set_day)
{
#if 1	
	static uint8_t write_cmd[8] = {0};
	static 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_month == 0)  //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);  //read time

    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]);

	if(set_minute != 0XFF)
	{
		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
	}
	else if (set_month != 0)
	{
		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
	}

    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
	}
	else
	{
		//BCD code
		for (uint8_t i = 0; i < 7; i++)
		{
			write_cmd[i + 1] = (read_time_data[i] / 10) * 16  + read_time_data[i] % 10;
		}
		//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:20%d, mon:%d, week:%d, d:%d, h:%d, min:%d, sec:%d\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)
{
#if 1	
    uint8_t i, check_sum = 0x52;
	static 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

    //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, 0, 0);

        //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);
	}
#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