Loading Documentation/devicetree/bindings/power/smb1360-charger-fg.txt +22 −0 Original line number Original line Diff line number Diff line Loading @@ -59,6 +59,19 @@ Optional Properties: signal when interrupt happened. If this property is not specified, signal when interrupt happened. If this property is not specified, the default configuration is static level irq. the default configuration is static level irq. - qcom,shdn-after-pwroff: A bool property to configure smb1360 for shutdown at power-off. - qcom,shdn-after-pwroff: A bool property to configure smb1360 for shutdown at power-off. - qcom,batt-profile-select A boolean flag to indicate of battery-profile selection is enabled. - qcom,profile-a-rid-kohm The battery-ID resistor (RID) in Kohm supported by profile-A of SMB1360. This should be specified if 'batt-profile-select' is defined. - qcom,profile-b-rid-kohm The battery-ID resistor (RID) in Kohm supported by profile-B of SMB1360. This should be specified if 'batt-profile-select' is defined. - qcom,batt-id-vref-uv The reference voltage on the battery-ID line specified in micro-volts. - qcom,batt-id-rpullup-kohm The pull-up resistor connected on the battery-ID (vref) line. - qcom,smb1360-vadc VADC device phandle (used for reading the RID) Example: Example: i2c@f9967000 { i2c@f9967000 { Loading @@ -69,6 +82,15 @@ Example: interrupts = <0x00 0xcd 0>; interrupts = <0x00 0xcd 0>; pinctrl-names = "default"; pinctrl-names = "default"; pinctrl-0 = <&smb_int_default>; pinctrl-0 = <&smb_int_default>; /* battery-profile selection properties */ qcom,batt-profile-select; qcom,smb1360-vadc = <&pm8916_vadc>; qcom,batt-id-vref-uv = <1800000>; qcom,batt-id-rpullup-kohm = <100>; qcom,profile-a-rid-kohm = <78>; qcom,profile-b-rid-kohm = <200>; qcom,float-voltage-mv = <4200>; qcom,float-voltage-mv = <4200>; qcom,iterm-ma = <100>; qcom,iterm-ma = <100>; qcom,charging-disabled; qcom,charging-disabled; Loading drivers/power/smb1360-charger-fg.c +271 −7 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/interrupt.h> #include <linux/math64.h> #include <linux/slab.h> #include <linux/slab.h> #include <linux/power_supply.h> #include <linux/power_supply.h> #include <linux/regulator/driver.h> #include <linux/regulator/driver.h> Loading @@ -26,6 +27,7 @@ #include <linux/of.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_gpio.h> #include <linux/bitops.h> #include <linux/bitops.h> #include <linux/qpnp/qpnp-adc.h> #define _SMB1360_MASK(BITS, POS) \ #define _SMB1360_MASK(BITS, POS) \ ((unsigned char)(((1 << (BITS)) - 1) << (POS))) ((unsigned char)(((1 << (BITS)) - 1) << (POS))) Loading Loading @@ -78,6 +80,9 @@ #define BATT_ID_ENABLED_BIT BIT(5) #define BATT_ID_ENABLED_BIT BIT(5) #define CHG_BATT_ID_FAIL BIT(4) #define CHG_BATT_ID_FAIL BIT(4) #define BATT_ID_FAIL_SELECT_PROFILE BIT(3) #define BATT_ID_FAIL_SELECT_PROFILE BIT(3) #define BATT_PROFILE_SELECT_MASK SMB1360_MASK(3, 0) #define BATT_PROFILEA_MASK 0x0 #define BATT_PROFILEB_MASK 0xF #define IRQ_CFG_REG 0x0F #define IRQ_CFG_REG 0x0F #define IRQ_BAT_HOT_COLD_HARD_BIT BIT(7) #define IRQ_BAT_HOT_COLD_HARD_BIT BIT(7) Loading Loading @@ -114,6 +119,8 @@ /* Command Registers */ /* Command Registers */ #define CMD_I2C_REG 0x40 #define CMD_I2C_REG 0x40 #define ALLOW_VOLATILE_BIT BIT(6) #define ALLOW_VOLATILE_BIT BIT(6) #define FG_ACCESS_ENABLED_BIT BIT(5) #define FG_RESET_BIT BIT(4) #define CMD_IL_REG 0x41 #define CMD_IL_REG 0x41 #define USB_CTRL_MASK SMB1360_MASK(1 , 0) #define USB_CTRL_MASK SMB1360_MASK(1 , 0) Loading Loading @@ -164,6 +171,9 @@ #define IRQ_H_REG 0x57 #define IRQ_H_REG 0x57 #define IRQ_I_REG 0x58 #define IRQ_I_REG 0x58 #define FG_ACCESS_ALLOWED_BIT BIT(0) #define BATT_ID_RESULT_BIT SMB1360_MASK(6, 4) #define BATT_ID_SHIFT 4 /* FG registers - IRQ config register */ /* FG registers - IRQ config register */ #define SOC_MAX_REG 0x24 #define SOC_MAX_REG 0x24 Loading @@ -174,6 +184,9 @@ /* FG SHADOW registers */ /* FG SHADOW registers */ #define SHDW_FG_ESR_ACTUAL 0x20 #define SHDW_FG_ESR_ACTUAL 0x20 #define SHDW_FG_BATT_STATUS 0x60 #define BATTERY_PROFILE_BIT BIT(0) #define SHDW_FG_MSYS_SOC 0x61 #define SHDW_FG_MSYS_SOC 0x61 #define SHDW_FG_CAPACITY 0x62 #define SHDW_FG_CAPACITY 0x62 #define SHDW_FG_VTG_NOW 0x69 #define SHDW_FG_VTG_NOW 0x69 Loading Loading @@ -208,6 +221,12 @@ enum fg_i2c_access_type { FG_ACCESS_PROFILE_B = 0x3 FG_ACCESS_PROFILE_B = 0x3 }; }; enum { BATTERY_PROFILE_A, BATTERY_PROFILE_B, BATTERY_PROFILE_MAX, }; struct smb1360_otg_regulator { struct smb1360_otg_regulator { struct regulator_desc rdesc; struct regulator_desc rdesc; struct regulator_dev *rdev; struct regulator_dev *rdev; Loading @@ -233,6 +252,7 @@ struct smb1360_chip { int vfloat_mv; int vfloat_mv; int safety_time; int safety_time; int resume_delta_mv; int resume_delta_mv; u32 default_batt_profile; unsigned int thermal_levels; unsigned int thermal_levels; unsigned int therm_lvl_sel; unsigned int therm_lvl_sel; unsigned int *thermal_mitigation; unsigned int *thermal_mitigation; Loading @@ -259,6 +279,8 @@ struct smb1360_chip { u8 irq_cfg_mask[3]; u8 irq_cfg_mask[3]; int usb_psy_ma; int usb_psy_ma; int charging_disabled_status; int charging_disabled_status; u32 connected_rid; u32 profile_rid[BATTERY_PROFILE_MAX]; u32 peek_poke_address; u32 peek_poke_address; u32 fg_access_type; u32 fg_access_type; Loading @@ -267,6 +289,7 @@ struct smb1360_chip { int skip_reads; int skip_reads; struct dentry *debug_root; struct dentry *debug_root; struct qpnp_vadc_chip *vadc_dev; struct power_supply *usb_psy; struct power_supply *usb_psy; struct power_supply batt_psy; struct power_supply batt_psy; struct smb1360_otg_regulator otg_vreg; struct smb1360_otg_regulator otg_vreg; Loading Loading @@ -1261,6 +1284,14 @@ static int fg_access_allowed_handler(struct smb1360_chip *chip, u8 rt_stat) return 0; return 0; } } static int batt_id_complete_handler(struct smb1360_chip *chip, u8 rt_stat) { pr_debug("batt_id = %x\n", (rt_stat & BATT_ID_RESULT_BIT) >> BATT_ID_SHIFT); return 0; } struct smb_irq_info { struct smb_irq_info { const char *name; const char *name; int (*smb_irq)(struct smb1360_chip *chip, int (*smb_irq)(struct smb1360_chip *chip, Loading Loading @@ -1429,11 +1460,9 @@ static struct irq_handler_info handlers[] = { { { .name = "fg_data_recovery", .name = "fg_data_recovery", }, }, { .name = "batt_id_result", }, { { .name = "batt_id_complete", .name = "batt_id_complete", .smb_irq = batt_id_complete_handler, }, }, }, }, }, }, Loading @@ -1441,6 +1470,8 @@ static struct irq_handler_info handlers[] = { #define IRQ_LATCHED_MASK 0x02 #define IRQ_LATCHED_MASK 0x02 #define IRQ_STATUS_MASK 0x01 #define IRQ_STATUS_MASK 0x01 #define BATT_ID_LATCHED_MASK 0x08 #define BATT_ID_STATUS_MASK 0x07 #define BITS_PER_IRQ 2 #define BITS_PER_IRQ 2 static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) { { Loading @@ -1448,7 +1479,7 @@ static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) int i, j; int i, j; u8 triggered; u8 triggered; u8 changed; u8 changed; u8 rt_stat, prev_rt_stat; u8 rt_stat, prev_rt_stat, irq_latched_mask, irq_status_mask; int rc; int rc; int handler_count = 0; int handler_count = 0; Loading @@ -1472,12 +1503,19 @@ static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) } } for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) { for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) { if (handlers[i].stat_reg == IRQ_I_REG && j == 2) { irq_latched_mask = BATT_ID_LATCHED_MASK; irq_status_mask = BATT_ID_STATUS_MASK; } else { irq_latched_mask = IRQ_LATCHED_MASK; irq_status_mask = IRQ_STATUS_MASK; } triggered = handlers[i].val triggered = handlers[i].val & (IRQ_LATCHED_MASK << (j * BITS_PER_IRQ)); & (irq_latched_mask << (j * BITS_PER_IRQ)); rt_stat = handlers[i].val rt_stat = handlers[i].val & (IRQ_STATUS_MASK << (j * BITS_PER_IRQ)); & (irq_status_mask << (j * BITS_PER_IRQ)); prev_rt_stat = handlers[i].prev_val prev_rt_stat = handlers[i].prev_val & (IRQ_STATUS_MASK << (j * BITS_PER_IRQ)); & (irq_status_mask << (j * BITS_PER_IRQ)); changed = prev_rt_stat ^ rt_stat; changed = prev_rt_stat ^ rt_stat; if (triggered || changed) if (triggered || changed) Loading Loading @@ -1513,6 +1551,8 @@ static int show_irq_count(struct seq_file *m, void *data) for (i = 0; i < ARRAY_SIZE(handlers); i++) for (i = 0; i < ARRAY_SIZE(handlers); i++) for (j = 0; j < 4; j++) { for (j = 0; j < 4; j++) { if (!handlers[i].irq_info[j].name) continue; seq_printf(m, "%s=%d\t(high=%d low=%d)\n", seq_printf(m, "%s=%d\t(high=%d low=%d)\n", handlers[i].irq_info[j].name, handlers[i].irq_info[j].name, handlers[i].irq_info[j].high handlers[i].irq_info[j].high Loading Loading @@ -1902,6 +1942,144 @@ static int smb1360_regulator_init(struct smb1360_chip *chip) return rc; return rc; } } static int smb1360_check_batt_profile(struct smb1360_chip *chip) { int rc, i, timeout = 50; u8 reg = 0, loaded_profile, new_profile = 0, bid_mask; if (!chip->connected_rid) { pr_debug("Skip batt-profile loading connected_rid=%d\n", chip->connected_rid); return 0; } rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, ®); if (rc) { pr_err("Couldn't read FG_BATT_STATUS rc=%d\n", rc); goto fail_profile; } loaded_profile = !!(reg & BATTERY_PROFILE_BIT) ? BATTERY_PROFILE_B : BATTERY_PROFILE_A; pr_debug("fg_batt_status=%x loaded_profile=%d\n", reg, loaded_profile); for (i = 0; i < BATTERY_PROFILE_MAX; i++) { pr_debug("profile=%d profile_rid=%d connected_rid=%d\n", i, chip->profile_rid[i], chip->connected_rid); if (abs(chip->profile_rid[i] - chip->connected_rid) < (div_u64(chip->connected_rid, 10))) break; } if (i == BATTERY_PROFILE_MAX) { pr_err("None of the battery-profiles match the connected-RID\n"); return 0; } else { if (i == loaded_profile) { pr_debug("Loaded Profile-RID == connected-RID\n"); return 0; } else { new_profile = (loaded_profile == BATTERY_PROFILE_A) ? BATTERY_PROFILE_B : BATTERY_PROFILE_A; bid_mask = (new_profile == BATTERY_PROFILE_A) ? BATT_PROFILEA_MASK : BATT_PROFILEB_MASK; pr_info("Loaded Profile-RID != connected-RID, switch-profile old_profile=%d new_profile=%d\n", loaded_profile, new_profile); } } /* set the BID mask */ rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, BATT_PROFILE_SELECT_MASK, bid_mask); if (rc) { pr_err("Couldn't reset battery-profile rc=%d\n", rc); goto fail_profile; } /* enable FG access */ rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, FG_ACCESS_ENABLED_BIT); if (rc) { pr_err("Couldn't enable FG access rc=%d\n", rc); goto fail_profile; } while (timeout) { /* delay for FG access to be granted */ msleep(100); rc = smb1360_read(chip, IRQ_I_REG, ®); if (rc) { pr_err("Could't read IRQ_I_REG rc=%d\n", rc); goto restore_fg; } if (reg & FG_ACCESS_ALLOWED_BIT) break; timeout--; } if (!timeout) { pr_err("FG access timed-out\n"); rc = -EAGAIN; goto restore_fg; } /* delay after handshaking for profile-switch to continue */ msleep(1500); /* reset FG */ rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, FG_RESET_BIT); if (rc) { pr_err("Couldn't reset FG rc=%d\n", rc); goto restore_fg; } /* un-reset FG */ rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, 0); if (rc) { pr_err("Couldn't un-reset FG rc=%d\n", rc); goto restore_fg; } /* disable FG access */ rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0); if (rc) { pr_err("Couldn't disable FG access rc=%d\n", rc); goto restore_fg; } timeout = 10; while (timeout) { /* delay for profile to change */ msleep(500); rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, ®); if (rc) { pr_err("Could't read FG_BATT_STATUS rc=%d\n", rc); goto restore_fg; } reg = !!(reg & BATTERY_PROFILE_BIT); if (reg == new_profile) { pr_info("New profile=%d loaded\n", new_profile); break; } timeout--; } if (!timeout) { pr_err("New profile could not be loaded\n"); return -EBUSY; } return 0; restore_fg: smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0); fail_profile: return rc; } static int determine_initial_status(struct smb1360_chip *chip) static int determine_initial_status(struct smb1360_chip *chip) { { int rc; int rc; Loading Loading @@ -2125,6 +2303,11 @@ static int smb1360_hw_init(struct smb1360_chip *chip) return rc; return rc; } } } } rc = smb1360_check_batt_profile(chip); if (rc) pr_err("Unable to modify battery profile\n"); /* /* * set chg en by cmd register, set chg en by writing bit 1, * set chg en by cmd register, set chg en by writing bit 1, * enable auto pre to fast * enable auto pre to fast Loading Loading @@ -2367,6 +2550,78 @@ static int smb1360_hw_init(struct smb1360_chip *chip) return rc; return rc; } } static int smb_parse_batt_id(struct smb1360_chip *chip) { int rc = 0, rpull = 0, vref = 0; int64_t denom, batt_id_uv; struct device_node *node = chip->dev->of_node; struct qpnp_vadc_result result; chip->vadc_dev = qpnp_get_vadc(chip->dev, "smb1360"); if (IS_ERR(chip->vadc_dev)) { rc = PTR_ERR(chip->vadc_dev); if (rc == -EPROBE_DEFER) pr_err("vadc not found - defer rc=%d\n", rc); else pr_err("vadc property missing, rc=%d\n", rc); return rc; } rc = of_property_read_u32(node, "qcom,profile-a-rid-kohm", &chip->profile_rid[0]); if (rc < 0) { pr_err("Couldn't read profile-a-rid-kohm rc=%d\n", rc); return rc; } rc = of_property_read_u32(node, "qcom,profile-b-rid-kohm", &chip->profile_rid[1]); if (rc < 0) { pr_err("Couldn't read profile-b-rid-kohm rc=%d\n", rc); return rc; } rc = of_property_read_u32(node, "qcom,batt-id-vref-uv", &vref); if (rc < 0) { pr_err("Couldn't read batt-id-vref-uv rc=%d\n", rc); return rc; } rc = of_property_read_u32(node, "qcom,batt-id-rpullup-kohm", &rpull); if (rc < 0) { pr_err("Couldn't read batt-id-rpullup-kohm rc=%d\n", rc); return rc; } /* read battery ID */ rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX2_BAT_ID, &result); if (rc) { pr_err("error reading batt id channel = %d, rc = %d\n", LR_MUX2_BAT_ID, rc); return rc; } batt_id_uv = result.physical; if (batt_id_uv == 0) { /* vadc not correct or batt id line grounded, report 0 kohms */ pr_err("batt_id_uv = 0, batt-id grounded using same profile\n"); return 0; } denom = div64_s64(vref * 1000000LL, batt_id_uv) - 1000000LL; if (denom == 0) { /* batt id connector might be open, return 0 kohms */ return 0; } chip->connected_rid = div64_s64(rpull * 1000000LL + denom/2, denom); pr_debug("batt_id_voltage = %lld, connected_rid = %d\n", batt_id_uv, chip->connected_rid); return 0; } static int smb_parse_dt(struct smb1360_chip *chip) static int smb_parse_dt(struct smb1360_chip *chip) { { int rc; int rc; Loading @@ -2377,6 +2632,15 @@ static int smb_parse_dt(struct smb1360_chip *chip) return -EINVAL; return -EINVAL; } } if (of_property_read_bool(node, "qcom,batt-profile-select")) { rc = smb_parse_batt_id(chip); if (rc < 0) { if (rc != -EPROBE_DEFER) pr_err("Unable to parse batt-id rc=%d\n", rc); return rc; } } chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq"); chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq"); rc = of_property_read_u32(node, "qcom,float-voltage-mv", rc = of_property_read_u32(node, "qcom,float-voltage-mv", Loading Loading
Documentation/devicetree/bindings/power/smb1360-charger-fg.txt +22 −0 Original line number Original line Diff line number Diff line Loading @@ -59,6 +59,19 @@ Optional Properties: signal when interrupt happened. If this property is not specified, signal when interrupt happened. If this property is not specified, the default configuration is static level irq. the default configuration is static level irq. - qcom,shdn-after-pwroff: A bool property to configure smb1360 for shutdown at power-off. - qcom,shdn-after-pwroff: A bool property to configure smb1360 for shutdown at power-off. - qcom,batt-profile-select A boolean flag to indicate of battery-profile selection is enabled. - qcom,profile-a-rid-kohm The battery-ID resistor (RID) in Kohm supported by profile-A of SMB1360. This should be specified if 'batt-profile-select' is defined. - qcom,profile-b-rid-kohm The battery-ID resistor (RID) in Kohm supported by profile-B of SMB1360. This should be specified if 'batt-profile-select' is defined. - qcom,batt-id-vref-uv The reference voltage on the battery-ID line specified in micro-volts. - qcom,batt-id-rpullup-kohm The pull-up resistor connected on the battery-ID (vref) line. - qcom,smb1360-vadc VADC device phandle (used for reading the RID) Example: Example: i2c@f9967000 { i2c@f9967000 { Loading @@ -69,6 +82,15 @@ Example: interrupts = <0x00 0xcd 0>; interrupts = <0x00 0xcd 0>; pinctrl-names = "default"; pinctrl-names = "default"; pinctrl-0 = <&smb_int_default>; pinctrl-0 = <&smb_int_default>; /* battery-profile selection properties */ qcom,batt-profile-select; qcom,smb1360-vadc = <&pm8916_vadc>; qcom,batt-id-vref-uv = <1800000>; qcom,batt-id-rpullup-kohm = <100>; qcom,profile-a-rid-kohm = <78>; qcom,profile-b-rid-kohm = <200>; qcom,float-voltage-mv = <4200>; qcom,float-voltage-mv = <4200>; qcom,iterm-ma = <100>; qcom,iterm-ma = <100>; qcom,charging-disabled; qcom,charging-disabled; Loading
drivers/power/smb1360-charger-fg.c +271 −7 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/interrupt.h> #include <linux/math64.h> #include <linux/slab.h> #include <linux/slab.h> #include <linux/power_supply.h> #include <linux/power_supply.h> #include <linux/regulator/driver.h> #include <linux/regulator/driver.h> Loading @@ -26,6 +27,7 @@ #include <linux/of.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_gpio.h> #include <linux/bitops.h> #include <linux/bitops.h> #include <linux/qpnp/qpnp-adc.h> #define _SMB1360_MASK(BITS, POS) \ #define _SMB1360_MASK(BITS, POS) \ ((unsigned char)(((1 << (BITS)) - 1) << (POS))) ((unsigned char)(((1 << (BITS)) - 1) << (POS))) Loading Loading @@ -78,6 +80,9 @@ #define BATT_ID_ENABLED_BIT BIT(5) #define BATT_ID_ENABLED_BIT BIT(5) #define CHG_BATT_ID_FAIL BIT(4) #define CHG_BATT_ID_FAIL BIT(4) #define BATT_ID_FAIL_SELECT_PROFILE BIT(3) #define BATT_ID_FAIL_SELECT_PROFILE BIT(3) #define BATT_PROFILE_SELECT_MASK SMB1360_MASK(3, 0) #define BATT_PROFILEA_MASK 0x0 #define BATT_PROFILEB_MASK 0xF #define IRQ_CFG_REG 0x0F #define IRQ_CFG_REG 0x0F #define IRQ_BAT_HOT_COLD_HARD_BIT BIT(7) #define IRQ_BAT_HOT_COLD_HARD_BIT BIT(7) Loading Loading @@ -114,6 +119,8 @@ /* Command Registers */ /* Command Registers */ #define CMD_I2C_REG 0x40 #define CMD_I2C_REG 0x40 #define ALLOW_VOLATILE_BIT BIT(6) #define ALLOW_VOLATILE_BIT BIT(6) #define FG_ACCESS_ENABLED_BIT BIT(5) #define FG_RESET_BIT BIT(4) #define CMD_IL_REG 0x41 #define CMD_IL_REG 0x41 #define USB_CTRL_MASK SMB1360_MASK(1 , 0) #define USB_CTRL_MASK SMB1360_MASK(1 , 0) Loading Loading @@ -164,6 +171,9 @@ #define IRQ_H_REG 0x57 #define IRQ_H_REG 0x57 #define IRQ_I_REG 0x58 #define IRQ_I_REG 0x58 #define FG_ACCESS_ALLOWED_BIT BIT(0) #define BATT_ID_RESULT_BIT SMB1360_MASK(6, 4) #define BATT_ID_SHIFT 4 /* FG registers - IRQ config register */ /* FG registers - IRQ config register */ #define SOC_MAX_REG 0x24 #define SOC_MAX_REG 0x24 Loading @@ -174,6 +184,9 @@ /* FG SHADOW registers */ /* FG SHADOW registers */ #define SHDW_FG_ESR_ACTUAL 0x20 #define SHDW_FG_ESR_ACTUAL 0x20 #define SHDW_FG_BATT_STATUS 0x60 #define BATTERY_PROFILE_BIT BIT(0) #define SHDW_FG_MSYS_SOC 0x61 #define SHDW_FG_MSYS_SOC 0x61 #define SHDW_FG_CAPACITY 0x62 #define SHDW_FG_CAPACITY 0x62 #define SHDW_FG_VTG_NOW 0x69 #define SHDW_FG_VTG_NOW 0x69 Loading Loading @@ -208,6 +221,12 @@ enum fg_i2c_access_type { FG_ACCESS_PROFILE_B = 0x3 FG_ACCESS_PROFILE_B = 0x3 }; }; enum { BATTERY_PROFILE_A, BATTERY_PROFILE_B, BATTERY_PROFILE_MAX, }; struct smb1360_otg_regulator { struct smb1360_otg_regulator { struct regulator_desc rdesc; struct regulator_desc rdesc; struct regulator_dev *rdev; struct regulator_dev *rdev; Loading @@ -233,6 +252,7 @@ struct smb1360_chip { int vfloat_mv; int vfloat_mv; int safety_time; int safety_time; int resume_delta_mv; int resume_delta_mv; u32 default_batt_profile; unsigned int thermal_levels; unsigned int thermal_levels; unsigned int therm_lvl_sel; unsigned int therm_lvl_sel; unsigned int *thermal_mitigation; unsigned int *thermal_mitigation; Loading @@ -259,6 +279,8 @@ struct smb1360_chip { u8 irq_cfg_mask[3]; u8 irq_cfg_mask[3]; int usb_psy_ma; int usb_psy_ma; int charging_disabled_status; int charging_disabled_status; u32 connected_rid; u32 profile_rid[BATTERY_PROFILE_MAX]; u32 peek_poke_address; u32 peek_poke_address; u32 fg_access_type; u32 fg_access_type; Loading @@ -267,6 +289,7 @@ struct smb1360_chip { int skip_reads; int skip_reads; struct dentry *debug_root; struct dentry *debug_root; struct qpnp_vadc_chip *vadc_dev; struct power_supply *usb_psy; struct power_supply *usb_psy; struct power_supply batt_psy; struct power_supply batt_psy; struct smb1360_otg_regulator otg_vreg; struct smb1360_otg_regulator otg_vreg; Loading Loading @@ -1261,6 +1284,14 @@ static int fg_access_allowed_handler(struct smb1360_chip *chip, u8 rt_stat) return 0; return 0; } } static int batt_id_complete_handler(struct smb1360_chip *chip, u8 rt_stat) { pr_debug("batt_id = %x\n", (rt_stat & BATT_ID_RESULT_BIT) >> BATT_ID_SHIFT); return 0; } struct smb_irq_info { struct smb_irq_info { const char *name; const char *name; int (*smb_irq)(struct smb1360_chip *chip, int (*smb_irq)(struct smb1360_chip *chip, Loading Loading @@ -1429,11 +1460,9 @@ static struct irq_handler_info handlers[] = { { { .name = "fg_data_recovery", .name = "fg_data_recovery", }, }, { .name = "batt_id_result", }, { { .name = "batt_id_complete", .name = "batt_id_complete", .smb_irq = batt_id_complete_handler, }, }, }, }, }, }, Loading @@ -1441,6 +1470,8 @@ static struct irq_handler_info handlers[] = { #define IRQ_LATCHED_MASK 0x02 #define IRQ_LATCHED_MASK 0x02 #define IRQ_STATUS_MASK 0x01 #define IRQ_STATUS_MASK 0x01 #define BATT_ID_LATCHED_MASK 0x08 #define BATT_ID_STATUS_MASK 0x07 #define BITS_PER_IRQ 2 #define BITS_PER_IRQ 2 static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) { { Loading @@ -1448,7 +1479,7 @@ static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) int i, j; int i, j; u8 triggered; u8 triggered; u8 changed; u8 changed; u8 rt_stat, prev_rt_stat; u8 rt_stat, prev_rt_stat, irq_latched_mask, irq_status_mask; int rc; int rc; int handler_count = 0; int handler_count = 0; Loading @@ -1472,12 +1503,19 @@ static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) } } for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) { for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) { if (handlers[i].stat_reg == IRQ_I_REG && j == 2) { irq_latched_mask = BATT_ID_LATCHED_MASK; irq_status_mask = BATT_ID_STATUS_MASK; } else { irq_latched_mask = IRQ_LATCHED_MASK; irq_status_mask = IRQ_STATUS_MASK; } triggered = handlers[i].val triggered = handlers[i].val & (IRQ_LATCHED_MASK << (j * BITS_PER_IRQ)); & (irq_latched_mask << (j * BITS_PER_IRQ)); rt_stat = handlers[i].val rt_stat = handlers[i].val & (IRQ_STATUS_MASK << (j * BITS_PER_IRQ)); & (irq_status_mask << (j * BITS_PER_IRQ)); prev_rt_stat = handlers[i].prev_val prev_rt_stat = handlers[i].prev_val & (IRQ_STATUS_MASK << (j * BITS_PER_IRQ)); & (irq_status_mask << (j * BITS_PER_IRQ)); changed = prev_rt_stat ^ rt_stat; changed = prev_rt_stat ^ rt_stat; if (triggered || changed) if (triggered || changed) Loading Loading @@ -1513,6 +1551,8 @@ static int show_irq_count(struct seq_file *m, void *data) for (i = 0; i < ARRAY_SIZE(handlers); i++) for (i = 0; i < ARRAY_SIZE(handlers); i++) for (j = 0; j < 4; j++) { for (j = 0; j < 4; j++) { if (!handlers[i].irq_info[j].name) continue; seq_printf(m, "%s=%d\t(high=%d low=%d)\n", seq_printf(m, "%s=%d\t(high=%d low=%d)\n", handlers[i].irq_info[j].name, handlers[i].irq_info[j].name, handlers[i].irq_info[j].high handlers[i].irq_info[j].high Loading Loading @@ -1902,6 +1942,144 @@ static int smb1360_regulator_init(struct smb1360_chip *chip) return rc; return rc; } } static int smb1360_check_batt_profile(struct smb1360_chip *chip) { int rc, i, timeout = 50; u8 reg = 0, loaded_profile, new_profile = 0, bid_mask; if (!chip->connected_rid) { pr_debug("Skip batt-profile loading connected_rid=%d\n", chip->connected_rid); return 0; } rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, ®); if (rc) { pr_err("Couldn't read FG_BATT_STATUS rc=%d\n", rc); goto fail_profile; } loaded_profile = !!(reg & BATTERY_PROFILE_BIT) ? BATTERY_PROFILE_B : BATTERY_PROFILE_A; pr_debug("fg_batt_status=%x loaded_profile=%d\n", reg, loaded_profile); for (i = 0; i < BATTERY_PROFILE_MAX; i++) { pr_debug("profile=%d profile_rid=%d connected_rid=%d\n", i, chip->profile_rid[i], chip->connected_rid); if (abs(chip->profile_rid[i] - chip->connected_rid) < (div_u64(chip->connected_rid, 10))) break; } if (i == BATTERY_PROFILE_MAX) { pr_err("None of the battery-profiles match the connected-RID\n"); return 0; } else { if (i == loaded_profile) { pr_debug("Loaded Profile-RID == connected-RID\n"); return 0; } else { new_profile = (loaded_profile == BATTERY_PROFILE_A) ? BATTERY_PROFILE_B : BATTERY_PROFILE_A; bid_mask = (new_profile == BATTERY_PROFILE_A) ? BATT_PROFILEA_MASK : BATT_PROFILEB_MASK; pr_info("Loaded Profile-RID != connected-RID, switch-profile old_profile=%d new_profile=%d\n", loaded_profile, new_profile); } } /* set the BID mask */ rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, BATT_PROFILE_SELECT_MASK, bid_mask); if (rc) { pr_err("Couldn't reset battery-profile rc=%d\n", rc); goto fail_profile; } /* enable FG access */ rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, FG_ACCESS_ENABLED_BIT); if (rc) { pr_err("Couldn't enable FG access rc=%d\n", rc); goto fail_profile; } while (timeout) { /* delay for FG access to be granted */ msleep(100); rc = smb1360_read(chip, IRQ_I_REG, ®); if (rc) { pr_err("Could't read IRQ_I_REG rc=%d\n", rc); goto restore_fg; } if (reg & FG_ACCESS_ALLOWED_BIT) break; timeout--; } if (!timeout) { pr_err("FG access timed-out\n"); rc = -EAGAIN; goto restore_fg; } /* delay after handshaking for profile-switch to continue */ msleep(1500); /* reset FG */ rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, FG_RESET_BIT); if (rc) { pr_err("Couldn't reset FG rc=%d\n", rc); goto restore_fg; } /* un-reset FG */ rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, 0); if (rc) { pr_err("Couldn't un-reset FG rc=%d\n", rc); goto restore_fg; } /* disable FG access */ rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0); if (rc) { pr_err("Couldn't disable FG access rc=%d\n", rc); goto restore_fg; } timeout = 10; while (timeout) { /* delay for profile to change */ msleep(500); rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, ®); if (rc) { pr_err("Could't read FG_BATT_STATUS rc=%d\n", rc); goto restore_fg; } reg = !!(reg & BATTERY_PROFILE_BIT); if (reg == new_profile) { pr_info("New profile=%d loaded\n", new_profile); break; } timeout--; } if (!timeout) { pr_err("New profile could not be loaded\n"); return -EBUSY; } return 0; restore_fg: smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0); fail_profile: return rc; } static int determine_initial_status(struct smb1360_chip *chip) static int determine_initial_status(struct smb1360_chip *chip) { { int rc; int rc; Loading Loading @@ -2125,6 +2303,11 @@ static int smb1360_hw_init(struct smb1360_chip *chip) return rc; return rc; } } } } rc = smb1360_check_batt_profile(chip); if (rc) pr_err("Unable to modify battery profile\n"); /* /* * set chg en by cmd register, set chg en by writing bit 1, * set chg en by cmd register, set chg en by writing bit 1, * enable auto pre to fast * enable auto pre to fast Loading Loading @@ -2367,6 +2550,78 @@ static int smb1360_hw_init(struct smb1360_chip *chip) return rc; return rc; } } static int smb_parse_batt_id(struct smb1360_chip *chip) { int rc = 0, rpull = 0, vref = 0; int64_t denom, batt_id_uv; struct device_node *node = chip->dev->of_node; struct qpnp_vadc_result result; chip->vadc_dev = qpnp_get_vadc(chip->dev, "smb1360"); if (IS_ERR(chip->vadc_dev)) { rc = PTR_ERR(chip->vadc_dev); if (rc == -EPROBE_DEFER) pr_err("vadc not found - defer rc=%d\n", rc); else pr_err("vadc property missing, rc=%d\n", rc); return rc; } rc = of_property_read_u32(node, "qcom,profile-a-rid-kohm", &chip->profile_rid[0]); if (rc < 0) { pr_err("Couldn't read profile-a-rid-kohm rc=%d\n", rc); return rc; } rc = of_property_read_u32(node, "qcom,profile-b-rid-kohm", &chip->profile_rid[1]); if (rc < 0) { pr_err("Couldn't read profile-b-rid-kohm rc=%d\n", rc); return rc; } rc = of_property_read_u32(node, "qcom,batt-id-vref-uv", &vref); if (rc < 0) { pr_err("Couldn't read batt-id-vref-uv rc=%d\n", rc); return rc; } rc = of_property_read_u32(node, "qcom,batt-id-rpullup-kohm", &rpull); if (rc < 0) { pr_err("Couldn't read batt-id-rpullup-kohm rc=%d\n", rc); return rc; } /* read battery ID */ rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX2_BAT_ID, &result); if (rc) { pr_err("error reading batt id channel = %d, rc = %d\n", LR_MUX2_BAT_ID, rc); return rc; } batt_id_uv = result.physical; if (batt_id_uv == 0) { /* vadc not correct or batt id line grounded, report 0 kohms */ pr_err("batt_id_uv = 0, batt-id grounded using same profile\n"); return 0; } denom = div64_s64(vref * 1000000LL, batt_id_uv) - 1000000LL; if (denom == 0) { /* batt id connector might be open, return 0 kohms */ return 0; } chip->connected_rid = div64_s64(rpull * 1000000LL + denom/2, denom); pr_debug("batt_id_voltage = %lld, connected_rid = %d\n", batt_id_uv, chip->connected_rid); return 0; } static int smb_parse_dt(struct smb1360_chip *chip) static int smb_parse_dt(struct smb1360_chip *chip) { { int rc; int rc; Loading @@ -2377,6 +2632,15 @@ static int smb_parse_dt(struct smb1360_chip *chip) return -EINVAL; return -EINVAL; } } if (of_property_read_bool(node, "qcom,batt-profile-select")) { rc = smb_parse_batt_id(chip); if (rc < 0) { if (rc != -EPROBE_DEFER) pr_err("Unable to parse batt-id rc=%d\n", rc); return rc; } } chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq"); chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq"); rc = of_property_read_u32(node, "qcom,float-voltage-mv", rc = of_property_read_u32(node, "qcom,float-voltage-mv", Loading