static int __devinit smb349_hwinit(struct smb349_struct *smb349_chg) { int ret; ret = smb349_write_reg(smb349_chg->client, CMD_A_REG, VOLATILE_W_PERM_BIT); if (ret) { pr_err("Failed to set VOLATILE_W_PERM_BIT rc=%d\n", ret); return ret; } ret = smb349_masked_write(smb349_chg->client, CHG_CTRL_REG, CURR_TERM_END_CHG_BIT, CURR_TERM_END_CHG_BIT); if (ret) { pr_err("Failed to set CURR_TERM_END_CHG_BIT rc=%d\n", ret); return ret; } ret = chg_current_set(smb349_chg); if (ret) { pr_err("Failed to set FAST_CHG_CURRENT rc=%d\n", ret); return ret; } return 0; }
static int set_reg(void *data, u64 val) { int addr = (int)data; int ret; u8 temp; temp = (u16) val; ret = smb349_write_reg(the_smb349_chg->client, addr, temp); if (ret) { pr_err("smb349_write_reg to %x value =%d errored = %d\n", addr, temp, ret); return -EAGAIN; } return 0; }
static int set_reg(void *data, u64 val) { struct smb349_charger *chip = data; int rc; u8 temp; temp = (u8) val; rc = smb349_write_reg(chip, chip->peek_poke_address, temp); if (rc < 0) { dev_err(chip->dev, "Couldn't write 0x%02x to 0x%02x rc= %d\n", chip->peek_poke_address, temp, rc); return -EAGAIN; } return 0; }
static int smb349_masked_write(struct i2c_client *client, int reg, u8 mask, u8 val) { s32 rc; u8 temp; rc = smb349_read_reg(client, reg, &temp); if (rc) { pr_err("smb349_read_reg failed: reg=%03X, rc=%d\n", reg, rc); return rc; } temp &= ~mask; temp |= val & mask; rc = smb349_write_reg(client, reg, temp); if (rc) { pr_err("smb349_write failed: reg=%03X, rc=%d\n", reg, rc); return rc; } return 0; }
static int smb349_masked_write(struct smb349_charger *chip, int reg, u8 mask, u8 val) { s32 rc; u8 temp; rc = smb349_read_reg(chip, reg, &temp); if (rc) { dev_err(chip->dev, "smb349_read_reg Failed: reg=%03X, rc=%d\n", reg, rc); return rc; } temp &= ~mask; temp |= val & mask; rc = smb349_write_reg(chip, reg, temp); if (rc) { dev_err(chip->dev, "smb349_write Failed: reg=%03X, rc=%d\n", reg, rc); return rc; } return 0; }
static int smb349_hw_init(struct smb349_charger *chip) { int rc; u8 reg = 0, mask = 0; /* * If the charger is pre-configured for autonomous operation, * do not apply additonal settings */ if (chip->chg_autonomous_mode) { dev_dbg(chip->dev, "Charger configured for autonomous mode\n"); return 0; } rc = smb349_read_reg(chip, CHG_REVISION_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read CHG_REVISION_REG rc=%d\n", rc); return rc; } /* * A4 silicon revision of SMB349 fails charger type detection * (apsd) due to interference on the D+/- lines by the USB phy. * Set the workaround flag to disable charger type reporting * for this revision. */ if ((reg & SMB349_REV_MASK) == SMB349_REV_A4) chip->workaround_flags |= WRKARND_APSD_FAIL; pr_debug("workaround_flags = %x\n", chip->workaround_flags); rc = smb349_enable_volatile_writes(chip); if (rc) { dev_err(chip->dev, "Couldn't configure volatile writes rc=%d\n", rc); return rc; } /* setup defaults for CHG_CNTRL_REG */ reg = CHG_CTRL_BATT_MISSING_DET_THERM_IO; mask = CHG_CTRL_BATT_MISSING_DET_MASK; rc = smb349_masked_write(chip, CHG_CTRL_REG, mask, reg); if (rc) { dev_err(chip->dev, "Couldn't set CHG_CTRL_REG rc=%d\n", rc); return rc; } /* setup defaults for PIN_CTRL_REG */ reg = CHG_PIN_CTRL_USBCS_REG_BIT | CHG_PIN_CTRL_CHG_EN_LOW_REG_BIT | CHG_PIN_CTRL_APSD_IRQ_BIT | CHG_PIN_CTRL_CHG_ERR_IRQ_BIT; mask = CHG_PIN_CTRL_CHG_EN_MASK | CHG_PIN_CTRL_USBCS_REG_MASK | CHG_PIN_CTRL_APSD_IRQ_MASK | CHG_PIN_CTRL_CHG_ERR_IRQ_MASK; rc = smb349_masked_write(chip, CHG_PIN_EN_CTRL_REG, mask, reg); if (rc) { dev_err(chip->dev, "Couldn't set CHG_PIN_EN_CTRL_REG rc=%d\n", rc); return rc; } /* setup USB 2.0/3.0 detection mechanism */ rc = smb349_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG, CHG_OTH_CTRL_USB_2_3_PIN_REG_MASK, CHG_OTH_CTRL_USB_2_3_REG_CTRL_BIT); if (rc) { dev_err(chip->dev, "Couldn't set USB_2_3_REG_CTRL_BIT rc=%d\n", rc); return rc; } /* setup USB suspend and APSD */ reg = VARIOUS_FUNC_USB_SUSP_EN_REG_BIT; if (!chip->disable_apsd) reg |= VARIOUS_FUNC_APSD_EN_BIT; mask = VARIOUS_FUNC_USB_SUSP_MASK | VARIOUS_FUNC_APSD_MASK; rc = smb349_masked_write(chip, VARIOUS_FUNC_REG, mask, reg); if (rc) { dev_err(chip->dev, "Couldn't set VARIOUS_FUNC_REG rc=%d\n", rc); return rc; } /* Fault and Status IRQ configuration */ reg = FAULT_INT_HOT_COLD_HARD_BIT | FAULT_INT_HOT_COLD_SOFT_BIT | FAULT_INT_INPUT_UV_BIT | FAULT_INT_AICL_COMPLETE_BIT; rc = smb349_write_reg(chip, FAULT_INT_REG, reg); if (rc) { dev_err(chip->dev, "Couldn't set FAULT_INT_REG rc=%d\n", rc); return rc; } reg = STATUS_INT_CHG_TIMEOUT_BIT | STATUS_INT_OTG_DETECT_BIT | STATUS_INT_BATT_OV_BIT | STATUS_INT_TERM_TAPER_BIT | STATUS_INT_FAST_CHG_BIT | STATUS_INT_LOW_BATT_BIT | STATUS_INT_MISSING_BATT_BIT; rc = smb349_write_reg(chip, STATUS_INT_REG, reg); if (rc) { dev_err(chip->dev, "Couldn't set STATUS_INT_REG rc=%d\n", rc); return rc; } /* setup THERM Monitor */ rc = smb349_masked_write(chip, THERM_A_CTRL_REG, THERM_A_THERM_MONITOR_EN_MASK, THERM_A_THERM_MONITOR_EN_BIT); if (rc) { dev_err(chip->dev, "Couldn't set THERM_A_CTRL_REG rc=%d\n", rc); return rc; } /* set the fast charge current limit */ rc = smb349_fastchg_current_set(chip); if (rc) { dev_err(chip->dev, "Couldn't set fastchg current rc=%d\n", rc); return rc; } /* set the float voltage */ if (chip->vfloat_mv != -EINVAL) { rc = smb349_float_voltage_set(chip, chip->vfloat_mv); if (rc < 0) { dev_err(chip->dev, "Couldn't set float voltage rc = %d\n", rc); return rc; } } /* set iterm */ if (chip->iterm_ma != -EINVAL) { if (chip->iterm_disabled) { dev_err(chip->dev, "Error: Both iterm_disabled and iterm_ma set\n"); return -EINVAL; } else { if (chip->iterm_ma <= 100) reg = CHG_ITERM_100MA; else if (chip->iterm_ma <= 200) reg = CHG_ITERM_200MA; else if (chip->iterm_ma <= 300) reg = CHG_ITERM_300MA; else if (chip->iterm_ma <= 400) reg = CHG_ITERM_400MA; else if (chip->iterm_ma <= 500) reg = CHG_ITERM_500MA; else if (chip->iterm_ma <= 600) reg = CHG_ITERM_600MA; else reg = CHG_ITERM_700MA; rc = smb349_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG, CHG_ITERM_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set iterm rc = %d\n", rc); return rc; } rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_CURR_TERM_END_MASK, 0); if (rc) { dev_err(chip->dev, "Couldn't enable iterm rc = %d\n", rc); return rc; } } } else if (chip->iterm_disabled) { rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_CURR_TERM_END_MASK, CHG_CTRL_CURR_TERM_END_MASK); if (rc) { dev_err(chip->dev, "Couldn't set iterm rc = %d\n", rc); return rc; } } /* set recharge-threshold */ if (chip->recharge_mv != -EINVAL) { if (chip->recharge_disabled) { dev_err(chip->dev, "Error: Both recharge_disabled and recharge_mv set\n"); return -EINVAL; } else { reg = 0; if (chip->recharge_mv > 50) reg = CHG_CTRL_RECHG_100MV_BIT; rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_RECHG_50_100_MASK | CHG_CTRL_AUTO_RECHARGE_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set rechg-cfg rc = %d\n", rc); return rc; } } } else if (chip->recharge_disabled) { rc = smb349_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_AUTO_RECHARGE_MASK, CHG_CTRL_AUTO_RECHARGE_MASK); if (rc) { dev_err(chip->dev, "Couldn't disable auto-rechg rc = %d\n", rc); return rc; } } /* enable/disable charging */ rc = smb349_masked_write(chip, CMD_A_REG, CMD_A_CHG_ENABLE_BIT, chip->charging_disabled ? 0 : CMD_A_CHG_ENABLE_BIT); if (rc) { dev_err(chip->dev, "Unable to %s charging. rc=%d\n", chip->charging_disabled ? "disable" : "enable", rc); } return rc; }