diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index c7168716b74e..62cfe031601f 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -3,7 +3,7 @@ * Copyright (c) 2015, Sony Mobile Communications, AB. */ /* - * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "WLED: %s: " fmt, __func__ @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -182,6 +184,7 @@ enum wled_version { WLED_PMI8998 = 4, WLED_PM660L, WLED_PM8150L, + WLED_PM7325B, }; enum wled_flash_mode { @@ -194,6 +197,7 @@ static const int version_table[] = { [0] = WLED_PMI8998, [1] = WLED_PM660L, [2] = WLED_PM8150L, + [3] = WLED_PM7325B, }; struct wled_config { @@ -220,6 +224,7 @@ struct wled { struct platform_device *pdev; struct regmap *regmap; struct iio_channel **iio_channels; + struct power_supply *batt_psy; struct mutex lock; struct wled_config cfg; ktime_t last_sc_event_time; @@ -241,6 +246,7 @@ struct wled { bool auto_calib_done; bool force_mod_disable; bool cabc_disabled; + bool use_psy; int (*cabc_config)(struct wled *wled, bool enable); struct led_classdev flash_cdev; @@ -299,7 +305,7 @@ static inline bool is_wled4(struct wled *wled) static inline bool is_wled5(struct wled *wled) { - if (*wled->version == WLED_PM8150L) + if (*wled->version == WLED_PM8150L || *wled->version == WLED_PM7325B) return true; return false; @@ -314,7 +320,7 @@ static int wled_module_enable(struct wled *wled, int val) return 0; /* Force HFRC off */ - if (*wled->version == WLED_PM8150L) { + if (is_wled5(wled)) { reg = val ? 0 : 3; rc = regmap_write(wled->regmap, wled->ctrl_addr + WLED5_CTRL_PBUS_WRITE_SYNC_CTL, reg); @@ -329,7 +335,7 @@ static int wled_module_enable(struct wled *wled, int val) return rc; /* Force HFRC off */ - if (*wled->version == WLED_PM8150L && val) { + if (is_wled5(wled) && val) { rc = regmap_write(wled->regmap, wled->sink_addr + WLED5_SINK_FLASH_SHDN_CLR_REG, 0); if (rc < 0) @@ -1561,6 +1567,7 @@ static int wled_get_max_avail_current(struct led_classdev *led_cdev, struct wled *wled; int rc, ocv_mv, r_bat_mohms, i_bat_ma, i_sink_ma = 0, max_fsc_ma; int64_t p_out_string, p_out, p_in, v_safe_mv, i_flash_ma, v_ph_mv; + union power_supply_propval prop = {}; if (!strcmp(led_cdev->name, "wled_switch")) wled = container_of(led_cdev, struct wled, switch_cdev); @@ -1576,26 +1583,59 @@ static int wled_get_max_avail_current(struct led_classdev *led_cdev, return 0; } - rc = wled_iio_get_prop(wled, OCV, &ocv_mv); - if (rc < 0) { - pr_err("Error in getting OCV rc=%d\n", rc); - return rc; - } - ocv_mv /= 1000; + if (wled->use_psy) { + if (!wled->batt_psy) + wled->batt_psy = power_supply_get_by_name("battery"); - rc = wled_iio_get_prop(wled, IBAT, &i_bat_ma); - if (rc < 0) { - pr_err("Error in getting I_BAT rc=%d\n", rc); - return rc; - } - i_bat_ma /= 1000; + if (!wled->batt_psy) { + pr_err("Failed to get battery power supply\n"); + return -ENODEV; + } - rc = wled_iio_get_prop(wled, RBATT, &r_bat_mohms); - if (rc < 0) { - pr_err("Error in getting R_BAT rc=%d\n", rc); - return rc; + rc = power_supply_get_property(wled->batt_psy, POWER_SUPPLY_PROP_VOLTAGE_OCV, + &prop); + if (rc < 0) { + pr_err("Failed to get battery OCV, rc=%d\n", rc); + return rc; + } + ocv_mv = prop.intval/1000; + + rc = power_supply_get_property(wled->batt_psy, POWER_SUPPLY_PROP_CURRENT_NOW, + &prop); + if (rc < 0) { + pr_err("Failed to get battery current, rc=%d\n", rc); + return rc; + } + i_bat_ma = -prop.intval/1000; + + rc = qti_battery_charger_get_prop("battery", BATTERY_RESISTANCE, &r_bat_mohms); + if (rc < 0) { + pr_err("Failed to get battery resistance, rc=%d\n", rc); + return rc; + } + r_bat_mohms /= 1000; + } else { + rc = wled_iio_get_prop(wled, OCV, &ocv_mv); + if (rc < 0) { + pr_err("Error in getting OCV rc=%d\n", rc); + return rc; + } + ocv_mv /= 1000; + + rc = wled_iio_get_prop(wled, IBAT, &i_bat_ma); + if (rc < 0) { + pr_err("Error in getting I_BAT rc=%d\n", rc); + return rc; + } + i_bat_ma /= 1000; + + rc = wled_iio_get_prop(wled, RBATT, &r_bat_mohms); + if (rc < 0) { + pr_err("Error in getting R_BAT rc=%d\n", rc); + return rc; + } + r_bat_mohms /= 1000; } - r_bat_mohms /= 1000; pr_debug("ocv: %d i_bat: %d r_bat: %d\n", ocv_mv, i_bat_ma, r_bat_mohms); @@ -2340,6 +2380,14 @@ static int wled_probe(struct platform_device *pdev) return -ENODEV; } + switch (*wled->version) { + case WLED_PM7325B: + wled->use_psy = true; + break; + default: + break; + } + rc = wled_configure(wled, &pdev->dev); if (rc < 0) { dev_err(&pdev->dev, "wled configure failed rc:%d\n", rc); @@ -2413,6 +2461,7 @@ static const struct of_device_id wled_match_table[] = { { .compatible = "qcom,pm8150l-spmi-wled", .data = &version_table[2] }, { .compatible = "qcom,pm6150l-spmi-wled", .data = &version_table[2] }, { .compatible = "qcom,pm660l-spmi-wled", .data = &version_table[1] }, + { .compatible = "qcom,pm7325b-spmi-wled", .data = &version_table[3] }, { }, };