static void smb347_init(struct i2c_client *client) { u8 reg; reg = 0x80; smb347_write(client, 0x30, ®, 1); /* close interrupt */ smb347_read(client, 0x38, ®, 1); smb347_read(client, 0x3a, ®, 1); reg = 0x0; smb347_write(client, 0x0c, ®, 1); smb347_write(client, 0x0d, ®, 1); if (g_smb347_dev->info->otg_power_form_smb == 0) { /* set dc charge when bosh inser dc and usb */ smb347_read(client, 0x02, ®, 1); reg = reg & 0xfb; smb347_write(client, 0x02, ®, 1); } smb347_set_otg_control(g_smb347_dev); smb347_set_current_limits(g_smb347_dev); }
static int smb347_irq_set(struct smb347_charger *smb, bool enable) { int ret; ret = smb347_set_writable(smb, true); if (ret < 0) return ret; /* * Enable/disable interrupts for: * - under voltage * - termination current reached * - charger error */ if (enable) { ret = smb347_write(smb, CFG_FAULT_IRQ, CFG_FAULT_IRQ_DCIN_UV); if (ret < 0) goto fail; ret = smb347_write(smb, CFG_STATUS_IRQ, CFG_STATUS_IRQ_TERMINATION_OR_TAPER); if (ret < 0) goto fail; ret = smb347_read(smb, CFG_PIN); if (ret < 0) goto fail; ret |= CFG_PIN_EN_CHARGER_ERROR; ret = smb347_write(smb, CFG_PIN, ret); } else { ret = smb347_write(smb, CFG_FAULT_IRQ, 0); if (ret < 0) goto fail; ret = smb347_write(smb, CFG_STATUS_IRQ, 0); if (ret < 0) goto fail; ret = smb347_read(smb, CFG_PIN); if (ret < 0) goto fail; ret &= ~CFG_PIN_EN_CHARGER_ERROR; ret = smb347_write(smb, CFG_PIN, ret); } fail: smb347_set_writable(smb, false); return ret; }
/* workqueue function */ static int cable_type_detect(void) { struct i2c_client *client = charger->client; u8 retval; int success = 0; int gpio = TEGRA_GPIO_PV1; if(grouper_query_pcba_revision() <= 0x02) return 0; mutex_lock(&charger->cable_lock); if (gpio_get_value(gpio)) { printk("INOK=H\n"); success = battery_callback(non_cable); } else { printk("INOK=L\n"); /* cable type dection */ retval = smb347_read(client, smb347_STS_REG_E); SMB_NOTICE("Reg3F : 0x%02x\n", retval); if(retval & USBIN) { //USBIN retval = smb347_read(client, smb347_STS_REG_D); SMB_NOTICE("Reg3E : 0x%02x\n", retval); if(retval & APSD_OK) { //APSD completed retval &= APSD_RESULT; if(retval == APSD_CDP) { //APSD resulted printk("Cable: CDP\n"); success = battery_callback(ac_cable); } else if(retval == APSD_DCP) { printk("Cable: DCP\n"); success = battery_callback(ac_cable); } else if(retval == APSD_OTHER) { printk("Cable: OTHER\n"); } else if(retval == APSD_SDP) { printk("Cable: SDP\n"); success = battery_callback(usb_cable); } else printk("Unkown Plug In Cable type !\n"); }else printk("APSD not completed\n"); } else { printk("USBIN=0\n"); } } mutex_unlock(&charger->cable_lock); return success; }
static irqreturn_t smb347_interrupt(int irq, void *data) { struct smb347_charger *smb = data; int stat_c, irqstat_e, irqstat_c; irqreturn_t ret = IRQ_NONE; stat_c = smb347_read(smb, STAT_C); if (stat_c < 0) { dev_warn(&smb->client->dev, "reading STAT_C failed\n"); return IRQ_NONE; } irqstat_c = smb347_read(smb, IRQSTAT_C); if (irqstat_c < 0) { dev_warn(&smb->client->dev, "reading IRQSTAT_C failed\n"); return IRQ_NONE; } irqstat_e = smb347_read(smb, IRQSTAT_E); if (irqstat_e < 0) { dev_warn(&smb->client->dev, "reading IRQSTAT_E failed\n"); return IRQ_NONE; } if (stat_c & STAT_C_CHARGER_ERROR) { dev_err(&smb->client->dev, "error in charger, disabling charging\n"); smb347_charging_disable(smb); power_supply_changed(&smb->battery); ret = IRQ_HANDLED; } if (irqstat_c & (IRQSTAT_C_TERMINATION_IRQ | IRQSTAT_C_TAPER_IRQ)) { if (irqstat_c & IRQSTAT_C_TERMINATION_STAT) power_supply_changed(&smb->battery); ret = IRQ_HANDLED; } if (irqstat_e & (IRQSTAT_E_USBIN_UV_IRQ | IRQSTAT_E_DCIN_UV_IRQ)) { if (smb347_update_status(smb) > 0) { smb347_update_online(smb); power_supply_changed(&smb->mains); power_supply_changed(&smb->usb); } ret = IRQ_HANDLED; } return ret; }
static int smb347_set_otg_control(struct smb347_device *smb_dev) { char ret; char reg; if (smb_dev->info->otg_power_form_smb == 1) { ret = smb347_read(smb_dev->client, 0x09, ®, 1); if (ret < 0) { xhc_printk("error,ret = %x\n", ret); return ret; } reg &= 0xef; reg |= 0x40; reg |= 0x20; ret = smb347_write(smb_dev->client,0x09,®,1); if (ret < 0) { xhc_printk("error,ret = %x\n", ret); return ret; } reg = 0x76; smb347_write(smb_dev->client,0x0a,®,1); if (ret < 0) { xhc_printk("error,ret = %x\n", ret); return ret; } } return 0; }
static int smb347_set_current_limits(struct smb347_charger *smb) { int ret, val; ret = smb347_read(smb, CFG_CURRENT_LIMIT); if (ret < 0) return ret; if (smb->mains_current_limit) { val = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl), smb->mains_current_limit); if (val < 0) return val; ret &= ~CFG_CURRENT_LIMIT_DC_MASK; ret |= val << CFG_CURRENT_LIMIT_DC_SHIFT; } if (smb->pdata->usb_hc_current_limit) { val = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl), smb->pdata->usb_hc_current_limit); if (val < 0) return val; ret &= ~CFG_CURRENT_LIMIT_USB_MASK; ret |= val; } return smb347_write(smb, CFG_CURRENT_LIMIT, ret); }
int smb347_volatile_writes(struct i2c_client *client, uint8_t value) { int ret = 0; if (value == smb347_ENABLE_WRITE) { /* Enable volatile write to config registers */ ret = smb347_update_reg(client, smb347_CMD_REG, ENABLE_WRT_ACCESS); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing" "register 0x%02x\n", __func__, smb347_CMD_REG); return ret; } } else { ret = smb347_read(client, smb347_CMD_REG); if (ret < 0) { dev_err(&client->dev, "%s: err %d\n", __func__, ret); return ret; } ret = smb347_write(client, smb347_CMD_REG, ret & (~(1<<7))); if (ret < 0) { dev_err(&client->dev, "%s: err %d\n", __func__, ret); return ret; } } return ret; }
static int smb347_charging_set(struct smb347_charger *smb, bool enable) { int ret = 0; if (smb->pdata->enable_control != SMB347_CHG_ENABLE_SW) { smb->charging_enabled = enable; if (smb->en_gpio) gpio_set_value( smb->en_gpio, (smb->pdata->enable_control == SMB347_CHG_ENABLE_PIN_ACTIVE_LOW) ^ enable); return 0; } mutex_lock(&smb->lock); if (smb->charging_enabled != enable) { ret = smb347_read(smb, CMD_A); if (ret < 0) goto out; smb->charging_enabled = enable; if (enable) ret |= CMD_A_CHG_ENABLED; else ret &= ~CMD_A_CHG_ENABLED; ret = smb347_write(smb, CMD_A, ret); } out: mutex_unlock(&smb->lock); return ret; }
int smb347_battery_online(void) { int val, ret; struct i2c_client *client = charger->client; /* Enable volatile writes to registers */ ret = smb347_volatile_writes(client, smb347_ENABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } val = smb347_read(client, smb347_INTR_STS_B); if (val < 0) { dev_err(&client->dev, "%s(): Failed in reading register" "0x%02x\n", __func__, smb347_INTR_STS_B); return val; } if (val & BATTERY_MISSING) return 0; else return 1; /* Disable volatile writes to registers */ ret = smb347_volatile_writes(client, smb347_DISABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } error: return ret; }
/** * smb347_update_status - updates the charging status * @smb: pointer to smb347 charger instance * * Function checks status of the charging and updates internal state * accordingly. Returns %0 if there is no change in status, %1 if the * status has changed and negative errno in case of failure. */ static int smb347_update_status(struct smb347_charger *smb) { bool usb = false; bool dc = false; int ret; ret = smb347_read(smb, IRQSTAT_E); if (ret < 0) return ret; /* * Dc and usb are set depending on whether they are enabled in * platform data _and_ whether corresponding undervoltage is set. */ if (smb->pdata->use_mains) dc = !(ret & IRQSTAT_E_DCIN_UV_STAT); if (smb->pdata->use_usb) usb = !(ret & IRQSTAT_E_USBIN_UV_STAT); mutex_lock(&smb->lock); ret = smb->mains_online != dc || smb->usb_online != usb; smb->mains_online = dc; smb->usb_online = usb; mutex_unlock(&smb->lock); return ret; }
static int smb347_charging_set(struct smb347_charger *smb, bool enable) { int ret = 0; if (smb->pdata->enable_control != SMB347_CHG_ENABLE_SW) { dev_dbg(&smb->client->dev, "charging enable/disable in SW disabled\n"); return 0; } mutex_lock(&smb->lock); if (smb->charging_enabled != enable) { ret = smb347_read(smb, CMD_A); if (ret < 0) goto out; smb->charging_enabled = enable; if (enable) ret |= CMD_A_CHG_ENABLED; else ret &= ~CMD_A_CHG_ENABLED; ret = smb347_write(smb, CMD_A, ret); } out: mutex_unlock(&smb->lock); return ret; }
static int smb347_set_voltage_limits(struct smb347_charger *smb) { int ret, val; ret = smb347_read(smb, CFG_FLOAT_VOLTAGE); if (ret < 0) return ret; if (smb->pdata->pre_to_fast_voltage) { val = smb->pdata->pre_to_fast_voltage; /* uV */ val = clamp_val(val, 2400000, 3000000) - 2400000; val /= 200000; ret &= ~CFG_FLOAT_VOLTAGE_THRESHOLD_MASK; ret |= val << CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT; } if (smb->pdata->max_charge_voltage) { val = smb->pdata->max_charge_voltage; /* uV */ val = clamp_val(val, 3500000, 4500000) - 3500000; val /= 20000; ret |= val; } return smb347_write(smb, CFG_FLOAT_VOLTAGE, ret); }
static int smb347_irq_set(struct smb347_charger *smb, bool enable) { int ret; ret = smb347_set_writable(smb, true); if (ret < 0) return ret; if (enable) { ret = smb347_write(smb, CFG_FAULT_IRQ, CFG_FAULT_IRQ_DCIN_UV); if (ret < 0) goto fail; ret = smb347_write(smb, CFG_STATUS_IRQ, CFG_STATUS_IRQ_TERMINATION_OR_TAPER); if (ret < 0) goto fail; ret = smb347_read(smb, CFG_PIN); if (ret < 0) goto fail; ret |= CFG_PIN_EN_CHARGER_ERROR; ret = smb347_write(smb, CFG_PIN, ret); } else { ret = smb347_write(smb, CFG_FAULT_IRQ, 0); if (ret < 0) goto fail; ret = smb347_write(smb, CFG_STATUS_IRQ, 0); if (ret < 0) goto fail; ret = smb347_read(smb, CFG_PIN); if (ret < 0) goto fail; ret &= ~CFG_PIN_EN_CHARGER_ERROR; ret = smb347_write(smb, CFG_PIN, ret); } fail: smb347_set_writable(smb, false); return ret; }
static void active_smb347(struct smb347_device *smb347_dev) { u8 reg; reg = 0x80; smb347_write(smb347_dev->client,0x30,®,1); smb347_read(smb347_dev->client, 0x02, ®, 1); reg = (reg | 0x80); smb347_write(smb347_dev->client,0x02,®,1); xhc_printk("%s\n", __func__); }
int smb347_is_chg_ok(void) { u8 reg = 0; int ret = 0; smb347_read(g_smb347_dev->client, 0x37, ®, 1); ret = (reg & 0x03); return ret; }
int smb347_is_charging(void) { int status = 0;//POWER_SUPPLY_STATUS_UNKNOWN; u8 data = 0; smb347_read(g_smb347_dev->client, SMB347_STATUS_D, &data, 1); if (data & 0x06) status = 1; return status; }
static int smb347_configure_charger(struct i2c_client *client, int value) { int ret = 0; /* Enable volatile writes to registers */ ret = smb347_volatile_writes(client, smb347_ENABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } if (value) { /* Enable charging */ ret = smb347_update_reg(client, smb347_CMD_REG, ENABLE_CHARGE); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing register" "0x%02x\n", __func__, smb347_CMD_REG); goto error; } /* Configure THERM ctrl */ /* ret = smb347_update_reg(client, smb347_THERM_CTRL, THERM_CTRL); if (ret < 0) { dev_err(&client->dev, "%s: err %d\n", __func__, ret); goto error; } */ } else { /* Disable charging */ ret = smb347_read(client, smb347_CMD_REG); if (ret < 0) { dev_err(&client->dev, "%s: err %d\n", __func__, ret); goto error; } ret = smb347_write(client, smb347_CMD_REG, (ret & (~(1<<1)))); if (ret < 0) { dev_err(&client->dev, "%s: err %d\n", __func__, ret); goto error; } } /* Disable volatile writes to registers */ ret = smb347_volatile_writes(client, smb347_DISABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } error: return ret; }
static int smb347_irq_init(struct smb347_charger *smb) { const struct smb347_charger_platform_data *pdata = smb->pdata; int ret, irq = gpio_to_irq(pdata->irq_gpio); ret = gpio_request_one(pdata->irq_gpio, GPIOF_IN, smb->client->name); if (ret < 0) goto fail; ret = request_threaded_irq(irq, NULL, smb347_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, smb->client->name, smb); if (ret < 0) goto fail_gpio; ret = smb347_set_writable(smb, true); if (ret < 0) goto fail_irq; /* * Configure the STAT output to be suitable for interrupts: disable * all other output (except interrupts) and make it active low. */ ret = smb347_read(smb, CFG_STAT); if (ret < 0) goto fail_readonly; ret &= ~CFG_STAT_ACTIVE_HIGH; ret |= CFG_STAT_DISABLED; ret = smb347_write(smb, CFG_STAT, ret); if (ret < 0) goto fail_readonly; ret = smb347_irq_enable(smb); if (ret < 0) goto fail_readonly; smb347_set_writable(smb, false); smb->client->irq = irq; return 0; fail_readonly: smb347_set_writable(smb, false); fail_irq: free_irq(irq, smb); fail_gpio: gpio_free(pdata->irq_gpio); fail: smb->client->irq = 0; return ret; }
/** * smb347_charging_status - returns status of charging * @smb: pointer to smb347 charger instance * * Function returns charging status. %0 means no charging is in progress, * %1 means pre-charging, %2 fast-charging and %3 taper-charging. */ static int smb347_charging_status(struct smb347_charger *smb) { int ret; if (!smb347_is_online(smb)) return 0; ret = smb347_read(smb, STAT_C); if (ret < 0) return 0; return (ret & STAT_C_CHG_MASK) >> STAT_C_CHG_SHIFT; }
static int smb347_usb_set_property(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) { int ret = -EINVAL; struct smb347_charger *smb = container_of(psy, struct smb347_charger, usb); bool oldval; switch (prop) { case POWER_SUPPLY_PROP_ONLINE: oldval = smb->usb_online; smb->usb_online = val->intval; if (smb->usb_online != oldval) power_supply_changed(psy); ret = 0; break; case POWER_SUPPLY_PROP_USB_HC: smb347_set_writable(smb, true); ret = smb347_write(smb, CMD_B, val->intval ? CMD_B_HC_MODE : CMD_B_USB59_MODE); smb347_set_writable(smb, false); smb->usb_hc_mode = val->intval; break; case POWER_SUPPLY_PROP_USB_OTG: ret = smb347_read(smb, CMD_A); if (ret < 0) return ret; if (val->intval) ret |= CMD_A_OTG_ENABLE; else ret &= ~CMD_A_OTG_ENABLE; ret = smb347_write(smb, CMD_A, ret); if (ret >= 0) smb->usb_otg_enabled = val->intval; break; default: break; } return ret; }
/* * smb347_set_writable - enables/disables writing to non-volatile registers * @smb: pointer to smb347 charger instance * * You can enable/disable writing to the non-volatile configuration * registers by calling this function. * * Returns %0 on success and negative errno in case of failure. */ static int smb347_set_writable(struct smb347_charger *smb, bool writable) { int ret; ret = smb347_read(smb, CMD_A); if (ret < 0) return ret; if (writable) ret |= CMD_A_ALLOW_WRITE; else ret &= ~CMD_A_ALLOW_WRITE; return smb347_write(smb, CMD_A, ret); }
static int smb347_irq_init(struct smb347_charger *smb) { const struct smb347_charger_platform_data *pdata = smb->pdata; int ret, irq = gpio_to_irq(pdata->irq_gpio); ret = gpio_request_one(pdata->irq_gpio, GPIOF_IN, smb->client->name); if (ret < 0) goto fail; ret = request_threaded_irq(irq, NULL, smb347_interrupt, IRQF_TRIGGER_FALLING, smb->client->name, smb); if (ret < 0) goto fail_gpio; ret = smb347_set_writable(smb, true); if (ret < 0) goto fail_irq; ret = smb347_read(smb, CFG_STAT); if (ret < 0) goto fail_readonly; ret &= ~CFG_STAT_ACTIVE_HIGH; ret |= CFG_STAT_DISABLED; ret = smb347_write(smb, CFG_STAT, ret); if (ret < 0) goto fail_readonly; ret = smb347_irq_enable(smb); if (ret < 0) goto fail_readonly; smb347_set_writable(smb, false); smb->client->irq = irq; return 0; fail_readonly: smb347_set_writable(smb, false); fail_irq: free_irq(irq, smb); fail_gpio: gpio_free(pdata->irq_gpio); fail: smb->client->irq = 0; return ret; }
static int smb347_mains_set_property(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) { struct smb347_charger *smb = container_of(psy, struct smb347_charger, mains); int ret; bool oldval; switch (prop) { case POWER_SUPPLY_PROP_ONLINE: oldval = smb->mains_online; smb->mains_online = val->intval; smb347_set_writable(smb, true); ret = smb347_read(smb, CMD_A); if (ret < 0) return -EINVAL; ret &= ~CMD_A_SUSPEND_ENABLED; if (val->intval) ret |= CMD_A_SUSPEND_ENABLED; ret = smb347_write(smb, CMD_A, ret); smb347_hw_init(smb); smb347_set_writable(smb, false); if (smb->mains_online != oldval) power_supply_changed(psy); return 0; case POWER_SUPPLY_PROP_CURRENT_MAX: smb->mains_current_limit = val->intval; smb347_hw_init(smb); return 0; default: return -EINVAL; } return -EINVAL; }
static int smb347_clear_reg(struct i2c_client *client, int reg, u8 value) { int ret, retval; retval = smb347_read(client, reg); if (retval < 0) { dev_err(&client->dev, "%s: err %d\n", __func__, retval); return retval; } ret = smb347_write(client, reg, retval & (~value)); if (ret < 0) { dev_err(&client->dev, "%s: err %d\n", __func__, ret); return ret; } return ret; }
static int smb347_set_charge_current(struct smb347_charger *smb) { int ret, val; ret = smb347_read(smb, CFG_CHARGE_CURRENT); if (ret < 0) return ret; if (smb->pdata->max_charge_current) { val = current_to_hw(fcc_tbl, ARRAY_SIZE(fcc_tbl), smb->pdata->max_charge_current); if (val < 0) return val; ret &= ~CFG_CHARGE_CURRENT_FCC_MASK; ret |= val << CFG_CHARGE_CURRENT_FCC_SHIFT; } if (smb->pdata->pre_charge_current) { val = current_to_hw(pcc_tbl, ARRAY_SIZE(pcc_tbl), smb->pdata->pre_charge_current); if (val < 0) return val; ret &= ~CFG_CHARGE_CURRENT_PCC_MASK; ret |= val << CFG_CHARGE_CURRENT_PCC_SHIFT; } if (smb->pdata->termination_current) { val = current_to_hw(tc_tbl, ARRAY_SIZE(tc_tbl), smb->pdata->termination_current); if (val < 0) return val; ret &= ~CFG_CHARGE_CURRENT_TC_MASK; ret |= val; } return smb347_write(smb, CFG_CHARGE_CURRENT, ret); }
static int smb347_update_status(struct smb347_charger *smb) { bool usb = false; bool dc = false; int ret; ret = smb347_read(smb, IRQSTAT_E); if (ret < 0) return ret; if (smb->pdata->use_mains) dc = !(ret & IRQSTAT_E_DCIN_UV_STAT); if (smb->pdata->use_usb) usb = !(ret & IRQSTAT_E_USBIN_UV_STAT); mutex_lock(&smb->lock); ret = smb->mains_online != dc || smb->usb_online != usb; smb->mains_online = dc; smb->usb_online = usb; mutex_unlock(&smb->lock); return ret; }
static int smb347_temp_limit_setting(void) { struct i2c_client *client = charger->client; int ret = 0, retval, val; /* Enable volatile writes to registers */ ret = smb347_volatile_writes(client, smb347_ENABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } val = smb347_read(client, smb347_HRD_SFT_TEMP); if (val < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb347_HRD_SFT_TEMP); goto error; } val &= 0xcf; /* Set Hard Limit Hot Temperature 59 Degree */ ret = smb347_write(client, smb347_HRD_SFT_TEMP, val | 0x20); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, val, smb347_HRD_SFT_TEMP); goto error; } /* Disable volatile writes to registers */ ret = smb347_volatile_writes(client, smb347_DISABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } return 0; error: return -1; }
static int smb347_debugfs_show(struct seq_file *s, void *data) { struct smb347_charger *smb = s->private; int ret; u8 reg; seq_printf(s, "Control registers:\n"); seq_printf(s, "==================\n"); for (reg = CFG_CHARGE_CURRENT; reg <= CFG_ADDRESS; reg++) { ret = smb347_read(smb, reg); seq_printf(s, "0x%02x:\t0x%02x\n", reg, ret); } seq_printf(s, "\n"); seq_printf(s, "Command registers:\n"); seq_printf(s, "==================\n"); ret = smb347_read(smb, CMD_A); seq_printf(s, "0x%02x:\t0x%02x\n", CMD_A, ret); ret = smb347_read(smb, CMD_B); seq_printf(s, "0x%02x:\t0x%02x\n", CMD_B, ret); ret = smb347_read(smb, CMD_C); seq_printf(s, "0x%02x:\t0x%02x\n", CMD_C, ret); seq_printf(s, "\n"); seq_printf(s, "Interrupt status registers:\n"); seq_printf(s, "===========================\n"); for (reg = IRQSTAT_A; reg <= IRQSTAT_F; reg++) { ret = smb347_read(smb, reg); seq_printf(s, "0x%02x:\t0x%02x\n", reg, ret); } seq_printf(s, "\n"); seq_printf(s, "Status registers:\n"); seq_printf(s, "=================\n"); for (reg = STAT_A; reg <= STAT_E; reg++) { ret = smb347_read(smb, reg); seq_printf(s, "0x%02x:\t0x%02x\n", reg, ret); } return 0; }
static irqreturn_t smb347_interrupt(int irq, void *data) { struct smb347_charger *smb = data; int stat_c, irqstat_e, irqstat_c; irqreturn_t ret = IRQ_NONE; stat_c = smb347_read(smb, STAT_C); if (stat_c < 0) { dev_warn(&smb->client->dev, "reading STAT_C failed\n"); return IRQ_NONE; } irqstat_c = smb347_read(smb, IRQSTAT_C); if (irqstat_c < 0) { dev_warn(&smb->client->dev, "reading IRQSTAT_C failed\n"); return IRQ_NONE; } irqstat_e = smb347_read(smb, IRQSTAT_E); if (irqstat_e < 0) { dev_warn(&smb->client->dev, "reading IRQSTAT_E failed\n"); return IRQ_NONE; } /* * If we get charger error we report the error back to user and * disable charging. */ if (stat_c & STAT_C_CHARGER_ERROR) { dev_err(&smb->client->dev, "error in charger, disabling charging\n"); smb347_charging_disable(smb); power_supply_changed(&smb->battery); ret = IRQ_HANDLED; } /* * If we reached the termination current the battery is charged and * we can update the status now. Charging is automatically * disabled by the hardware. */ if (irqstat_c & (IRQSTAT_C_TERMINATION_IRQ | IRQSTAT_C_TAPER_IRQ)) { if (irqstat_c & IRQSTAT_C_TERMINATION_STAT) power_supply_changed(&smb->battery); ret = IRQ_HANDLED; } /* * If we got an under voltage interrupt it means that AC/USB input * was disconnected. */ if (irqstat_e & (IRQSTAT_E_USBIN_UV_IRQ | IRQSTAT_E_DCIN_UV_IRQ)) ret = IRQ_HANDLED; if (smb347_update_status(smb) > 0) { smb347_update_online(smb); power_supply_changed(&smb->mains); power_supply_changed(&smb->usb); ret = IRQ_HANDLED; } return ret; }
static int smb347_hw_init(struct smb347_charger *smb) { int ret; ret = smb347_set_writable(smb, true); if (ret < 0) return ret; /* * Program the platform specific configuration values to the device * first. */ ret = smb347_set_charge_current(smb); if (ret < 0) goto fail; ret = smb347_set_current_limits(smb); if (ret < 0) goto fail; ret = smb347_set_voltage_limits(smb); if (ret < 0) goto fail; ret = smb347_set_temp_limits(smb); if (ret < 0) goto fail; /* If USB charging is disabled we put the USB in suspend mode */ if (!smb->pdata->use_usb) { ret = smb347_read(smb, CMD_A); if (ret < 0) goto fail; ret |= CMD_A_SUSPEND_ENABLED; ret = smb347_write(smb, CMD_A, ret); if (ret < 0) goto fail; } ret = smb347_read(smb, CFG_OTHER); if (ret < 0) goto fail; /* * If configured by platform data, we enable hardware Auto-OTG * support for driving VBUS. Otherwise we disable it. */ ret &= ~CFG_OTHER_RID_MASK; if (smb->pdata->use_usb_otg) ret |= CFG_OTHER_RID_ENABLED_AUTO_OTG; ret = smb347_write(smb, CFG_OTHER, ret); if (ret < 0) goto fail; ret = smb347_read(smb, CFG_PIN); if (ret < 0) goto fail; /* * Make the charging functionality controllable by a write to the * command register unless pin control is specified in the platform * data. */ ret &= ~(CFG_PIN_EN_CTRL_MASK | CFG_PIN_USB_MODE_CTRL); switch (smb->pdata->enable_control) { case SMB347_CHG_ENABLE_SW: /* Do nothing, 0 means i2c control */ break; case SMB347_CHG_ENABLE_PIN_ACTIVE_LOW: ret |= CFG_PIN_EN_CTRL_ACTIVE_LOW; break; case SMB347_CHG_ENABLE_PIN_ACTIVE_HIGH: ret |= CFG_PIN_EN_CTRL_ACTIVE_HIGH; break; } if (smb->pdata->usb_mode_pin_ctrl) ret |= CFG_PIN_USB_MODE_CTRL; /* Disable Automatic Power Source Detection (APSD) interrupt. */ ret &= ~CFG_PIN_EN_APSD_IRQ; ret = smb347_write(smb, CFG_PIN, ret); if (ret < 0) goto fail; ret = smb347_update_status(smb); if (ret < 0) goto fail; ret = smb347_update_online(smb); fail: smb347_set_writable(smb, false); return ret; }