static int ncp6335d_set_mode(struct regulator_dev *rdev,
					unsigned int mode)
{
	int rc;
	struct ncp6335d_info *dd = rdev_get_drvdata(rdev);

	/* only FAST and NORMAL mode types are supported */
	if (mode != REGULATOR_MODE_FAST && mode != REGULATOR_MODE_NORMAL) {
		dev_err(dd->dev, "Mode %d not supported\n", mode);
		return -EINVAL;
	}

	rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND, dd->mode_bit,
			(mode == REGULATOR_MODE_FAST) ? dd->mode_bit : 0);
	if (rc) {
		dev_err(dd->dev, "Unable to set operating mode rc(%d)", rc);
		return rc;
	}

	rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND,
					NCP6335D_DVS_PWM_MODE,
					(mode == REGULATOR_MODE_FAST) ?
					NCP6335D_DVS_PWM_MODE : 0);
	if (rc)
		dev_err(dd->dev, "Unable to set DVS trans. mode rc(%d)", rc);


	dump_registers(dd, REG_NCP6335D_COMMAND, __func__);

	return rc;
}
static int ncp6335d_set_voltage(struct regulator_dev *rdev,
                                int min_uV, int max_uV, unsigned *selector)
{
    int rc, set_val, new_uV;
    struct ncp6335d_info *dd = rdev_get_drvdata(rdev);

    set_val = DIV_ROUND_UP(min_uV - dd->min_voltage, dd->step_size);
    new_uV = (set_val * dd->step_size) + dd->min_voltage;
    if (new_uV > max_uV) {
        dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
                min_uV, max_uV);
        return -EINVAL;
    }
#if 0
    rc = ncp6335x_update_bits(dd, dd->vsel_reg,
                              NCP6335D_VOUT_SEL_MASK, (set_val & NCP6335D_VOUT_SEL_MASK));
#else
    rc = ncp6335x_update_bits(dd, dd->vsel_reg,
                              0xFF, ((set_val & NCP6335D_VOUT_SEL_MASK)|0x80));

#endif

    if (rc) {
        dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
                min_uV, max_uV);
    } else {
        ncp633d_slew_delay(dd, dd->curr_voltage, new_uV);
        dd->curr_voltage = new_uV;
    }

    dump_registers(dd, dd->vsel_reg, __func__);

    return rc;
}
static int ncp6335d_set_voltage(struct regulator_dev *rdev,
			int min_uV, int max_uV, unsigned *selector)
{
	int rc, set_val, new_uV;
	struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
	//<oliver 20150716>++ modify ncp output voltage for stability
	static enum msm_cpu cur_cpu; //static variable constraint to this file
	static char* buf = "0.0";

	cur_cpu = socinfo_get_msm_cpu();
	buf = OLIVER_socinfo_get_msm_cpu_revision();
	set_val = DIV_ROUND_UP(min_uV - dd->min_voltage, dd->step_size);
	if (!strncmp("3.0",buf,3)) {
		//printk("OLIVER 3.0 found\n");
	} else if ((MSM_CPU_8939 == cur_cpu)&&(asus_PRJ_ID == ASUS_ZE550KL)){
		if (!strncmp("3",asus_project_stage,2)||!strncmp("1",asus_project_stage,2)) {
			if (set_val < 80)
				set_val = set_val + 5;
			else if (set_val < 120) {
				set_val = set_val + 4;
				if (set_val > 120)
					set_val = 120;
			}

		}else {
			if (set_val < 80) {
				set_val = set_val + 4;
				if (set_val > 80)
					set_val = 80;
			}
		}
	}
	//<oliver 20150716>--
	new_uV = (set_val * dd->step_size) + dd->min_voltage;
	if (new_uV > max_uV) {
		dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
							min_uV, max_uV);
		return -EINVAL;
	}

	rc = ncp6335x_update_bits(dd, dd->vsel_reg,
		NCP6335D_VOUT_SEL_MASK, (set_val & NCP6335D_VOUT_SEL_MASK));
	if (rc) {
		dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
							min_uV, max_uV);
	} else {
		ncp633d_slew_delay(dd, dd->curr_voltage, new_uV);
		dd->curr_voltage = new_uV;
	}

	dump_registers(dd, dd->vsel_reg, __func__);

	return rc;
}
static int ncp6335d_restore_working_reg(struct device_node *node,
                                        struct ncp6335d_info *dd)
{
    int ret;
    unsigned int val1;
    unsigned int val2;
    unsigned int val3;

    /* Restore register from back up register */
    ret = ncp6335x_read(dd, dd->vsel_backup_reg, &val1);
    dev_err(dd->dev, "%s: khl NCP6335D: Reg_back1= %x, Val = %x\n", __func__, dd->vsel_backup_reg, val1);

    if (ret < 0) {
        dev_err(dd->dev, "Failed to get backup data from reg %d, ret = %d\n",
                dd->vsel_backup_reg, ret);
        return ret;
    }
    ret = ncp6335x_read(dd, dd->vsel_reg, &val2);
    dev_err(dd->dev, "%s: khl NCP6335D: Reg_back2= %x, Val = %x\n", __func__, dd->vsel_reg, val2);

#if 0
    ret = ncp6335x_update_bits(dd, dd->vsel_reg,
                               NCP6335D_VOUT_SEL_MASK, val);
#else
    ret = ncp6335x_update_bits(dd, dd->vsel_reg,
                               0xFF, (val1 |0x80));
    ret = ncp6335x_read(dd, dd->vsel_reg, &val3);

    dev_err(dd->dev, "%s: khl NCP6335D: Reg_back3= %x, Val = %x\n", __func__, dd->vsel_reg, val3);

#endif

    if (ret < 0) {
        dev_err(dd->dev, "Failed to update working reg %d, ret = %d\n",
                dd->vsel_reg,  ret);
        return ret;
    }


    return ret;
}
static int ncp6335d_disable(struct regulator_dev *rdev)
{
	int rc;
	struct ncp6335d_info *dd = rdev_get_drvdata(rdev);

	rc = ncp6335x_update_bits(dd, dd->vsel_reg,
					NCP6335D_ENABLE, 0);
	if (rc)
		dev_err(dd->dev, "Unable to disable regualtor rc(%d)", rc);

	dump_registers(dd, dd->vsel_reg, __func__);

	return rc;
}
static int ncp6335d_set_voltage(struct regulator_dev *rdev,
			int min_uV, int max_uV, unsigned *selector)
{
	int rc = 0, set_val, new_uV;
	struct ncp6335d_info *dd = rdev_get_drvdata(rdev);


	set_val = DIV_ROUND_UP(min_uV - dd->min_voltage, dd->step_size);
	new_uV = (set_val * dd->step_size) + dd->min_voltage;
	if (new_uV > max_uV) {
		dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
							min_uV, max_uV);
		return -EINVAL;
	}

	mutex_lock(&dd->ncp_mutex);
	if (dd->is_suspend) {
		dev_info(dd->dev, "Ignore voltage setting after suspend: %d\n",
			new_uV);
			goto out;
	}
	rc = ncp6335x_update_bits(dd, dd->vsel_reg,
		NCP6335D_VOUT_SEL_MASK, (set_val & NCP6335D_VOUT_SEL_MASK));
	if (rc) {
		dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
							min_uV, max_uV);
	} else {
		ncp633d_slew_delay(dd, dd->curr_voltage, new_uV);
		dd->curr_voltage = new_uV;
	}

	dump_registers(dd, dd->vsel_reg, __func__);

out:
	mutex_unlock(&dd->ncp_mutex);
	return rc;
}
static int ncp6335d_restore_working_reg(struct device_node *node,
					struct ncp6335d_info *dd)
{
	int ret;
	unsigned int val;

	/* Restore register from back up register */
	ret = ncp6335x_read(dd, dd->vsel_backup_reg, &val);
	if (ret < 0) {
		dev_err(dd->dev, "Failed to get backup data from reg %d, ret = %d\n",
			dd->vsel_backup_reg, ret);
		return ret;
	}

	ret = ncp6335x_update_bits(dd, dd->vsel_reg,
					NCP6335D_VOUT_SEL_MASK, val);
	if (ret < 0) {
		dev_err(dd->dev, "Failed to update working reg %d, ret = %d\n",
			dd->vsel_reg,  ret);
		return ret;
	}

	return ret;
}
static int ncp6335d_init(struct i2c_client *client, struct ncp6335d_info *dd,
			const struct ncp6335d_platform_data *pdata)
{
	int rc;
	unsigned int val;

	switch (pdata->default_vsel) {
	case NCP6335D_VSEL0:
		dd->vsel_reg = REG_NCP6335D_PROGVSEL0;
		dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL1;
		dd->mode_bit = NCP6335D_PWM_MODE0;
	break;
	case NCP6335D_VSEL1:
		dd->vsel_reg = REG_NCP6335D_PROGVSEL1;
		dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL0;
		dd->mode_bit = NCP6335D_PWM_MODE1;
	break;
	default:
		dev_err(dd->dev, "Invalid VSEL ID %d\n", pdata->default_vsel);
		return -EINVAL;
	}

	if (of_property_read_bool(client->dev.of_node, "onnn,restore-reg")) {
		rc = ncp6335d_restore_working_reg(client->dev.of_node, dd);
		if (rc)
			return rc;
	}

	rc = ncp6335d_parse_gpio(client->dev.of_node, dd);
	if (rc)
		return rc;

	/* get the current programmed voltage */
	rc = ncp6335x_read(dd, dd->vsel_reg, &val);
	if (rc) {
		dev_err(dd->dev, "Unable to get volatge rc(%d)", rc);
		return rc;
	}
	dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) *
				dd->step_size) + dd->min_voltage;

	/* set discharge */
	rc = ncp6335x_update_bits(dd, REG_NCP6335D_PGOOD,
					NCP6335D_PGOOD_DISCHG,
					(pdata->discharge_enable ?
					NCP6335D_PGOOD_DISCHG : 0));
	if (rc) {
		dev_err(dd->dev, "Unable to set Active Discharge rc(%d)\n", rc);
		return -EINVAL;
	}

	/* set slew rate */
	if (pdata->slew_rate_ns < dd->min_slew_ns ||
			pdata->slew_rate_ns > dd->max_slew_ns) {
		dev_err(dd->dev, "Invalid slew rate %d\n", pdata->slew_rate_ns);
		return -EINVAL;
	}

	dd->slew_rate = pdata->slew_rate_ns;
	val = DIV_ROUND_UP(pdata->slew_rate_ns, dd->min_slew_ns);
	val = ilog2(val);

	rc = ncp6335x_update_bits(dd, REG_NCP6335D_TIMING,
			NCP6335D_SLEW_MASK, val << NCP6335D_SLEW_SHIFT);
	if (rc)
		dev_err(dd->dev, "Unable to set slew rate rc(%d)\n", rc);

	/* Set Sleep mode bit */
	rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND,
				NCP6335D_SLEEP_MODE, pdata->sleep_enable ?
						NCP6335D_SLEEP_MODE : 0);
	if (rc)
		dev_err(dd->dev, "Unable to set sleep mode (%d)\n", rc);

	dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
	dump_registers(dd, REG_NCP6335D_PROGVSEL0, __func__);
	dump_registers(dd, REG_NCP6335D_TIMING, __func__);
	dump_registers(dd, REG_NCP6335D_PGOOD, __func__);

	return rc;
}