static int smb347_read_status(struct smb_charger_callbacks *ptr) { struct smb347_chg_data *chg = container_of(ptr, struct smb347_chg_data, callbacks); u8 res = 0; u8 reg_c; int ret; ret = smb347_i2c_read(chg->client, SMB347_STATUS_C, ®_c); if (ret < 0) { dev_err(&chg->client->dev, "%s: I2C Read fail addr : 0x%x\n", __func__, SMB347_STATUS_C); msleep(50); smb347_i2c_read(chg->client, SMB347_STATUS_C, ®_c); } dev_info(&chg->client->dev, "addr : 0x%x, data : 0x%x\n", SMB347_STATUS_C, reg_c); if (reg_c & SMB347_CHARGER_ERROR) res = CHARGER_STATUS_CHARGERERR; else if (reg_c & SMB347_CHARGING_STATUS) res = CHARGER_STATUS_FULL; return res; }
static int smb347_get_charging_health(struct i2c_client *client) { int health = POWER_SUPPLY_HEALTH_GOOD; u8 data_a = 0; u8 data_b = 0; u8 data_c = 0; u8 data_d = 0; u8 data_e = 0; smb347_i2c_read(client, SMB347_STATUS_A, &data_a); dev_info(&client->dev, "%s : charger status A(0x%02x)\n", __func__, data_a); smb347_i2c_read(client, SMB347_STATUS_B, &data_b); dev_info(&client->dev, "%s : charger status B(0x%02x)\n", __func__, data_b); smb347_i2c_read(client, SMB347_STATUS_C, &data_c); dev_info(&client->dev, "%s : charger status C(0x%02x)\n", __func__, data_c); smb347_i2c_read(client, SMB347_STATUS_D, &data_d); dev_info(&client->dev, "%s : charger status D(0x%02x)\n", __func__, data_d); smb347_i2c_read(client, SMB347_STATUS_E, &data_e); dev_info(&client->dev, "%s : charger status E(0x%02x)\n", __func__, data_e); /* Is enabled ? */ /* if (data_c & 0x01) { if (!(data_a & 0x02)) // Input current is NOT OK // health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; } */ return (int)health; }
static int smb347_get_charging_status(struct i2c_client *client) { int status = POWER_SUPPLY_STATUS_UNKNOWN; u8 data_a = 0; u8 data_b = 0; u8 data_c = 0; u8 data_d = 0; u8 data_e = 0; smb347_i2c_read(client, SMB347_STATUS_A, &data_a); dev_info(&client->dev, "%s : charger status A(0x%02x)\n", __func__, data_a); smb347_i2c_read(client, SMB347_STATUS_B, &data_b); dev_info(&client->dev, "%s : charger status B(0x%02x)\n", __func__, data_b); smb347_i2c_read(client, SMB347_STATUS_C, &data_c); dev_info(&client->dev, "%s : charger status C(0x%02x)\n", __func__, data_c); smb347_i2c_read(client, SMB347_STATUS_D, &data_d); dev_info(&client->dev, "%s : charger status D(0x%02x)\n", __func__, data_d); smb347_i2c_read(client, SMB347_STATUS_E, &data_e); dev_info(&client->dev, "%s : charger status E(0x%02x)\n", __func__, data_e); /* At least one charge cycle terminated, * Charge current < Termination Current */ if ((data_c & 0x20) == 0x20) { /* top-off by full charging */ status = POWER_SUPPLY_STATUS_FULL; goto charging_status_end; } /* Is enabled ? */ if (data_c & 0x01) { /* check for 0x06 : no charging (0b00) */ /* not charging */ if (!(data_c & 0x06)) { status = POWER_SUPPLY_STATUS_NOT_CHARGING; goto charging_status_end; } else { status = POWER_SUPPLY_STATUS_CHARGING; goto charging_status_end; } } else status = POWER_SUPPLY_STATUS_DISCHARGING; charging_status_end: return (int)status; }
static void smb347_test_read(struct i2c_client *client) { u8 data = 0; u32 addr = 0; for (addr = 0; addr <= 0x0f; addr++) { smb347_i2c_read(client, addr, &data); dev_dbg(&client->dev, "smb347 addr : 0x%02x data : 0x%02x\n", addr, data); } for (addr = 0x30; addr <= 0x3f; addr++) { smb347_i2c_read(client, addr, &data); dev_dbg(&client->dev, "smb347 addr : 0x%02x data : 0x%02x\n", addr, data); } }
static void smb347_read_regs(struct i2c_client *client, char *str) { u8 data = 0; u32 addr = 0; for (addr = 0; addr <= 0x0f; addr++) { smb347_i2c_read(client, addr, &data); sprintf(str+strlen(str), "0x%x, ", data); } /* "#" considered as new line in application */ sprintf(str+strlen(str), "#"); for (addr = 0x30; addr <= 0x3f; addr++) { smb347_i2c_read(client, addr, &data); sprintf(str+strlen(str), "0x%x, ", data); } }
static void smb347_test_read(struct smb347_chg_data *chg) { u8 data = 0; u32 addr = 0; pr_info("%s\n", __func__); for (addr = 0; addr <= 0x0E; addr++) { smb347_i2c_read(chg->client, addr, &data); dev_info(&chg->client->dev, "smb347 addr : 0x%02x data : 0x%02x\n", addr, data); } for (addr = 0x30; addr <= 0x3F; addr++) { smb347_i2c_read(chg->client, addr, &data); dev_info(&chg->client->dev, "smb347 addr : 0x%02x data : 0x%02x\n", addr, data); } }
static void smb347_allow_volatile_writes(struct i2c_client *client) { int val, reg; u8 data; reg = SMB347_COMMAND_A; val = smb347_i2c_read(client, reg, &data); if ((val >= 0) && !(data & 0x80)) { dev_dbg(&client->dev, "%s : reg(0x%02x): 0x%02x", __func__, reg, data); data |= (0x1 << 7); if (smb347_i2c_write(client, reg, &data) < 0) dev_err(&client->dev, "%s : error!\n", __func__); val = smb347_i2c_read(client, reg, &data); if (val >= 0) { data = (u8) data; dev_dbg(&client->dev, " => 0x%02x\n", data); } } }
static void smb347_set_charging_current( struct i2c_client *client, int charging_current) { struct sec_charger_info *charger = i2c_get_clientdata(client); u8 data; smb347_i2c_read(client, SMB347_CHARGE_CURRENT, &data); data &= 0xe0; data |= smb347_get_fast_charging_current_data(charging_current); smb347_set_command(client, SMB347_CHARGE_CURRENT, data); }
static void smb347_set_command(struct i2c_client *client, int reg, int datum) { int val; u8 data = 0; val = smb347_i2c_read(client, reg, &data); if (val >= 0) { dev_dbg(&client->dev, "%s : reg(0x%02x): 0x%02x", __func__, reg, data); if (data != datum) { data = datum; if (smb347_i2c_write(client, reg, &data) < 0) dev_err(&client->dev, "%s : error!\n", __func__); val = smb347_i2c_read(client, reg, &data); if (val >= 0) dev_dbg(&client->dev, " => 0x%02x\n", data); } } }
static void smb347_test_read(void) { struct smb347_chg_data *chg = smb347_chg; u8 data = 0; u32 addr = 0; pr_info("%s\n", __func__); /* Only for P4C rev0.2, Check vbus for opeartion charger */ if (!smb347_check_powersource(chg)) return; for (addr = 0; addr <= 0x0E; addr++) { smb347_i2c_read(chg->client, addr, &data); pr_info("smb347 addr : 0x%02x data : 0x%02x\n", addr, data); } for (addr = 0x30; addr <= 0x3F; addr++) { smb347_i2c_read(chg->client, addr, &data); pr_info("smb347 addr : 0x%02x data : 0x%02x\n", addr, data); } }
static int smb347_get_charger_is_full(void) { struct smb347_chg_data *chg = smb347_chg; int status = POWER_SUPPLY_STATUS_UNKNOWN; u8 data = 0; smb347_i2c_read(chg->client, SMB347_STATUS_C, &data); pr_info("%s : 0x%xh(0x%02x)\n", __func__, SMB347_STATUS_C, data); if (data & SMB347_CHARGER_ERROR) status = POWER_SUPPLY_STATUS_DISCHARGING; else if (data & SMB347_CHARGING_STATUS) status = POWER_SUPPLY_STATUS_FULL; return status; }
ssize_t sec_hal_chg_store_attrs(struct device *dev, const ptrdiff_t offset, const char *buf, size_t count) { struct power_supply *psy = dev_get_drvdata(dev); struct sec_charger_info *chg = container_of(psy, struct sec_charger_info, psy_chg); int ret = 0; int x = 0; u8 data = 0; switch (offset) { case CHG_REG: if (sscanf(buf, "%x\n", &x) == 1) { chg->reg_addr = x; smb347_i2c_read(chg->client, chg->reg_addr, &data); chg->reg_data = data; dev_dbg(dev, "%s: (read) addr = 0x%x, data = 0x%x\n", __func__, chg->reg_addr, chg->reg_data); ret = count; } break; case CHG_DATA: if (sscanf(buf, "%x\n", &x) == 1) { data = (u8)x; dev_dbg(dev, "%s: (write) addr = 0x%x, data = 0x%x\n", __func__, chg->reg_addr, data); smb347_i2c_write(chg->client, chg->reg_addr, &data); ret = count; } break; default: ret = -EINVAL; break; } return ret; }
int smb347_get_charging_current(void) { struct smb347_chg_data *chg = smb347_chg; u8 data = 0; int get_current = 0; smb347_i2c_read(chg->client, SMB347_CHARGE_CURRENT, &data); switch (data >> 5) { case 0: get_current = 700; break; case 1: get_current = 900; break; case 2: get_current = 1200; break; case 3: get_current = 1500; break; case 4: get_current = 1800; break; case 5: get_current = 2000; break; case 6: get_current = 2200; break; case 7: get_current = 2500; break; default: get_current = 700; break; } pr_debug("%s: Get charging current as %dmA.\n", __func__, get_current); return get_current; }
static int smb347_get_charging_state(void) { struct smb347_chg_data *chg = smb347_chg; int status = POWER_SUPPLY_STATUS_UNKNOWN; u8 data = 0; smb347_i2c_read(chg->client, SMB347_STATUS_C, &data); pr_info("%s : 0x%xh(0x%02x)\n", __func__, SMB347_STATUS_C, data); if (data & SMB347_CHARGING_ENABLE) status = POWER_SUPPLY_STATUS_CHARGING; else { /* if error bit check, ignore the status of charger-ic */ if (data & SMB347_CHARGER_ERROR) status = POWER_SUPPLY_STATUS_DISCHARGING; /* At least one charge cycle terminated */ /*Charge current < Termination Current */ else if (data & SMB347_CHARGING_STATUS) status = POWER_SUPPLY_STATUS_FULL; } return status; }
bool sec_hal_chg_get_property(struct i2c_client *client, enum power_supply_property psp, union power_supply_propval *val) { struct sec_charger_info *charger = i2c_get_clientdata(client); u8 data; switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = smb347_get_charging_status(client); break; case POWER_SUPPLY_PROP_CHARGE_TYPE: if (charger->is_charging) val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; else val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; break; case POWER_SUPPLY_PROP_HEALTH: val->intval = smb347_get_charging_health(client); break; /* calculated input current limit value */ case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_CURRENT_AVG: /* charging current */ if (charger->charging_current) { smb347_i2c_read(client, SMB347_STATUS_B, &data); if (data & 0x20) switch (data & 0x18) { case 0: val->intval = 100; break; case 1: val->intval = 150; break; case 2: val->intval = 200; break; case 3: val->intval = 250; break; } else switch (data & 0x07) { case 0: val->intval = 700; break; case 1: val->intval = 900; break; case 2: val->intval = 1200; break; case 3: val->intval = 1500; break; case 4: val->intval = 1800; break; case 5: val->intval = 2000; break; case 6: val->intval = 2200; break; case 7: val->intval = 2500; break; } } else val->intval = 0; dev_dbg(&client->dev, "%s : set-current(%dmA), current now(%dmA)\n", __func__, charger->charging_current, val->intval); break; default: return false; } return true; }