/* 2012-09-16: File added and changed by Sony Corporation */
/*
 * icx_lcd.c
 *
 * Copyright 2011 Sony Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include <common.h>

#if defined(CONFIG_ICX) || defined(CONFIG_ICD)

#include <asm/errno.h>

#include "reg.h"

#include "icx_io.h"
#include "icx_gpio.h"
#include "icx_pmu.h"
#include "icx_nvp.h"
#include "icx_lcdc.h"
#include "icx_lcd.h"
#include "icx.h"


/**************/
/*@ valiables */
/**************/

#if defined(CONFIG_ICX)
/* TOVIS LG4553DS */
extern lcd_ops_t     lcd_tovis_lg4553ds_ops;
extern lcdc_config_t lcdc_tovis_lg4553ds_config;

/* TOVIS R61505W */
extern lcd_ops_t	 lcd_tovis_r61505w_ops;
extern lcdc_config_t lcdc_tovis_r61505w_config;
#endif

#if defined(CONFIG_ICD)
/* UC1611 */
extern lcd_ops_t	 lcd_uc_1611_ops;
extern lcdc_config_t lcdc_uc_1611_config;

/* ST7571 */
extern lcd_ops_t	 lcd_st7571_ops;
extern lcdc_config_t lcd_st7571_config;
#endif

static lcd_ops_t     *lcd_ops     = NULL;
static lcdc_config_t *lcdc_config = NULL;

static int lcd_on			  = 0;
static int current_brightness = 0;


/********************/
/*@ Global routines */
/********************/

/*-----------------------------------------------------------------------------
 * Function : lcd_init
 * Abstruct : Initialize LCDC/IMC
 * Input    : none
 * Returen  : 0 : OK / -ENODEV : NG
 *----------------------------------------------------------------------------*/
int lcd_init(void)
{
#if defined(CONFIG_ICX)
	unsigned int lcd_type;

	/* initialize lcdc */
	lcdc_init();

	/* LCD_XRST */
	outl(((inl(CHG_PINSEL_G128) & 0xFFFFFFFD) | 0x00000002), CHG_PINSEL_G128);
	outl(((inl(CHG_PULL20     ) & 0xFFFFFF0F) | 0x00000000), CHG_PULL20     );

	gpio_set_value(GPIO_LCD_XRST, 0x0);
	gpio_set_direction(GPIO_LCD_XRST, GPIO_OUT);
#else /* CONFIG_ICD */
	/* LCD_XRST,CD */
	outl(((inl(CHG_PINSEL_G128) & 0xFFFFF3FF) | 0x00000C00), CHG_PINSEL_G128);
	outl(((inl(CHG_PULL21     ) & 0xFFFF00FF) | 0x00000000), CHG_PULL21     );

	gpio_set_value(GPIO_LCD_XRST, 0x0);
	gpio_set_direction(GPIO_LCD_XRST, GPIO_OUT);
	gpio_set_value(GPIO_LCD_CD, 0x0);
	gpio_set_direction(GPIO_LCD_CD, GPIO_OUT);
#endif

	/* regulator on */
	pmu_regulator_on(REGULATOR_LOG);
	udelay(10000);
#ifdef CONFIG_ICX
	pmu_regulator_on(REGULATOR_ANA);
#else /* CONFIG_ICD */
	pmu_regulator_on(REGULATOR_GP4);
#endif
	udelay(10000);

#if defined(CONFIG_ICX)

	/* select LCD device */
	lcd_type = nvp_get_sysinfo_lcd();

	switch (lcd_type) {

		case NVP_SYSIMFO_LCD_CR :
			lcd_ops     = &lcd_tovis_lg4553ds_ops;
			lcdc_config = &lcdc_tovis_lg4553ds_config;
			break;

		case NVP_SYSIMFO_LCD_BR :
			lcd_ops     = &lcd_tovis_r61505w_ops;
			lcdc_config = &lcdc_tovis_r61505w_config;
			break;

		default :
			return -ENODEV;
	}
#else /* CONFIG_ICD */
	if (icx_inst_initrd_size == 0) {
    lcd_ops     = &lcd_st7571_ops;
    lcdc_config = &lcd_st7571_config;
	}
#endif

	/* clear fb area */
	if (lcdc_config)
		memset((char *)lcdc_config->frameadr, 0, LCDC_FRAME_SIZE(lcdc_config->width, lcdc_config->height));

	return 0;
}

/*-----------------------------------------------------------------------------
 * Function : lcd_exit
 * Abstruct : Shutdown LCD
 * Input    : none
 * Returen  : none
 *----------------------------------------------------------------------------*/
void lcd_exit(void)
{
	lcd_ops     = NULL;
	lcdc_config = NULL;

	pmu_regulator_off(REGULATOR_ANA);
	pmu_regulator_off(REGULATOR_LOG);

	return;
}

/*-----------------------------------------------------------------------------
 * Function : lcd_power_on
 * Abstruct : Power ON LCD
 * Input    : none
 * Returen  : 0 : OK / others : NG
 *----------------------------------------------------------------------------*/
int lcd_power_on(void)
{
	int ret = -1; 

	if (lcd_on != 0)  
		return 0;

	if (lcd_ops == NULL)
		return -1;

	if (lcd_ops->power_on) {
		ret = lcd_ops->power_on(lcdc_config);

		if (ret == 0) {
			lcdc_backlight_init(lcdc_config);
																						    
			lcd_on             = 1;
			current_brightness = 0;
		}   
	}

	return ret;
}

/*-----------------------------------------------------------------------------
 * Function : lcd_power_off
 * Abstruct : Power OFF LCD
 * Input    : none
 * Returen  : none
 *----------------------------------------------------------------------------*/
void lcd_power_off(void)
{
	if (lcd_on == 0)
		return;
	
	if (lcd_ops == NULL)
		return;
	
	lcdc_backlight_exit(lcdc_config);

	if (lcd_ops->power_off)
		lcd_ops->power_off();
		
	lcd_on = 0;
	current_brightness = 0;

	return;
}

/*-----------------------------------------------------------------------------
 * Function : lcd_draw_image
 * Abstruct : Draw image
 * Input    : id : area ID
 * Returen  : 0 : OK / others : NG
 *----------------------------------------------------------------------------*/
int lcd_draw_image(int id)
{
	if (lcdc_config)
		nvp_get_image_data(id, (char *)lcdc_config->frameadr, LCDC_FRAME_SIZE(lcdc_config->width, lcdc_config->height));

	return 0;
}

/*-----------------------------------------------------------------------------
 * Function : lcd_set_brightness
 * Abstruct : Control backlight brightness
 * Input    : deg      : percentage of brightness
 *          : interval : interval per step
 * Returen  : 0 : OK / others : NG
 *----------------------------------------------------------------------------*/
int lcd_set_brightness(int brightness, int interval)
{
	int step = 1;
	int ret  = 0;

	if (lcd_ops == NULL)
		return -1;

	if (lcd_on == 0)
		return -1;

#if defined(CONFIG_ICX)
	if (brightness > LCD_BRIGHTNESS_MIN)
		lcdc_hw_switch(1);

	if (lcdc_config == NULL) {
		if (brightness == LCD_BRIGHTNESS_MIN)
			lcdc_hw_switch(0);

		return 0;
	}
#endif

	if (brightness < current_brightness)
		step = -step;

	while (current_brightness != brightness) {

		current_brightness += step;

		ret = lcdc_backlight_control(lcdc_config, current_brightness);
		if (ret < 0) {
			current_brightness -= step;
			break;
		}

		udelay(interval);
	}

	if (brightness == 0)
#if defined(CONFIG_ICX)
		lcdc_hw_switch(0);
#else
		/* [TODO] 黒画を描画する */
#endif

	return ret;
}

#endif /* CONFIG_ICX || CONFIG_ICD */

