/**
 * @file  gpio-fp.c
 * @brief GPIO API for Fastcall driver(Fingerprint)
 *
 * Copyright (c) 2014-2015 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 <stdbool.h>
#include <stdint.h>
#include "handler.h"
#include "kernel_api.h"

#include "gpio-fp.h"

#if defined(CONFIG_FP_TZ_CONTROL)

struct gpio_fp_saved_status {
	unsigned long gpiocon;
	unsigned long gpiodat;
	unsigned long gpiopud;
	unsigned long gpiodrv;
} g_saved_val;

uint32_t fp_handler_main(uint32_t val_1, uint32_t val_2) {

	uint32_t ret = 0;

	switch(val_1) {
	case FP_SET_POWEROFF:
		ret = fp_set_poweroff_regs();
		break;
	case FP_SET_POWERON_INACTIVE:
		ret = fp_set_poweron_inactive_regs();
		break;
	case FP_SET_TZPC_SECURE:
		ret = fp_set_tzpc_secure();
		break;
	default:
		printf("CSMC: default %d, %d\n", val_1, val_2);
		ret = (uint32_t)-2;
	}
	return ret;
}

/************************************************************************/
/* TZPC control functions                                               */
/************************************************************************/
uint32_t fp_set_tzpc_secure(void) {
	unsigned long ret = 0;
#if (FP_TZPC_SET_ENABLE)
	unsigned long is_secure;
#endif
#if (FP_TZPC_SET_ENABLE & FP_TZPC_SET_GPIO)
	unsigned long read_value = 0, write_value = 0;
#endif

#if (FP_TZPC_SET_ENABLE & FP_TZPC_SET_USI)
	/* set USI TZPC secure */
	WRITE_SFR((uint32_t)FP_TZPC_USI_SFR_BASE, FP_TZPC_DECPROTCLR, FP_TZPC_USI_CH0_M);
	/* check USI TZPC Status */
	is_secure = READ_SFR((uint32_t)FP_TZPC_USI_SFR_BASE, FP_TZPC_DECPROTSTAT);
	is_secure &= (unsigned long)FP_TZPC_USI_CH0_M;
	if (is_secure != (unsigned long)FP_TZPC_SECURE) {
		ret |= (unsigned long)FP_TZPC_SET_USI;
		ret |= (unsigned long)FP_TZPC_ERROR_RETURN;
		printf("set_fp_tzpc_secure(usi) is failed\n");
	}
#endif

#if (FP_TZPC_SET_ENABLE & FP_TZPC_SET_USI_MODE)
	/* set USI MODE TZPC secure */
	WRITE_SFR((uint32_t)FP_TZPC_USI_MODE_SFR_BASE, FP_TZPC_USI_MODE_DECPROTCLR, FP_TZPC_USI_MODE_M);
	/* check USI MODE TZPC Status */
	is_secure = READ_SFR((uint32_t)FP_TZPC_USI_MODE_SFR_BASE, FP_TZPC_USI_MODE_DECPROTSTAT);
	is_secure &= (unsigned long)FP_TZPC_USI_MODE_M;
	if (is_secure != (unsigned long)FP_TZPC_SECURE) {
		ret |= (unsigned long)FP_TZPC_SET_USI_MODE;
		ret |= (unsigned long)FP_TZPC_ERROR_RETURN;
		printf("set_fp_tzpc_secure(usi_mode) is failed\n");
	}
#endif

#if (FP_TZPC_SET_ENABLE & FP_TZPC_SET_GPIO)
	/* set GPIO TZPC secure */
	read_value = READ_SFR((uint32_t)FP_TZPC_PERIC0_0_SFR_BASE, FP_TZPC_GPIO_DECSTAT_NUM);
	write_value = read_value & FP_TZPC_GPIO_PERIC0_M;
	WRITE_SFR((uint32_t)FP_TZPC_PERIC0_0_SFR_BASE, FP_TZPC_GPIO_DECPROT_NUM, write_value);
	/* check GPIO TZPC Status */
	is_secure = READ_SFR((uint32_t)FP_TZPC_PERIC0_0_SFR_BASE, FP_TZPC_GPIO_DECSTAT_NUM);
	is_secure &= ~(unsigned long)FP_TZPC_GPIO_PERIC0_M;
	if (is_secure != (unsigned long)FP_TZPC_SECURE) {
		ret |= (unsigned long)FP_TZPC_SET_GPIO;
		ret |= (unsigned long)FP_TZPC_ERROR_RETURN;
		printf("set_fp_tzpc_secure(gpio) is failed\n");
	}
#endif

	if ((ret & (unsigned long)FP_ERROR_PREFIX) == 0)
		ret = (unsigned long)FP_TZPC_SET_ENABLE;

	printf("set_fp_tzpc result : 0x%08lx\n", ret);
	return (uint32_t) ret;

}
uint32_t fp_set_poweroff_regs(void) {

	unsigned long read_con = 0, read_dat = 0, read_pud = 0, read_drv = 0, read_conpdn = 0, read_pudpdn = 0;
	unsigned long write_con = 0, write_dat = 0, write_pud = 0, write_drv = 0, write_conpdn = 0, write_pudpdn = 0;

	read_con = 	READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOCON) & ~FP_GPIOCON_MASK;
	read_dat = 	READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIODAT) & ~FP_GPIODAT_MASK;
	read_pud = 	READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOPUD) & ~FP_GPIOPUD_MASK;
	read_drv =  READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIODRV) & ~FP_GPIODRV_MASK;
	read_conpdn = 	READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOCONPDN) & ~FP_GPIOCONPDN_MASK;
	read_pudpdn =  READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOPUDPDN) & ~FP_GPIOPUDPDN_MASK;

	write_con = read_con | FP_GPIOCON_INIT_VALUE;
	write_dat = read_dat | FP_GPIODAT_INIT_VALUE;
	write_pud = read_pud | FP_GPIOPUD_INIT_VALUE;
	write_drv = read_drv | FP_GPIODRV_INIT_VALUE;
	write_conpdn = read_conpdn | FP_GPIOCONPDN_POWEROFF_VALUE;
	write_pudpdn = read_pudpdn | FP_GPIOPUDPDN_POWEROFF_VALUE;

	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOCON, write_con);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIODAT, write_dat);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOPUD, write_pud);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIODRV, write_drv);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOCONPDN, write_conpdn);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOPUDPDN, write_pudpdn);

	return (uint32_t) FP_RET_SUCCESS;
}

uint32_t fp_set_poweron_inactive_regs(void) {

	unsigned long read_con = 0, read_dat = 0, read_pud = 0, read_drv = 0, read_conpdn = 0, read_pudpdn = 0;
	unsigned long write_con = 0, write_dat = 0, write_pud = 0, write_drv = 0, write_conpdn = 0, write_pudpdn = 0;

	read_con = 	READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOCON) & ~FP_GPIOCON_MASK;
	read_dat = 	READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIODAT) & ~FP_GPIODAT_MASK;
	read_pud = 	READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOPUD) & ~FP_GPIOPUD_MASK;
	read_drv =  READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIODRV) & ~FP_GPIODRV_MASK;
	read_conpdn = 	READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOCONPDN) & ~FP_GPIOCONPDN_MASK;
	read_pudpdn =  READ_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOPUDPDN) & ~FP_GPIOPUDPDN_MASK;

	write_con = read_con | FP_GPIOCON_POWERON_INACTIVE_VALUE;
	write_dat = read_dat | FP_GPIODAT_POWERON_INACTIVE_VALUE;
	write_pud = read_pud | FP_GPIOPUD_POWERON_INACTIVE_VALUE;
	write_drv = read_drv | FP_GPIODRV_POWERON_INACTIVE_VALUE;
	write_conpdn = read_conpdn | FP_GPIOCONPDN_POWERON_INACTIVE_VALUE;
	write_pudpdn = read_pudpdn | FP_GPIOPUDPDN_POWERON_INACTIVE_VALUE;

	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOCON, write_con);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIODAT, write_dat);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOPUD, write_pud);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIODRV, write_drv);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOCONPDN, write_conpdn);
	WRITE_SFR((uint32_t)FP_GPIO_PERIC0_SFR_BASE, FP_GPIOPUDPDN, write_pudpdn);

	return (uint32_t) FP_RET_SUCCESS;
}
#endif
