static irqreturn_t pm8058_chg_chgval_handler(int irq, void *dev_id)
{
    u8 old, temp;
    int ret;

    if (!is_chg_plugged_in()) {	/*this debounces it */
        ret = pm8058_read(pm8058_chg.pm_chip, PM8058_OVP_TEST_REG,
                          &old, 1);
        temp = old | BIT(FORCE_OVP_OFF);
        ret = pm8058_write(pm8058_chg.pm_chip, PM8058_OVP_TEST_REG,
                           &temp, 1);
        temp = 0xFC;
        ret = pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST,
                           &temp, 1);
        pr_debug("%s forced wrote 0xFC to test ret=%d\n",
                 __func__, ret);
        /* 20 ms sleep is for the VCHG to discharge */
        msleep(20);
        temp = 0xF0;
        ret = pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST,
                           &temp, 1);
        ret = pm8058_write(pm8058_chg.pm_chip, PM8058_OVP_TEST_REG,
                           &old, 1);
    }

    return IRQ_HANDLED;
}
int pm8058_reset_pwr_off(int reset)
{
	int rc;
	uint8_t pon, ctrl, smpl;

	/* Set regulator L22 to 1.225V in high power mode. */
	rc = pm8058_read(SSBI_REG_ADDR_L22_CTRL, &ctrl, 1);
	if (rc) {
		goto get_out3;
	}
	/* Leave pull-down state intact. */
	ctrl &= 0x40;
	ctrl |= 0x93;

	rc = pm8058_write(SSBI_REG_ADDR_L22_CTRL, &ctrl, 1);
	if (rc) {
	}

get_out3:
	if (!reset) {
		/* Only modify the SLEEP_CNTL reg if shutdown is desired. */
		rc = pm8058_read(SSBI_REG_ADDR_SLEEP_CNTL, &smpl, 1);
		if (rc) {
			goto get_out2;
		}

		smpl &= ~PM8058_SLEEP_SMPL_EN_MASK;
		smpl |= PM8058_SLEEP_SMPL_EN_PWR_OFF;

		rc = pm8058_write(SSBI_REG_ADDR_SLEEP_CNTL, &smpl, 1);
		if (rc)
		{
		}
	}

get_out2:
	rc = pm8058_read(SSBI_REG_ADDR_PON_CNTL_1, &pon, 1);
	if (rc) {
		goto get_out;
	}

	pon &= ~PM8058_PON_WD_EN_MASK;
	pon |= reset ? PM8058_PON_WD_EN_RESET : PM8058_PON_WD_EN_PWR_OFF;

	/* Enable all pullups */
	pon |= PM8058_PON_PUP_MASK;

	rc = pm8058_write(SSBI_REG_ADDR_PON_CNTL_1, &pon, 1);
	if (rc) {
		goto get_out;
	}

get_out:
	return rc;
}
static int pm8058_init_regulator(struct pm8058_chip *chip,
		struct pm8058_vreg *vreg)
{
	int rc = 0, i;
	u8 bank;

	/* save the current control register state */
	rc = pm8058_read(chip, vreg->ctrl_addr, &vreg->ctrl_reg, 1);
	if (rc)
		return rc;

	/* save the current test/test2 register state */
	if (vreg->type == REGULATOR_TYPE_LDO) {
		for (i = 0; i < LDO_TEST_BANKS; i++) {
			bank = REGULATOR_BANK_SEL(i);
			rc = pm8058_write(chip, vreg->test_addr,
					&bank, 1);
			if (rc)
				goto bail;

			rc = pm8058_read(chip, vreg->test_addr,
					&vreg->test_reg[i], 1);
			if (rc)
				goto bail;
		}
	} else if (vreg->type == REGULATOR_TYPE_SMPS) {
		for (i = 0; i < SMPS_TEST_BANKS; i++) {
			bank = REGULATOR_BANK_SEL(i);
			rc = pm8058_write(chip, vreg->test2_addr,
					&bank, 1);
			if (rc)
				goto bail;

			rc = pm8058_read(chip, vreg->test2_addr,
					&vreg->test2_reg[i], 1);
			if (rc)
				goto bail;
		}

		rc = pm8058_read(chip, vreg->clk_ctrl_addr,
				&vreg->clk_ctrl_reg, 1);
		if (rc)
			goto bail;
	}

bail:
	if (rc)
		pr_err("%s: pm8058_read/write failed\n", __func__);

	return rc;
}
static int pm8058_usb_voltage_lower_limit(void)
{
    u8 temp, old;
    int ret = 0;

    temp = 0x10;
    ret |= pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST, &temp, 1);
    ret |= pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TEST, &old, 1);
    old = old & ~BIT(IGNORE_LL);
    temp = 0x90  | (0xF & old);
    pr_debug("%s writing 0x%x to test\n", __func__, temp);
    ret |= pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST, &temp, 1);

    return ret;
}
/*
 * The API pm8058_micbias_enable() allows to configure
 * the MIC_BIAS. Only the lines which are not used for
 * headset detection can be configured using this API.
 * The API returns an error code if it fails to configure
 * the specified MIC_BIAS line, else it returns 0.
 */
int pm8058_micbias_enable(enum othc_micbias micbias,
		enum othc_micbias_enable enable)
{
	int rc;
	u8 reg;
	struct pm8058_othc *dd = config[micbias];

	if (dd == NULL) {
		pr_err("MIC_BIAS not registered, cannot enable\n");
		return -ENODEV;
	}

	if (dd->othc_pdata->micbias_capability != OTHC_MICBIAS) {
		pr_err("MIC_BIAS enable capability not supported\n");
		return -EINVAL;
	}

	rc = pm8058_read(dd->pm_chip, dd->othc_base + 1, &reg, 1);
	if (rc < 0) {
		pr_err("PM8058 read failed\n");
		return rc;
	}

	reg &= PM8058_OTHC_EN_SIG_MASK;
	reg |= (enable << PM8058_OTHC_EN_SIG_SHIFT);

	rc = pm8058_write(dd->pm_chip, dd->othc_base + 1, &reg, 1);
	if (rc < 0) {
		pr_err("PM8058 write failed\n");
		return rc;
	}

	return rc;
}
Exemple #6
0
static int pm8058_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
{
	int	rc;
	u8	reg;

	if (start) {
		reg = pwm->pwm_ctl[0] | PM8058_PWM_PWM_START;
		if (ramp_start)
			reg |= PM8058_PWM_RAMP_GEN_START;
		else
			reg &= ~PM8058_PWM_RAMP_GEN_START;
	} else {
		reg = pwm->pwm_ctl[0] & ~PM8058_PWM_PWM_START;
		reg &= ~PM8058_PWM_RAMP_GEN_START;
	}

	rc = pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_CTL(0),
			  &reg, 1);
	if (rc)
		pr_err("%s: pm8058_write(): rc=%d (Enable PWM Ctl 0)\n",
		       __func__, rc);
	else
		pwm->pwm_ctl[0] = reg;
	return rc;
}
Exemple #7
0
/* Internal functions */
static int pm8058_pwm_bank_enable(struct pwm_device *pwm, int enable)
{
    int	rc;
    u8	reg;
    struct pm8058_pwm_chip	*chip;

    chip = pwm->chip;

    if (enable)
        reg = chip->bank_mask | (1 << pwm->pwm_id);
    else
        reg = chip->bank_mask & ~(1 << pwm->pwm_id);
#ifdef CONFIG_MSM_SSBI
    rc = pm8058_writeb(pwm_chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_EN, reg);
#else
    rc = pm8058_write(chip->pm_chip, SSBI_REG_ADDR_LPG_BANK_EN, &reg, 1);
#endif
    if (rc) {
        pr_err("%s: pm8058_write(): rc=%d (Enable LPG Bank)\n",
               __func__, rc);
        goto bail_out;
    }
    chip->bank_mask = reg;

bail_out:
    return rc;
}
static inline int pm8058_tm_write_ctrl(struct pm8058_chip *chip, u8 reg)
{
	int rc;

	rc = pm8058_write(chip, SSBI_REG_TEMP_ALRM_CTRL, &reg, 1);
	if (rc)
		pr_err("%s: pm8058_write FAIL: rc=%d\n", __func__, rc);

	return rc;
}
Exemple #9
0
static int pmic8058_kp_write_u8(struct pmic8058_kp *kp,
				 u8 data, u16 reg)
{
	int rc;

	rc = pm8058_write(kp->pm_chip, reg, &data, 1);
	if (rc < 0)
		dev_warn(kp->dev, "Error writing pmic8058: %X - ret %X\n",
				reg, rc);
	return rc;
}
static int pm8058_pwm_bank_sel(struct pwm_device *pwm)
{
	int	rc;
	u8	reg;

	reg = pwm->pwm_id;
	rc = pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_BANK_SEL,
			     &reg, 1);
	if (rc)
		pr_err("pm8058_write(): rc=%d (Select PWM Bank)\n", rc);
	return rc;
}
static int pm8058_vreg_write(struct pm8058_chip *chip,
		u16 addr, u8 val, u8 mask, u8 *reg_save)
{
	int rc;
	u8 reg;

	reg = (*reg_save & ~mask) | (val & mask);
	rc = pm8058_write(chip, addr, &reg, 1);
	if (rc)
		pr_err("%s: pm8058_write failed\n", __func__);
	else
		*reg_save = reg;
	return rc;
}
Exemple #12
0
int pm8058_mwrite(uint16_t addr, uint8_t val, uint8_t mask,
				uint8_t *reg_save)
{
	int rc = 0;
	uint8_t reg;

	reg = (*reg_save & ~mask) | (val & mask);
	if (reg != *reg_save)
		rc = pm8058_write(addr, &reg, 1);
	if (rc)
		dprintf(CRITICAL,"pm8058_write failed; addr=%03X, rc=%d\n", addr, rc);
	else
		*reg_save = reg;
	return rc;
}
Exemple #13
0
static int pm8058_reg_write(struct pm8058_chip *chip, u16 addr, u8 val, u8 mask,
			    u8 *reg_save)
{
	int rc = 0;
	u8 reg;

	reg = (*reg_save & ~mask) | (val & mask);
	if (reg != *reg_save)
		rc = pm8058_write(chip, addr, &reg, 1);
	if (rc)
		pr_err("pm8058_write failed; addr=%03X, rc=%d\n", addr, rc);
	else
		*reg_save = reg;
	return rc;
}
Exemple #14
0
static int pm8058_pwm_bank_sel(struct pwm_device *pwm)
{
    int	rc;
    u8	reg;
    /*pr_notice("%s: 1\n", __func__);*/
    reg = pwm->pwm_id;
#ifdef CONFIG_MSM_SSBI
    rc = pm8058_writeb(pwm_chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_SEL, reg);
#else
    rc = pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_BANK_SEL,
                      &reg, 1);
#endif
    if (rc)
        pr_err("%s: pm8058_write(): rc=%d (Select PWM Bank)\n",
               __func__, rc);
    return rc;
}
Exemple #15
0
int pm8058_rtc0_alarm_irq_disable(void)
{
	int rc;
	uint8_t reg;

	rc = pm8058_read(PM8058_RTC_CTRL, &reg, 1);
	if (rc)
	{
		return rc;
	}
	reg = (reg & ~PM8058_RTC_ALARM_ENABLE);

	rc = pm8058_write(PM8058_RTC_CTRL, &reg, 1);
	if (rc) {
		return rc;
	}

	return rc;
}
Exemple #16
0
static int data_set(void *data, u64 val)
{
	struct pm8058_dbg_device *dbgdev = data;
	u8 reg = val;
	int rc;

	mutex_lock(&dbgdev->dbg_mutex);

	rc = check_addr(dbgdev->addr, __func__);
	if (rc)
		goto done;

	rc = pm8058_write(dbgdev->pm_chip, dbgdev->addr, &reg, 1);

	if (rc)
		pr_err("%s: FAIL pm8058_write(0x%03X)=0x%02X: rc=%d\n",
			__func__, dbgdev->addr, reg, rc);
done:
	mutex_unlock(&dbgdev->dbg_mutex);
	return rc;
}
int pm8058_mpp_config(unsigned mpp, unsigned type, unsigned level,
		      unsigned control)
{
	u8	config;
	int	rc;
	struct pm8058_chip *pm_chip;

	if (mpp >= PM8058_MPPS)
		return -EINVAL;

	pm_chip = dev_get_drvdata(pm8058_mpp_chip.chip.dev);

	config = (type << PM8058_MPP_TYPE_SHIFT) & PM8058_MPP_TYPE_MASK;
	config |= (level << PM8058_MPP_CONFIG_LVL_SHIFT) &
			PM8058_MPP_CONFIG_LVL_MASK;
	config |= control & PM8058_MPP_CONFIG_CTL_MASK;

	rc = pm8058_write(pm_chip, SSBI_MPP_CNTRL(mpp), &config, 1);
	if (rc)
		pr_err("%s: pm8058_write(): rc=%d\n", __func__, rc);

	return rc;
}
/* Internal functions */
static int pm8058_pwm_bank_enable(struct pwm_device *pwm, int enable)
{
	int	rc;
	u8	reg;
	struct pm8058_pwm_chip	*chip;

	chip = pwm->chip;

	if (enable)
		reg = chip->bank_mask | (1 << pwm->pwm_id);
	else
		reg = chip->bank_mask & ~(1 << pwm->pwm_id);

	rc = pm8058_write(chip->pm_chip, SSBI_REG_ADDR_LPG_BANK_EN, &reg, 1);
	if (rc) {
		pr_err("pm8058_write(): rc=%d (Enable LPG Bank)\n", rc);
		goto bail_out;
	}
	chip->bank_mask = reg;

bail_out:
	return rc;
}
Exemple #19
0
static int pm8058_configure_othc(struct pm8058_othc *dd)
{
	int rc;
	u8 reg, value;
	u32 value1;
	u16 base_addr = dd->othc_base;
	struct othc_hsed_config *hsed_config = dd->othc_pdata->hsed_config;

	/* Intialize the OTHC module */
	/* Control Register 1*/
	rc = pm8058_read(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* set iDAC high current threshold */
	value = (hsed_config->othc_highcurr_thresh_uA / 100) - 2;
	reg =  (reg & PM8058_OTHC_HIGH_CURR_MASK) | value;

	rc = pm8058_write(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 2*/
	rc = pm8058_read(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = dd->othc_pdata->micbias_enable;
	reg &= PM8058_OTHC_EN_SIG_MASK;
	reg |= (value << PM8058_OTHC_EN_SIG_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_hyst_prediv_us << 10) / USEC_PER_SEC;
	while (value1 != 0) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 7) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_PREDIV_MASK;
	reg |= (value << PM8058_OTHC_HYST_PREDIV_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_period_clkdiv_us << 10) / USEC_PER_SEC;
	while (value1 != 1) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 8) {
		pr_err("%s: Invalid input argument - othc_period_clkdiv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg &  PM8058_OTHC_CLK_PREDIV_MASK) | (value - 1);

	rc = pm8058_write(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 3 */
	rc = pm8058_read(dd->pm_chip, base_addr + 2 , &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = hsed_config->othc_hyst_clk_us /
					hsed_config->othc_hyst_prediv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_CLK_MASK;
	reg |= value << PM8058_OTHC_HYST_CLK_SHIFT;

	value = hsed_config->othc_period_clk_us /
					hsed_config->othc_period_clkdiv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg & PM8058_OTHC_PERIOD_CLK_MASK) | value;

	rc = pm8058_write(dd->pm_chip, base_addr + 2, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Configure the ADC if n_switch_headset is supported */
	if (dd->othc_support_n_switch == true) {
		rc = adc_channel_open(dd->switch_config->adc_channel,
							&dd->adc_handle);
		if (rc) {
			pr_err("%s: Unable to open ADC channel\n", __func__);
			return -ENODEV;
		}
		pr_debug("%s: ADC channel open SUCCESS\n", __func__);
	}

	return 0;
}
static int pmic8058_write_u8(u8 data, u16 reg)
{
	return pm8058_write(reg, &data, 1);
}
static int pm8058_configure_othc(struct pm8058_othc *dd)
{
	int rc;
	u8 reg, value;
	u32 value1;
	u16 base_addr = dd->othc_base;
	struct othc_hsed_config *hsed_config = dd->othc_pdata->hsed_config;

	/* Intialize the OTHC module */
	/* Control Register 1*/
	rc = pm8058_read(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	if (hsed_config->othc_headset == OTHC_HEADSET_NO) {
		/* set iDAC high current threshold */
		value = (hsed_config->othc_highcurr_thresh_uA / 100) - 2;
		reg =  (reg & PM8058_OTHC_HIGH_CURR_MASK) | value;
	} else {
		/* set iDAC low current threshold */
		value = (hsed_config->othc_lowcurr_thresh_uA / 10) - 1;
		reg &= PM8058_OTHC_LOW_CURR_MASK;
		reg |= (value << PM8058_OTHC_LOW_CURR_SHIFT);
	}

	rc = pm8058_write(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 2*/
	rc = pm8058_read(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = dd->othc_pdata->micbias_enable;
	reg &= PM8058_OTHC_EN_SIG_MASK;
	reg |= (value << PM8058_OTHC_EN_SIG_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_hyst_prediv_us << 10) / USEC_PER_SEC;
	while (value1 != 0) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 7) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_PREDIV_MASK;
	reg |= (value << PM8058_OTHC_HYST_PREDIV_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_period_clkdiv_us << 10) / USEC_PER_SEC;
	while (value1 != 1) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 8) {
		pr_err("%s: Invalid input argument - othc_period_clkdiv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg &  PM8058_OTHC_CLK_PREDIV_MASK) | (value - 1);

	rc = pm8058_write(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 3 */
	rc = pm8058_read(dd->pm_chip, base_addr + 2 , &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = hsed_config->othc_hyst_clk_us /
					hsed_config->othc_hyst_prediv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_CLK_MASK;
	reg |= value << PM8058_OTHC_HYST_CLK_SHIFT;

	value = hsed_config->othc_period_clk_us /
					hsed_config->othc_period_clkdiv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg & PM8058_OTHC_PERIOD_CLK_MASK) | value;

	rc = pm8058_write(dd->pm_chip, base_addr + 2, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	return 0;
}