static void crystalcove_gpio_dbg_show(struct seq_file *s,
				struct gpio_chip *chip)
{
	struct crystalcove_gpio *cg =
		container_of(chip, struct crystalcove_gpio, chip);
	int gpio, offset;
	u8 ctlo, ctli, mirqs0, mirqsx, irq;

	for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
		offset = gpio < 8 ? gpio : gpio - 8;
		ctlo = intel_mid_pmic_readb(
			(gpio < 8 ? GPIO0P0CTLO : GPIO1P0CTLO) + offset);
		ctli = intel_mid_pmic_readb(
			(gpio < 8 ? GPIO0P0CTLI : GPIO1P0CTLI) + offset);
		mirqs0 = intel_mid_pmic_readb(
			gpio < 8 ? MGPIO0IRQS0 : MGPIO1IRQS0);
		mirqsx = intel_mid_pmic_readb(
			gpio < 8 ? MGPIO0IRQSX : MGPIO1IRQSX);
		irq = intel_mid_pmic_readb(
			gpio < 8 ? GPIO0IRQ : GPIO1IRQ);
		seq_printf(s,
			" gpio-%-2d %s %s %s %s "
			"ctlo=%2x,%s %s %s\n",
			gpio,
			ctlo & CTLO_DIR_OUT ? "out" : "in ",
			ctli & 0x1 ? "hi" : "lo",
			ctli & CTLI_INTCNT_NE ? "fall" : "    ",
			ctli & CTLI_INTCNT_PE ? "rise" : "    ",
			ctlo,
			mirqs0 & (1 << offset) ? "s0 mask  " : "s0 unmask",
			mirqsx & (1 << offset) ? "sx mask  " : "sx unmask",
			irq & (1 << offset) ? "pending" : "       ");
	}
}
static int get_charging_status(struct chgr_info *info)
{
	int stat = POWER_SUPPLY_STATUS_UNKNOWN;
	int vbus_stat, chgr_stat, chgr_irq_stat;

	dev_info(&info->pdev->dev, "crystalcove chargering status\n");

	vbus_stat = crystal_cove_vbus_on_status();
	if (vbus_stat < 0)
		goto chgr_stat_read_fail;

	chgr_stat = intel_mid_pmic_readb(CRYSTALCOVE_MCHGRIRQS0_REG);
	if (chgr_stat < 0)
		goto chgr_stat_read_fail;
	else
		chgr_stat = intel_mid_pmic_readb(CRYSTALCOVE_MCHGRIRQSX_REG);
	if (chgr_stat < 0)
		goto chgr_stat_read_fail;

	chgr_irq_stat = intel_mid_pmic_readb(CRYSTALCOVE_CHGRIRQ_REG);
	if (chgr_irq_stat < 0)
		goto chgr_stat_read_fail;

	if (vbus_stat != 1)
		stat = POWER_SUPPLY_STATUS_DISCHARGING;
	else if (vbus_stat == 1 && chgr_stat == 0)
		stat = POWER_SUPPLY_STATUS_CHARGING;
	else if (chgr_irq_stat == 1)
		stat = POWER_SUPPLY_STATUS_FULL;
	else
		stat = POWER_SUPPLY_STATUS_NOT_CHARGING;

chgr_stat_read_fail:
	return stat;
}
static int get_charger_health(struct chgr_info *info)
{
	int ret, pwr_stat, chgr_stat, pwr_irq;
	int health = POWER_SUPPLY_HEALTH_UNKNOWN;

	dev_info(&info->pdev->dev, "crystalcove charger health\n");

	ret = crystal_cove_vbus_on_status();
	if ((ret < 0) || (ret == 0))
		goto health_read_fail;
	else
		pwr_stat = ret;

	ret = intel_mid_pmic_readb(CRYSTALCOVE_MCHGRIRQS0_REG);
	if (ret < 0)
		goto health_read_fail;
	else
		ret = intel_mid_pmic_readb(CRYSTALCOVE_MCHGRIRQSX_REG);
		if (ret < 0)
			goto health_read_fail;
		else
			pwr_irq = ret;

	if (pwr_stat == 1)
		health = POWER_SUPPLY_HEALTH_GOOD;

health_read_fail:
	return health;
}
static void ov8865_verify_gpio_power(void)
{
	OV8865_PLAT_LOG(1,"CAMERA: start check ov8865 gpio\n");
	OV8865_PLAT_LOG(1,"CAMERA_1_RESET: %d\n", gpio_get_value(CAMERA_0_RESET));
	OV8865_PLAT_LOG(1,"CAMERA_1_PWDN: %d\n", gpio_get_value(CAMERA_0_PWDN));
	OV8865_PLAT_LOG(1,"CAMERA_DOVDD_EN: %d\n", gpio_get_value(CAMERA_DOVDD_EN));
	OV8865_PLAT_LOG(1,"CAMERA_AVDD_EN: %d\n", gpio_get_value(CAMERA_AVDD_EN));
	OV8865_PLAT_LOG(1,"CAMERA_DVDD_EN: %d\n", gpio_get_value(CAMERA_DVDD_EN));
	OV8865_PLAT_LOG(1,"VPROG_3P3V  addr:0x%x value:%x\n", VPROG_3P3V, intel_mid_pmic_readb(VPROG_3P3V));
	OV8865_PLAT_LOG(1,"VPROG_2P8V  addr:0x%x value:%x\n", VPROG_2P8V, intel_mid_pmic_readb(VPROG_2P8V));
	OV8865_PLAT_LOG(1,"VPROG_1P8V  addr:0x%x value:%x\n", VPROG_1P8V, intel_mid_pmic_readb(VPROG_1P8V));
}
static irqreturn_t gpadc_isr(int irq, void *data)
{
	struct gpadc_info *info = iio_priv(data);
	u8 pending0, pending1;

	pending0 = intel_mid_pmic_readb(ADCIRQ0);
	pending1 = intel_mid_pmic_readb(ADCIRQ1);
	intel_mid_pmic_writeb(ADCIRQ0, pending0);
	intel_mid_pmic_writeb(ADCIRQ0, pending1);
	info->irq_pending |= pending0 + (pending1 << 8);
	wake_up(&info->wait);
	return IRQ_HANDLED;
}
static int crystalcove_gpadc_show(struct seq_file *s, void *unused)
{
	int num;
	char *names[GPADC_CH_NUM];
	int vals[GPADC_CH_NUM];
	int i, j;
	struct iio_channel *chs;
	char *ch_names[] = {"VIBAT", "BATID", "PMICTEMP", "BATTEMP",
		"SYSTEMP", "THERMAL"};
	int ret = 0;

	seq_printf(s, "ADCCNTL:\t0x%02x\n", intel_mid_pmic_readb(ADCCNTL));
	seq_printf(s, "ADCVZSE:\t0x%02x\n", intel_mid_pmic_readb(ADCVZSE));
	seq_printf(s, "ADCVGE:\t\t0x%02x\n", intel_mid_pmic_readb(ADCVGE));
	seq_printf(s, "VRIMONCTL:\t0x%02x\n", intel_mid_pmic_readb(VRIMONCTL));
	seq_printf(s, "MANCONV0:\t0x%02x\n", intel_mid_pmic_readb(MANCONV0));
	seq_printf(s, "MANCONV1:\t0x%02x\n", intel_mid_pmic_readb(MANCONV1));
	seq_printf(s, "ADCIRQ0:\t0x%02x\n", intel_mid_pmic_readb(ADCIRQ0));
	seq_printf(s, "ADCIRQ1:\t0x%02x\n", intel_mid_pmic_readb(ADCIRQ1));
	seq_printf(s, "MADCIRQ0:\t0x%02x\n", intel_mid_pmic_readb(MADCIRQ0));
	seq_printf(s, "MADCIRQ1:\t0x%02x\n", intel_mid_pmic_readb(MADCIRQ1));

	memset(names, 0, sizeof(names));
	for (i = 0; i < GPADC_CH_NUM; i++) {
		names[i] = kmalloc(256, GFP_KERNEL);
		if (names[i] == NULL) {
			ret = -ENOMEM;
			goto err;
		}
	}
	for (i = 0; i < sizeof(ch_names)/sizeof(ch_names[0]); i++) {
		chs = iio_st_channel_get_all(ch_names[i]);
		if (chs) {
			num = iio_st_channel_get_num(chs);
			iio_st_channel_get_name(chs, names);
			iio_st_read_channel_raw(chs, vals);
			iio_st_channel_release_all(chs);
			for (j = 0; j < num; j++)
				seq_printf(s, "%s:%s\t%d\n",
					ch_names[i], names[j], vals[j]);
		}
	}
err:
	for (i = 0; i < GPADC_CH_NUM; i++)
		kfree(names[i]);

	return 0;
}
static irqreturn_t pb_isr(int irq, void *dev_id)
{
	int ret;
	int state;

	ret = intel_mid_pmic_readb(DC_TI_SIRQ_REG);
	if (ret < 0) {
		pr_err("[%s] power button SIRQ REG read fail %d\n",
						pb_input->name, ret);
		return IRQ_NONE;
	}

	state = ret & SIRQ_PWRBTN_REL;

	if (force_trigger && state) {
		/* If we lost the press interrupt when short pressing
		 * power button to wake up board from S3, simulate one.
		 */
		input_event(pb_input, EV_KEY, KEY_POWER, 1);
		input_sync(pb_input);
		input_event(pb_input, EV_KEY, KEY_POWER, 0);
		input_sync(pb_input);
	} else {
		input_event(pb_input, EV_KEY, KEY_POWER, !state);
		input_sync(pb_input);
		pr_info("[%s] power button %s\n", pb_input->name, state ? "released" : "pressed");
	}

	if (force_trigger)
		force_trigger = 0;

	return IRQ_HANDLED;
}
void p088pw_reset(struct intel_dsi_device *dsi)
{
    int val;
	struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
	struct drm_device *dev = intel_dsi->base.base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;

	DRM_DEBUG_KMS("\n");
	//printk("p088pw_reset\n");
	val = intel_mid_pmic_readb(0x12);
    val |= 1<<5;
	intel_mid_pmic_writeb(0x12, val);
    usleep_range(100000, 120000);
	vlv_gpio_nc_write(dev_priv, GPIO_NC_9_PCONF0, 0x2000CC00);//reset
	vlv_gpio_nc_write(dev_priv, GPIO_NC_9_PAD, 0x00000004);
	usleep_range(100000, 120000);
	vlv_gpio_nc_write(dev_priv, GPIO_NC_10_PCONF0, 0x2000CC00);
	vlv_gpio_nc_write(dev_priv, GPIO_NC_10_PAD, 0x00000005);
	usleep_range(100000, 120000);
	vlv_gpio_nc_write(dev_priv, GPIO_NC_11_PCONF0, 0x2000CC00);
	vlv_gpio_nc_write(dev_priv, GPIO_NC_11_PAD, 0x00000005);
	msleep(10);
	vlv_gpio_nc_write(dev_priv, GPIO_NC_9_PCONF0, 0x2000CC00);
	vlv_gpio_nc_write(dev_priv, GPIO_NC_9_PAD, 0x00000005);
}
/**
* intel_pmic_reg_setvoltage - Set voltage to the regulator
* @rdev:    regulator_dev structure
* @min_uV: Minimum required voltage in uV
* @max_uV: Maximum acceptable voltage in uV
* @selector: Voltage value passed back to core layer
* Sets a voltage regulator to the desired output voltage
* @return value : Returns 0 if success
*			: Return error value on failure
*/
static int intel_pmic_reg_setvoltage(struct regulator_dev *rdev, int min_uV,
					int max_uV, unsigned *selector)
{
	struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
	int reg_value;
	u8 vsel;

	for (vsel = 0; vsel < pmic_info->table_len; vsel++) {
		int mV = pmic_info->table[vsel];
		int uV = mV * 1000;
		if (min_uV > uV || uV > max_uV)
			continue;

		*selector = vsel;
		reg_value = intel_mid_pmic_readb(pmic_info->pmic_reg);
		if (reg_value < 0) {
			dev_err(&rdev->dev,
			"intel_mid_pmic_readb returns error %08x\n", reg_value);
			return reg_value;
		}
		reg_value &= ~REG_VSEL_MASK;
		reg_value |= vsel << VSEL_SHIFT;
		dev_dbg(&rdev->dev,
			"intel_pmic_reg_setvoltage voltage: %u uV\n", uV);
		return intel_mid_pmic_writeb(pmic_info->pmic_reg, reg_value);
	}
	return -EINVAL;
}
static void p088pw_disable(struct intel_dsi_device *dsi)
{
    int val = 0;
	struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
	struct drm_device *dev = intel_dsi->base.base.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	DRM_DEBUG_KMS("\n");
	printk("p088pw_disable\n");
	msleep(200);
	dsi_vc_dcs_write_0(intel_dsi, 0, 0x28);
	msleep(80);

	dsi_vc_dcs_write_0(intel_dsi, 0, 0x10);
	msleep(34);
	val = intel_mid_pmic_readb(0x12);    	
	val &= ~(1<<5);		
	intel_mid_pmic_writeb(0x12, val);		
	usleep_range(100000, 120000);	
	vlv_gpio_nc_write(dev_priv, GPIO_NC_9_PCONF0, 0x2000CC00);	
	vlv_gpio_nc_write(dev_priv, GPIO_NC_9_PAD, 0x00000004);	
	usleep_range(100000, 120000);	
	vlv_gpio_nc_write(dev_priv, GPIO_NC_10_PCONF0, 0x2000CC00);	
	vlv_gpio_nc_write(dev_priv, GPIO_NC_10_PAD, 0x00000004);	
	usleep_range(100000, 120000);	
	vlv_gpio_nc_write(dev_priv, GPIO_NC_11_PCONF0, 0x2000CC00);	
	vlv_gpio_nc_write(dev_priv, GPIO_NC_11_PAD, 0x00000004);
}
static int dollar_cove_init(void)
{
	pr_info("Dollar Cove: IC_TYPE 0x%02X\n", intel_mid_pmic_readb(0x03));
	dc_xpwr_pwrsrc_pdata();
	dc_xpwr_fg_pdata();
	dc_xpwr_chrg_pdata();
	return 0;
}
void auo_reset(struct intel_dsi_device *dsi)
{
    int val;
	DRM_DEBUG_KMS("\n");
	val = intel_mid_pmic_readb(0x12);
    val |= 1<<5;
	intel_mid_pmic_writeb(0x12, val);
    msleep(40);
}
static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
{
	struct crystalcove_gpio *cg = data;
	int pending;
	int gpio;

	pending = intel_mid_pmic_readb(GPIO0IRQ) & 0xff;
	pending |= (intel_mid_pmic_readb(GPIO1IRQ) & 0xff) << 8;
	intel_mid_pmic_writeb(GPIO0IRQ, pending & 0xff);
	intel_mid_pmic_writeb(GPIO1IRQ, (pending >> 8) & 0xff);
	local_irq_disable();
	for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
		if (pending & (1 << gpio)) {
			pr_err("crystalcove pin %d triggered\n", gpio);
			generic_handle_irq(cg->irq_base + gpio);
		}
	}
	local_irq_enable();
	return IRQ_HANDLED;
}
Ejemplo n.º 14
0
static int pmic_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
	int i;
	struct mfd_cell *cell_dev = i2c->dev.platform_data;

	mutex_init(&pmic->io_lock);
	mutex_init(&pmic->irq_lock);
	pmic->workqueue =
		create_singlethread_workqueue("crystal cove");
	INIT_WORK(&pmic->work, pmic_work);
	pmic->i2c = i2c;
	pmic->dev = &i2c->dev;
	pmic->irq = i2c->irq;
	pmic_irq_init();
	dev_info(&i2c->dev, "Crystal Cove: ID 0x%02X, VERSION 0x%02X\n",
		intel_mid_pmic_readb(CHIPID), intel_mid_pmic_readb(CHIPVER));
	for (i = 0; cell_dev[i].name != NULL; i++)
		;
	return mfd_add_devices(pmic->dev, -1, cell_dev, i,
			NULL, pmic->irq_base);
}
Ejemplo n.º 15
0
static irqreturn_t pmic_irq_thread(int irq, void *data)
{
	int i;
	int pending;

	mutex_lock(&pmic->irq_lock);
	intel_mid_pmic_writeb(MIRQLVL1, (u8)pmic->irq_mask);
	pending = intel_mid_pmic_readb(IRQLVL1) & (~pmic->irq_mask);
	for (i = 0; i < PMIC_IRQ_NUM; i++)
		if (pending & (1 << i))
			handle_nested_irq(pmic->irq_base + i);
	mutex_unlock(&pmic->irq_lock);
	return IRQ_HANDLED;
}
/**
* intel_pmic_reg_disable - To disable the regulator
* @rdev:    regulator_dev structure
* @return value :0 - Regulator disabling success
*		:nonzero - Regulator disabling failed
*/
static int intel_pmic_reg_disable(struct regulator_dev *rdev)
{
	struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
	int reg_value;

	reg_value = intel_mid_pmic_readb(pmic_info->pmic_reg);
	if (reg_value < 0) {
		dev_err(&rdev->dev,
			"intel_mid_pmic_readb returns error %08x\n", reg_value);
		return reg_value;
	}

	return intel_mid_pmic_writeb(pmic_info->pmic_reg,
				((reg_value | REG_CNT_ENBL) & REG_OFF));
}
static void auo_disable(struct intel_dsi_device *dsi)
{   
    struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
    int val = 0;
	DRM_DEBUG_KMS("\n");
	dsi_vc_dcs_write_0(intel_dsi, 0, 0x28);
	msleep(80);

	dsi_vc_dcs_write_0(intel_dsi, 0, 0x10);
	msleep(34);
	val = intel_mid_pmic_readb(0x12);
    val &= ~(1<<5);
	intel_mid_pmic_writeb(0x12, val);	

}
static int pmic_chrg_reg_readb(struct pmic_chrg_info *info, int reg)
{
    int ret, i;

    for (i = 0; i < RETRY_RW; i++) {
        ret = intel_mid_pmic_readb(reg);
        if (ret < 0) {
            dev_warn(&info->pdev->dev,
                     "failed to read reg 0x%x: %d\n", reg, ret);
            usleep_range(1000, 2000);
        } else
            break;
    }
    return ret;
}
/**
 * iio_crystalcove_gpadc_sample - do gpadc sample.
 * @indio_dev: industrial IO GPADC device handle
 * @ch: gpadc bit set of channels to sample, for example, set ch = (1<<0)|(1<<2)
 *	means you are going to sample both channel 0 and 2 at the same time.
 * @res:gpadc sampling result
 *
 * Returns 0 on success or an error code.
 *
 * This function may sleep.
 */
int iio_crystalcove_gpadc_sample(struct iio_dev *indio_dev,
				int ch, struct gpadc_result *res)
{
	struct gpadc_info *info = iio_priv(indio_dev);
	int i;
	int ret;
	int mask = 0;
	u8 th, tl;

	for (i = 0; i < GPADC_CH_NUM; i++) {
		if (ch & (1 << i))
			mask |= (1 << i);
	}
	mutex_lock(&info->lock);
	info->irq_pending = 0;
	intel_mid_pmic_setb(MANCONV0, (u8)mask);
	intel_mid_pmic_setb(MANCONV1, (u8)(mask >> 8));
	ret = wait_event_timeout(info->wait,
			((info->irq_pending & mask) == mask), HZ);
	if (ret == 0) {
		ret = -ETIMEDOUT;
		dev_err(info->dev, "sample timeout, return %d\n", ret);
		goto done;
	} else
		ret = 0;
	for (i = 0; i < GPADC_CH_NUM; i++) {
		if (ch & (1 << i)) {
			th = intel_mid_pmic_readb(gpadc_regmaps[i].rslth);
			tl = intel_mid_pmic_readb(gpadc_regmaps[i].rsltl);
			res->data[i] = ((th & 0x3) << 8) + tl;
		}
	}
done:
	mutex_unlock(&info->lock);
	return ret;
}
/**
* intel_pmic_reg_get_cntrl - To get the control of the regulator
* @rdev:    regulator_dev structure
* @return value :0  - success
*		:nonzero - Error
*/
static int intel_pmic_reg_initialize(u16 pmic_reg, u8 state)
{
	int reg_value;
	u8 val;

	reg_value = intel_mid_pmic_readb(pmic_reg);
	if (reg_value < 0)
		return reg_value;

	if (state)
		val = reg_value | REG_CNT_ENBL | REG_ON;
	else
		val = (reg_value & REG_OFF) | REG_CNT_ENBL;

	return intel_mid_pmic_writeb(pmic_reg, val);
}
static int pmic_fg_reg_readb(struct pmic_fg_info *info, int reg)
{
	int ret, i;

	for (i = 0; i < NR_RETRY_CNT; i++) {
		ret = intel_mid_pmic_readb(reg);
		if (ret == -EAGAIN || ret == -ETIMEDOUT)
			continue;
		else
			break;
	}
	if (ret < 0)
		dev_err(&info->pdev->dev, "pmic reg read err:%d\n", ret);

	return ret;
}
/**
* intel_pmic_reg_is_enabled - To check if the regulator is enabled
* @rdev:    regulator_dev structure
* @return value : 1 - Regulator is ON
*		:0 - Regulator is OFF
*		:< 0 - Error
*/
static int intel_pmic_reg_is_enabled(struct regulator_dev *rdev)
{
	struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
	int reg_value;

	reg_value = intel_mid_pmic_readb(pmic_info->pmic_reg);
	if (reg_value < 0) {
		dev_err(&rdev->dev,
			"intel_mid_pmic_readb returns error %08x\n", reg_value);
		return reg_value;
	}

	if (!(reg_value & REG_CNT_ENBL))
		return -EINVAL;

	return reg_value & REG_ENA_STATUS_MASK;
}
Ejemplo n.º 23
0
static int pmic_irq_init(void)
{
	int cur_irq;
	int ret;

	pmic->irq_mask = 0xff;
	intel_mid_pmic_writeb(MIRQLVL1, pmic->irq_mask);
	pmic->irq_mask = intel_mid_pmic_readb(MIRQLVL1);
	pmic->irq_base = irq_alloc_descs(VV_PMIC_IRQBASE, 0, PMIC_IRQ_NUM, 0);
	if (pmic->irq_base < 0) {
		dev_warn(pmic->dev, "Failed to allocate IRQs: %d\n",
			 pmic->irq_base);
		pmic->irq_base = 0;
		return -EINVAL;
	}

	/* Register them with genirq */
	for (cur_irq = pmic->irq_base;
	     cur_irq < PMIC_IRQ_NUM + pmic->irq_base;
	     cur_irq++) {
		irq_set_chip_data(cur_irq, pmic);
		irq_set_chip_and_handler(cur_irq, &pmic_irq_chip,
					 handle_edge_irq);
		irq_set_nested_thread(cur_irq, 1);
		irq_set_noprobe(cur_irq);
	}

	ret = request_threaded_irq(pmic->irq, pmic_irq_isr, pmic_irq_thread,
			IRQF_TRIGGER_RISING | IRQF_ONESHOT,
			"intel_mid_pmic", pmic);
	if (ret != 0) {
		dev_err(pmic->dev, "Failed to request IRQ %d: %d\n",
				pmic->irq, ret);
		return ret;
	}
	ret = enable_irq_wake(pmic->irq);
	if (ret != 0) {
		dev_warn(pmic->dev, "Can't enable PMIC IRQ as wake source: %d\n",
			 ret);
	}

	return 0;
}
/*
 * WA for BTY as simple VRF management
 */
int camera_set_pmic_power(enum camera_pmic_pin pin, bool flag)
{
	u8 reg_addr[CAMERA_POWER_NUM] = {VPROG_1P8V, VPROG_2P8V};
	u8 reg_value[2] = {VPROG_DISABLE, VPROG_ENABLE};
	int val;
	static DEFINE_MUTEX(mutex_power);
	int ret = 0;

	if (pin >= CAMERA_POWER_NUM)
		return -EINVAL;

	mutex_lock(&mutex_power);
	val = intel_mid_pmic_readb(reg_addr[pin]) & 0x3;

	if ((flag && (val == VPROG_DISABLE)) ||
		(!flag && (val == VPROG_ENABLE)))
		ret = intel_mid_pmic_writeb(reg_addr[pin], reg_value[flag]);

	mutex_unlock(&mutex_power);
	return ret;
}
/**
* intel_pmic_reg_getvoltage - Return the current voltage value in  uV
* @rdev:    regulator_dev structure
*  @return value : Returns the voltage value.
*/
static int intel_pmic_reg_getvoltage(struct regulator_dev *rdev)
{
	struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
	u8  vsel;
	int reg_value;

	reg_value = intel_mid_pmic_readb(pmic_info->pmic_reg);
	if (reg_value < 0) {
		dev_err(&rdev->dev,
			"intel_mid_pmic_readb returns error %08x\n", reg_value);
		return reg_value;
	}
	vsel = (reg_value & REG_VSEL_MASK) >> VSEL_SHIFT;
	if (vsel >= pmic_info->table_len) {
		dev_err(&rdev->dev, "vsel value is out of range\n");
		return -EINVAL;
	}
	dev_dbg(&rdev->dev, "Voltage value is %d mV\n",
		pmic_info->table[vsel]);
	return pmic_info->table[vsel] * 1000;
}
static irqreturn_t crystalcove_chgr_isr(int irq, void *data)
{
	struct chgr_info *info = data;
	int chgrirq;

	chgrirq = intel_mid_pmic_readb(CRYSTALCOVE_CHGRIRQ_REG);

	if (chgrirq < 0) {
		dev_err(&info->pdev->dev, "CHGRIRQ read failed\n");
		goto pmic_irq_fail;
	}

	dev_dbg(&info->pdev->dev, "crystalcove charger irq happens, chgrirq=%x\n", chgrirq);

/*--------------CHGRIRQ HANDLER--------------*/
	power_supply_changed(&info->psy_usb);


pmic_irq_fail:
	intel_mid_pmic_writeb(CRYSTALCOVE_CHGRIRQ_REG, chgrirq);

	return IRQ_HANDLED;
}
static int ov8865_power_ctrl(struct v4l2_subdev *sd, int flag)
{
	int ret = 0;
	int value = 0;

	ov8865_power_pins();
	if (flag) {
		if (!camera_vprog1_on) {
#ifdef CONFIG_CRYSTAL_COVE
			/* AVDD on First */
			value = intel_mid_pmic_readb(VPROG_3P3V);
			value = value | VPROG_ENABLE;
			OV8865_PLAT_LOG(1,"try to enable VPROG_3P3V: value=0x%x\n", value);
			ret = intel_mid_pmic_writeb(VPROG_3P3V, value);

			usleep_range(2000, 2100);
			/* power up sequence control via GPIO*/
			gpio_set_value(camera_avdd_en, 1);
			usleep_range(1000, 1500);
			/* DOVDD and DVDD On*/
			OV8865_PLAT_LOG(1,"try to enable VPROG_1P8V\n");
			ret = intel_mid_pmic_writeb(VPROG_1P8V, VPROG_ENABLE);
			if (ret)
				return ret;
			gpio_set_value(camera_reset, 1); /* reset is active low */
		      /* ov8865 reset pulse should be more than 2ms
		      */
		      usleep_range(3500, 4000);
			/* VCM 2P8 power on*/
			OV8865_PLAT_LOG(1,"try to enable VPROG_2P8V\n");
			ret = intel_mid_pmic_writeb(VPROG_2P8V, VPROG_ENABLE);
			if (ret)
				return ret;

		#if 0
			gpio_set_value(camera_power_down, 1);
			//gpio_set_value(camera_dovdd_en, 1);
			usleep_range(2500, 3500);
		#endif

			gpio_set_value(camera_dvdd_en, 1);
			gpio_set_value(camera_vcm_en, 1);
			usleep_range(1000, 1500);

			#elif defined(CONFIG_INTEL_SCU_IPC_UTIL)
			ret = intel_scu_ipc_msic_vprog1(1);
#else
			pr_err("ov8865 power is not set.\n");
#endif
			if (!ret) {
				/* ov8865 VDIG rise to XCLR release */
				usleep_range(1000, 1200);
				camera_vprog1_on = 1;
			}
			return ret;
		}
	} else {
		if (camera_vprog1_on) {
#ifdef CONFIG_CRYSTAL_COVE
			/* power down sequence control via GPIO*/
			gpio_set_value(camera_dvdd_en, 0);
			gpio_set_value(camera_vcm_en, 0);
			usleep_range(2500, 3500);
			//gpio_set_value(camera_power_down, 0);
			//gpio_set_value(camera_dovdd_en, 0);

			/* power down power rail*/
			ret = intel_mid_pmic_writeb(VPROG_2P8V, VPROG_DISABLE);
			if (ret)
				return ret;
			ret = intel_mid_pmic_writeb(VPROG_1P8V, VPROG_DISABLE);
			gpio_set_value(camera_reset, 0);
			gpio_set_value(camera_avdd_en, 0);

			
			/* WA: We don't know previous status of VPROG_3P3V
			 * So keep it ON here
			 */

#elif defined(CONFIG_INTEL_SCU_IPC_UTIL)
			ret = intel_scu_ipc_msic_vprog1(0);
#else
			pr_err("ov8865 power is not set.\n");
#endif
			if (!ret)
				camera_vprog1_on = 0;
			return ret;
		}
	}
	return ret;
}
static int crystal_cove_init(void)
{
	pr_info("Crystal Cove: ID 0x%02X, VERSION 0x%02X\n",
		intel_mid_pmic_readb(CHIPID), intel_mid_pmic_readb(CHIPVER));
	return 0;
}
static int dollar_cove_init(void)
{
	pr_info("Dollar Cove: IC_TYPE 0x%02X\n", intel_mid_pmic_readb(0x03));
	return 0;
}
static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
{
	u8 ctli = gpio < 8 ? GPIO0P0CTLI + gpio : GPIO1P0CTLI + (gpio - 8);

	return intel_mid_pmic_readb(ctli) & 0x1;
}