int smb358_get_charging_status(struct opchg_charger *chip)
{
    int rc;
    u8 reg = 0;
    
    rc = opchg_read_reg(chip, STATUS_C_REG, &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, &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, &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, &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, &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, &reg);
        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, &reg);
        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, &reg);
        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);
        }
    }
}
Esempio n. 5
0
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;
}
Esempio n. 6
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, &reg);
        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, &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, &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, &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, &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, &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, &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, &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, &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;
}