/**
 * @file  gpio-mst.c
 * @brief GPIO controller API for MST driver
 *
 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
 *
 * This software is proprietary of Samsung Electronics.
 * No part of this software, either material or conceptual may be copied
 * or distributed, transmitted, transcribed, stored in a retrieval system
 * or translated into any human or computer language in any form by any means,
 * electronic, mechanical, manual or otherwise, or disclosed to third parties
 * without the express written permission of Samsung Electronics.
 */

#include "drStd.h"
#include "DrApi/DrApiCommon.h"
#include "DrApi/DrApiFastCall.h"
#include "drMobicore.h"
#include "gpio-mst.h"
#include "regs-gpio-mst.h"
#include "fcUART.h"
#include "fcTIMA.h"
#include "dbg.h"
#include "mstdrv.h"
#if TBASE_API_LEVEL >= 5
#include "DrApi/DrApiMm.h"
#include "DrApi/DrApiMmExt.h"
#endif

#define VEC_MST_MD	0
#define VEC_MST_PD	1
#define VEC_MST_PWR_EN	2
#define NUM_GPIO_MST	3
#define RECOVER_GPIO_NFC	6
#define RECOVER_GPIO_TOUCH	7

extern int delay_timer(uint32_t arg);

static uint32_t gpio_mst_status;

struct exynos_mst_gpio_list{
	uint32_t offset[GPIO_MST_REG_NUM];
	uint32_t val[GPIO_MST_REG_NUM];
};

struct exynos_mst_gpio_list gpio_list[2];

struct regs {
	uint32_t offset;
};
#if TBASE_API_LEVEL >= 5
struct gpio_vecs {
	struct regs con;
	struct regs dat;
	struct regs pud;
	struct regs drv_sr;
	struct regs con_pdn;
	struct regs pud_pdn;
};

static struct gpio_vecs gpio_vec[NUM_GPIO_MST] = {
	{ /* GPIO_GPJ0[2] */
		.con = {
			.offset = GPJ0CON, },
		.dat = {
			.offset = GPJ0DAT, },
		.pud = {
			.offset = GPJ0PUD, },
		.drv_sr = {
			.offset = GPJ0DRV_SR, },
		.con_pdn = {
			.offset = GPJ0CON_PDN, },
		.pud_pdn = {
			.offset = GPJ0PUD_PDN, },
	}, { /* GPIO_GPJ1[2] */
		.con = {
			.offset = GPJ1CON, },
		.dat = {
			.offset = GPJ1DAT, },
		.pud = {
			.offset = GPJ1PUD, },
		.drv_sr = {
			.offset = GPJ1DRV_SR, },
		.con_pdn = {
			.offset = GPJ1CON_PDN, },
		.pud_pdn = {
			.offset = GPJ1PUD_PDN, },
	},  { /* GPIO_GPF3[2] */
		.con = {
			.offset = GPF3CON, },
		.dat = {
			.offset = GPF3DAT, },
		.pud = {
			.offset = GPF3PUD, },
		.drv_sr = {
			.offset = GPF3DRV_SR, },
		.con_pdn = {
			.offset = GPF3CON_PDN, },
		.pud_pdn = {
			.offset = GPF3PUD_PDN, },
	},
};

extern addr_t gpj0_va, gpj1_va, gpf3_va, tzpc13_va, tzpc_peric_va;
uint32_t gpio_vecs_base[NUM_GPIO_MST];
void set_gpio_vecs_base(void)
{
	gpio_vecs_base[0] = (uint32_t *)gpj0_va;
	gpio_vecs_base[1] = (uint32_t *)gpj1_va;
	gpio_vecs_base[2] = (uint32_t *)gpf3_va;
}
#else
struct gpio_vecs {
	uint32_t base;
	struct regs con;
	struct regs dat;
	struct regs pud;
	struct regs drv_sr;
	struct regs con_pdn;
	struct regs pud_pdn;
};

static struct gpio_vecs gpio_vec[NUM_GPIO_MST] = {
	{ /* GPIO_GPJ0[2] */
		.base = VA_GPJ0,
		.con = {
			.offset = GPJ0CON, },
		.dat = {
			.offset = GPJ0DAT, },
		.pud = {
			.offset = GPJ0PUD, },
		.drv_sr = {
			.offset = GPJ0DRV_SR, },
		.con_pdn = {
			.offset = GPJ0CON_PDN, },
		.pud_pdn = {
			.offset = GPJ0PUD_PDN, },
	}, { /* GPIO_GPJ1[2] */
		.base = VA_GPJ1,
		.con = {
			.offset = GPJ1CON, },
		.dat = {
			.offset = GPJ1DAT, },
		.pud = {
			.offset = GPJ1PUD, },
		.drv_sr = {
			.offset = GPJ1DRV_SR, },
		.con_pdn = {
			.offset = GPJ1CON_PDN, },
		.pud_pdn = {
			.offset = GPJ1PUD_PDN, },
	},  { /* GPIO_GPF3[2] */
		.base = VA_GPF3,
		.con = {
			.offset = GPF3CON, },
		.dat = {
			.offset = GPF3DAT, },
		.pud = {
			.offset = GPF3PUD, },
		.drv_sr = {
			.offset = GPF3DRV_SR, },
		.con_pdn = {
			.offset = GPF3CON_PDN, },
		.pud_pdn = {
			.offset = GPF3PUD_PDN, },
	},	
};
#endif

#if defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS9810)
uint32_t set_gpio_mst_secure(uint32_t pin_conf)
{
	uint32_t ret = 0;
	uint32_t is_secure;
	uint32_t target_port;

	target_port = (~(GPIO_MST_DATA | GPIO_MST_EN));

	write_sfr_value((uint32_t)tzpc_peric_va + MST_OFFSET, read_sfr_value((uint32_t)tzpc_peric_va + MST_OFFSET) & target_port);

	is_secure = read_sfr_value((uint32_t)tzpc_peric_va + MST_OFFSET) & ~target_port;

	UART_PSH("set_gpio_mst_secure() : is_secure = ", is_secure);
	
	if(is_secure != TZPC_SECURE){
		ret = 1;
	}
	return ret;
}
#else
uint32_t set_gpio_mst_secure(uint32_t pin_conf)
{
	uint32_t ret = 0;
	uint32_t is_secure;
	uint32_t target_port;

	if(pin_conf == ZERO_IN_MODE)
		target_port = GPIO_NFC | GPIO_TOUCH;
	else if(pin_conf == NOBLE_ZERO2_IN_MODE)
		target_port = GPIO_NFC;
	else
		target_port = GPIO_MST;
#if TBASE_API_LEVEL >= 5
 	write_sfr_value((uint32_t)tzpc13_va + DECPROT0CLR, target_port);
	is_secure = read_sfr_value((uint32_t)tzpc13_va + DECPROT0STAT);
	UART_PSH("(uint32_t *)tzpc13_va + DECPROT0CLR = ", (uint32_t *)tzpc13_va + DECPROT0CLR);
	UART_PSH("(uint32_t)(tzpc13_va + DECPROT0CLR) = ", (uint32_t)(tzpc13_va + DECPROT0CLR));
#else
	write_sfr_value(VA_TZPC13 + DECPROT0CLR, target_port);
 	is_secure = read_sfr_value(VA_TZPC13 + DECPROT0STAT);
#endif
	UART_PSH("set_gpio_mst_secure() : is_secure = ", is_secure);
	is_secure &= (target_port);
	if(is_secure != TZPC_SECURE){
		ret = 1;
	}
	return ret;
}
#endif

#if defined(CONFIG_EXYNOS7420)
void set_gpio_mst_default(uint32_t pin_conf)
{
	uint32_t value;

	/* Clock enable */
	//value = read_sfr_value(VA_CMU_PERIC1 + PCLK_PERIC1);
	//value |= PCLK_GPIO_NFC_ENABLE | PCLK_GPIO_TOUCH_ENABLE;
	//write_sfr_value(VA_CMU_PERIC1 + PCLK_PERIC1, value);
#if TBASE_API_LEVEL >= 5
if(pin_conf == ZERO_IN_MODE){
		// GPJ0CON set
		value = CON0_SET(CON_FUNC) | CON1_SET(CON_FUNC) | CON2_SET(CON_OUTPUT);
		write_sfr_value((uint32_t)gpj0_va + GPJ0CON, value);

		// GPJ0PUD set
		value = PUD0_SET(PULL_UP) | PUD1_SET(PULL_UP) | PUD2_SET(PULL_DISABLED);
		write_sfr_value((uint32_t)gpj0_va + GPJ0PUD, value);
		
		// GPJ0DAT set
		value = DAT0_SET(HIGH) | DAT1_SET(HIGH) | DAT2_SET(LOW);
		write_sfr_value((uint32_t)gpj0_va + GPJ0DAT, value);
		
		// GPJ1CON set
		value = CON0_SET(CON_FUNC) | CON1_SET(CON_FUNC) | CON2_SET(CON_OUTPUT);
		write_sfr_value((uint32_t)gpj1_va + GPJ1CON, value);

		// GPJ1PUD set
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value((uint32_t)gpj1_va + GPJ1PUD, value);
		// GPJ1DAT set
		value = DAT0_SET(HIGH) | DAT1_SET(HIGH) | DAT2_SET(LOW);
		write_sfr_value((uint32_t)gpj1_va + GPJ1DAT, value);

}else{
		// GPJ0CON set
		value = CON0_SET(CON_INPUT) | CON1_SET(CON_OUTPUT) | CON2_SET(CON_OUTPUT);
		write_sfr_value((uint32_t)gpj0_va + GPJ0CON, value);

		// GPJ0PUD set
		value = PUD0_SET(PULL_DOWN) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value((uint32_t)gpj0_va + GPJ0PUD, value);
		
		// GPJ0DAT set
		value = DAT0_SET(LOW) | DAT1_SET(LOW) | DAT2_SET(LOW);
		write_sfr_value((uint32_t)gpj0_va + GPJ0DAT, value);
	}
#else //TBASE_API_LEVEL >= 5
	if(pin_conf == ZERO_IN_MODE){
		// GPJ0CON set
		value = CON0_SET(CON_FUNC) | CON1_SET(CON_FUNC) | CON2_SET(CON_OUTPUT);
		write_sfr_value(VA_GPJ0 + GPJ0CON, value);

		// GPJ0PUD set
		value = PUD0_SET(PULL_UP) | PUD1_SET(PULL_UP) | PUD2_SET(PULL_DISABLED);
		write_sfr_value(VA_GPJ0 + GPJ0PUD, value);
		
		// GPJ0DAT set
		value = DAT0_SET(HIGH) | DAT1_SET(HIGH) | DAT2_SET(LOW);
		write_sfr_value(VA_GPJ0 + GPJ0DAT, value);
		
		// GPJ1CON set
		value = CON0_SET(CON_FUNC) | CON1_SET(CON_FUNC) | CON2_SET(CON_OUTPUT);
		write_sfr_value(VA_GPJ1 + GPJ1CON, value);

		// GPJ1PUD set
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value(VA_GPJ1 + GPJ1PUD, value);
		
		// GPJ1DAT set
		value = DAT0_SET(HIGH) | DAT1_SET(HIGH) | DAT2_SET(LOW);
		write_sfr_value(VA_GPJ1 + GPJ1DAT, value);
	}else{
		// GPJ0CON set
		value = CON0_SET(CON_INPUT) | CON1_SET(CON_OUTPUT) | CON2_SET(CON_OUTPUT);
		write_sfr_value(VA_GPJ0 + GPJ0CON, value);

		// GPJ0PUD set
		value = PUD0_SET(PULL_DOWN) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value(VA_GPJ0 + GPJ0PUD, value);
		
		// GPJ0DAT set
		value = DAT0_SET(LOW) | DAT1_SET(LOW) | DAT2_SET(LOW);
		write_sfr_value(VA_GPJ0 + GPJ0DAT, value);
	}
#endif
}
#elif defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7880) || \
	  defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS7885)
void set_gpio_mst_default(uint32_t pin_conf)
{
	uint32_t value;
	uint32_t cur;
#if TBASE_API_LEVEL >= 5
	/* GRACE : It shares port with IRIS I2C line and IRIS has it's own init routine */
	if(pin_conf == GRACE_PHASE_EN_MODE){
		cur = read_sfr_value((uint32_t)gpj0_va + GPJ0CON);
		cur |= CON2_SET(CON_INPUT);
		write_sfr_value((uint32_t)gpj0_va + GPJ0CON, cur);

		cur = read_sfr_value((uint32_t)gpj0_va + GPJ0PUD);
		cur |= PUD2_SET(PULL_DOWN);
		write_sfr_value((uint32_t)gpj0_va + GPJ0PUD, cur);

		cur = read_sfr_value((uint32_t)gpj0_va + GPJ0DAT);
		cur |= DAT2_SET(LOW);
		write_sfr_value((uint32_t)gpj0_va + GPJ0DAT, cur);
	}else if(pin_conf == DREAM_PHASE_EN_MODE){
		cur = read_sfr_value((uint32_t)gpj0_va + GPJ0CON);
		value = CON1_SET(CON_OUTPUT) | CON2_SET(CON_OUTPUT);
		cur |= value;
		write_sfr_value((uint32_t)gpj0_va + GPJ0CON, cur);

		cur = read_sfr_value((uint32_t)gpj0_va + GPJ0PUD);
		value = PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		cur |= value;
		write_sfr_value((uint32_t)gpj0_va + GPJ0PUD, cur);

		cur = read_sfr_value((uint32_t)gpj0_va + GPJ0DAT);
		value = DAT1_SET(LOW) | DAT2_SET(LOW);
		cur |= value;
		write_sfr_value((uint32_t)gpj0_va + GPJ0DAT, cur);
	}else{		
		// GPC4CON set
		value = CON0_SET(CON_OUTPUT) | CON1_SET(CON_OUTPUT) | CON2_SET(CON_INPUT);
		write_sfr_value((uint32_t)gpj0_va + GPJ0CON, value);

		// GPC4PUD set
		value = PUD0_SET(PULL_DOWN) | PUD1_SET(PULL_DOWN) | PUD2_SET(PULL_DOWN);
		write_sfr_value((uint32_t)gpj0_va + GPJ0PUD, value);

		// GPC4DAT set
		value = DAT0_SET(LOW) | DAT1_SET(LOW) | DAT2_SET(LOW);
		write_sfr_value((uint32_t)gpj0_va + GPJ0DAT, value);
	}
#else
	/* GRACE : It shares port with IRIS I2C line and IRIS has it's own init routine */
	if(pin_conf == GRACE_PHASE_EN_MODE){
		cur = read_sfr_value(VA_GPJ0 + GPJ0CON);
		cur |= CON2_SET(CON_INPUT);
		write_sfr_value(VA_GPJ0 + GPJ0CON, cur);

		cur = read_sfr_value(VA_GPJ0 + GPJ0PUD);
		cur |= PUD2_SET(PULL_DOWN);
		write_sfr_value(VA_GPJ0 + GPJ0PUD, cur);

		cur = read_sfr_value(VA_GPJ0 + GPJ0DAT);
		cur |= DAT2_SET(LOW);
		write_sfr_value(VA_GPJ0 + GPJ0DAT, cur);
	}else{		
		// GPC4CON set
		value = CON0_SET(CON_OUTPUT) | CON1_SET(CON_OUTPUT) | CON2_SET(CON_INPUT);
		write_sfr_value(VA_GPJ0 + GPJ0CON, value);

		// GPC4PUD set
		value = PUD0_SET(PULL_DOWN) | PUD1_SET(PULL_DOWN) | PUD2_SET(PULL_DOWN);
		write_sfr_value(VA_GPJ0 + GPJ0PUD, value);

		// GPC4DAT set
		value = DAT0_SET(LOW) | DAT1_SET(LOW) | DAT2_SET(LOW);
		write_sfr_value(VA_GPJ0 + GPJ0DAT, value);
	}
#endif
}
#endif

/* gpio con/dat/pud set func with corresponding gpio pin num */
static uint32_t set_gpio_pud(uint32_t value, uint8_t pin_num, uint32_t pud_state){
	switch (pin_num) {                                                                        
		case 0:                                 
			value &= ~PUD0_SET(3);
			value |= PUD0_SET(pud_state);
			break;                                 
		case 1:                                 
			value &= ~PUD1_SET(3);
			value |= PUD1_SET(pud_state);
			break;                                 
		case 2:                                 
			value &= ~PUD2_SET(3);
			value |= PUD2_SET(pud_state);
			break;                                 
		case 3:                                 
			value &= ~PUD3_SET(3);
			value |= PUD3_SET(pud_state);
			break;                                             
		case 4:                                 
			value &= ~PUD4_SET(3);
			value |= PUD4_SET(pud_state);
			break;                                 
		case 5:                                 
			value &= ~PUD5_SET(3);
			value |= PUD5_SET(pud_state);
			break;                                 
		case 6:                                 
			value &= ~PUD6_SET(3);
			value |= PUD6_SET(pud_state);
			break;                                 
		case 7:                                 
			value &= ~PUD7_SET(3);
			value |= PUD7_SET(pud_state);
			break;                                 
		default:                                                  
			return value;  // wrong cmd_id                                 
	}                           
	return value;
}

static uint32_t set_gpio_dat(uint32_t value, uint8_t pin_num, uint32_t dat_state){
	switch (pin_num) {                                                                        
		case 0:                                 
			value &= ~DAT0_SET(1);
			value |= DAT0_SET(dat_state);
			break;                                 
		case 1:                                 
			value &= ~DAT1_SET(1);
			value |= DAT1_SET(dat_state);
			break;                                 
		case 2:                                 
			value &= ~DAT2_SET(1);
			value |= DAT2_SET(dat_state);
			break;                                 
		case 3:                                 
			value &= ~DAT3_SET(1);
			value |= DAT3_SET(dat_state);
			break;                                             
		case 4:                                 
			value &= ~DAT4_SET(1);
			value |= DAT4_SET(dat_state);
			break;                                 
		case 5:                                 
			value &= ~DAT5_SET(1);
			value |= DAT5_SET(dat_state);
			break;                                 
		case 6:                                 
			value &= ~DAT6_SET(1);
			value |= DAT6_SET(dat_state);
			break;                                 
		case 7:                                 
			value &= ~DAT7_SET(1);
			value |= DAT7_SET(dat_state);
			break;                                 
		default:                                                  
			return value;  // wrong cmd_id                                 
	}                           
	return value;
}

static uint32_t set_gpio_con(uint32_t value, uint8_t pin_num, uint32_t con_state){
	switch (pin_num) {                                                                        
		case 0:                                 
			value &= ~CON0_SET(0xF);
			value |= CON0_SET(con_state);
			break;                                 
		case 1:                                 
			value &= ~CON1_SET(0xF);
			value |= CON1_SET(con_state);
			break;                                 
		case 2:                                 
			value &= ~CON2_SET(0xF);
			value |= CON2_SET(con_state);
			break;                                 
		case 3:                                 
			value &= ~CON3_SET(0xF);
			value |= CON3_SET(con_state);
			break;                                             
		case 4:                                 
			value &= ~CON4_SET(0xF);
			value |= CON4_SET(con_state);
			break;                                 
		case 5:                                 
			value &= ~CON5_SET(0xF);
			value |= CON5_SET(con_state);
			break;                                 
		case 6:                                 
			value &= ~CON6_SET(0xF);
			value |= CON6_SET(con_state);
			break;                                 
		case 7:                                 
			value &= ~CON7_SET(0xF);
			value |= CON7_SET(con_state);
			break;                                 
		default:                                                  
			return value;  // wrong cmd_id                                 
	}                           
	return value;
}

void gpio_set_mst_init(uint32_t pin_conf, uint8_t gpio_mst_md_pin, uint8_t gpio_mst_pd_pin, uint8_t gpio_mst_pwr_en_pin)
{
	int idx;
	int vec_idx;
	uint32_t value;

	/* Clock enable */
	//value = read_sfr_value(VA_CMU_PERIC1 + PCLK_PERIC1);
	//value |= PCLK_GPIO_NFC_ENABLE;
	//write_sfr_value(VA_CMU_PERIC1 + PCLK_PERIC1, value);
#if TBASE_API_LEVEL >= 5
	set_gpio_vecs_base();
#endif
	for (idx = 0; idx < NUM_GPIO_MST; idx++) {
		vec_idx = idx;

		/* NOBLE/ZERO2 model only => mst gpio is allocated on 1 port not to affect other i2c */
		if((pin_conf == NOBLE_ZERO2_IN_MODE) && (idx == 1))
			gpio_mst_pd_pin = 2;

		/* HERO model only => GPJ1 base phy addr is for GRACE that it will just skip for HERO model*/
		if((pin_conf == HERO_PHASE_EN_MODE) && (idx == 1))
			vec_idx = 0;

		/* PUD set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].pud.offset);
#else
		value = read_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].pud.offset);
#endif
		UART_PSH("gpio_set_mst_init(pud) : value = ", value);

		if(idx == VEC_MST_MD){
			value = set_gpio_pud(value, gpio_mst_md_pin, PULL_DOWN);
		}else if(idx == VEC_MST_PD){
			value = set_gpio_pud(value, gpio_mst_pd_pin, PULL_DOWN);
		}else{
#if !defined(TIMA_MST_MFC_CHIP)
			value = set_gpio_pud(value, gpio_mst_pwr_en_pin, PULL_DOWN);
#endif
		}
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].pud.offset, value);
#else
		write_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].pud.offset, value);
#endif
		
		/* DAT set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].dat.offset);
#else
		value = read_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].dat.offset);
#endif
		UART_PSH("gpio_set_mst_init(dat) : value = ", value);
		if(idx == VEC_MST_MD){
			value = set_gpio_dat(value, gpio_mst_md_pin, LOW);
		}else if(idx == VEC_MST_PD){
			value = set_gpio_dat(value, gpio_mst_pd_pin, LOW);
		}else{
#if !defined(TIMA_MST_MFC_CHIP)
			value = set_gpio_dat(value, gpio_mst_pwr_en_pin, LOW);
#endif
		}

#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].dat.offset, value);
#else
		write_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].dat.offset, value);
#endif
		
		/* CON set */

#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].con.offset);
#else
		value = read_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].con.offset);
#endif
		UART_PSH("gpio_set_mst_init(con) : value = ", value);
		if(idx == VEC_MST_MD){
			value = set_gpio_con(value, gpio_mst_md_pin, CON_OUTPUT);
		}else if(idx == VEC_MST_PD){
			value = set_gpio_con(value, gpio_mst_pd_pin, CON_OUTPUT);
		}else{
#if !defined(TIMA_MST_MFC_CHIP)
			value = set_gpio_con(value, gpio_mst_pwr_en_pin, CON_OUTPUT);
#endif
		}
 #if TBASE_API_LEVEL >= 5
 		write_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].con.offset, value);
 #else
		write_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].con.offset, value);
 #endif
	}
	if(pin_conf == NOBLE_ZERO2_IN_MODE){
		/* PUD set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[0] + gpio_vec[0].pud.offset);
#else
		value = read_sfr_value(gpio_vec[0].base + gpio_vec[0].pud.offset);
#endif
		UART_PSH("gpio_set_mst_init(pud) : value = ", value);
		value &= ~PUD1_SET(3);
		value |= PUD1_SET(PULL_UP);
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[0] + gpio_vec[0].pud.offset, value);
#else
		write_sfr_value(gpio_vec[0].base + gpio_vec[0].pud.offset, value);
#endif

		/* DAT set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[0] + gpio_vec[0].dat.offset);
#else
		value = read_sfr_value(gpio_vec[0].base + gpio_vec[0].dat.offset);
#endif
		UART_PSH("gpio_set_mst_init(dat) : value = ", value);
		value &= ~DAT1_SET(1);
		value |= DAT1_SET(LOW);
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[0] + gpio_vec[0].dat.offset, value);
#else
		write_sfr_value(gpio_vec[0].base + gpio_vec[0].dat.offset, value);
#endif

		/* CON set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[0] + gpio_vec[0].con.offset);
#else
		value = read_sfr_value(gpio_vec[0].base + gpio_vec[0].con.offset);
#endif
		UART_PSH("gpio_set_mst_init(con) : value = ", value);
		value &= ~CON1_SET(0xF);
		value |= CON1_SET(CON_OUTPUT);
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[0] + gpio_vec[0].con.offset, value);
#else
		write_sfr_value(gpio_vec[0].base + gpio_vec[0].con.offset, value);
#endif
	}
	gpio_mst_status = CON_OUTPUT;
}

void gpio_set_mst_exit(uint32_t pin_conf, uint8_t gpio_mst_md_pin, uint8_t gpio_mst_pd_pin, uint8_t gpio_mst_pwr_en_pin)
{
	int idx;
	int vec_idx;
	uint32_t value;

#if TBASE_API_LEVEL >= 5
	set_gpio_vecs_base();
#endif
	for (idx = 0; idx < NUM_GPIO_MST; idx++) {
		vec_idx = idx;

		/* NOBLE/ZERO2 model only => mst gpio is allocated on 1 port not to affect other i2c */
		if(pin_conf == NOBLE_ZERO2_IN_MODE && idx == 1)
			gpio_mst_pd_pin = 2;

		/* HERO model only => GPJ1 base phy addr is for GRACE that it will just skip for HERO model*/
		if((pin_conf == HERO_PHASE_EN_MODE) && (idx == 1))
			vec_idx = 0;

		/* PUD set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].pud.offset);
#else
		value = read_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].pud.offset);
#endif
		UART_PSH("gpio_set_mst_exit(pud) : value = ", value);
		if(idx == VEC_MST_MD){
			value = set_gpio_pud(value, gpio_mst_md_pin, PULL_DOWN);
		}else if(idx == VEC_MST_PD){
			value = set_gpio_pud(value, gpio_mst_pd_pin, PULL_DOWN);
		}else{
#if !defined(TIMA_MST_MFC_CHIP)
			value = set_gpio_pud(value, gpio_mst_pwr_en_pin, PULL_DOWN);
#endif
		}
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].pud.offset, value);
#else
		write_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].pud.offset, value);
#endif
		
		/* DAT set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].dat.offset);
#else
		value = read_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].dat.offset);
#endif
		UART_PSH("gpio_set_mst_exit(dat) : value = ", value);
		if(idx == VEC_MST_MD){
			value = set_gpio_dat(value, gpio_mst_md_pin, LOW);
		}else if(idx == VEC_MST_PD){
			value = set_gpio_dat(value, gpio_mst_pd_pin, LOW);
		}else{
#if !defined(TIMA_MST_MFC_CHIP)
			value = set_gpio_dat(value, gpio_mst_pwr_en_pin, LOW);
#endif
		}
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].dat.offset, value);
#else
		write_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].dat.offset, value);
#endif
		
		/* CON set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].con.offset);
#else
		value = read_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].con.offset);
#endif
		UART_PSH("gpio_set_mst_exit(con) : value = ", value);
		if(idx == VEC_MST_MD){
			value = set_gpio_con(value, gpio_mst_md_pin, CON_INPUT);
		}else if(idx == VEC_MST_PD){
			value = set_gpio_con(value, gpio_mst_pd_pin, CON_INPUT);
		}else{
#if !defined(TIMA_MST_MFC_CHIP)
			value = set_gpio_con(value, gpio_mst_pwr_en_pin, CON_INPUT);
#endif
		}
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[vec_idx] + gpio_vec[vec_idx].con.offset, value);
#else
		write_sfr_value(gpio_vec[vec_idx].base + gpio_vec[vec_idx].con.offset, value);
#endif
	}
	if(pin_conf == NOBLE_ZERO2_IN_MODE){
		/* PUD set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[0] + gpio_vec[0].pud.offset);
#else
		value = read_sfr_value(gpio_vec[0].base + gpio_vec[0].pud.offset);
#endif
		UART_PSH("gpio_set_mst_exit(pud) : value = ", value);
		value &= ~PUD1_SET(3);
		value |= PUD1_SET(PULL_DOWN);
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[0] + gpio_vec[0].pud.offset, value);
#else
		write_sfr_value(gpio_vec[0].base + gpio_vec[0].pud.offset, value);
#endif

		/* DAT set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[0] + gpio_vec[0].dat.offset);
#else
		value = read_sfr_value(gpio_vec[0].base + gpio_vec[0].dat.offset);
#endif
		UART_PSH("gpio_set_mst_exit(dat) : value = ", value);
		value &= ~DAT1_SET(1);
		value |= DAT1_SET(LOW);
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[0] + gpio_vec[0].dat.offset, value);
#else
		write_sfr_value(gpio_vec[0].base + gpio_vec[0].dat.offset, value);
#endif

		/* CON set */
#if TBASE_API_LEVEL >= 5
		value = read_sfr_value(gpio_vecs_base[0] + gpio_vec[0].con.offset);
#else
		value = read_sfr_value(gpio_vec[0].base + gpio_vec[0].con.offset);
#endif
		UART_PSH("gpio_set_mst_exit(con) : value = ", value);
		value &= ~CON1_SET(0xF);
		value |= CON1_SET(CON_INPUT);
#if TBASE_API_LEVEL >= 5
		write_sfr_value(gpio_vecs_base[0] + gpio_vec[0].con.offset, value);
#else
		write_sfr_value(gpio_vec[0].base + gpio_vec[0].con.offset, value);
#endif
	}
	gpio_mst_status = CON_INPUT;
}

inline int gpio_set_mst_data(uint32_t data, const int mst, uint8_t gpio_mst_pin)
{
	int idx = mst;
	uint32_t value;

#if TBASE_API_LEVEL >= 5
	set_gpio_vecs_base();
#endif
	if (!gpio_mst_status)
		/* GPIO isn't set as output port */
		return -1;

#if TBASE_API_LEVEL >= 5
	value = read_sfr_value(gpio_vecs_base[idx] + gpio_vec[idx].dat.offset);
#else
	value = read_sfr_value(gpio_vec[idx].base + gpio_vec[idx].dat.offset);
#endif
	UART_PSH("gpio_set_mst_data(dat) : value = ", value);

	switch (data) {
	case 0:
		value = set_gpio_dat(value, gpio_mst_pin, LOW);
		break;
	case 1:
		value = set_gpio_dat(value, gpio_mst_pin, HIGH);
		break;
	default:
		/* Invalid Input */
		return -1;
	}
#if TBASE_API_LEVEL >= 5
	write_sfr_value(gpio_vecs_base[idx] + gpio_vec[idx].dat.offset, value);
#else
	write_sfr_value(gpio_vec[idx].base + gpio_vec[idx].dat.offset, value);
#endif

	return 0;
}

/* _____________NOBLE,ZERO2 PROJECT ONLY START_____________ */
inline int gpio_set_mst_data_positive(uint32_t data)
{
	uint32_t value;

#if TBASE_API_LEVEL >= 5
	set_gpio_vecs_base();
#endif
	if (!gpio_mst_status)
		/* GPIO isn't set as output port */
		return -1;

#if TBASE_API_LEVEL >= 5
	value = read_sfr_value(gpio_vecs_base[0] + gpio_vec[0].dat.offset);
#else
	value = read_sfr_value(gpio_vec[0].base + gpio_vec[0].dat.offset);
#endif
 	value &= ~DAT1_SET(1);
	value &= ~DAT2_SET(1);

	switch (data) {
	case 0:
		value |= DAT1_SET(LOW);
		value |= DAT2_SET(LOW);
		break;
	case 1:
		value |= DAT1_SET(HIGH);
		value |= DAT2_SET(HIGH);
		break;
	default:
		/* Invalid Input */
		return -1;
	}
#if TBASE_API_LEVEL >= 5
	write_sfr_value(gpio_vecs_base[0] + gpio_vec[0].dat.offset, value);
#else
	write_sfr_value(gpio_vec[0].base + gpio_vec[0].dat.offset, value);
#endif

	return 0;
}

inline int gpio_set_mst_data_negative(uint32_t data)
{
	uint32_t value;

#if TBASE_API_LEVEL >= 5
	set_gpio_vecs_base();
#endif
	if (!gpio_mst_status)
		/* GPIO isn't set as output port */
		return -1;

#if TBASE_API_LEVEL >= 5
	value = read_sfr_value(gpio_vecs_base[0] + gpio_vec[0].dat.offset);
#else
	value = read_sfr_value(gpio_vec[0].base + gpio_vec[0].dat.offset);
#endif
	value &= ~DAT1_SET(1);
	value &= ~DAT2_SET(1);

	switch (data) {
	case 0:
		value |= DAT1_SET(HIGH);
		value |= DAT2_SET(LOW);
		break;
	case 1:
		value |= DAT1_SET(LOW);
		value |= DAT2_SET(HIGH);
		break;
	default:
		/* Invalid Input */
		return -1;
	}
#if TBASE_API_LEVEL >= 5
	write_sfr_value(gpio_vecs_base[0] + gpio_vec[0].dat.offset, value);
#else
	write_sfr_value(gpio_vec[0].base + gpio_vec[0].dat.offset, value);
#endif

	return 0;
}
/* _____________NOBLE,ZERO2 PROJECT ONLY END_____________ */

inline void udelay(uint32_t usec)
{
	delay_timer(usec * 1000);	
}

uint32_t save_mst_gpio_regs(uint32_t pin_conf)
{
	uint32_t gp_num, gp_reg, offset, value, rt;

#if TBASE_API_LEVEL >= 5
	set_gpio_vecs_base();
	value = read_sfr_value((uint32_t)gpj0_va + GPJ0CON);
	UART_PSH("save_mst_gpio_regs(0con) : value = ", value);
	rt = value;
	
	value = read_sfr_value((uint32_t)gpj0_va + GPJ0PUD);
	UART_PSH("save_mst_gpio_regs(0pud) : value = ", value);
	value = value & 0x0f;
	rt = rt + (value<<12);

	value = read_sfr_value((uint32_t)gpj1_va + GPJ1CON);
	UART_PSH("save_mst_gpio_regs(1con) : value = ", value);
	rt = rt + (value<<16);
	
	value = read_sfr_value((uint32_t)gpj1_va + GPJ1PUD);
	UART_PSH("save_mst_gpio_regs(1pud) : value = ", value);
	value = value & 0x0f;
	rt = rt + (value<<28);

 #else
	value = read_sfr_value(VA_GPJ0 + GPJ0CON);
 	UART_PSH("save_mst_gpio_regs(0con) : value = ", value);
	rt = value;
	
	value = read_sfr_value(VA_GPJ0 + GPJ0PUD);
	UART_PSH("save_mst_gpio_regs(0pud) : value = ", value);
	value = value & 0x0f;
	rt = rt + (value<<12);

	value = read_sfr_value(VA_GPJ1 + GPJ1CON);
	UART_PSH("save_mst_gpio_regs(1con) : value = ", value);
	rt = rt + (value<<16);
	
	value = read_sfr_value(VA_GPJ1 + GPJ1PUD);
	UART_PSH("save_mst_gpio_regs(1pud) : value = ", value);
	value = value & 0x0f;
	rt = rt + (value<<28);

#endif
	for (gp_num = 0; gp_num < GPIO_MST_NUM; gp_num++) {
		if(pin_conf != ZERO_IN_MODE && gp_num == 1)
			continue;
		for (gp_reg = 0; gp_reg < GPIO_MST_REG_NUM; gp_reg++) {
			offset = gpio_list[gp_num].offset[gp_reg];
#if TBASE_API_LEVEL >= 5
			value = read_sfr_value(gpio_vecs_base[gp_num] + offset);
#else
			value = read_sfr_value(gpio_vec[gp_num].base + offset);
#endif
			UART_PSH("save_mst_gpio_regs(final) : value = ", value);
			gpio_list[gp_num].val[gp_reg] = value;
		}
	}

	return rt;
}

uint32_t restore_mst_gpio_regs(uint32_t pin_conf)
{
	uint32_t gp_num, gp_reg, offset, value, rt;

#if TBASE_API_LEVEL >= 5
	set_gpio_vecs_base();
#endif
	for (gp_num = 0; gp_num < GPIO_MST_NUM; gp_num++) {
		if(pin_conf != ZERO_IN_MODE && gp_num == 1)
			continue;
		for (gp_reg = 0; gp_reg < GPIO_MST_REG_NUM; gp_reg++) {
			offset = gpio_list[gp_num].offset[gp_reg];
			value = gpio_list[gp_num].val[gp_reg];
#if TBASE_API_LEVEL >= 5
			write_sfr_value(gpio_vecs_base[gp_num] + offset, value);
#else
			write_sfr_value(gpio_vec[gp_num].base + offset, value);
#endif
		}
	}
#if TBASE_API_LEVEL >= 5
	value = read_sfr_value((uint32_t)gpj0_va + GPJ0CON);
	UART_PSH("restore_mst_gpio_regs(0con) : value = ", value);
	rt = value;

	value = read_sfr_value((uint32_t)gpj0_va + GPJ0PUD);
	UART_PSH("restore_mst_gpio_regs(0pud) : value = ", value);
	value = value & 0x0f;
	rt = rt + (value<<12);

	value = read_sfr_value((uint32_t)gpj1_va + GPJ1CON);
	UART_PSH("restore_mst_gpio_regs(1con) : value = ", value);
	rt = rt + (value<<16);

	value = read_sfr_value((uint32_t)gpj1_va + GPJ1PUD);
	UART_PSH("restore_mst_gpio_regs(1pud) : value = ", value);
	value = value & 0x0f;
	rt = rt + (value<<28);
 #else
	value = read_sfr_value(VA_GPJ0 + GPJ0CON);
 	UART_PSH("restore_mst_gpio_regs(0con) : value = ", value);
	rt = value;
	
	value = read_sfr_value(VA_GPJ0 + GPJ0PUD);
	UART_PSH("restore_mst_gpio_regs(0pud) : value = ", value);
	value = value & 0x0f;
	rt = rt + (value<<12);

	value = read_sfr_value(VA_GPJ1 + GPJ1CON);
	UART_PSH("restore_mst_gpio_regs(1con) : value = ", value);
	rt = rt + (value<<16);

	value = read_sfr_value(VA_GPJ1 + GPJ1PUD);
	UART_PSH("restore_mst_gpio_regs(1pud) : value = ", value);
	value = value & 0x0f;
	rt = rt + (value<<28);
#endif
	return rt;	
}

void set_saved_gpio_mst_default(void)
{
	int gp_num, gp_reg;

	for (gp_num = 0; gp_num < GPIO_MST_NUM; gp_num++) {
		for (gp_reg = 0; gp_reg < GPIO_MST_REG_NUM; gp_reg++) {
			gpio_list[gp_num].offset[gp_reg] = gpio_offset[gp_reg];
		}
	}
}

#if defined(CONFIG_EXYNOS7420)
uint32_t set_gpio_sleep_state(uint32_t pin_conf){
	int value;

	if(pin_conf == ZERO_IN_MODE){
		//GPJ0PUDPDN
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value(VA_GPJ0 + GPJ0PUD_PDN, value);

		//GPJ1PUDPDN
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value(VA_GPJ1 + GPJ1PUD_PDN, value);

		//GPJ0CONPDN
		value = CONPDN0_SET(INPUT) | CONPDN1_SET(INPUT) | CONPDN2_SET(PREVIOUS_STATE);
		write_sfr_value(VA_GPJ0 + GPJ0CON_PDN, value);

		//GPJ1CONPDN
		value = CONPDN0_SET(INPUT) | CONPDN1_SET(INPUT) | CONPDN2_SET(PREVIOUS_STATE);
		write_sfr_value(VA_GPJ1 + GPJ1CON_PDN, value);
	}else{
		//GPJ0PUDPDN
		value = PUD0_SET(PULL_DOWN) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value(VA_GPJ0 + GPJ0PUD_PDN, value);

		//GPJ0CONPDN
		value = CONPDN0_SET(INPUT) | CONPDN1_SET(PREVIOUS_STATE) | CONPDN2_SET(PREVIOUS_STATE);
		write_sfr_value(VA_GPJ0 + GPJ0CON_PDN, value);
	}

	return pin_conf;
}
#elif defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7880) || \
	  defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS9810)
uint32_t set_gpio_sleep_state(uint32_t pin_conf){
	int value;
#if TBASE_API_LEVEL >= 5
	//GPJ0PUDPDN
	value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DOWN);
	write_sfr_value((uint32_t)gpj0_va + GPJ0PUD_PDN, value);

	//GPJ0CONPDN
	value = CONPDN0_SET(PREVIOUS_STATE) | CONPDN1_SET(PREVIOUS_STATE) | CONPDN2_SET(INPUT);
	write_sfr_value((uint32_t)gpj0_va + GPJ0CON_PDN, value);
#else
	//GPJ0PUDPDN
	value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DOWN);
	write_sfr_value(VA_GPJ0 + GPJ0PUD_PDN, value);

	//GPJ0CONPDN
	value = CONPDN0_SET(PREVIOUS_STATE) | CONPDN1_SET(PREVIOUS_STATE) | CONPDN2_SET(INPUT);
	write_sfr_value(VA_GPJ0 + GPJ0CON_PDN, value);
#endif
	return pin_conf;
}

#endif

void set_gpio_lpa_mode(uint32_t pin_conf){
	int value;
#if TBASE_API_LEVEL >= 5
	if(pin_conf == ZERO_IN_MODE){
		//GPJ0PUDPDN
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value((uint32_t)gpj0_va + GPJ0PUD_PDN, value);

		//GPJ1PUDPDN
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value((uint32_t)gpj1_va + GPJ1PUD_PDN, value);

		//GPJ0CONPDN
		value = CONPDN0_SET(PREVIOUS_STATE) | CONPDN1_SET(PREVIOUS_STATE) | CONPDN2_SET(PREVIOUS_STATE);
		write_sfr_value((uint32_t)gpj0_va + GPJ0CON_PDN, value);

		//GPJ1CONPDN
		value = CONPDN0_SET(PREVIOUS_STATE) | CONPDN1_SET(PREVIOUS_STATE) | CONPDN2_SET(PREVIOUS_STATE);
		write_sfr_value((uint32_t)gpj1_va + GPJ1CON_PDN, value);
	}else{
		//GPJ0PUDPDN
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value((uint32_t *)gpj0_va + GPJ0PUD_PDN, value);

		//GPJ0CONPDN
		value = CONPDN0_SET(PREVIOUS_STATE) | CONPDN1_SET(PREVIOUS_STATE) | CONPDN2_SET(PREVIOUS_STATE);
		write_sfr_value((uint32_t *)gpj0_va + GPJ0CON_PDN, value);
	}
 
 #else
	if(pin_conf == ZERO_IN_MODE){
		//GPJ0PUDPDN
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value(VA_GPJ0 + GPJ0PUD_PDN, value);

		//GPJ1PUDPDN
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value(VA_GPJ1 + GPJ1PUD_PDN, value);

		//GPJ0CONPDN
		value = CONPDN0_SET(PREVIOUS_STATE) | CONPDN1_SET(PREVIOUS_STATE) | CONPDN2_SET(PREVIOUS_STATE);
		write_sfr_value(VA_GPJ0 + GPJ0CON_PDN, value);

		//GPJ1CONPDN
		value = CONPDN0_SET(PREVIOUS_STATE) | CONPDN1_SET(PREVIOUS_STATE) | CONPDN2_SET(PREVIOUS_STATE);
		write_sfr_value(VA_GPJ1 + GPJ1CON_PDN, value);
	}else{
		//GPJ0PUDPDN
		value = PUD0_SET(PULL_DISABLED) | PUD1_SET(PULL_DISABLED) | PUD2_SET(PULL_DISABLED);
		write_sfr_value(VA_GPJ0 + GPJ0PUD_PDN, value);

		//GPJ0CONPDN
		value = CONPDN0_SET(PREVIOUS_STATE) | CONPDN1_SET(PREVIOUS_STATE) | CONPDN2_SET(PREVIOUS_STATE);
		write_sfr_value(VA_GPJ0 + GPJ0CON_PDN, value);
	}
 #endif
}

void recover_gpio_mst(int gpio)
{
	int cnt;
	int con_addr, dat_addr;
	int sda_val, scl_val, value;
#if TBASE_API_LEVEL >= 5

if (gpio == RECOVER_GPIO_NFC) {
		con_addr = (uint32_t *)gpj0_va + GPJ0CON;
		dat_addr = (uint32_t *)gpj0_va + GPJ0DAT;
	} else if (gpio == RECOVER_GPIO_TOUCH) {
		con_addr = (uint32_t *)gpj1_va + GPJ1CON;
		dat_addr = (uint32_t *)gpj1_va + GPJ1DAT;
	} else {
		// Invalid input
		return;
	}
#else
	if (gpio == RECOVER_GPIO_NFC) {
		con_addr = VA_GPJ0 + GPJ0CON;
		dat_addr = VA_GPJ0 + GPJ0DAT;
	} else if (gpio == RECOVER_GPIO_TOUCH) {
		con_addr = VA_GPJ1 + GPJ1CON;
		dat_addr = VA_GPJ1 + GPJ1DAT;
	} else {
		// Invalid input
		return;
	}
#endif
	UART_PSH("recover_gpio_mst():con_addr = ", con_addr);
	UART_PSH("recover_gpio_mst():dat_addr = ", dat_addr);
	sda_val = DAT0_GET(read_sfr_value(dat_addr)); // SDA
	scl_val = DAT1_GET(read_sfr_value(dat_addr)); // SCL
	UART_PSH("recover_gpio_mst(dat_addr) : sda_val = ", sda_val);
	UART_PSH("recover_gpio_mst(dat_addr) : scl_val = ", scl_val);
	/* Just return if sda value is high */
	if (sda_val == 1)
		return;
	/* Wait for SCL as high for 500msec */
	if (scl_val == 0) {
		for (cnt = 0; cnt < 50; cnt++) {
			if (DAT1_GET(read_sfr_value(dat_addr)) != 0) // SCL
			break;
			udelay(10000);
			}
	}
	sda_val = DAT0_GET(read_sfr_value(dat_addr)); // DAT
	if (sda_val == 0) {
		value = read_sfr_value(con_addr);
		UART_PSH("recover_gpio_mst(con_addr) : value = ", value);
		value &= ~CON1_SET(0xF);
		value |= CON1_SET(CON_OUTPUT);
		write_sfr_value(con_addr, value);
		for (cnt = 0; cnt < 100; cnt++) {
			write_sfr_value(dat_addr, DAT1_SET(LOW));
			udelay(5);
			write_sfr_value(dat_addr, DAT1_SET(HIGH));
			udelay(5);
			sda_val = DAT0_GET(read_sfr_value(dat_addr)); // DAT
			if (sda_val == 1) // break if SDA is high
				break;
			}
	}
	value = CON0_SET(CON_FUNC) | CON1_SET(CON_FUNC) | CON2_SET(CON_OUTPUT);
	write_sfr_value(con_addr, value);
}

