static int evitareul_s5k6a1gx03_power_off(void)
{
	pr_info("[CAM] %s ++", __func__);
	int pcbid = htc_get_pcbid_info();

#if defined(CONFIG_RAWCHIP_ENABLE)
	if ((pcbid >= PROJECT_PHASE_XB) || (pcbid == PROJECT_PHASE_EVM))
	{
		/* set gpio output low : O(L) */
		tegra_gpio_enable(MCAM_SPI_CLK);
		ENR_msleep(1);

		tegra_gpio_enable(MCAM_SPI_DO);
		tegra_gpio_enable(MCAM_SPI_DI);
		tegra_gpio_enable(MCAM_SPI_CS0);
		tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_KB_ROW0, TEGRA_PUPD_PULL_DOWN);
		tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_CLK3_REQ, TEGRA_PUPD_PULL_DOWN);
		ENR_msleep(1);

		/* RAW RSTN*/
		gpio_direction_output(RAW_RSTN, 0);
		ENR_msleep(3);
	}
#endif

	tegra_gpio_enable(CAM_MCLK);
	ENR_msleep(1);

	/* CAM SEL */
	gpio_direction_output(CAM_SEL, 0);
	ENR_msleep(1);

	/* vcm */
	regulator_disable(cam_vcm2v85_en);
	ENR_msleep(1);

	/* digital */
	gpio_direction_output(CAM2_D1V2_EN, 0);
	ENR_msleep(1);

	/* RSTN */
	gpio_direction_output(FRONT_CAM_RST, 0);
	ENR_msleep(1);

#if defined(CONFIG_RAWCHIP_ENABLE)
	if ((pcbid >= PROJECT_PHASE_XB) || (pcbid == PROJECT_PHASE_EVM))
	{
		/* core */
		gpio_direction_output(CAM_D1V2_EN, 0);
		ENR_msleep(1);

		/* RAW_1V8_EN */
		gpio_direction_output(RAW_1V8_EN, 0);
		ENR_msleep(1);
		rawchip_spi_clock_control(0);
	}
#endif

	/* analog */
	regulator_disable(cam_a2v85_en);
	ENR_msleep(5);

	/* IO */
	tegra_gpio_enable(CAM_I2C_SCL);
	tegra_gpio_enable(CAM_I2C_SDA);
	gpio_direction_output(CAMIO_1V8_EN, 0);
	ENR_msleep(10);
	tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_KB_ROW6, TEGRA_PUPD_PULL_DOWN);

	pr_info("[CAM] %s --", __func__);
	return 0;
}
static long aic3008_ioctl(struct file *file, unsigned int cmd,
		unsigned long argc)
{
	struct AIC3008_PARAM para;
	void *table;
	int ret = 0, i = 0, mem_size, volume = 0;
	CODEC_SPI_CMD reg[4];
	unsigned char data;
	int len= 0; /* for dump dsp length. */
	int pcbid = 0;
	
	AUD_DBG("IOCTL command:0x%02X, argc:%ld\n", cmd, argc);

	if (aic3008_uplink == NULL || aic3008_downlink == NULL || aic3008_minidsp
			== NULL) {
		AUD_ERR("cmd 0x%x, invalid pointers\n", cmd);
		return -EFAULT;
	}

	switch (cmd) {
	/* first IO command from HAL */
	case AIC3008_IO_SET_TX_PARAM:
	/* second IO command from HAL */
	case AIC3008_IO_SET_RX_PARAM:
		if (copy_from_user(&para, (void *) argc, sizeof(para))) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}

		AUD_DBG("parameters(%d, %d, %p)\n",
				para.row_num, para.col_num, para.cmd_data);

		if (cmd == AIC3008_IO_SET_TX_PARAM)
			table = aic3008_uplink[0];
		else
			table = aic3008_downlink[0];

		/* confirm indicated size doesn't exceed the allocated one */
		if (para.row_num > IO_CTL_ROW_MAX || para.col_num != IO_CTL_COL_MAX) {
			AUD_ERR("data size mismatch with allocated memory (%d,%d)\n",
					IO_CTL_ROW_MAX, IO_CTL_COL_MAX);
			return -EFAULT;
		}

		mem_size = para.row_num * para.col_num * sizeof(CODEC_SPI_CMD);
		if (copy_from_user(table, para.cmd_data, mem_size)) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}

		/* invoking initialization procedure of AIC3008 */
		if (cmd == AIC3008_IO_SET_TX_PARAM)
			aic3008_tx_config(INITIAL);

		AUD_INFO("update RX/TX tables(%d, %d) successfully\n",
				para.row_num, para.col_num);
		break;

		/* third io command from HAL */
	case AIC3008_IO_SET_DSP_PARAM:
		if (copy_from_user(&para, (void *) argc, sizeof(para))) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}

		AUD_DBG("parameters(%d, %d, %p)\n",
				para.row_num, para.col_num, para.cmd_data);

		table = aic3008_minidsp[0];

		/* confirm indicated size doesn't exceed the allocated one */
		if (para.row_num > MINIDSP_ROW_MAX ||
				para.col_num != MINIDSP_COL_MAX) {
			AUD_ERR("data size mismatch with allocated memory (%d, %d)\n",
					MINIDSP_ROW_MAX, MINIDSP_COL_MAX);
			return -EFAULT;
		}

		mem_size = para.row_num * para.col_num * sizeof(CODEC_SPI_CMD);
		if (copy_from_user(table, para.cmd_data, mem_size)) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}

		AUD_INFO("update dsp table(%d, %d) successfully\n",
				para.row_num, para.col_num);
		break;

		/* these IO commands are called to set path */
	case AIC3008_IO_CONFIG_TX:
	case AIC3008_IO_CONFIG_RX:
	case AIC3008_IO_CONFIG_MEDIA:
		if (copy_from_user(&i, (void *) argc, sizeof(int))) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}
		/* call aic3008_set_config() to issue SPI commands */
		ret = aic3008_set_config(cmd, i, 1);
		if (ret < 0)
			AUD_ERR("configure(%d) error %d\n", i, ret);
		break;

	case AIC3008_IO_CONFIG_VOLUME_L:
		if (copy_from_user(&volume, (void *) argc, sizeof(int))) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}

		if (volume < -127 || volume > 48) {
			AUD_ERR("volume out of range\n");
			return -EFAULT;
		}

		AUD_DBG("AIC3008 config left volume %d\n", volume);

		CODEC_SET_VOLUME_L[1].data = volume;

		/* call extended aic3008_config_ex() to set up volume */
		aic3008_config_ex(CODEC_SET_VOLUME_L, ARRAY_SIZE(CODEC_SET_VOLUME_L));
		break;

	case AIC3008_IO_CONFIG_VOLUME_R:
		if (copy_from_user(&volume, (void *) argc, sizeof(int))) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}

		if (volume < -127 || volume > 48) {
			AUD_ERR("volume out of range\n");
			return -EFAULT;
		}

		AUD_DBG("AIC3008 config right volume %d\n", volume);

		CODEC_SET_VOLUME_R[1].data = volume;

		/* call extended aic3008_config_ex() to set up volume */
		aic3008_config_ex(CODEC_SET_VOLUME_R, ARRAY_SIZE(CODEC_SET_VOLUME_R));
		break;

		/* dump specific audio codec page */
	case AIC3008_IO_DUMP_PAGES:
		if (copy_from_user(&i, (void *) argc, sizeof(int))) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}
		if (i > AIC3008_MAX_PAGES) {
			AUD_ERR("invalid page number %d\n", i);
			return -EINVAL;
		}

		AUD_DBG("========== dump page %d ==========\n", i);
		/* indicated page number of AIC3008 */
		codec_spi_write(0x00, i, true);
		for (i = 0; i < AIC3008_MAX_REGS; i++) {
			ret = codec_spi_read(i, &data, true);
			if (ret < 0) {
				AUD_ERR("read fail on register 0x%X\n", i);
				0;
			} else {
				AUD_DBG("(addr:0x%02X, data:0x%02X)\n", i, data);
				0;
			}
		}
		AUD_DBG("=============================================\n");
		break;
	case AIC3008_IO_DUMP_DSP:
		AUD_DBG("========== dump dsp %d ==========\n", aic3008_dsp_mode);

		/* indicated dsp number of AIC3008 */
		len = (aic3008_minidsp[aic3008_dsp_mode][0].reg << 8) | aic3008_minidsp[aic3008_dsp_mode][0].data;
		AUD_DBG("len = %d", len);
		spi_read_list(&aic3008_minidsp[aic3008_dsp_mode][1], len);
		AUD_DBG("=============================================\n");
		break;

		/* write specific audio codec register */
	case AIC3008_IO_WRITE_REG:
		AUD_INFO("========== WRITE_REG ==========\n");
		if (copy_from_user(&reg, (void *) argc, sizeof(CODEC_SPI_CMD) * 4)) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}
		AUD_DBG("command list (%c,%02X,%02X) (%c,%02X,%02X) (%c,%02X,%02X) (%c,%02X,%02X)\n",
				reg[0].act, reg[0].reg, reg[0].data,
				reg[1].act, reg[1].reg, reg[1].data,
				reg[2].act, reg[2].reg, reg[2].data,
				reg[3].act, reg[3].reg, reg[3].data);
//		aic3008_config_ex(reg, 4);
		for (i = 0; i < 4; i++) {
			if (reg[i].act == 'r' || reg[i].act == 'R')
				codec_spi_read(reg[i].reg, &reg[i].data, true);
			else if (reg[i].act == 'w' || reg[i].act == 'W')
				codec_spi_write(reg[i].reg, reg[i].data, true);
			else
				return -EINVAL;
		}
		AUD_INFO("========== WRITE_REG end ==========\n");
		break;

		/* read specific audio codec register */
	case AIC3008_IO_READ_REG:
		AUD_INFO("========== READ_REG ==========\n");
		if (copy_from_user(&reg, (void *) argc, sizeof(CODEC_SPI_CMD) * 4)) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}
		for (i = 0; i < 4; i++) {
			if (reg[i].act == 'r' || reg[i].act == 'R')
				codec_spi_read(reg[i].reg, &reg[i].data, true);
			else if (reg[i].act == 'w' || reg[i].act == 'W')
				codec_spi_write(reg[i].reg, reg[i].data, true);
			else
				return -EINVAL;
		}
		if (copy_to_user((void *) argc, &reg, sizeof(CODEC_SPI_CMD) * 2)) {
			AUD_ERR("failed on copy_to_user\n");
			return -EFAULT;
		}
		AUD_INFO("========== READ_REG end==========\n");
		break;

	case AIC3008_IO_POWERDOWN: /* power down IO command */
		mutex_lock(&lock);
		aic3008_powerdown();
		mutex_unlock(&lock);
		break;

	case AIC3008_IO_LOOPBACK: /* loopback IO command */
		if (copy_from_user(&i, (void *) argc, sizeof(int))) {
			AUD_ERR("failed on copy_from_user\n");
			return -EFAULT;
		}
		AUD_DBG("index %d for LOOPBACK\n", i);

		/* set up the loopback with specific id */
		aic3008_set_loopback(i);
		break;

	case AIC3008_IO_GET_PCBID: /* get pcbid */
		pcbid = htc_get_pcbid_info();
		if (copy_to_user((void *) argc, &pcbid, sizeof(int))) {
			AUD_ERR("failed on copy_to_user\n");
			return -EFAULT;
		}
		break;

	default:
		AUD_ERR("invalid command %d\n", _IOC_NR(cmd));
		ret = -EINVAL;
	}

	return ret;
}
static int evitareul_s5k6a1gx03_power_on(void)
{
	int ret;
	int pcbid = htc_get_pcbid_info();
	pr_info("[CAM] %s ++", __func__);

	enrc2u_set_regulator();

	gpio_direction_output(CAM_MCLK, 0);

#if defined(CONFIG_RAWCHIP_ENABLE)
	if ((pcbid >= PROJECT_PHASE_XB) || (pcbid == PROJECT_PHASE_EVM))
	{
		tegra_gpio_disable(MCAM_SPI_CLK);
		tegra_gpio_disable(MCAM_SPI_DO);
		tegra_gpio_disable(MCAM_SPI_DI);
		tegra_gpio_disable(MCAM_SPI_CS0);
		tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_KB_ROW0, TEGRA_PUPD_NORMAL);
		tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_CLK3_REQ, TEGRA_PUPD_NORMAL);
	}
#endif

	tegra_gpio_disable(CAM_I2C_SCL);
	tegra_gpio_disable(CAM_I2C_SDA);

	gpio_direction_output(CAM1_PWDN, 0);

	gpio_direction_output(FRONT_CAM_RST, 0);

	gpio_direction_output(CAM1_VCM_PD, 0);

#if defined(CONFIG_RAWCHIP_ENABLE)
	if ((pcbid >= PROJECT_PHASE_XB) || (pcbid == PROJECT_PHASE_EVM))
	{
		gpio_direction_output(RAW_RSTN, 0);
	}
#endif

	gpio_direction_output(CAM_SEL, 0);

#if defined(CONFIG_RAWCHIP_ENABLE)
	if ((pcbid >= PROJECT_PHASE_XB) || (pcbid == PROJECT_PHASE_EVM))
	{
		/* RAW_1V8_EN */
		gpio_direction_output(RAW_1V8_EN, 1);
		ENR_usleep(200);
	}
#endif

	/* vcm */
	ret = regulator_enable(cam_vcm2v85_en);
	if (ret < 0)
	{
		pr_err("[CAM] couldn't enable regulator cam_vcm2v85_en\n");
		regulator_put(cam_vcm2v85_en);
		cam_vcm2v85_en = NULL;
		return ret;
	}
	ENR_usleep(200);

	/* analog */
	ret = regulator_enable(cam_a2v85_en);
	if (ret < 0)
	{
		pr_err("[CAM] couldn't enable regulator cam_a2v85_en\n");
		regulator_put(cam_a2v85_en);
		cam_a2v85_en = NULL;
		return ret;
	}
	ENR_usleep(200);

#if defined(CONFIG_RAWCHIP_ENABLE)
	if ((pcbid >= PROJECT_PHASE_XB) || (pcbid == PROJECT_PHASE_EVM))
	{
		/* main camera core */
		gpio_direction_output(CAM_D1V2_EN, 1);
		ENR_usleep(200);
	}
#endif

	/* IO */
	gpio_direction_output(CAMIO_1V8_EN, 1);
	ENR_usleep(200);
	tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_KB_ROW6, TEGRA_PUPD_NORMAL);

	/* RSTN */
	gpio_direction_output(FRONT_CAM_RST, 1);

	/* digital */
	gpio_direction_output(CAM2_D1V2_EN, 1);
	ENR_usleep(200);

	/* CAM SEL */
	gpio_direction_output(CAM_SEL, 1);
	ENR_msleep(1);

	tegra_gpio_disable(CAM_MCLK);
	ENR_msleep(1);

#if defined(CONFIG_RAWCHIP_ENABLE)
	if ((pcbid >= PROJECT_PHASE_XB) || (pcbid == PROJECT_PHASE_EVM))
	{
		/* RAW_RSTN */
		ret = gpio_direction_output(RAW_RSTN, 1);
		ENR_msleep(1);
		rawchip_spi_clock_control(1);
		/* SPI send command to configure RAWCHIP here! */
		yushan_spi_write(0x0008, 0x7f);
		ENR_msleep(1);
	}
#endif

	pr_info("[CAM] %s --", __func__);
	return 0;
}