/*
 * @history 2025_03_06  [SDK3.7] RTCが電池切れのときI2Cハンドラを解放しない不具合を修正 (#5792)
 */
/*
    FAT file system
    Disk driver
    
    Copyright (c) 2015, eForce Co.,Ltd.
    
    2015-08-18: Created
*/

#include "kernel.h"
#include "AG903_errno.h"
#include "ffsysdrv.h"
#include "ffsysdrv_cfg.h"
#include "DDR_AG903_SD.h"
#include "DDR_AG903_CF_CFG.h"
#include "i2c/i2cmgr.h"

ER ffs_drv_cfg_ini(ID dev_id)
{
    /* Initialization for mount */

    return E_OK;
}

ER ffs_drv_cfg_cd(ID dev_id)
{
    ER ercd;
    ER ercd_cd;
    UW reg;
    UH sts;

    /* Card detect */

    ercd_cd = E_OBJ;   /* Disk is not ready */

	if(FFS_DEVID_SD == dev_id) {
	    sts = 0x00u;
	    ercd = sd_sts(0, &sts);
	    if (ercd == E_OK) {
	        if ((sts & SD_STS_CD) != 0x00) {
	            ercd_cd = E_OK;    /* Detected */
	        }
	    }
	}
	else if(FFS_DEVID_CF == dev_id) {
	    reg = REG_BSC.CFC_PWR_MSTS;
	    if ((reg & 0x00000100u) == 0x00u) {
	        ercd_cd = E_OK;    /* Detected */
	    }
	}
	else {
		ercd_cd = E_OK;
	}

    return ercd_cd;
}

ER ffs_drv_cfg_wp(ID dev_id)
{
    ER ercd;
    ER ercd_wp;
    UH sts;

    /* Write protect */

    ercd_wp = E_OK;    /* Write protected */

 	if(FFS_DEVID_SD == dev_id) {
	   sts = 0x00u;
	    ercd = sd_sts(0, &sts);
	    if (ercd == E_OK) {
	        if ((sts & SD_STS_WP) == 0x00) {
	            ercd_wp = E_OBJ;   /* Now writable */
	        }
	    }
	}
	else {
		ercd_wp = E_OBJ;
	}

    return ercd_wp;
}

/***********************************
       RTC Access
 ***********************************/
#define AG903_RTC_I2C_CH	(1)		/* RTC I2Cチャネル */
#define AG903_RTC_SADDR		(0x64)	/* RTC Slave Addr */

typedef struct _RTC_TIME {
    uint8_t sec;     /* Seconds 0..59 */
    uint8_t min;     /* Minutes 0..59 */
    uint8_t hour;    /* Hours   0..23 */
    uint8_t days;    /* Days    1..31 */
    uint8_t month;   /* Months  1..12 */
    uint8_t year;    /* Years */
} RTC_TIME;

static _Bool	RtcReadEnd=false;

static void Rtc_Callback(AG903_I2CMgrHandle* handle, uint32_t event)
{
	if(AG903_I2C_EVENT_WRITE_END & event) {
		/* 処理なし */
	}
	if(AG903_I2C_EVENT_READ_END & event) {
		RtcReadEnd=true;
	}
	if( (AG903_I2C_EVENT_LOSES_ARBITRATION|AG903_I2C_EVENT_SEQUENCE_ERR|AG903_I2C_EVENT_WRITE_ERR|
		AG903_I2C_EVENT_READ_ERR) & event) {
		/* 処理なし */
	}
	return;
}

static int32_t Rtc_WaitRead(uint32_t timout)
{
	int32_t		retval = AG903_ENONE;
	uint32_t	cnt;
	uint32_t	loop;
	
	cnt = timout/10;
	if(timout%10) {
		cnt++;
	}
	for(loop=0; loop<cnt; loop++) {
		if(true == RtcReadEnd) {
			RtcReadEnd = false;
			break;
		}
		dly_tsk(10);
	}
	if(cnt<=loop) {
		retval = -AG903_ETIMEDOUT;
	}
	
	return retval;
}

static uint8_t BCDtoDEC(uint8_t bcd)
{
	uint8_t	dec;

	dec  = (bcd>>4)*10;
	dec += (bcd&0x0F);
	return dec;
}

static uint8_t Rtc_12Hto24H(uint8_t val)
{
	uint8_t ret=val;
	
	if(0x12==val) {
		/* 処理なし */
		ret = 0x00;
	}
	else {
		if(0x20&val) {
			val &= (~0x20);
			if((0x08==val)||(0x09==val)) {
				ret = val + 0x18;
			}
			else if(0x11>=val) {
				ret = val + 0x12;
			}
			else {
				ret = val;
			}
		}
	}
	
	return ret;
}

static int32_t Rtc_GetTime(RTC_TIME* time)
{
	AG903_I2CMgrHandle*		handle;
	AG903_I2CMgrReadParam 	rd;
	AG903_I2CMgrWriteParam 	wr;
	int32_t		retval = E_OBJ;
	int32_t		result;
	uint8_t		regaddr;
	uint8_t		rxbuf[16];

	result = AG903_I2CMgrGetHandle(AG903_RTC_I2C_CH, &handle);
	if(AG903_ENONE != result) {
		return retval;;
	}

	do{
		result = AG903_I2CMgrSetCallback(handle, (AG903_I2CMgrClbk)Rtc_Callback);
		if(AG903_ENONE != result) {
			break;
		}
		/* RTC Read [Standard read method] */
		regaddr = 0; /* Seconds〜 */
		wr.addr = AG903_RTC_SADDR;
		wr.buf  = &regaddr;
		wr.size = 1;
		wr.stop = false; /* ReStart */
		result = AG903_I2CMgrMasterWrite(handle, &wr);
		if(AG903_ENONE != result) {
			break;
		}
		rd.addr = (AG903_RTC_SADDR|0x01); /* bit0：R/W */
		rd.buf  = rxbuf;
		rd.size = 16; /* ALL Regster Read */
		result  = AG903_I2CMgrMasterRead(handle, &rd);
		if(AG903_ENONE != result) {
			break;
		}
		result = Rtc_WaitRead(500);
		if(AG903_ENONE != result) {
			break;
		}
		if((1<<5) & ~rxbuf[14]) {	/* RTC /12,24bit */
			rxbuf[2] = Rtc_12Hto24H(rxbuf[2]);
		}
		time->sec  = BCDtoDEC(rxbuf[0]);
		time->min  = BCDtoDEC(rxbuf[1]);
		time->hour = BCDtoDEC(rxbuf[2]);
		time->days = BCDtoDEC(rxbuf[4]);
		time->month= BCDtoDEC(rxbuf[5]);
		time->year = BCDtoDEC(rxbuf[6]);
		retval = E_OK;
	}while(0);

	if(retval != E_OK) {
		AG903_I2CMgrReset(handle);
	}

	AG903_I2CMgrReleaseHandle(handle);

	return retval;
}

ER ffs_drv_cfg_tm(T_FFS_DRV_TM* tm)
{
	RTC_TIME time;
	int32_t	 result;

	result = Rtc_GetTime(&time);
	if(E_OK != result) {
	    /* default: 2012-12-28 12:57:58 */
	    tm->tm_sec  = 59;
	    tm->tm_min  = 57;
	    tm->tm_hour = 12;
	    tm->tm_mday = 28;
	    tm->tm_mon  = 12 - 1;
	    tm->tm_year = 2012 - 1900;
	}
	else {
	    tm->tm_sec  = time.sec;
	    tm->tm_min  = time.min;
	    tm->tm_hour = time.hour;
	    tm->tm_mday = time.days;
	    tm->tm_mon  = time.month-1;
	    tm->tm_year = time.year+100;
	}

    return E_OK;
}
