/* 2012-09-16: File added and changed by Sony Corporation */
/*
 * icx_dac_cs47L01.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>

#ifdef CONFIG_ICX

#include "reg.h"
#include "icx_io.h"
#include "icx_smu.h"
#include "icx_gpio.h"
#include "icx_i2c.h"
#include "icx_pwc.h"
#include "icx_pmu.h"
#include "icx_dac.h"


/****************/
/*@ Definitions */
/****************/

/* port assign */
#define GPIO_ADA_XRST					GPIO_P007
#define GPIO_HP_XMUTE					GPIO_P119

/* refclock */
#define DAC_CS47L01_REFCLK_OSC_OFF		(0xFF)
#define DAC_CS47L01_REFCLK_OSC_ON		(0x00)
#define	DAC_CS47L01_REFCLK_DIV			(SMU_PLLSEL_OSC0 | SMU_DIV(2))


/***************/
/*@ Prototypes */
/***************/

static void dac_cs47l01_init(void);
static void dac_cs47l01_exit(void);
static void dac_cs47l01_enable_mute(void);
static void dac_cs47l01_disable_mute(void);
static void dac_cs47l01_beep_on(unsigned int period);
static void dac_cs47l01_beep_off(void);
static void dac_cs47l01_on_boot(void);
static void dac_cs47l01_setup_platform(void);


/**************/
/*@ Variables */
/**************/

dac_ops_t dac_cs47l01_ops = {
	.power_on     = dac_cs47l01_init,
	.power_off    = dac_cs47l01_exit,
	.enable_mute  = dac_cs47l01_enable_mute,
	.disable_mute = dac_cs47l01_disable_mute,
	.beep_on      = dac_cs47l01_beep_on,
	.beep_off     = dac_cs47l01_beep_off,
	.on_boot      = dac_cs47l01_on_boot,
};

static i2c_config_t i2c_config = {
	.ctrl		= IIC_IICC0_WTIM0,
	.slave_adr	= 0x3c,     /* (0x1e << 1) */
	.clock		= IIC_IICCL0_SMC_FAST,
	.flag		= IIC_IICF0_STCEN_EN | IIC_IICF0_IICRSV_EN,
};


/*************/
/*@ Routines */
/*************/

/*-----------------------------------------------------------------------------
 * Function : dac_cs47l01_init
 * Abstruct : initialize the beep module
 * Input    : none
 * Return   : none
 *----------------------------------------------------------------------------*/
static void dac_cs47l01_init(void)
{
	/* setup platform */
	dac_cs47l01_setup_platform();

	/* power on */
	pmu_regulator_on(REGULATOR_R1);
	pmu_regulator_on(REGULATOR_R2);
	pmu_regulator_on(REGULATOR_ANA);
	udelay(10000);

	/* open clock gate */
	outl(((inl(CHG_PINSEL_G000) & ~0x00000010) | 0x00000000), CHG_PINSEL_G000);
	/* osc on */
	outl(DAC_CS47L01_REFCLK_DIV,    SMU_REFCLKDIV);
	outl(DAC_CS47L01_REFCLK_OSC_ON, SMU_OSC0CTRL1);
	smu_clockgate_control(SMU_CLK_REF, SMU_GCLKCTRL_OPEN);

	/* 50 msec delay */
	/* udelay(50000); */
	
	/* codec unreset */
	gpio_set_value(GPIO_ADA_XRST, 0x1);

	/* 10 msec delay */
	udelay(10000);
	
	i2c_init(&i2c_config);

	i2c_write(&i2c_config, 0x08, 0xa0);     /* clock master, left-justified */
	i2c_write(&i2c_config, 0x07, 0xf3);     /* HP out A/B on				*/

	/* 75 msec delay */
	/* wait for analog volume stable */
	udelay(75000);

	i2c_write(&i2c_config, 0x06, 0xfc);     /* Master power on				*/
	i2c_write(&i2c_config, 0x27, 0xff);     /* BEEP freq=2004Hz, on=5.66sec */
	i2c_write(&i2c_config, 0x28, 0x12);     /* BEEP off=1.34sec, vol=-42db	*/
	i2c_write(&i2c_config, 0x29, 0x00);     /* DAC (A) volume= 0db			*/
	i2c_write(&i2c_config, 0x2a, 0x00);     /* DAC (B) volume= 0db			*/
	i2c_write(&i2c_config, 0x2e, 0xfd);     /* HP  (A) volume=-3db			*/
	i2c_write(&i2c_config, 0x2f, 0xfd);     /* HP  (B) volume=-3db			*/
}

/*-----------------------------------------------------------------------------
 * Function : dac_cs47l01_exit
 * Abstruct : exit the beep module
 * Input    : none
 * Return   : none
 *----------------------------------------------------------------------------*/
static void dac_cs47l01_exit(void)
{
	/* mute on */
	gpio_set_value(GPIO_HP_XMUTE, 0x0);

	/* 20 msec delay */
	udelay(20000);

	/* reset */
	gpio_set_value(GPIO_ADA_XRST, 0x0);

	/* close clock */
	smu_clockgate_control(SMU_CLK_REF, SMU_GCLKCTRL_CLOSE);
	outl(DAC_CS47L01_REFCLK_OSC_OFF, SMU_OSC0CTRL1);

	/* poweroff */
	pmu_regulator_off(REGULATOR_R1);
	pmu_regulator_off(REGULATOR_R2);
	pmu_regulator_off(REGULATOR_ANA);
}

/*-----------------------------------------------------------------------------
 * Function : dac_cs47l01_enable_mute
 * Abstruct : enable the mute
 * Input    : none
 * Return   : none
 *----------------------------------------------------------------------------*/
static void dac_cs47l01_enable_mute(void)
{
	dac_cs47l01_beep_off();

	/* mute on */
	gpio_set_value(GPIO_HP_XMUTE, 0x0);

	return;
}

/*-----------------------------------------------------------------------------
 * Function : dac_cs47l01_disable_mute
 * Abstruct : disable the mute
 * Input    : none
 * Return   : none
 *----------------------------------------------------------------------------*/
static void dac_cs47l01_disable_mute(void)
{
	/* mute off */
	gpio_set_value(GPIO_HP_XMUTE, 0x1);

	return;
}

/*-----------------------------------------------------------------------------
 * Function : dac_cs47l01_beep_on
 * Abstruct : sound a beep
 * Input    : period : period to sound a beep(us)
 *			:		   (0:coutinuous)
 * Return   : none
 *----------------------------------------------------------------------------*/
static void  dac_cs47l01_beep_on(unsigned int period)
{
   	/* sound a beep */
	i2c_write(&i2c_config, 0x26, 0xc0);     /* beep! */

	if (period > 0) {
		udelay(period);
		dac_cs47l01_beep_off();
	}

	return;
}

/*-----------------------------------------------------------------------------
 * Function : dac_cs47l01_beep_off
 * Abstruct : stop to sound a beep
 * Input    : none
 * Return   : none
 *----------------------------------------------------------------------------*/
static void dac_cs47l01_beep_off(void)
{
	i2c_write(&i2c_config, 0x26, 0x00);     /* beep! */

	return;
}

/*-----------------------------------------------------------------------------
 * Function : dac_cs47l01_on_boot
 * Abstruct : on kernel boot (u-boot->kernel)
 * Input    : none
 * Return   : none
 *----------------------------------------------------------------------------*/
static void dac_cs47l01_on_boot(void)
{
	/* mute hp volume */
	i2c_write(&i2c_config, 0x2e, 0x40);     /* HP  (A) volume=MUTE */
	i2c_write(&i2c_config, 0x2f, 0x40);     /* HP  (B) volume=MUTE */

	return;
}

/*-----------------------------------------------------------------------------
 * Function : dac_cs47l01_setup_platform
 * Abstruct : setup platform
 * Input    : none
 * Return   : none
 *----------------------------------------------------------------------------*/
static void dac_cs47l01_setup_platform(void)
{
	/******************/
	/* setting PINSEL */
	/******************/

	/* ADA_XRST(GPIO_P007) */
	outl(((inl(CHG_PINSEL_G000) & ~0x00000080) | 0x00000080), CHG_PINSEL_G000);
	outl(((inl(CHG_PULL0      ) & ~0xF0000000) | 0x00000000), CHG_PULL0      );
	
	/* HP_XMUTE(GPIO_P119) */
	outl(((inl(CHG_PINSEL_G096) & ~0x00800000) | 0x00800000), CHG_PINSEL_G096);
	outl(((inl(CHG_PULL14     ) & ~0xF0000000) | 0x00000000), CHG_PULL14     );

	/****************/
	/* setting GPIO */
	/****************/

	/* in/out */
	gpio_set_value(GPIO_HP_XMUTE, 0x0);
	gpio_set_direction(GPIO_HP_XMUTE, GPIO_OUT);
	gpio_set_value(GPIO_ADA_XRST, 0x0);
	gpio_set_direction(GPIO_ADA_XRST, GPIO_OUT);
}

#endif /* CONFIG_ICX */

