static void dump_regs(struct smb349_charger *chip) { int rc; u8 reg; u8 addr; for (addr = 0; addr <= LAST_CNFG_REG; addr++) { rc = smb349_read_reg(chip, addr, ®); if (rc) dev_err(chip->dev, "Couldn't read 0x%02x rc = %d\n", addr, rc); else pr_debug("0x%02x = 0x%02x\n", addr, reg); } for (addr = FIRST_STATUS_REG; addr <= LAST_STATUS_REG; addr++) { rc = smb349_read_reg(chip, addr, ®); if (rc) dev_err(chip->dev, "Couldn't read 0x%02x rc = %d\n", addr, rc); else pr_debug("0x%02x = 0x%02x\n", addr, reg); } for (addr = FIRST_CMD_REG; addr <= LAST_CMD_REG; addr++) { rc = smb349_read_reg(chip, addr, ®); if (rc) dev_err(chip->dev, "Couldn't read 0x%02x rc = %d\n", addr, rc); else pr_debug("0x%02x = 0x%02x\n", addr, reg); } }
static int determine_initial_state(struct smb349_charger *chip) { int rc; u8 reg = 0; rc = smb349_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; } chip->battery_missing = (reg & IRQ_B_BATT_MISSING_BIT) ? true : false; rc = smb349_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 = smb349_read_reg(chip, IRQ_A_REG, ®); if (rc < 0) { dev_err(chip->dev, "Couldn't read irq A rc = %d\n", rc); return rc; } if (reg & IRQ_A_HOT_HARD_BIT) chip->batt_hot = true; if (reg & IRQ_A_COLD_HARD_BIT) chip->batt_cold = true; if (reg & IRQ_A_HOT_SOFT_BIT) chip->batt_warm = true; if (reg & IRQ_A_COLD_SOFT_BIT) chip->batt_cool = true; rc = smb349_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) { chg_uv(chip, 1); } else { chg_uv(chip, 0); apsd_complete(chip, 1); } return 0; fail_init_status: dev_err(chip->dev, "Couldn't determine intial status\n"); return rc; }
static int smb349_get_prop_charge_type(struct smb349_dual_charger *chip) { int rc; u8 reg = 0; if (chip->chg_present && !chip->charging_disabled) { rc = smb349_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; } dev_dbg(chip->dev, "%s: STATUS_C_REG=%x\n", __func__, reg); reg &= STATUS_C_CHARGING_MASK; if ((reg == STATUS_C_FAST_CHARGING) || (reg == STATUS_C_TAPER_CHARGING)) return POWER_SUPPLY_CHARGE_TYPE_FAST; else if (reg == STATUS_C_PRE_CHARGING) return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; } return POWER_SUPPLY_CHARGE_TYPE_NONE; }
static int smb349_get_prop_batt_status(struct smb349_charger *chip) { int rc; u8 reg = 0; if (chip->batt_full) return POWER_SUPPLY_STATUS_FULL; rc = smb349_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; } dev_dbg(chip->dev, "%s: STATUS_C_REG=%x\n", __func__, reg); 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; }
static void handle_stat_irqs(struct smb349_dual_charger *chip) { int i, j; u8 triggered; u8 changed; u8 rt_stat, prev_rt_stat; int rc; int handler_count = 0; dev_dbg(chip->dev, "%s\n", __func__); for (i = 0; i < ARRAY_SIZE(handlers); i++) { rc = smb349_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) 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("cradle psy changed\n"); power_supply_changed(&chip->cradle_psy); } }
static int smb349_get_charging_status(struct smb349_charger *chip) { int rc; u8 reg = 0; rc = smb349_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; }
static int show_status_regs(struct seq_file *m, void *data) { struct smb349_charger *chip = m->private; int rc; u8 reg; u8 addr; for (addr = FIRST_STATUS_REG; addr <= LAST_STATUS_REG; addr++) { rc = smb349_read_reg(chip, addr, ®); if (!rc) seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); } return 0; }
static int smb349_chg_otg_regulator_is_enable(struct regulator_dev *rdev) { int rc = 0; u8 reg = 0; struct smb349_charger *chip = rdev_get_drvdata(rdev); rc = smb349_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; }
static int get_reg(void *data, u64 *val) { struct smb349_charger *chip = data; int rc; u8 temp; rc = smb349_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 get_reg(void *data, u64 *val) { int addr = (int)data; int ret; u8 temp = 0; ret = smb349_read_reg(the_smb349_chg->client, addr, &temp); if (ret) { pr_err("smb349_read_reg to %x value =%d errored = %d\n", addr, temp, ret); return -EAGAIN; } *val = temp; 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_get_prop_cradle_status(struct smb349_dual_charger *chip) { int rc; u8 reg = 0; if (chip->chg_present && !chip->charging_disabled) { rc = smb349_read_reg(chip, STATUS_C_REG, ®); if (rc) { dev_dbg(chip->dev, "Couldn't read STAT_C rc = %d\n", rc); return POWER_SUPPLY_STATUS_UNKNOWN; } dev_dbg(chip->dev, "%s: STATUS_C_REG=%x\n", __func__, reg); if ((reg & STATUS_C_CHARGING_MASK) && !(reg & STATUS_C_CHG_ERR_STATUS_BIT)) return POWER_SUPPLY_STATUS_CHARGING; } return POWER_SUPPLY_STATUS_DISCHARGING; }
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 apsd_complete(struct smb349_charger *chip, u8 status) { int rc; u8 reg = 0; enum power_supply_type type = POWER_SUPPLY_TYPE_UNKNOWN; /* * If apsd is disabled, charger detection is done by * DCIN UV irq. * status = ZERO - indicates charger removed, handled * by DCIN UV irq */ if (chip->disable_apsd || status == 0) { dev_dbg(chip->dev, "APSD %s, status = %d\n", chip->disable_apsd ? "disabled" : "enabled", !!status); return 0; } rc = smb349_read_reg(chip, STATUS_D_REG, ®); if (rc) { dev_err(chip->dev, "Couldn't read STATUS D rc = %d\n", rc); return rc; } dev_dbg(chip->dev, "%s: STATUS_D_REG=%x\n", __func__, reg); switch (reg) { case STATUS_D_PORT_ACA_DOCK: case STATUS_D_PORT_ACA_C: case STATUS_D_PORT_ACA_B: case STATUS_D_PORT_ACA_A: type = POWER_SUPPLY_TYPE_USB_ACA; break; case STATUS_D_PORT_CDP: type = POWER_SUPPLY_TYPE_USB_CDP; break; case STATUS_D_PORT_DCP: type = POWER_SUPPLY_TYPE_USB_DCP; break; case STATUS_D_PORT_SDP: type = POWER_SUPPLY_TYPE_USB; break; case STATUS_D_PORT_OTHER: type = POWER_SUPPLY_TYPE_USB_DCP; break; default: type = POWER_SUPPLY_TYPE_USB; break; } chip->chg_present = !!status; /* * Report the charger type as UNKNOWN if the * apsd-fail flag is set. This nofifies the USB driver * to initiate a s/w based charger type detection. */ if (chip->workaround_flags & WRKARND_APSD_FAIL) type = POWER_SUPPLY_TYPE_UNKNOWN; dev_dbg(chip->dev, "APSD complete. USB type detected=%d chg_present=%d", type, chip->chg_present); power_supply_set_supply_type(chip->usb_psy, type); /* SMB is now done sampling the D+/D- lines, indicate USB driver */ dev_dbg(chip->dev, "%s updating usb_psy present=%d", __func__, chip->chg_present); power_supply_set_present(chip->usb_psy, chip->chg_present); return 0; }
static irqreturn_t smb349_chg_stat_handler(int irq, void *dev_id) { struct smb349_charger *chip = dev_id; int i, j; u8 triggered; u8 changed; u8 rt_stat, prev_rt_stat; int rc; int handler_count = 0; mutex_lock(&chip->irq_complete); init_completion(&chip->resumed); chip->irq_waiting = true; if (!chip->resume_completed) { dev_dbg(chip->dev, "IRQ triggered before device-resume\n"); wait_for_completion_interruptible(&chip->resumed); } chip->irq_waiting = false; for (i = 0; i < ARRAY_SIZE(handlers); i++) { rc = smb349_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) 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); } mutex_unlock(&chip->irq_complete); return IRQ_HANDLED; }
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; }
static int smb349_charger_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc, irq; struct smb349_charger *chip; struct power_supply *usb_psy; u8 reg = 0; usb_psy = power_supply_get_by_name("usb"); if (!usb_psy) { dev_dbg(&client->dev, "USB psy not found; deferring probe\n"); return -EPROBE_DEFER; } chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) { dev_err(&client->dev, "Couldn't allocate memory\n"); return -ENOMEM; } chip->client = client; chip->dev = &client->dev; chip->usb_psy = usb_psy; chip->fake_battery_soc = -EINVAL; /* probe the device to check if its actually connected */ rc = smb349_read_reg(chip, CHG_OTH_CURRENT_CTRL_REG, ®); if (rc) { pr_err("Failed to detect SMB349, device may be absent\n"); return -ENODEV; } rc = smb_parse_dt(chip); if (rc) { dev_err(&client->dev, "Couldn't parse DT nodes rc=%d\n", rc); return rc; } i2c_set_clientdata(client, chip); chip->batt_psy.name = "battery"; chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY; chip->batt_psy.get_property = smb349_battery_get_property; chip->batt_psy.set_property = smb349_battery_set_property; chip->batt_psy.property_is_writeable = smb349_batt_property_is_writeable; chip->batt_psy.properties = smb349_battery_properties; chip->batt_psy.num_properties = ARRAY_SIZE(smb349_battery_properties); chip->batt_psy.external_power_changed = smb349_external_power_changed; chip->resume_completed = true; init_completion(&chip->resumed); mutex_init(&chip->irq_complete); rc = power_supply_register(chip->dev, &chip->batt_psy); if (rc < 0) { dev_err(&client->dev, "Couldn't register batt psy rc=%d\n", rc); return rc; } dump_regs(chip); rc = smb349_regulator_init(chip); if (rc) { dev_err(&client->dev, "Couldn't initialize smb349 ragulator rc=%d\n", rc); return rc; } rc = smb349_hw_init(chip); if (rc) { dev_err(&client->dev, "Couldn't intialize hardware rc=%d\n", rc); goto fail_smb349_hw_init; } rc = determine_initial_state(chip); if (rc) { dev_err(&client->dev, "Couldn't determine initial state rc=%d\n", rc); goto fail_smb349_hw_init; } if (gpio_is_valid(chip->chg_valid_gpio)) { rc = gpio_request(chip->chg_valid_gpio, "smb349_chg_valid"); if (rc) { dev_err(&client->dev, "gpio_request for %d failed rc=%d\n", chip->chg_valid_gpio, rc); goto fail_smb349_hw_init; } irq = gpio_to_irq(chip->chg_valid_gpio); if (irq < 0) { dev_err(&client->dev, "Invalid chg_valid irq = %d\n", irq); goto fail_chg_valid_irq; } rc = devm_request_threaded_irq(&client->dev, irq, NULL, smb349_chg_valid_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "smb349_chg_valid_irq", chip); if (rc) { dev_err(&client->dev, "Failed request_irq irq=%d, gpio=%d rc=%d\n", irq, chip->chg_valid_gpio, rc); goto fail_chg_valid_irq; } smb349_chg_valid_handler(irq, chip); enable_irq_wake(irq); } /* STAT irq configuration */ if (client->irq) { rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, smb349_chg_stat_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "smb349_chg_stat_irq", chip); if (rc) { dev_err(&client->dev, "Failed STAT irq=%d request rc = %d\n", client->irq, rc); goto fail_chg_valid_irq; } enable_irq_wake(client->irq); } chip->debug_root = debugfs_create_dir("smb349", NULL); if (!chip->debug_root) dev_err(chip->dev, "Couldn't create debug dir\n"); if (chip->debug_root) { struct dentry *ent; ent = debugfs_create_file("config_registers", S_IFREG | S_IRUGO, chip->debug_root, chip, &cnfg_debugfs_ops); if (!ent) dev_err(chip->dev, "Couldn't create cnfg debug file rc = %d\n", rc); ent = debugfs_create_file("status_registers", S_IFREG | S_IRUGO, chip->debug_root, chip, &status_debugfs_ops); if (!ent) dev_err(chip->dev, "Couldn't create status debug file rc = %d\n", rc); ent = debugfs_create_file("cmd_registers", S_IFREG | S_IRUGO, chip->debug_root, chip, &cmd_debugfs_ops); if (!ent) dev_err(chip->dev, "Couldn't create cmd debug file rc = %d\n", rc); ent = debugfs_create_x32("address", S_IFREG | S_IWUSR | S_IRUGO, chip->debug_root, &(chip->peek_poke_address)); if (!ent) dev_err(chip->dev, "Couldn't create address debug file rc = %d\n", rc); ent = debugfs_create_file("data", S_IFREG | S_IWUSR | S_IRUGO, chip->debug_root, chip, &poke_poke_debug_ops); if (!ent) dev_err(chip->dev, "Couldn't create data debug file rc = %d\n", rc); ent = debugfs_create_file("force_irq", S_IFREG | S_IWUSR | S_IRUGO, chip->debug_root, chip, &force_irq_ops); if (!ent) dev_err(chip->dev, "Couldn't create data debug file rc = %d\n", rc); ent = debugfs_create_file("irq_count", S_IFREG | S_IRUGO, chip->debug_root, chip, &irq_count_debugfs_ops); if (!ent) dev_err(chip->dev, "Couldn't create count debug file rc = %d\n", rc); } dump_regs(chip); dev_info(chip->dev, "SMB349 successfully probed. charger=%d, batt=%d\n", chip->chg_present, smb349_get_prop_batt_present(chip)); return 0; fail_chg_valid_irq: if (gpio_is_valid(chip->chg_valid_gpio)) gpio_free(chip->chg_valid_gpio); fail_smb349_hw_init: power_supply_unregister(&chip->batt_psy); regulator_unregister(chip->otg_vreg.rdev); return rc; }