int smb358_get_charging_status(struct opchg_charger *chip) { int rc; u8 reg = 0; rc = opchg_read_reg(chip, STATUS_C_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read STAT_C rc = %d\n", rc); return 0; } return (reg & STATUS_C_CHG_ENABLE_STATUS_BIT) ? 1 : 0; }
int smb358_get_otg_regulator_is_enable(struct regulator_dev *rdev) { int rc = 0; u8 reg = 0; struct opchg_charger *chip = rdev_get_drvdata(rdev); rc = opchg_read_reg(chip, CMD_A_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read OTG enable bit rc=%d\n", rc); return rc; } return (reg & CMD_A_OTG_ENABLE_BIT) ? 1 : 0; }
int smb358_get_initial_state(struct opchg_charger *chip) { int rc; u8 reg = 0; rc = opchg_read_reg(chip, IRQ_B_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read IRQ_B rc = %d\n", rc); goto fail_init_status; } /* Use PMIC BTM way to detect battery exist */ rc = opchg_read_reg(chip, IRQ_C_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read IRQ_C rc = %d\n", rc); goto fail_init_status; } chip->batt_full = (reg & IRQ_C_TERM_BIT) ? true : false; rc = opchg_read_reg(chip, IRQ_E_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read IRQ_E rc = %d\n", rc); goto fail_init_status; } if (reg & IRQ_E_INPUT_UV_BIT) { smb358_chg_uv(chip, 1); } else { smb358_chg_uv(chip, 0); } return 0; fail_init_status: dev_err(chip->dev, "Couldn't determine intial status\n"); return rc; }
void smb358_dump_regs(struct opchg_charger *chip) { int rc; u8 reg, addr; // read config register for (addr = 0; addr <= SMB358_LAST_CNFG_REG; addr++) { rc = opchg_read_reg(chip, addr, ®); if (rc) { dev_err(chip->dev, "Couldn't read 0x%02x rc = %d\n", addr, rc); } else { pr_debug("smb358_read_reg 0x%02x = 0x%02x\n", addr, reg); } } // read status register for (addr = SMB358_FIRST_STATUS_REG; addr <= SMB358_LAST_STATUS_REG; addr++) { rc = opchg_read_reg(chip, addr, ®); if (rc) { dev_err(chip->dev, "Couldn't read 0x%02x rc = %d\n", addr, rc); } else { pr_debug("smb358_read_reg 0x%02x = 0x%02x\n", addr, reg); } } // read command register for (addr = SMB358_FIRST_CMD_REG; addr <= SMB358_LAST_CMD_REG; addr++) { rc = opchg_read_reg(chip, addr, ®); if (rc) { dev_err(chip->dev, "Couldn't read 0x%02x rc = %d\n", addr, rc); } else { pr_debug("smb358_read_reg 0x%02x = 0x%02x\n", addr, reg); } } }
static int get_reg(void *data, u64 *val) { struct opchg_charger *chip = data; int rc; u8 temp; rc = opchg_read_reg(chip, chip->peek_poke_address, &temp); if (rc < 0) { dev_err(chip->dev, "Couldn't read reg %x rc = %d\n", chip->peek_poke_address, rc); return -EAGAIN; } *val = temp; return 0; }
static int show_status_regs(struct seq_file *m, void *data) { struct opchg_charger *chip = m->private; int rc; u8 reg; u8 addr; for (addr = FIRST_STATUS_REG; addr <= LAST_STATUS_REG; addr++) { rc = opchg_read_reg(chip, addr, ®); if (!rc) { seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); } } return 0; }
int smb358_get_otg_enable(void) { int rc = 0; u8 reg = 0; if(opchg_chip == NULL) { return rc; } rc = opchg_read_reg(opchg_chip, CMD_A_REG, ®); if (rc) { pr_debug("Couldn't read OTG enable bit rc=%d\n", rc); } else { pr_debug("smb358_get_otg_enable read OTG enable bit =%d\n", reg); } return rc; }
int smb358_get_prop_batt_status(struct opchg_charger *chip) { int rc; u8 reg = 0; rc = opchg_read_reg(chip, STATUS_C_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read STAT_C rc = %d\n", rc); return POWER_SUPPLY_STATUS_UNKNOWN; } if (reg & STATUS_C_CHG_HOLD_OFF_BIT) { return POWER_SUPPLY_STATUS_NOT_CHARGING; } if ((reg & STATUS_C_CHARGING_MASK) && !(reg & STATUS_C_CHG_ERR_STATUS_BIT)) { return POWER_SUPPLY_STATUS_CHARGING; } return POWER_SUPPLY_STATUS_DISCHARGING; }
int smb358_get_prop_charge_type(struct opchg_charger *chip) { int rc; u8 reg = 0; rc = opchg_read_reg(chip, STATUS_C_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read STAT_C rc = %d\n", rc); return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; } reg &= STATUS_C_CHARGING_MASK; if (reg == STATUS_C_FAST_CHARGING) return POWER_SUPPLY_CHARGE_TYPE_FAST; else if (reg == STATUS_C_TAPER_CHARGING) return POWER_SUPPLY_CHARGE_TYPE_TAPER; else if (reg == STATUS_C_PRE_CHARGING) return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; else return POWER_SUPPLY_CHARGE_TYPE_NONE; }
int smb358_hw_init(struct opchg_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 = opchg_read_reg(chip, CHG_REVISION_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read CHG_REVISION_REG rc=%d\n", rc); return rc; } rc = smb358_set_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 = opchg_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 = opchg_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 suspend and APSD */ rc = opchg_masked_write(chip, VARIOUS_FUNC_REG, VARIOUS_FUNC_USB_SUSP_MASK, VARIOUS_FUNC_USB_SUSP_EN_REG_BIT); if (rc) { dev_err(chip->dev, "Couldn't set VARIOUS_FUNC_REG rc=%d\n", rc); return rc; } if (!chip->disable_apsd) { reg = CHG_CTRL_APSD_EN_BIT; } else { reg = 0; } rc = opchg_masked_write(chip, CHG_CTRL_REG, CHG_CTRL_APSD_EN_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set CHG_CTRL_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 | FAULT_INT_INPUT_OV_BIT; rc = opchg_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_CHGING_BIT | STATUS_INT_CHG_INHI_BIT | STATUS_INT_INOK_BIT | STATUS_INT_LOW_BATT_BIT | STATUS_INT_MISSING_BATT_BIT; rc = opchg_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 = opchg_masked_write(chip, THERM_A_CTRL_REG, THERM_A_THERM_MONITOR_EN_MASK, THERM_A_THERM_MONITOR_EN_MASK); if (rc) { dev_err(chip->dev, "Couldn't set THERM_A_CTRL_REG rc=%d\n", rc); return rc; } /* setup switching frequency */ rc = opchg_masked_write(chip, THERM_A_CTRL_REG, THERM_A_SWITCHING_FREQ_MASK, THERM_A_SWITCHING_FREQ_1_5MHZ); if (rc) { dev_err(chip->dev, "Couldn't set THERM_A_CTRL_REG rc=%d\n", rc); return rc; } /* setup otg current limit */ rc = opchg_masked_write(chip, OTG_TLIM_THERM_REG, OTG_CURRENT_LIMIT_MASK, OTG_CURRENT_LIMIT_BIT); if (rc) { dev_err(chip->dev, "Couldn't set OTG_TLIM_THERM_REG rc=%d\n", rc); return rc; } /* set the fast charge current limit */ opchg_set_fast_chg_current(chip, chip->max_fast_current[FAST_CURRENT_MIN]); /* set the float voltage */ opchg_set_float_voltage(chip, chip->min_term_voltage[TERM_VOL_MIN]); #if 0 /* set low_battery voltage threshold */ reg = 0x0f;//3.58V rc = opchg_masked_write(chip, LOW_BATT_THRESHOLD_REG, CHG_LOW_BATT_THRESHOLD_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set LOW_BATT_THRESHOLD_REG rc=%d\n", rc); return rc; } #endif /* set pre-charging current */ reg = CHG_PRE_450MA; rc = opchg_masked_write(chip, CHG_CURRENT_CTRL_REG, CHG_PRE_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set CHG_CURRENT_CTRL_REG rc=%d\n", rc); return rc; } /* set iterm */ rc = smb358_set_term_current(chip); if (rc) dev_err(chip->dev, "Couldn't set term current rc=%d\n", rc); /* set recharge */ rc = smb358_set_recharge_and_inhibit(chip); if (rc) dev_err(chip->dev, "Couldn't set recharge para rc=%d\n", rc); rc = opchg_masked_write(chip, INPUT_CURRENT_LIMIT_REG, VFLT_MASK, reg); if (rc) { dev_err(chip->dev, "Couldn't set inhibit threshold rc = %d\n", rc); return rc; } /* enable/disable stat output */ rc = opchg_masked_write(chip, CMD_A_REG, CMD_A_STAT_DISABLE_MASK, CMD_A_STAT_DISABLE_BIT); if (rc) { dev_err(chip->dev, "Unable to %s stat pin. rc=%d\n", CMD_A_STAT_DISABLE_BIT ? "disable" : "enable", rc); } /* enable/disable charging */ //opchg_config_charging_disable(chip, USER_DISABLE, !!chip->disabled_status); /* enable/disable charging */ if (chip->charging_disabled) { rc = smb358_charging_disable(chip, USER, 1); if (rc) dev_err(chip->dev, "Couldn't '%s' charging rc = %d\n", chip->charging_disabled ? "disable" : "enable", rc); } else { /* * Enable charging explictly, * because not sure the default behavior. */ rc = smb358_set_charging_disable(chip, 0); if (rc) dev_err(chip->dev, "Couldn't enable charging\n"); } /* enable/disable fast charging setting */ rc = opchg_masked_write(chip, CMD_A_REG, CMD_A_FAST_CHARGING_SET_MASK, CMD_A_FAST_CHARGING_SET_BIT); if (rc) { dev_err(chip->dev, "Unable to %s fast charging set. rc=%d\n", CMD_A_FAST_CHARGING_SET_BIT ? "disable" : "enable", rc); } /* * Workaround for recharge frequent issue: When battery is * greater than 4.2v, and charging is disabled, charger * stops switching. In such a case, system load is provided * by battery rather than input, even though input is still * there. Make reg09[0:3] to be a non-zero value which can * keep the switcher active */ rc = opchg_masked_write(chip, OTHER_CTRL_REG, CHG_LOW_BATT_THRESHOLD_MASK, SMB358_BATT_GOOD_THRE_2P5); if (rc) dev_err(chip->dev, "Couldn't write OTHER_CTRL_REG, rc = %d\n",rc); return rc; }
void smb358_chg_irq_handler(int irq, struct opchg_charger *chip) { //struct opchg_charger *chip = dev_id; int i, j; u8 reg = 0; u8 triggered; u8 changed; u8 rt_stat, prev_rt_stat; int rc; int handler_count = 0; rc = opchg_read_reg(chip, FAULT_INT_REG, ®); if (rc < 0) { dev_err(chip->dev, "Couldn't read %d rc = %d\n", FAULT_INT_REG, rc); } rc = opchg_read_reg(chip, STATUS_INT_REG, ®); if (rc < 0) { dev_err(chip->dev, "Couldn't read %d rc = %d\n", STATUS_INT_REG, rc); } rc = opchg_read_reg(chip, STATUS_D_REG, ®); if (rc < 0) { dev_err(chip->dev, "Couldn't read %d rc = %d\n", STATUS_D_REG, rc); } rc = opchg_read_reg(chip, STATUS_E_REG, ®); if (rc < 0) { dev_err(chip->dev, "Couldn't read %d rc = %d\n", STATUS_E_REG, rc); } for (i = 0; i < ARRAY_SIZE(handlers); i++) { rc = opchg_read_reg(chip, handlers[i].stat_reg,&handlers[i].val); if (rc < 0) { dev_err(chip->dev, "Couldn't read %d rc = %d\n",handlers[i].stat_reg, rc); continue; } for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) { triggered = handlers[i].val & (IRQ_LATCHED_MASK << (j * BITS_PER_IRQ)); rt_stat = handlers[i].val & (IRQ_STATUS_MASK << (j * BITS_PER_IRQ)); prev_rt_stat = handlers[i].prev_val & (IRQ_STATUS_MASK << (j * BITS_PER_IRQ)); changed = prev_rt_stat ^ rt_stat; if (triggered || changed) { pr_debug("irq %s: triggered = 0x%02x, rt_stat = 0x%02x, prev_rt_stat = 0x%02x\n", handlers[i].irq_info[j].name, triggered,rt_stat, prev_rt_stat); rt_stat ? handlers[i].irq_info[j].high++ : handlers[i].irq_info[j].low++; } if ((triggered || changed) && handlers[i].irq_info[j].smb_irq != NULL) { handler_count++; rc = handlers[i].irq_info[j].smb_irq(chip, rt_stat); if (rc < 0) { dev_err(chip->dev, "Couldn't handle %d irq for reg 0x%02x rc = %d\n", j, handlers[i].stat_reg, rc); } } } handlers[i].prev_val = handlers[i].val; } pr_debug("handler count = %d\n", handler_count); if (handler_count) { pr_debug("batt psy changed\n"); power_supply_changed(&chip->batt_psy); } //return IRQ_HANDLED; }