
#include <common.h>
#include <i2c.h>
#include "pcf50606.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

#define PCF50606_I2C_ADDR		0x08

void pcf50606_reg_write(u_int8_t reg, u_int8_t val)
{
	i2c_write(PCF50606_I2C_ADDR, reg, 1, &val, 1);
}

u_int8_t pcf50606_reg_read(u_int8_t reg)
{
	u_int8_t tmp;
	i2c_read(PCF50606_I2C_ADDR, reg, 1, &tmp, 1);
	return tmp;
}

u_int8_t pcf50606_reg_set_bit_mask(u_int8_t reg, u_int8_t mask, u_int8_t val)
{
	u_int8_t tmp = pcf50606_reg_read(reg);
	pcf50606_reg_write(reg, (val & mask) | (tmp & ~mask));
}

static const u_int8_t regs_valid[] = {
	PCF50606_REG_OOCS, PCF50606_REG_INT1M, PCF50606_REG_INT2M,
	PCF50606_REG_INT3M, PCF50606_REG_OOCC1, PCF50606_REG_OOCC2,
	PCF50606_REG_PSSC, PCF50606_REG_PWROKM, PCF50606_REG_DCDC1,
	PCF50606_REG_DCDC2, PCF50606_REG_DCDC3, PCF50606_REG_DCDC4,
	PCF50606_REG_DCDEC1, PCF50606_REG_DCDEC2, PCF50606_REG_DCUDC1,
	PCF50606_REG_DCUDC2, PCF50606_REG_IOREGC, PCF50606_REG_D1REGC1,
	PCF50606_REG_D2REGC1, PCF50606_REG_D3REGC1, PCF50606_REG_LPREGC1,
	PCF50606_REG_LPREGC2, PCF50606_REG_MBCC1, PCF50606_REG_MBCC2,
	PCF50606_REG_MBCC3, PCF50606_REG_BBCC, PCF50606_REG_ADCC1,
	PCF50606_REG_ADCC2, PCF50606_REG_ACDC1, PCF50606_REG_BVMC,
	PCF50606_REG_PWMC1, PCF50606_REG_LEDC1, PCF50606_REG_LEDC2,
	PCF50606_REG_GPOC1, PCF50606_REG_GPOC2, PCF50606_REG_GPOC3,
	PCF50606_REG_GPOC4, PCF50606_REG_GPOC5,
};


static const u_int8_t initial_register_set[__NUM_PCF50606_REGS] = {
	[PCF50606_REG_OOCS] 	= 0x00,
	/* gap */
	[PCF50606_REG_INT1M]	= PCF50606_INT1_SECOND,
	[PCF50606_REG_INT2M]	= 0x00,
	[PCF50606_REG_INT3M]	= PCF50606_INT3_TSCPRES,
	[PCF50606_REG_OOCC1] 	= PCF50606_OOCC1_RTCWAK |
				  PCF50606_OOCC1_CHGWAK |
				  PCF50606_OOCC1_EXTONWAK_HIGH,
	[PCF50606_REG_OOCC2]	= PCF50606_OOCC2_ONKEYDB_14ms |
				  PCF50606_OOCC2_EXTONDB_14ms,
	/* gap */
	[PCF50606_REG_PSSC]	= 0x00,
	[PCF50606_REG_PWROKM]	= 0x00,
	/* gap */
#if defined(CONFIG_ARCH_GTA01B_v2)
	[PCF50606_REG_DCDC1]	= 0x1e,	/* GL_3V3: off */
#elif defined(CONFIG_ARCH_GTA01B_v3)
	[PCF50606_REG_DCDC1]	= 0x18,	/* GL_1V5: off */
#endif
	[PCF50606_REG_DCDC2]	= 0x00,
	[PCF50606_REG_DCDC3]	= 0x00,
	[PCF50606_REG_DCDC4]	= 0x30, /* 1.25A */

	[PCF50606_REG_DCDEC1]	= 0xe8, /* IO_3V3: on */
	[PCF50606_REG_DCDEC2]	= 0x00,

#if defined(CONFIG_ARCH_GTA01_v3) || defined(CONFIG_ARCH_GTA01_v4)
	[PCF50606_REG_DCUDC1]	= 0xe3, /* CORE_1V8: 1.8V */
#elif defined(CONFIG_ARCH_GTA01B_v2) || defined(CONFIG_ARCH_GTA01B_v3)
	[PCF50606_REG_DCUDC1]	= 0xe4, /* CORE_1V8: 2.1V */
#endif
	[PCF50606_REG_DCUDC2]	= 0x30, /* 1.25A current limit */

#if defined(CONFIG_ARCH_GTA01_v3)
	[PCF50606_REG_IOREGC]	= 0x13, /* VTCXO_2V8: off */
#elif defined(CONFIG_ARCH_GTA01_v4) || defined(CONFIG_ARCH_GTA01B_v2) || defined(CONFIG_ARCH_GTA01B_v3)
	//see internal bug 94 [PCF50606_REG_IOREGC]	= 0x18, /* CODEC_3V3: off */
	[PCF50606_REG_IOREGC]	= 0xf8, /* CODEC_3V3: on */
#endif

#if defined(CONFIG_ARCH_GTA01_v3) || defined(CONFIG_ARCH_GTA01_v4)
	[PCF50606_REG_D1REGC1]	= 0x15, /* VRF_3V: off */
#elif defined(CONFIG_ARCH_GTA01B_v2) || defined(CONFIG_ARCH_GTA01B_v3)
	[PCF50606_REG_D1REGC1]	= 0x16, /* BT_3V15: off */
#endif

#if defined(CONFIG_ARCH_GTA01_v3)
	[PCF50606_REG_D2REGC1]	= 0xf8, /* SD_3V3: on */
#elif defined(CONFIG_ARCH_GTA01_v4) || defined(CONFIG_ARCH_GTA01B_v2) || defined(CONFIG_ARCH_GTA01B_v3)
	[PCF50606_REG_D2REGC1]	= 0x10, /* GL_2V5: off */
#endif

#if defined(CONFIG_ARCH_GTA01_v3)
	[PCF50606_REG_D3REGC1]	= 0x18, /* CODEC_3V3: off */
#elif defined(CONFIG_ARCH_GTA01_v4)
	[PCF50606_REG_D3REGC1]	= 0x13, /* VTXCO_2V8: off */
#elif defined(CONFIG_ARCH_GTA01B_v2) || defined(CONFIG_ARCH_GTA01B_v3)
	[PCF50606_REG_D3REGC1]	= 0x00, /* USER1: off */
#endif

	[PCF50606_REG_LPREGC1]	= 0xf8, /* LCM_3V3: on */
	[PCF50606_REG_LPREGC2]	= 0x00,

	[PCF50606_REG_MBCC1]	= 0x01, /* CHGAPE */
	[PCF50606_REG_MBCC2]	= 0x00,	/* unlimited charging */
	[PCF50606_REG_MBCC3]	= 0x1a, /* 0.2*Ifast, 4.20V */
	[PCF50606_REG_BBCC]	= 0x13, /* 50uA */
	[PCF50606_REG_ADCC1]	= 0x00,
	[PCF50606_REG_ADCC2]	= 0x00,
	/* gap */
	[PCF50606_REG_ACDC1]	= 0x00,
	[PCF50606_REG_BVMC]	= PCF50606_BVMC_THRSHLD_2V8,
	[PCF50606_REG_PWMC1]	= 0x00,
	[PCF50606_REG_LEDC1]	= 0x00,
	[PCF50606_REG_LEDC2]	= 0x00,
	[PCF50606_REG_GPOC1]	= 0x00,
	[PCF50606_REG_GPOC2]	= 0x00,
	[PCF50606_REG_GPOC3]	= 0x00,
	[PCF50606_REG_GPOC4]	= 0x00,
	[PCF50606_REG_GPOC5]	= 0x00,
};


/* initialize PCF50606 register set */
void pcf50606_init(void)
{
#if 0
	/* We don't want to write to RTC, Alarm and other status registers
	 * but rather concentrate on efficiently writing/stting those we
	 * need */

	pcf50606_reg_write(PCF50606_REG_OOCS,
			   initial_register_set[PCF50606_REG_OOCS]);

	/* GAP: 0x02-0x04 */

	i2c_write(PCF50606_I2C_ADDR, 0x05, 1,
		  &initial_register_set[0x05], 5);

	/* GAP: 0x0a..0a17 */

	i2c_write(PCF50606_I2C_ADDR, 0x18, 1,
		  &initial_register_set[0x18], 2);

	/* GAP: 0x1a */

	i2c_write(PCF50606_I2C_ADDR, 0x1b, 1,
		  &initial_register_set[0x1b], 17);

	/* GAP: 0x2c */

	i2c_write(PCF50606_I2C_ADDR, 0x2d, 1,
		  &initial_register_set[0x2d], 3);

	/* GAP: 0x30-0x32 */
	i2c_write(PCF50606_I2C_ADDR, 0x23, 1,
		  &initial_register_set[0x33], 10);
#else
	int i;
	for (i = 0; i < ARRAY_SIZE(regs_valid); i++)
		pcf50606_reg_write(regs_valid[i],
				   initial_register_set[regs_valid[i]]);
#endif
}
