/**
 * @brief			ボード依存部
 * @file			board.c
 * @author			AXELL
 * @history			2016_07_07	初版(main.c及びcommon.cから分離)<p>
 *					2018_03_30	[SDK2.1] タクトスイッチの接続/未接続の設定追加 (#1895)
 *                  2024_03_22  [SDK3.6] 機能グループ24のUART3に対応するGPIOピン番号のコメントを修正 (#5205)
 *                  2025_03_06  [SDK3.7] SSPライブラリにSPIモードでの送受信アクセス機能を追加 (#5662)
 * @description
 * @note
*/

/*
 * This program was created by Axell Corporation.
 * Copyright (C) 2017-2025 Axell Corporation, all rights reserved.
 */

#include "AG903_UC3.h"
#include "sample_common.h"
#include "i2c/i2cmgr.h"
#include "via/viamgr.h"
#include "sys/sscprm.h"
#include "sys/spcprm.h"

#ifdef  AG903_SAMPLE_USE_FS
#include "DDR_AG903_CF_cfg.h"
#endif/*AG903_SAMPLE_USE_FS*/

#define AG903_SAMPLE_USE_BLP0	(0)

/*-- プロトタイプ定義 --*/
static void FPGA_RegWrite(uint8_t addr, uint8_t data);
static void FPGA_RegRead(uint8_t addr, uint8_t* data);
static void Bd_I2cWrite(uint8_t ch, uint8_t saddr, uint8_t addr, uint8_t data);
static void Bd_I2cRead(uint8_t saddr, uint8_t addr, uint8_t* data);
static void Bd_I2cCallback(AG903_I2CMgrHandle* handle, uint32_t event);
static int32_t Bd_I2cWaitWrite(uint32_t timout);
static int32_t Bd_I2cWaitRead(uint32_t timout);
static void Ssp_SetClkSrc(uint8_t ch, uint8_t src, uint8_t div);


extern void Port_SetFunction(uint8_t group, uint8_t function);
extern void Port_DisableGpio(uint8_t gpio, uint8_t num);

/*-- 変数定義 --*/
static _Bool	I2cWriteEnd=false;
static _Bool	I2cReadEnd=false;


/**
 * @brief		ポートファンクション設定
 * @param		なし
 * @return		なし
 * @note		なし
*/
void Board_SetPotrFunc(void)
{
	Port_SetFunction( 0, PORT_FUNCTION_3);	/* グループ0 = Function3 [EQS] */
	Port_DisableGpio(60, 4);				/* GPIO60〜GP63 = Disable */

	Port_SetFunction( 1, PORT_FUNCTION_3);	/* グループ1 = Function3 [EQS] */
	Port_DisableGpio(58, 2);				/* GPIO58〜GP59 = Disable */

	Port_SetFunction( 2, PORT_FUNCTION_2);	/* グループ2 = Function2 [DVO] */
	Port_SetFunction( 3, PORT_FUNCTION_2);	/* グループ3 = Function2 [DVO] */
	Port_SetFunction( 4, PORT_FUNCTION_2);	/* グループ4 = Function2 [DVO] */
	Port_SetFunction( 5, PORT_FUNCTION_2);	/* グループ5 = Function2 [DVO] */
	Port_DisableGpio(64, 29);				/* GPIO64〜GPIO92 = Disable */

	Port_SetFunction( 6, PORT_FUNCTION_4);	/* グループ6 = Function4 [CF/IDE] */
	Port_DisableGpio(104, 2);				/* GPIO104〜GPIO105 = Disable */

	Port_EnableGpio(106, 2);				/* GPIO106〜GPIO107 = Enable [GPIO] */

#if AG903_SAMPLE_USE_BLP0
	Port_SetFunction( 6, PORT_FUNCTION_2);	/* グループ6 = Function2 [BLP0] 注：[CF/IDE]と排他 */
	Port_SetFunction( 7, PORT_FUNCTION_2);	/* グループ7 = Function2 [BLP0] 注：[GPIO]と排他 */
	Port_DisableGpio(104, 4);				/* GPIO104〜GPIO107 = Disable */
#endif
	Port_SetFunction( 8, PORT_FUNCTION_2);	/* グループ8 = Function2 [BLP1] */
	Port_SetFunction( 9, PORT_FUNCTION_2);	/* グループ9 = Function2 [BLP1] */
	Port_DisableGpio(108, 4);				/* GPIO108〜GPIO111 = Disable */

	Port_SetFunction(10, PORT_FUNCTION_1);	/* グループ10 = Function1 [UART0] */
	Port_DisableGpio(96, 2);				/* GPIO96〜GPIO97 = Disable */

	Port_SetFunction(12, PORT_FUNCTION_3);	/* グループ12 = Function3 [CF/IDE] */
	Port_DisableGpio(94, 2);				/* GPIO94〜GPIO95 = Disable */

	Port_SetFunction(15, PORT_FUNCTION_4);	/* グループ15 = Function4 [CF/IDE] */
	Port_DisableGpio(124, 2);				/* GPIO124〜GPIO125 = Disable */

	Port_SetFunction(16, PORT_FUNCTION_4);	/* グループ16 = Function4 [SSP3] */
	Port_DisableGpio(100, 4);				/* GPIO100〜GPIO103 = Disable */

											/* Fixed Function [USB] */
	Port_DisableGpio(112, 2);				/* GPIO112〜GPIO113 = Disable */

	Port_SetFunction(17, PORT_FUNCTION_4);	/* グループ17 = Function4 [CF/IDE] */
	Port_DisableGpio(114, 5);				/* GPIO114〜GPIO118 = Disable */

	Port_SetFunction(18, PORT_FUNCTION_4);	/* グループ18 = Function4 [CF/IDE] */
	Port_DisableGpio(119, 1);				/* GPIO119 = Disable */
	Port_DisableGpio(126, 1);				/* GPIO126 = Disable */

	Port_SetFunction(19, PORT_FUNCTION_3);	/* グループ19 = Function3 [EQS] */
	Port_DisableGpio(93, 1);				/* GPIO93 = Disable */

	Port_SetFunction(20, PORT_FUNCTION_4);	/* グループ20 = Function4 [CF/IDE] */
	Port_DisableGpio(120, 2);				/* GPIO120〜GPIO121 = Disable */

	Port_SetFunction(21, PORT_FUNCTION_2);	/* グループ21 = Function2 [CF/IDE] */

	Port_SetFunction(22, PORT_FUNCTION_4);	/* グループ22 = Function4 [CF/IDE] */
	Port_DisableGpio(32, 3);				/* GPIO32〜GPIO34 = Disable */

	Port_SetFunction(24, PORT_FUNCTION_4);	/* グループ24 = Function4 [UART3B] */
	Port_DisableGpio(43, 4);				/* GPIO43〜GPIO46(Pin131〜Pin134) = Disable */

	Port_SetFunction(25, PORT_FUNCTION_4);	/* グループ25 = Function4 [SDC] */
	Port_DisableGpio(47, 2);				/* GPIO47〜GPIO48 = Disable */

	Port_SetFunction(26, PORT_FUNCTION_4);	/* グループ26 = Function4 [SDC] */
	Port_DisableGpio(49, 2);				/* GPIO49〜GPIO50 = Disable */

	Port_SetFunction(27, PORT_FUNCTION_4);	/* グループ27 = Function4 [SDC] */
	Port_DisableGpio(51, 6);				/* GPIO51〜GPIO56 = Disable */

	Port_SetFunction(29, PORT_FUNCTION_4);	/* グループ29 = Function4 [CF/IDE] */
	Port_DisableGpio(0, 16);				/* GPIO0〜GPIO15 = Disable */

	Port_SetFunction(30, PORT_FUNCTION_3);	/* グループ30 = Function3 [CF/IDE] */
	Port_DisableGpio(16, 5);				/* GPIO51〜GPIO56 = Disable */

	Port_SetFunction(31, PORT_FUNCTION_4);	/* グループ31 = Function4 [SSP2] */
	Port_DisableGpio(21, 4);				/* GPIO21〜GPIO24 = Disable */
}

#ifdef  AG903_SAMPLE_USE_FS
/**
 * @brief		CF I/F設定
 * @param		なし
 * @return		なし
 * @note		なし
*/
void Board_SetCfInterface(void)
{

	#if (CFG_CF_CLK_MHZ == 100)
    	AG903_SPCPrmSetIdeClk(AG903_SPC_IDECLK_PLL0DIV4); /* IDE 100MHz (PLL0/4) */
    #else
    	AG903_SPCPrmSetIdeClk(AG903_SPC_IDECLK_PLL0DIV3); /* IDE 133MHz (PLL0/3) */
    #endif

	REG_BSC.PMPACR = 0x02;			/* TrueIDE Select */

	FPGA_RegWrite(0x16, 0x01);		/* TrueIDE 接続 */
}

/**
 * @brief		SDカード I/F設定
 * @param		なし
 * @return		なし
 * @note		なし
*/
void Board_SetSdInterface(void)
{
	FPGA_RegWrite(0x15, 0x01);		/* SDカードI/F 接続 */
}
#endif/*AG903_SAMPLE_USE_FS*/


/**
 * @brief	アナログ入力初期化
 * @param	cvbs_mode [in] 制御パラメータ
 * @return	AG903_ENONE 正常終了
 * @return	-AG903_EINVAL cvbs_mode設定値範囲外
 * @note	なし
 */
int32_t Board_SetupCvbs(int32_t cvbs_mode)
{
	AG903_SPCPrmPllnParam	pll3;
	AG903_SPCPrmPllaParam	plla;

	if(cvbs_mode >= TEST_CVBS_NUM_SET) {
	    return -AG903_EINVAL;
	}

	pll3.en = false; /* パワーダウン */
	AG903_SPCPrmSetPll3Ctrl(&pll3);

	pll3.src    = AG903_SPC_PLL3_CLKSRC_XOUT; /* クロックソース */
	pll3.ns     = 0x04; /* 逓倍率 */
	pll3.ms     = 0x01; /* プリスケーラ分周比 */
	pll3.div    = 0x07; /* ポストスケーラ分周比 */
	pll3.frange = 0;	/* 動作レンジ (20〜40MHz) */
	pll3.en     = true; /* アクティブ */
	AG903_SPCPrmSetPll3Ctrl(&pll3);

	plla.en = false; /* パワーダウン */
	AG903_SPCPrmSetPllACtrl(&plla);

	switch (cvbs_mode) {
		case TEST_CVBS_NTSC_BT:
		case TEST_CVBS_PAL_BT:
			plla.src = AG903_SPC_PLLA_CLKSRC_OSC; /* クロックソース */
			plla.ns  = 0x90; /* 逓倍率 */
			plla.ms  = 0x08; /* プリスケーラ分周比 */
			plla.fr  = 0x02; /* ポストスケーラ1分周比 */
			plla.div = 0x03; /* ポストスケーラ2分周比 */
			plla.cc  = 0x05; /* PLLAループフィルタ */
			plla.en  = true; /* アクティブ */
			break;
		case TEST_CVBS_NTSC_SQ:
			plla.src = AG903_SPC_PLLA_CLKSRC_OSC; /* クロックソース */
			plla.ns  = 0xB4; /* 逓倍率 */
			plla.ms  = 0x0B; /* プリスケーラ分周比 */
			plla.fr  = 0x02; /* ポストスケーラ1分周比 */
			plla.div = 0x03; /* ポストスケーラ2分周比 */
			plla.cc  = 0x05; /* PLLAループフィルタ */
			plla.en  = true; /* アクティブ */
			break;
		case TEST_CVBS_NTSC_4F:
			plla.src = AG903_SPC_PLLA_CLKSRC_OSC; /* クロックソース */
			plla.ns  = 0xD2; /* 逓倍率 */
			plla.ms  = 0x0B; /* プリスケーラ分周比 */
			plla.fr  = 0x02; /* ポストスケーラ1分周比 */
			plla.div = 0x03; /* ポストスケーラ2分周比 */
			plla.cc  = 0x05; /* PLLAループフィルタ */
			plla.en  = true; /* アクティブ */
			break;
		case TEST_CVBS_PAL_SQ:
			plla.src = AG903_SPC_PLLA_CLKSRC_OSC; /* クロックソース */
			plla.ns  = 0x76; /* 逓倍率 */
			plla.ms  = 0x08; /* プリスケーラ分周比 */
			plla.fr  = 0x01; /* ポストスケーラ1分周比 */
			plla.div = 0x03; /* ポストスケーラ2分周比 */
			plla.cc  = 0x05; /* PLLAループフィルタ */
			plla.en  = true; /* アクティブ */
			break;
		default:
			break;
	}
	AG903_SPCPrmSetPllACtrl(&plla);

	AG903_ViaMgrInit();

	return AG903_ENONE;
}

/**
 * @brief	バックライト制御回路接続先選択
 * @param	ch [in] バックライト制御回路CH
 * @param	sel [in] 0:常時ON, 1:バックライト制御回路, 2:LED[4:1], 2:LED[4:1](遅延あり), 4:GPIO[3:0], 5:他方のバックライト制御回路に連動
 * @return	none
 * @note	none
*/
void Board_BacklightSel(uint32_t ch, uint32_t sel)
{
	if(ch > 1 || sel > 5) return;
	FPGA_RegWrite(0x0E + ch, sel);		/* バックライト制御回路接続先選択 */
}

/**
 * @brief	DVI-TX出力設定
 * @param	none
 * @return	none
 * @note	none
*/
void Board_SelectDviTX(void)
{
	Port_SetFunction( 2, PORT_FUNCTION_2);	/* グループ2 = Function2 [VOD] */
	Port_SetFunction( 3, PORT_FUNCTION_2);	/* グループ3 = Function2 [VOD] */
	Port_SetFunction( 4, PORT_FUNCTION_2);	/* グループ4 = Function2 [VOD] */
	Port_SetFunction( 5, PORT_FUNCTION_2);	/* グループ5 = Function2 [VOD] */
	Port_DisableGpio(64, 29);				/* GPIO64〜GPIO92 = Disable */

	AG903_SSCPrmDspSetup dsp_setup = {
		.dot0	= AG903_SSC_PINDIR_OUTPUT,
		.dot1	= AG903_SSC_PINDIR_OUTPUT,
		.field0	= AG903_SSC_PINDIR_OUTPUT,
		.field1	= AG903_SSC_PINDIR_OUTPUT,
		.vsync0	= AG903_SSC_PINDIR_OUTPUT,
		.vsync1	= AG903_SSC_PINDIR_OUTPUT,
	};
	AG903_SSCPrmSetDspPinDir(&dsp_setup);

	uint8_t rst;

	FPGA_RegRead(0x04, &rst);		/* リセット制御の状態を取得 */

	rst &= ~0x08;
	FPGA_RegWrite(0x04, rst);		/* DVI-TXをリセット状態にする */
    sys_dlytsk(100);

	FPGA_RegWrite(0x07, 0x1);		/* DVO選択を24bit出力に設定 */

	rst |= 0x8;
	FPGA_RegWrite(0x04, rst);		/* DVI-TXのリセット状態解除 */
}


/**
 * @brief	DVI-RX動作設定
 * @param	none
 * @return	none
 * @note	none
*/
void Board_SelectDviRX(void)
{
	Port_SetFunction( 2, PORT_FUNCTION_3);	/* グループ2 = Function3 [VID] */
	Port_SetFunction( 3, PORT_FUNCTION_3);	/* グループ3 = Function3 [VID] */
	Port_SetFunction( 4, PORT_FUNCTION_3);	/* グループ4 = Function3 [VID] */
	Port_SetFunction( 5, PORT_FUNCTION_3);	/* グループ5 = Function3 [VID] */
	Port_DisableGpio(64, 29);				/* GPIO64〜GPIO92 = Disable */

	AG903_SSCPrmDspSetup dsp_setup = {
		.dot0	= AG903_SSC_PINDIR_INPUT,
		.dot1	= AG903_SSC_PINDIR_INPUT,
		.field0	= AG903_SSC_PINDIR_INPUT,
		.field1	= AG903_SSC_PINDIR_INPUT,
		.vsync0	= AG903_SSC_PINDIR_INPUT,
		.vsync1	= AG903_SSC_PINDIR_INPUT,
	};
	AG903_SSCPrmSetDspPinDir(&dsp_setup);


	uint8_t rst;

	FPGA_RegRead(0x04, &rst);		/* リセット制御の状態を取得 */

	rst &= ~0x10;
	FPGA_RegWrite(0x04, rst);		/* DVI-RXをパワーダウン状態にする */
    sys_dlytsk(100);

	FPGA_RegWrite(0x07, 0x2);		/* DVI入力回路接続 */

	rst |= 0x10;
	FPGA_RegWrite(0x04, rst);		/* DVI-RXのパワーダウン状態解除 */
}


/**
 * @brief		EQS-RAM接続
 * @param		なし
 * @return		なし
 * @note		なし
*/
void Board_ConnectEqsAndRam(void)
{
	FPGA_RegWrite(0x08, 0x09);					/* FPGA内臓RAM接続				*/
}

/**
 * @brief	UART選択
 * @param	ch [in] UARTチャンネル
 * @param	sel [in] 接続先
 * @return	none
 * @note	ch3[40pin〜43pin]はch=3、ch3[131pin〜134pin]はch=4を設定して下さい。
*/
void Board_SelectUartConnection(uint8_t ch, uint8_t sel)
{
	uint8_t addr = 0x09;	/* UART0選択レジスタ */

	FPGA_RegWrite((addr+ch), sel);
}

/**
 * @brief	バックライトポート接続選択
 * @param	port [in] バックライトポート（0〜1）
 * @param	sel [in] 接続先,IO
 * @return	none
 * @note	未接続を選択した場合、常時ON、PWM100%となります。
*/
void Board_SelectBlpConnection(uint8_t port, uint8_t sel)
{
	uint8_t addr = 0x0E;	/* バックライト制御0選択レジスタ */

	FPGA_RegWrite((addr+port), sel);
}

/**
 * @brief	LED制御設定
 * @param	led [in] LED設定（ビット指定）
 * @return	none
 * @note	LED設定は"0"=点灯,"1"=消灯です。
*/
void Board_SetLedStatus(uint8_t led)
{
	FPGA_RegWrite(0x05, led);
}

/**
 * @brief	LED状態取得
 * @param	led [out] LED状態
 * @return	none
 * @note	LED状態は"0"=点灯,"1"=消灯です。
*/
void Board_GetLedStatus(uint8_t* led)
{
	FPGA_RegRead(0x05, led);
}

/**
 * @brief	オーディオCODECリセット解除
 * @param	none
 * @return	none
 * @note	none
*/
void Board_ActivateAudioCodec(void)
{
	uint8_t rst;

	FPGA_RegRead(0x04, &rst);
	FPGA_RegWrite(0x04, rst|0x04);	/* Codec リセット解除 */
}

/**
 * @brief	Ethernet選択
 * @param	type [in] Ethernet種別
 * @return	none
 * @note	none
*/
void Board_SelectEthernetType(uint8_t type)
{
	FPGA_RegWrite(0x17, type);
}

/**
 * @brief	USBモード選択
 * @param	mode [in] USBモード
 * @return	none
 * @note	none
*/
void Board_SelectUsbMode(uint8_t mode)
{
	if(AG903_USB_MODE_FUNCTION == mode) {
		FPGA_RegWrite(0x18, 0x01);
	}
	else {
		FPGA_RegWrite(0x18, 0x03);
	}
}

/**
 * @brief	SSP通信設定
 * @param	ch [in] SSPチャンネル
 * @param	type [in] 設定種別
 * @return	none
 * @note	none
*/
void Board_SetSspCommuType(uint8_t ch, uint8_t type)
{
	AG903_SSCPrmSspSetup	  ssp;

	switch(type) {
		case AG903_I2S_MASTER_READ:
			FPGA_RegWrite(0x10, 0x00);		/* SSPマスタ- */
			FPGA_RegWrite(0x11+ch, 0x45);	/* RXDにMCLK出力, 入力元ADC_SDOUT1 */
			ssp.mclk_div = 0; 						  /* 分周なし */
			ssp.mclk_dir = AG903_SSC_PINDIR_INPUT;	  /* MCLK 入力 */
			ssp.mode     = AG903_SSC_SSPMODE_HLFDPLX; /* 半二重 */
			ssp.dir      = AG903_SSC_PINDIR_INPUT;	  /* TXD=RXD */
			AG903_SSCPrmSetSspSetup(ch, &ssp);
			break;
		case AG903_I2S_MASTER_WRITE:
			FPGA_RegWrite(0x10, 0x00);		/* SSPマスタ- */
			FPGA_RegWrite(0x11+ch, 0x41);	/* RXDにMCLK出力, 出力先ADC_SDIN1 */
			ssp.mclk_div = 0; 						  /* 分周なし */
			ssp.mclk_dir = AG903_SSC_PINDIR_INPUT;	  /* MCLK 入力 */
			ssp.mode     = AG903_SSC_SSPMODE_HLFDPLX; /* 半二重 */
			ssp.dir      = AG903_SSC_PINDIR_OUTPUT;	  /* TXD=TXD */
			AG903_SSCPrmSetSspSetup(ch, &ssp);
			break;
		default:
			/* 上記以外は非対応 */
			break;
	}
	Ssp_SetClkSrc(ch, AG903_SPC_SSP_CLKSRC_MCLK, 0); /* SSPn_MCLK 1分周 11.2896[MHz] */
}

void Board_SetSpiFlashInterface(void)
{
	/* Pin function Group0 to SSP0 */
	Port_SetFunction( 0, PORT_FUNCTION_4);
	/* 60:SSP0_SCLK */
	/* 61:SSP0_TXD */
	/* 62:SSP0_RXD */
	/* 63:SSP0_FS */
	Port_DisableGpio(60, 4);

	FPGA_RegWrite(0x08, 0x00);  /* 08h:EQS 0:未接続 */
	FPGA_RegWrite(0x11, 0x00);	/* 11h:AUIDO 0:SSP0=RXD未接続/TXD未接続 */

	AG903_SSCPrmSspSetup	  ssp = {0};
	ssp.mclk_div = 0; 						  /* MCLK出力以外のとき設定無効 */
	ssp.mclk_dir = AG903_SSC_PINDIR_OUTPUT;	  /* MCLK半二重以外のとき設定無効 */
	ssp.mode     = AG903_SSC_SSPMODE_FLLDPLX; /* 全二重 */
	ssp.dir      = AG903_SSC_PINDIR_OUTPUT;	  /* MCLK半二重以外のとき設定無効 */
	AG903_SSCPrmSetSspSetup(0, &ssp);

	Ssp_SetClkSrc(0, AG903_SPC_SSP_CLKSRC_XOUT, 1-1); /* XOUT(24.0[MHz]) / 1分周 = 24.0[MHz] */
}

void Board_UnsetSpiFlashInterface(void)
{
	/* Repaire EQS */
	Port_SetFunction( 0, PORT_FUNCTION_3);
	Port_DisableGpio(60, 4);
	Board_ConnectEqsAndRam();
}

static void Ssp_SetClkSrc(uint8_t ch, uint8_t src, uint8_t div)
{
	AG903_SPCPrmSspClkSel	clk_src;
	AG903_SPCPrmSspClkDiv	clk_div;

	AG903_SPCPrmGetSspClkSrc(&clk_src);
	AG903_SPCPrmGetSspClkDiv(&clk_div);
	switch(ch) {
		case 0:
			clk_src.ssp0 = src;
			clk_div.ssp0 = div;
			break;
		case 1:
			clk_src.ssp1 = src;
			clk_div.ssp1 = div;
			break;
		case 2:
			clk_src.ssp2 = src;
			clk_div.ssp2 = div;
			break;
		case 3:
			clk_src.ssp3 = src;
			clk_div.ssp3 = div;
			break;
		default:
			break;
	}
	AG903_SPCPrmSetSspClkSrc(&clk_src);
	AG903_SPCPrmSetSspClkDiv(&clk_div);

	return;
}

/**
 * @brief	Audio Codec レジスタ書込み
 * @param	addr [in] アドレス
 * @param	data [in] データ
 * @return	none
 * @note	none
*/
void Board_WriteAudioCodec(uint8_t addr, uint8_t data)
{
	Bd_I2cWrite(AG903_CODEC_I2C_CH, AG903_CODEC_I2C_SADDR, addr, data);
}

/**
 * @brief	パラレルバス割込みの設定
 * @param	num [in] パラレルバス割込み番号
 * @param	en  [in] nINTnの状態
 * @return	none
 * @note	nINTnの状態は"en=false"でHi-Z,"en=true"でLowとなります.
 */
void Board_EnablePbInt(uint8_t num, _Bool en)
{
	uint8_t itn;

	Bd_I2cRead(AG903_FPGA_SADDR, 0x1d, &itn);

	if(en == false){
		itn &= (~(1 << num) & 0x0f);
	}else{
		itn |= ((1 << num) & 0x0f);
	}
	Bd_I2cWrite(AG903_FPGA_I2C_CH, AG903_FPGA_SADDR, 0x1d, itn);
}

/**
 * @brief	タクトスイッチの接続/未接続の設定
 * @param	en  [in] trueなら接続、falseなら未接続
 * @return	none
 * @note	M02基板の時、UART0_RTS←SW4、UART0_CTS←SW5の接続を行う.
 */
void Board_ConnectTactSwitchs(_Bool en)
{
	uint8_t val;

	Bd_I2cRead(AG903_FPGA_SADDR, 0x00, &val);

	/* ボードバージョンチェック */
	if(val == AG903_VER_PKG_M02){
		Bd_I2cRead(AG903_FPGA_SADDR, 0x09, &val);
		if(en == false){
			/* 未接続 */
			val &= ~AG903_UART0_TACTSW;
		}else{
			/* 接続 */
			val |=  AG903_UART0_TACTSW;
		}
		Bd_I2cWrite(AG903_FPGA_I2C_CH, AG903_FPGA_SADDR, 0x09, val);
	}
}

static void FPGA_RegWrite(uint8_t addr, uint8_t data)
{
	Bd_I2cWrite(AG903_FPGA_I2C_CH, AG903_FPGA_SADDR, addr, data);
	return;
}

static void FPGA_RegRead(uint8_t addr, uint8_t* data)
{
	Bd_I2cRead(AG903_FPGA_SADDR, addr, data);
	return;
}

static void Bd_I2cWrite(uint8_t ch, uint8_t saddr, uint8_t addr, uint8_t data)
{
	AG903_I2CMgrHandle*		handle;
	AG903_I2CMgrWriteParam 	wr;
	int32_t	result;
	uint8_t	val[2];

	do{
		result = AG903_I2CMgrGetHandle(ch, &handle);
		if(AG903_ENONE != result) {
			break;
		}
		result = AG903_I2CMgrSetCallback(handle, (AG903_I2CMgrClbk)Bd_I2cCallback);
		if(AG903_ENONE != result) {
			AG903_I2CMgrReleaseHandle(handle);
			break;
		}
		val[0]=addr;
		val[1]=data;
		wr.addr = saddr;
		wr.buf  = val;
		wr.size = 2;
		wr.stop = true;
		result = AG903_I2CMgrMasterWrite(handle, &wr);
		if(AG903_ENONE != result) {
			AG903_I2CMgrReleaseHandle(handle);
			break;
		}
		Bd_I2cWaitWrite(300);
		AG903_I2CMgrReleaseHandle(handle);
	}while(0);

	return;
}

static void Bd_I2cRead(uint8_t saddr, uint8_t addr, uint8_t* data)
{
	AG903_I2CMgrHandle*		handle;
	AG903_I2CMgrReadParam 	rd;
	AG903_I2CMgrWriteParam 	wr;
	int32_t	result;
	uint8_t	val;

	do{
		result = AG903_I2CMgrGetHandle(AG903_FPGA_I2C_CH, &handle);
		if(AG903_ENONE != result) {
			break;
		}
		result = AG903_I2CMgrSetCallback(handle, (AG903_I2CMgrClbk)Bd_I2cCallback);
		if(AG903_ENONE != result) {
			AG903_I2CMgrReleaseHandle(handle);
			break;
		}
		val=addr;
		wr.addr = saddr;
		wr.buf  = &val;
		wr.size = 1;
		wr.stop = false; /* ReStart */
		result = AG903_I2CMgrMasterWrite(handle, &wr);
		if(AG903_ENONE != result) {
			AG903_I2CMgrReleaseHandle(handle);
			break;
		}
		result = Bd_I2cWaitWrite(300);
		if(AG903_ENONE != result) {
			AG903_I2CMgrReleaseHandle(handle);
			break;
		}
		rd.addr = (saddr|0x01); /* bit0：R/W */
		rd.buf  = data;
		rd.size = 1;
		result  = AG903_I2CMgrMasterRead(handle, &rd);
		if(AG903_ENONE != result) {
			AG903_I2CMgrReleaseHandle(handle);
			break;
		}
		result = Bd_I2cWaitRead(300);
		AG903_I2CMgrReleaseHandle(handle);
	}while(0);

	return;
}

static void Bd_I2cCallback(AG903_I2CMgrHandle* handle, uint32_t event)
{
	if(AG903_I2C_EVENT_WRITE_END & event) {
		I2cWriteEnd=true;
	}
	if(AG903_I2C_EVENT_READ_END & event) {
		I2cReadEnd=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 Bd_I2cWaitWrite(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 == I2cWriteEnd) {
			I2cWriteEnd = false;
			break;
		}
		sys_dlytsk(10);
	}
	if(cnt<=loop) {
		retval = -AG903_ETIMEDOUT;
	}

	return retval;
}

static int32_t Bd_I2cWaitRead(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 == I2cReadEnd) {
			I2cReadEnd = false;
			break;
		}
		sys_dlytsk(10);
	}
	if(cnt<=loop) {
		retval = -AG903_ETIMEDOUT;
	}

	return retval;
}

