From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: mcc45tr Date: Sun, 30 Aug 2026 13:36:54 +0300 Subject: [PATCH 051/117] power: supply: stop Nabu charging on connector overheat --- .../boot/dts/qcom/sm8150-xiaomi-nabu.dts | 12 +++++ drivers/power/supply/qcom_smbx.c | 52 ++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts b/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts index 340508d530e8..d54ad6641184 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts @@ -718,6 +718,14 @@ vol_up_n: vol-up-n-state { }; }; +&pm8150b_adc { + channel@4f { + reg = ; + qcom,pre-scaling = <1 1>; + label = "conn_therm"; + }; +}; + &pm8150b_fg { status = "okay"; monitored-battery = <&battery>; @@ -728,6 +736,10 @@ &pm8150b_charger { status = "okay"; monitored-battery = <&battery>; input-power-supply = <&pm8150b_typec>; + io-channels = <&pm8150b_adc ADC5_USB_IN_I>, + <&pm8150b_adc ADC5_USB_IN_V_16>, + <&pm8150b_adc ADC5_AMUX_THM3_100K_PU>; + io-channel-names = "usbin_i", "usbin_v", "connector_temp"; #cooling-cells = <2>; /* OEM Nabu levels; the driver retains its verified 1.95 A ceiling. */ diff --git a/drivers/power/supply/qcom_smbx.c b/drivers/power/supply/qcom_smbx.c index ce7695a0e7f6..b43b4bdd29f4 100644 --- a/drivers/power/supply/qcom_smbx.c +++ b/drivers/power/supply/qcom_smbx.c @@ -210,6 +210,8 @@ enum smb_generation { #define SMB5_PD_6P5V_UV 6500000 #define SMB5_PD_7P5V_UV 7500000 #define SMB5_PD_8P5V_UV 8500000 +#define SMB5_CONNECTOR_SHUTDOWN_MC 70000 +#define SMB5_CONNECTOR_RESTART_MC 60000 /* pmi8998 registers represent current in increments of 1/40th of an amp */ #define CURRENT_SCALE_FACTOR 25000 @@ -270,6 +272,8 @@ struct smb_init_register { * @cdev: Linux thermal cooling device * @input_psy: Optional TCPM power supply describing the PD contract * @nb: Battery and TCPM power-supply change notifier + * @connector_temp_chan: USB connector thermistor temperature channel + * @connector_overheat: Connector shutdown latch with restart hysteresis * @cable_irq: USB plugin IRQ * @wakeup_enabled: If the cable IRQ will cause a wakeup * @usb_in_i_chan: USB_IN current measurement channel @@ -308,6 +312,8 @@ struct smb_chip { struct thermal_cooling_device *cdev; struct power_supply *input_psy; struct notifier_block nb; + struct iio_channel *connector_temp_chan; + bool connector_overheat; int cable_irq; bool wakeup_enabled; @@ -871,6 +877,13 @@ static int smb_merge_health(int hardware, int software) if (hardware == POWER_SUPPLY_HEALTH_COLD || software == POWER_SUPPLY_HEALTH_COLD) return POWER_SUPPLY_HEALTH_COLD; + if ((hardware != POWER_SUPPLY_HEALTH_GOOD && + hardware != POWER_SUPPLY_HEALTH_WARM && + hardware != POWER_SUPPLY_HEALTH_COOL) || + (software != POWER_SUPPLY_HEALTH_GOOD && + software != POWER_SUPPLY_HEALTH_WARM && + software != POWER_SUPPLY_HEALTH_COOL)) + return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; if ((hardware == POWER_SUPPLY_HEALTH_WARM && software == POWER_SUPPLY_HEALTH_COOL) || (hardware == POWER_SUPPLY_HEALTH_COOL && @@ -886,6 +899,29 @@ static int smb_merge_health(int hardware, int software) return POWER_SUPPLY_HEALTH_GOOD; } +static int smb_get_connector_health(struct smb_chip *chip, int *health) +{ + int temp_mc, rc; + + if (!chip->connector_temp_chan) { + *health = POWER_SUPPLY_HEALTH_GOOD; + return 0; + } + + rc = iio_read_channel_processed(chip->connector_temp_chan, &temp_mc); + if (rc < 0) + return rc; + + if (temp_mc >= SMB5_CONNECTOR_SHUTDOWN_MC) + chip->connector_overheat = true; + else if (temp_mc <= SMB5_CONNECTOR_RESTART_MC) + chip->connector_overheat = false; + + *health = chip->connector_overheat ? POWER_SUPPLY_HEALTH_OVERHEAT : + POWER_SUPPLY_HEALTH_GOOD; + return 0; +} + static unsigned int smb_get_thermal_input_limit(struct smb_chip *chip, unsigned long state) { @@ -1018,7 +1054,7 @@ static void smb_thermal_work(struct work_struct *work) container_of(work, struct smb_chip, thermal_work.work); unsigned int jeita_current_ua = UINT_MAX; unsigned int jeita_voltage_uv = UINT_MAX; - int hardware_health, software_health, health, rc; + int hardware_health, software_health, connector_health, health, rc; smb_update_input_contract(chip); rc = smb_get_prop_health(chip, &hardware_health); @@ -1038,6 +1074,10 @@ static void smb_thermal_work(struct work_struct *work) jeita_voltage_uv = 0; } health = smb_merge_health(hardware_health, software_health); + rc = smb_get_connector_health(chip, &connector_health); + if (rc < 0) + connector_health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + health = smb_merge_health(health, connector_health); } rc = smb_apply_charge_policy(chip, health, jeita_current_ua, @@ -1724,6 +1764,16 @@ static int smb_probe(struct platform_device *pdev) "Couldn't get usbin_i IIO channel\n"); } + if (device_property_match_string(chip->dev, "io-channel-names", + "connector_temp") >= 0) { + chip->connector_temp_chan = devm_iio_channel_get( + chip->dev, "connector_temp"); + if (IS_ERR(chip->connector_temp_chan)) + return dev_err_probe( + chip->dev, PTR_ERR(chip->connector_temp_chan), + "Couldn't get connector temperature channel\n"); + } + match_data = (const struct smb_match_data *)device_get_match_data(chip->dev); chip->gen = match_data->gen;