/*******************************************************************************
*	Copyright (c) 2013 WonderMedia Technologies, Inc.
*
*	Abstract:
*		This program is designed to show the charge animation
*
******************************Release History ***********************************
*
* Version 1.0 , HowayHuo, 2013/5/8
* First version: Created by Howayhuo
*
**********************************************************************************/
#include <common.h>
#include <command.h>
#include <asm/arch/common_def.h>
#include <asm/byteorder.h>
#include <bmp_layout.h>
#include "../../../board/wmt/include/wmt_pmc.h"
#include "../../../board/wmt/wmt_battery/wmt_battery.h"
#include "../minivgui.h"
#include "../wmt_display.h"

#define HSP3_STATUS (0xD8130000 + 0x3C)
#define REBOOT_BIT 0x10

#define POWERUP_SOURCE_STATUS (0xD8130000 + 0xD0)
#define PWRBTN_BIT           0x01
#define VBAT_RISING_BIT      0x02
#define DCDET_RISING_BIT     0x04
#define DCDET_FALLING_BIT    0x08
#define DCDET_BIT            0x10

#define ENV_MPTOOL_DETECT    "wmt.mptool.detect"
#define ENV_MPTOOL_TIMEOUT   "wmt.mptool.timeout"
#define ENV_USBPC_TIMEOUT    "wmt.usbpc.timeout"

static unsigned char *sp_mem_addr = (unsigned char *)0x3000000;

static int s_usb_to_pc;
static int s_pwm_duty_decreased;
static int s_battery_init_ok = -1;
static int s_animation_init_ok = -1;
static int s_lcd_first_light = 1;

/*
s_step_by_step_light value:
1: the backlight is light step by setp.
0: the backlight is light right now
*/
static int s_step_by_step_light = 1;

extern int g_tf_boot;

//extern char* CMD_LOAD_SCRIPT;
extern int g_show_logo;
extern int udc_fastboot_init(void);
extern void udc_fastboot_transfer(void);
extern void udc_fastboot_exit(void);
extern int wmt_udc_connected(void);
extern int udc_fastboot_is_init(void);
extern void do_wmt_poweroff(void);
extern int wmt_mptool_ready(void);
extern int usb_plugin(void);
extern void run_fastboot(int backlight_on);

extern struct nand_chip *get_current_nand_chip(void);
extern int WMTAccessNandEarier(unsigned long long naddr, unsigned int maddr,
                               unsigned int size, int write);

extern unsigned int pwm_get_enable(int no);
extern void lcd_blt_enable(int no, int enable);
extern void lcd_set_power_down(int enable);
//extern void hint_battery_checking(void);

static int sleep_sec(int sec)
{
	ulong start = get_timer(0);
	ulong delay;

	delay = sec * CFG_HZ;

	while (get_timer(start) < delay) {
		if (ctrlc ()) {
			return (-1);
		}
		udelay (100);
	}

	return 0;
}

//return level ( 0 ~ 5 ), level < 0 is error
static int get_battery_level(int *p_percent)
{
	int capacity, level = 0;

	if (wmt_battery_is_charging_full() == 1) {
		printf("power is full\n");
		capacity = 100;
	} else
		capacity = wmt_battery_get_capacity();

	*p_percent = capacity;

	if (capacity >= 0 && capacity <= 100)
		level = capacity / 20;

	return level;
}

static void decrease_pwm_duty(int duty_percent)
{
	int duty;

	if(!(g_display_vaild & DISPLAY_ENABLE))
		return;

	//if(s_pwm_duty_decreased == 1)
	//	return;

	if (g_display_param.vout == VPP_VOUT_LCD) {
		if ((g_display_vaild & PWMDEFMASK) == PWMDEFTP) {
			if(duty_percent <= g_pwm_setting.duty) {
				lcd_blt_set_pwm(g_pwm_setting.pwm_no,
				                duty_percent, g_pwm_setting.period);

				s_pwm_duty_decreased = 1;

				mdelay(10);
			}
		} else {
			duty = (duty_percent * g_pwm_setting.period) / 100;
			if(duty <= g_pwm_setting.duty) {
				pwm_set_duty(g_pwm_setting.pwm_no, duty - 1);

				s_pwm_duty_decreased = 1;

				mdelay(10);
			}
		}
	}
}

static void restore_pwm_duty(void)
{
	if(s_pwm_duty_decreased == 0)
		return;

	if(!(g_display_vaild & DISPLAY_ENABLE))
		return;

	if (g_display_param.vout == VPP_VOUT_LCD) {
		if ((g_display_vaild & PWMDEFMASK) == PWMDEFTP) {
			lcd_blt_set_pwm(g_pwm_setting.pwm_no,
			                g_pwm_setting.duty, g_pwm_setting.period);
		} else {
			pwm_set_duty(g_pwm_setting.pwm_no,
			             g_pwm_setting.duty - 1);
		}
	}

	s_pwm_duty_decreased = 0;
}

static void set_lcd_backlight(int on)
{
	int duty, i = 0;
	int charger_type;

	if(on) {
		charger_type = wmt_charger_cable_type();
		if((charger_type == CABLE_TYPE_USB) && s_usb_to_pc && !wmt_charger_pc_charging()) {
			if(wmt_battery_is_lowlevel() > 0)
				decrease_pwm_duty(30);
			else
				restore_pwm_duty();
		}

		if(s_lcd_first_light) {
			if(!(REG32_VAL(HSP3_STATUS) & REBOOT_BIT)
			    && !wmt_is_dc_plugin()
			    && !(REG8_VAL(POWERUP_SOURCE_STATUS) & PWRBTN_BIT)) {
				printf("Adapter is removed when open lcd backlight.\nPower off\n");
				do_wmt_poweroff();
			}
			s_lcd_first_light = 0;
		}

		if(s_step_by_step_light) {
			decrease_pwm_duty(30);
			duty = 30;
			lcd_blt_enable(g_pwm_setting.pwm_no, 1);
			while(duty < g_pwm_setting.duty) {
			    mdelay(20);
			    duty = 40 + 5 * i;
			    i++;
			    decrease_pwm_duty(duty);
			}
		} else
			lcd_blt_enable(g_pwm_setting.pwm_no, 1);
	} else
		lcd_blt_enable(g_pwm_setting.pwm_no, 0);
}

static void low_battery_picture_show(void)
{
	//clear_charge_percent(sp_mem_addr);
	mv_clearFB();
	show_charge_picture(sp_mem_addr, 6);
}

static void update_current_battery_picture(void)
{
	int index, percent;

	if(wmt_battery_is_lowlevel() > 0)
		low_battery_picture_show();
	else {
		index = get_battery_level(&percent);
		if(index >= 0) {
			display_charge_percent(sp_mem_addr, percent);
			show_charge_picture(sp_mem_addr, index);
		}
	}
}

static int charge_animation_init(void)
{
	int ret;
	unsigned int nand_addr;
	char *s, *s_logosize_uboot, *s_logosize_charge;
	unsigned int logo_size, total_size;

	//printf("charging animation init\n");

	if(s_animation_init_ok == 0)
		return -1;
	else if(s_animation_init_ok == 1)
		return 0;

	if(!g_tf_boot) {
		//1: check nand flash env
		s = getenv("wmt.nfc.mtd.u-boot-logo");
		if(s == NULL) {
			printf("wmt.nfc.mtd.u-boot-logo isn't set\n");
			s_animation_init_ok = 0;
			return -1;
		} else {
			nand_addr = simple_strtoul (s, NULL, 16);

			total_size = 0;
			s_logosize_uboot = getenv("wmt.logosize.uboot");
			if(s_logosize_uboot) {
				s_logosize_charge = getenv("wmt.logosize.charge");
				if(s_logosize_charge)
					total_size = simple_strtoul(s_logosize_uboot, NULL, 0)
					             + simple_strtoul(s_logosize_charge, NULL, 0);
			}

			if(total_size == 0)
				total_size = 0x380000;

			printf("anim init: nand_addr = 0x%x, mem_addr = 0x%x, read_size = 0x%x\n",
			       nand_addr, (unsigned int)sp_mem_addr, total_size);

			REG32_VAL(GPIO_BASE_ADDR + 0x200) &= ~(1 << 11); //PIN_SHARE_SDMMC1_NAND
			ret = WMTAccessNandEarier(nand_addr, (unsigned int)sp_mem_addr, total_size, 0);
			if(ret) {
				printf("load charge-anim fail\n");
				s_animation_init_ok = 0;
				return -1;
			}
		}

		//2: check bmp header
		if(*sp_mem_addr != 'B') {
			printf("logo isn't BMP format\n");
			s_animation_init_ok = 0;
			return -1;
		}

		logo_size = (*(unsigned short *)(sp_mem_addr + 4) << 16) + (*(unsigned short *)(sp_mem_addr + 2));

		if(*(sp_mem_addr + logo_size) != 'B') {
			printf("charge-anim isn't BMP format\n");
			s_animation_init_ok = 0;
			return -1;
		}
	} else {
		ret = run_command("mmcinit 1", 0);
		if(ret == -1) {
			printf("TF: run \"mmcinit 1\" failed\n");
			s_animation_init_ok = 0;
			return -1;
		} else {
			char tmp[100] = {0};
			sprintf(tmp, "fatload mmc 1 0x%x charge-logo.bmp", (unsigned int)sp_mem_addr);
			ret = run_command(tmp, 0);
			if(ret == -1) {
				printf("TF: fatload charge-logo.bmp failed\n");
				s_animation_init_ok = 0;
				return -1;
			}
		}

		if(*sp_mem_addr != 'B') {
			printf("TF: charge-anim isn't BMP format\n");
			s_animation_init_ok = 0;
			return -1;
		}
	}

	s_animation_init_ok = 1;

	printf("load charge-animation ok\n");

	return 0;
}

/*
static int need_battery_adjust(void)
{
	char *s;

	s = getenv("wmt.battery.adjust");
	if((s != NULL) && !strcmp(s, "0")) {
		return 0;
	}

	return 1;

}
*/

static int battery_init(void)
{
	int ret;

	if(s_battery_init_ok == 0)
		return -1;
	else if(s_battery_init_ok == 1)
		return 0;

	ret = wmt_power_supply_init();
	if(ret) {
		printf("battery init error\n");
		s_battery_init_ok = 0;
		return -1;
	}

	s_battery_init_ok = 1;

	return 0;
}

int low_power_detect(void)
{
	int ret;
	int delay;

	if(wmt_is_dc_plugin())
		return 0;

	ret = battery_init();
	if(ret) {
		printf("battery init error. Skip Low power detect\n");
		return -1;
	}

	printf("check whether low power or not\n");

	ret = wmt_battery_is_lowlevel();
	if(ret < 0) {
		printf("check battery low failed\n");
		return -1;
	} else if(ret == 0) {
		//printf("battery power enough\n");
		return 0;
	} else {
		printf("low power detected\n");
	}

	if(wmt_battery_is_gauge() == 1)
		delay = 3;
	else
		delay = 60;

	while(delay) {
		if(delay % 10 == 0) {
			if (tstc()) {
				if (getc() == 0xd)	{
					printf("Got 'Enter' key. Cancel Low power detect\n");
					g_show_logo = 1;
					return 0;
				}
			}
		}

		if(wmt_is_dc_plugin()) {
			printf("Detected adapter plugin. Cancel Low power detect\n");
			break;
		}

		mdelay(50);

		ret = wmt_battery_is_lowlevel();
		if(ret < 0) {
			restore_pwm_duty();
			printf("check battery low failed\n");
			break;
		} else if(ret == 0) {
			restore_pwm_duty();
			printf("battery power enough\n");
			break;
		}

		delay--;
	}

	//printf("low power detect complete\n");

	//display low power picture
	if(delay == 0) {
		if (!(g_display_vaild & DISPLAY_ENABLE)) {
			ret = display_init(0, 0);
			if(ret == -1) {
				printf("Display init fail. Skip Low power detect\n");
				return -1;
			}
		}
		charge_animation_init();
		low_battery_picture_show();
		decrease_pwm_duty(30);
		set_lcd_backlight(1);

		delay = 500;
		while(delay) {
			if(delay % 100 == 0) {
				if (tstc()) {
					if (getc() == 0xd)	{
						printf("Got 'Enter' key. Cancel Low power picture display\n");
						g_show_logo = 1;
						return 0;
					}
				}
			}

			if(wmt_is_dc_plugin()) {
				printf("Detected adapter plugin. Cancel Low power picture display\n");
				return 0;
			}

			mdelay(10);
			delay--;
		}

		set_lcd_backlight(0);
		lcd_set_power_down(1);
		mdelay(500); //delay for avoiding lcd blink
		printf("----> low power. power off\n");
		do_wmt_poweroff();
	}

	return 0;
}

#define TIMEOUT_USBPC_CHECK          400      // 400 ms
#define TIMEOUT_MPTOOL_CHECK         3000     // 3 s

/*
* Function: check_udc_to_pc
*
* Return:
*     1: usb device connect to pc
*     0: udc device doesn't connect to pc
*     <0: error
*/
int check_udc_to_pc(int force)
{
	int ret, delay_check_connected;
	static int udc_had_check;
	static int check_result;
	unsigned int timeout;
	char *s;

	if(force)
		udc_had_check = 0;

	if(udc_had_check == 1)
		return check_result;

	udc_had_check = 1;

	if(!usb_plugin()) {
		printf("check_udc_to_pc: usb plugout\n");
		s_usb_to_pc = 0;
		check_result = 0;
		return 0;
	} else
		printf("check_udc_to_pc: usb plugin\n");

	s = getenv(ENV_USBPC_TIMEOUT);
	if(s) {
		timeout = simple_strtoul(s, NULL, 0);
		printf("Manually set usbpc timeout: %u ms\n", timeout);
	} else
		timeout = TIMEOUT_USBPC_CHECK;

	if(timeout > 300000) {
		printf("usbpc timeout force change to 300000 ms\n");
		timeout = 300000;
	}

	if(!udc_fastboot_is_init()) {
		ret = udc_fastboot_init();
		if(ret) {
			printf("udc_fastboot_init error. check_udc_to_pc fail\n");
			s_usb_to_pc = 0;
			check_result = -1;
			return -1;
		}
	}

	delay_check_connected = 0;

	while(1) {
		udc_fastboot_transfer();
		if(wmt_udc_connected()) {
			printf("usb connect to pc, detect_time = %d ms\n", delay_check_connected);
			s_usb_to_pc = 1;
			check_result = 1;
			return 1;
		}

		if(delay_check_connected >= timeout)
			break;

		delay_check_connected++;

		if (tstc()) {
			if(getc() == 0x0d) {
				printf("Got 'Enter'. Cancel usbpc check. check time: %d ms\n", delay_check_connected);
				break;
			}
		}

		mdelay(1);
	}

	if(delay_check_connected >= timeout)
		printf("usb doesn't connect to pc\n");

	s_usb_to_pc = 0;
	check_result = 0;
	return 0;
}

/*
* Function: check_mptool
*
* Return:
*     1: mptool is detected
*     0: mptool is NOT detected
*    <0: mptool checking is cancel
*/
int check_mptool(void)
{
	char *s;
	int ret, delay_check_mptool;
	unsigned int timeout;

	if((s = getenv(ENV_MPTOOL_DETECT)) != NULL && !strcmp(s, "0"))
		return 0;

	if(s_usb_to_pc == 0)
		return 0;

	s = getenv(ENV_MPTOOL_TIMEOUT);
	if(s) {
		timeout = simple_strtoul(s, NULL, 0);
		printf("Manually set mptool timeout: %u ms\n", timeout);
	} else
		timeout = TIMEOUT_MPTOOL_CHECK;

	if(timeout > 600000) {
		printf("mptool timeout force change to 600000 ms\n");
		timeout = 600000;
	}

	if(!udc_fastboot_is_init()) {
		ret = udc_fastboot_init();
		if(ret) {
			printf("udc_fastboot_init error. check mptool fail\n");
			return 0;
		}
	}

	delay_check_mptool = 0;

	printf("Hint: Press 'Enter' key to Cancel MPTool detection\n");
	while(1) {
		udc_fastboot_transfer();
		if(wmt_mptool_ready()) {
			printf("MPTool is detected\n");
			return 1;
		}

		if(delay_check_mptool >= timeout)
			break;

		delay_check_mptool++;

		if (tstc()) {
			switch(getc()) {
			case 0x03:
				printf("Got 'Ctrl+C'. Cancel mptool check. check time: %d ms\n", delay_check_mptool);
				return -1;

				// we think the mptool is not found when pressing 'Enter' key
			case 0x0d:
				printf("Got 'Enter'. Cancel mptool check. check time: %d ms\n", delay_check_mptool);
				return 0;

			default:
				break;
			}
		}

		mdelay(1);
	}

	if(delay_check_mptool >= timeout)
		printf("MPTool is NOT detected\n");

	return 0;
}

int set_charge_current(void)
{
	int ret, usb_to_pc;

	ret = battery_init();
	if(ret) {
		printf("battery_init error. set_charge_current fail\n");
		return -1;
	}

	if(wmt_is_dc_plugin()) {
		if(wmt_charger_cable_type() == CABLE_TYPE_USB) {
			usb_to_pc = check_udc_to_pc(0);
			if(usb_to_pc == 0) {
				printf("usb_adapter plugin. set large current charge\n");
				wmt_charger_event_callback(POWER_EVENT_DCDET_ADAPTER);
			} else if(usb_to_pc == 1)
				printf("usb connect to pc. default small current charge\n");
			else {
				printf("check usb_to_pc fail. set large current charge");
				wmt_charger_event_callback(POWER_EVENT_DCDET_ADAPTER);
			}
		}
	}

	return 0;
}

static void check_pmc_busy(void)
{
	while (PMCS2_VAL & 0x3F0038)
		;
}

static void set_arm_freq(int freq)
{
	auto_pll_divisor(DEV_ARM, CLK_ENABLE, 0, 0);
	auto_pll_divisor(DEV_ARM, SET_PLLDIV, 2, freq);
	check_pmc_busy();
}

#define PERIOD_CHECK           10    		// 10 ms    //how long time to check
#define PERIOD_PLAY            250    		// 250 ms   //the play speed
#define PERIOD_PAUSE           700  		// 700 ms   //the pause time after a play peroid complete
#define PERIOD_DETECTADAPT     50           // 50 ms    //check if the power adapter is unplug
#define PERIOD_READBATT        1 * 1000  	// 1 s     //how long time to read battery
#define PERIOD_READPWRKEY      10           // 10ms    //how long time to detect power key
#define PERIOD_LONGPRESS       500          // 500 ms   //how long time is regarded as long press
#define PERIOD_BLTIMEOUT       10 * 1000    // 10 s     //how long time to close backlight
#define PERIOD_USBDETECT       50          // 50 ms   //how long time to detect usb
#define PERIOD_GAUGE_READBATT     10 * 1000  	// 10 s     //how long time to read battery

/*
* play_charge_animation()
* return:
* 0: play charging animation success
* 1: fail to play charging animation. need detect low power
* <0: fail to play charging animation. needn't detect low power
*/
int play_charge_animation(void)
{
	const int max_play_count = (PERIOD_PLAY) / (PERIOD_CHECK);
	const int max_pause_count = (PERIOD_PAUSE - PERIOD_PLAY) / (PERIOD_CHECK);
	const int max_detectAdapter_count = (PERIOD_DETECTADAPT) / (PERIOD_CHECK);
	int max_readBatt_count = (PERIOD_READBATT) / (PERIOD_CHECK);
	const int max_readPwrKey_count = (PERIOD_READPWRKEY) / (PERIOD_CHECK);
	const int max_longPress_count = (PERIOD_LONGPRESS) / (PERIOD_CHECK);
	const int max_blTimeout_count = (PERIOD_BLTIMEOUT) / (PERIOD_CHECK);
	const int max_usbDetect_count = (PERIOD_USBDETECT) / (PERIOD_CHECK);

	int play_count;             //play period
	int pause_count;            //pause time after a play period complete
	int detectAdapter_count;    //check if the adapter is unpluged
	int readBatt_count;         //how long time to read battery
	int readPwrKey_count;       //how long time to detect power key
	int longPress_count;        //how long time is regarded as long press
	int blTimeout_count;        //how long time to close backlight
	int usbDetect_count;        //how long time to detect usb

	int frame_num, frame_index, start_index, backup_start_index;
	int is_powerKey_press, backup_pwm_status;

	int battery_is_full = 0, udc_is_init;
	int ret;
	char *s;
	int charger_type = CABLE_TYPE_UNKNOWN;
	int percent;
	int delay;
	int saved_arm_freq;
	int full_event_sended = 0;
	int is_charging = 1;
	int is_usb_plugin = 0;
	int need_check_mptool;
	//int current_arm_freq;
	//printf("play charging animation\n");

	//1: detect "enter key"
	if (tstc()) {
		if (getc() == 0xd) { // "Enter" key
			puts("Got 'Enter' key. Cancel charge animation play\n");
			return 0;
		}
	}

	// 2: check power source
	if(!wmt_is_dc_plugin() && !(REG8_VAL(POWERUP_SOURCE_STATUS) & PWRBTN_BIT)) {
		printf("Adatper is removed when init charging-animation.\nPower off\n");
		do_wmt_poweroff();
	}

	//3: detect power key press
	if(PMPB_VAL & BIT24) {
		printf("Power key detected. Skip charge-anim play\n");
		return 1;
	}

	//4: check power on by reset
	if((REG32_VAL(HSP3_STATUS) & REBOOT_BIT) == REBOOT_BIT) {
		printf("system Reboot. Skip charge-anim play\n");
		return 1;
	}

	//5: check charge animation env
	s = getenv(ENV_CHARGE_ANIMATION);
	if((s != NULL) && !strcmp(s, "0"))  //if wmt.display.chargeanim is set to 0
		return 1;

	//6: check dircect boot env
	if(((s = getenv("wmt_sys_directboot")) != NULL && !strcmp(s, "1"))  \
	    || ((s = getenv("wmt_sys_restore")) != NULL && !strcmp(s, "1")))
		return 1;


	//7: battery init
	ret = battery_init();
	if(ret) {
		printf("battery init error. Don't play charge-anim\n");
		return -1;
	}

	if(wmt_battery_is_gauge() == 1) {
		printf("battery is gauge\n");
		max_readBatt_count = (PERIOD_GAUGE_READBATT) / (PERIOD_CHECK);
	}

	//printf("REG32_VAL(PM_CTRL_BASE_ADDR + 0x00D0) = 0x%x\n", REG8_VAL(PM_CTRL_BASE_ADDR + 0xd0));

	//8: lcd init. but don't open backlight
	s = getenv("wmt.backlight.stepbystep"); //if wmt.backlight.stepbystep is set to 0
	if((s != NULL) && !strcmp(s, "0"))
		s_step_by_step_light = 0;

	if (!(g_display_vaild & DISPLAY_ENABLE)) {
		ret = display_init(0, 0);
		if(ret == -1) {
			printf("Display init fail. Don't play charge-anim\n");
			return -1;
		}
	}
	mv_clearFB();

	//9: check adapter
	charger_type = wmt_charger_cable_type();

	if(wmt_is_dc_plugin()) {
		if(charger_type == CABLE_TYPE_DC)
			printf("AC charger plugin\n");
		else if(charger_type == CABLE_TYPE_USB) {
			printf("usb plugin\n");
		} else {
			printf("charger type error. Don't play charge-anim\n");
			return -1;
		}
	} else {
		printf("Battery power supply\n");
		if((REG8_VAL(POWERUP_SOURCE_STATUS) & PWRBTN_BIT) == 0) {
			printf("POWERUP_SOURCE_STATUS = 0x%x\n",  REG8_VAL(POWERUP_SOURCE_STATUS));
			printf("Adatper is removed when start play charging-animation.\nPower off\n");
			do_wmt_poweroff();
		}
		low_power_detect();
		if(!wmt_is_dc_plugin())
			return -1;

		// when using usb charge, if plugin adapter during low_power_detect, re-check udc to pc
		if(charger_type == CABLE_TYPE_USB) {
			printf("check if usb connect to pc\n");
			if(!udc_fastboot_is_init()) {
				ret = udc_fastboot_init();
				if(ret) {
					printf("udc_fastboot_init error. Don't play charge-anim\n");
					return -1;
				}
			}
			check_udc_to_pc(1);
			set_charge_current();
			if(s_usb_to_pc == 0)
				restore_pwm_duty();
		}
	}

	//10: charge animation init
	ret = charge_animation_init();
	if(ret) {
		printf("charge-anim init fail. Don't play charge-anim\n");
		return -1;
	}

	//11: get battery level
	start_index = get_battery_level(&percent);
	if(start_index < 0)	{
		printf("Battery level error(%d). Don't play charge-anim\n", start_index);
		return -1;
	}

	printf("Hit 'Enter' key to stop animation\n");

	//12: show the first charge picture
	frame_num = 6;
	play_count = -1;
	pause_count = 0;
	detectAdapter_count = 0;
	readBatt_count = 0;
	readPwrKey_count = 0;
	longPress_count = -1;
	is_powerKey_press = 0;
	backup_pwm_status = 0;
	blTimeout_count = 0;
	usbDetect_count = 0;

	frame_index = start_index;

	init_charge_percent();
	//display_charge_percent(sp_mem_addr, percent);
	show_charge_picture(sp_mem_addr, frame_index);

	if(start_index != frame_num - 1) //not last frame
		frame_index++;

	//13: when using usb charge, detect low power if usb connect to pc
	if((charger_type == CABLE_TYPE_USB) && s_usb_to_pc && !wmt_charger_pc_charging()) {
		ret = wmt_battery_is_lowlevel();
		if(ret > 0) {
			printf("USB connect to PC. Low power\n");

			if(wmt_battery_is_gauge() == 1)
				delay = 3;
			else
				delay = 60;

			while(delay) {
				if (tstc()) {
					if (getc() == 0xd) {
						printf("Got 'Enter' key. Cancel Low power detect during USB connect to PC\n");
						return 0;
					}
				}

				if(!wmt_is_dc_plugin()) {
					low_battery_picture_show();
					decrease_pwm_duty(30);
					set_lcd_backlight(1);
					sleep_sec(5);
					set_lcd_backlight(0);
					lcd_set_power_down(1);
					mdelay(500); //delay for avoiding lcd blink
					printf("----> USB connect to PC. Low power. power off\n");
					do_wmt_poweroff();
				}

				mdelay(50);

				ret = wmt_battery_is_lowlevel();
				if(ret < 0) {
					printf("Low power detect failed during USB connect to PC\n");
					return -1;
				} else if(ret == 0) {
					printf("battery power enough during USB connect to PC\n");
					break;
				}

				delay--;
			}

			if(delay == 0)
				low_battery_picture_show();

		} else if(ret < 0) {
			printf("Low power detect failed during USB connect to PC\n");
			return -1;
		} else
			printf("USB connect to PC. Power enough\n");

		set_lcd_backlight(1);
	} else
		set_lcd_backlight(1);

	//14: set cpu freq to 300MHz
	saved_arm_freq = auto_pll_divisor(DEV_ARM, GET_FREQ, 0, 0);
	//printf("save cpu freq = %d\n", saved_arm_freq);
	set_arm_freq(300);
	//current_arm_freq = auto_pll_divisor(DEV_ARM, GET_FREQ, 0, 0);
	//printf("set cpu freq = %d\n", current_arm_freq);

	//15: set charge current and control led
	if (charger_type == CABLE_TYPE_DC) {
		wmt_charger_event_callback(POWER_EVENT_DCDET_ADAPTER);
	} else if (charger_type == CABLE_TYPE_USB) {
		if (s_usb_to_pc == 1)
			wmt_charger_event_callback(POWER_EVENT_DCDET_USBPC);
		else
			wmt_charger_event_callback(POWER_EVENT_DCDET_ADAPTER);
	}

	if(usb_plugin()) {
		printf("usb plugin before charging\n");
		is_usb_plugin = 1;
	} else {
		printf("usb plugout before charging\n");
		is_usb_plugin = 0;
	}

	//16: check whether detect mptool or not
	if((s = getenv(ENV_MPTOOL_DETECT)) != NULL && !strcmp(s, "0"))
		need_check_mptool = 0;
	else
		need_check_mptool = 1;

	//17: enter the animation loop
	while(1) {
		if (tstc()) {//we got a key press
			printf("we got a key press\n");
			//Check if the key is 'Enter' which ascii code is 13
			// If the key is 'Enter', exit
			if (getc() == 13)
				break;
		}

		//check if usb connect to pc. And check mptool when usb connect to pc
		if(need_check_mptool) {
			if(usbDetect_count >= 0)
				usbDetect_count++;

			if(usbDetect_count > max_usbDetect_count) {
				if(usb_plugin()) {
					if(is_usb_plugin == 0) {
						is_usb_plugin = 1;
						printf("usb plugin during charging\n");
					}

					if(!udc_fastboot_is_init()) {
						ret = udc_fastboot_init();
						if(ret) {
							printf("udc_fastboot_init error during playing charge-anim\n");
							udc_is_init = 0;
						} else
							udc_is_init = 1;
					} else
						udc_is_init = 1;
				} else {
					if(is_usb_plugin == 1) {
						is_usb_plugin = 0;
						printf("usb plugout during charging\n");
					}
					udc_fastboot_exit();
					udc_is_init = 0;
					if(s_usb_to_pc) {
						s_usb_to_pc = 0;
						if(charger_type == CABLE_TYPE_USB && wmt_is_dc_plugin())
							wmt_charger_event_callback(POWER_EVENT_DCDET_ADAPTER);
					}
				}

				if(udc_is_init) {
					udc_fastboot_transfer();
					if(s_usb_to_pc == 0) {
						if(wmt_udc_connected()) {
							printf("usb connect to pc\n");
							s_usb_to_pc = 1;
							if(charger_type == CABLE_TYPE_USB) {
								wmt_charger_event_callback(POWER_EVENT_DCDET_USBPC);
								if(!wmt_charger_pc_charging())
									update_current_battery_picture();
							}
						}
					} else {
						if(wmt_mptool_ready()) {
							set_arm_freq(saved_arm_freq / 1000000);
							udc_fastboot_exit();
							run_fastboot(1);
							break;
						}
					}
				}

				usbDetect_count = 0;
			}
		}

		if((charger_type == CABLE_TYPE_USB) && s_usb_to_pc && !wmt_charger_pc_charging())
			is_charging = 0;
		else
			is_charging = 1;

		readBatt_count++;
		readPwrKey_count++;
		detectAdapter_count++;

		if(longPress_count >= 0)
			longPress_count++;

		if(blTimeout_count >= 0)
			blTimeout_count++;

		if(detectAdapter_count > max_detectAdapter_count) {
			detectAdapter_count = 0;
			if(!wmt_is_dc_plugin()) {
				if(is_charging) {
					display_charge_percent(sp_mem_addr, percent);
					show_charge_picture(sp_mem_addr, start_index);
				}

				printf("unplug power adapter\n");
				if(!pwm_get_enable(g_pwm_setting.pwm_no)) {
					set_lcd_backlight(1);
					if(is_charging == 0)
						update_current_battery_picture();
				}

				wmt_charger_event_callback(POWER_EVENT_DCDET_PLUGOUT);
				sleep_sec(3);
				set_lcd_backlight(0);
				lcd_set_power_down(1);
				mdelay(500); //delay for avoiding lcd blink
				printf("power off\n");
				do_wmt_poweroff();
			}
		}

		if(readBatt_count > max_readBatt_count)	{
			readBatt_count = 0;
			backup_start_index = start_index;
			start_index = get_battery_level(&percent);

			if (percent == 100 && is_charging) {
				if (!full_event_sended) {
					wmt_charger_event_callback(POWER_EVENT_CHARGING_FULL);
					full_event_sended = 1;
				}
			} else
				full_event_sended = 0;

			if(start_index < 0 || start_index >= frame_num)	{
				if(is_charging) {
					display_charge_percent(sp_mem_addr, percent);
					show_charge_picture(sp_mem_addr, backup_start_index);
				}
				printf("read battery error\n");
				if(!pwm_get_enable(g_pwm_setting.pwm_no)) {
					set_lcd_backlight(1);
					if(is_charging == 0)
						update_current_battery_picture();
				}

				sleep_sec(2);
				set_lcd_backlight(0);
				lcd_set_power_down(1);
				mdelay(500); //delay for avoiding lcd blink
				printf("power off\n");
				do_wmt_poweroff();
			}

			if(is_charging == 0)
				update_current_battery_picture();
			else
				display_charge_percent(sp_mem_addr, percent);
		}

		if(blTimeout_count > max_blTimeout_count) {
			blTimeout_count = -1;
			if(pwm_get_enable(g_pwm_setting.pwm_no)) {
				printf("close backlight during charging\n");
				set_lcd_backlight(0);
			}
		}

		if(readPwrKey_count > max_readPwrKey_count)	{
			readPwrKey_count = 0;
			if((PMPB_VAL & BIT24) || (PMWS_VAL & BIT14)) {
				if(PMWS_VAL & BIT14)
					PMWS_VAL |= BIT14;
				if(is_powerKey_press == 0) {
					backup_pwm_status = pwm_get_enable(g_pwm_setting.pwm_no);
					printf("press pwr key, backup_pwm_status = %d\n", backup_pwm_status);
					if(!backup_pwm_status) {
						set_lcd_backlight(1);
						if(is_charging == 0)
							update_current_battery_picture();
					}

					is_powerKey_press = 1;
					blTimeout_count = -1;
					longPress_count = 0;
				}
			} else {
				if(is_powerKey_press == 1) {
					printf("release pwr key, backup_pwm_status = %d\n", backup_pwm_status);
					is_powerKey_press = 0;
					if(backup_pwm_status) {
						if(pwm_get_enable(g_pwm_setting.pwm_no))
							set_lcd_backlight(0);
						blTimeout_count = -1;
					} else {
						if(!pwm_get_enable(g_pwm_setting.pwm_no)) {
							set_lcd_backlight(1);
							if(is_charging == 0)
								update_current_battery_picture();
						}
						blTimeout_count = 0;
					}
				}
				longPress_count = -1;
			}
		}

		if(longPress_count > max_longPress_count) {
			printf("charge_animation: long press key detected\n");
			// if is_charging = 0 and detect battery low, don't startup system
			if(is_charging == 0 && wmt_battery_is_lowlevel() > 0) {
				printf("USB connect to PC and low power. skip long press\n");
			} else
				break;
		}

		udelay(PERIOD_CHECK * 1000);

		//if is_charging =  0, don't play animation
		if(is_charging == 0)
			continue;

		if(play_count >= 0)
			play_count++;

		if(pause_count >= 0)
			pause_count++;

		if(play_count > max_play_count)	{
			show_charge_picture(sp_mem_addr, frame_index);

			if((frame_index == start_index) || (frame_index == frame_num - 1)) { //a play period complete
				pause_count = 0;  //enable pause
				play_count = -1;  //disable play
			} else {
				play_count = 0;  //restart play period
				pause_count = -1;
			}

			frame_index++;
			if(frame_index >= frame_num)
				frame_index = start_index;
		}

		if(pause_count > max_pause_count) {
			if((start_index == frame_num - 1) && (frame_index == start_index)) { //the battery is full, always pause, don't play
				if(battery_is_full == 0) {
					display_charge_percent(sp_mem_addr, percent);
					show_charge_picture(sp_mem_addr, frame_index);
					battery_is_full = 1;
				}
				play_count = -1;  //disable play
				pause_count = 0;  //enable pause
			} else {
				play_count = 0; //enable play
				pause_count = -1; //disable pause
				battery_is_full = 0;
			}
		}
	}

	//restore cpu freq
	set_arm_freq(saved_arm_freq / 1000000);
	//current_arm_freq = auto_pll_divisor(DEV_ARM, GET_FREQ, 0, 0);
	//printf("restore cpu freq = %d\n", current_arm_freq);

	return 0;
}

static int do_check_usbtopc(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	int ret;
	int delay = 0;
	int max_delay = 300;
	int exit_flag = 0;

	ret = udc_fastboot_init();
	if(ret)
		return -1;

	while (++delay <= max_delay) {
		udc_fastboot_transfer();
		if(wmt_udc_connected()) {
			printf("usb connetct = 1, delay = %d\n", delay);
			break;
		}
		exit_flag |= ctrlc();
		if(exit_flag)
			break;
		mdelay(1);
	}

	if(delay > max_delay)
		printf("usb connetct = 0\n");

	udc_fastboot_exit();

	return 0;
}


U_BOOT_CMD(
        isusbtopc, 1,	0,	do_check_usbtopc,
        "isusbtopc - check if usb connect to pc\n",
        "- check if usb connect to pc\n"
);