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, ®, 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, ®, 1); if (rc < 0) { pr_err("PM8058 write failed\n"); return rc; } return rc; }
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), ®, 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; }
/* 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, ®, 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, ®, 1); if (rc) pr_err("%s: pm8058_write FAIL: rc=%d\n", __func__, rc); return rc; }
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, ®, 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, ®, 1); if (rc) pr_err("%s: pm8058_write failed\n", __func__); else *reg_save = reg; return rc; }
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, ®, 1); if (rc) dprintf(CRITICAL,"pm8058_write failed; addr=%03X, rc=%d\n", addr, rc); else *reg_save = reg; return rc; }
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, ®, 1); if (rc) pr_err("pm8058_write failed; addr=%03X, rc=%d\n", addr, rc); else *reg_save = reg; return rc; }
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, ®, 1); #endif if (rc) pr_err("%s: pm8058_write(): rc=%d (Select PWM Bank)\n", __func__, rc); return rc; }
int pm8058_rtc0_alarm_irq_disable(void) { int rc; uint8_t reg; rc = pm8058_read(PM8058_RTC_CTRL, ®, 1); if (rc) { return rc; } reg = (reg & ~PM8058_RTC_ALARM_ENABLE); rc = pm8058_write(PM8058_RTC_CTRL, ®, 1); if (rc) { return rc; } return rc; }
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, ®, 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, ®, 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; }
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, ®, 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, ®, 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, ®, 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, ®, 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 , ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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 , ®, 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, ®, 1); if (rc < 0) { pr_err("%s: PM8058 read failed \n", __func__); return rc; } return 0; }