leds: qpnp-flash-v2: Add support for thermal current mitigation

Based on the thermal thresholds triggered, use the LUT to
limit the maximum available flash current.

CRs-Fixed: 1043718
Change-Id: I456d6491987183e07eba921edc826ff801fdeee3
Signed-off-by: Devesh Jhunjhunwala <deveshj@codeaurora.org>
This commit is contained in:
Devesh Jhunjhunwala 2016-07-20 12:06:57 -07:00
parent f816e044c2
commit 49d96e8bc7
2 changed files with 147 additions and 1 deletions

View file

@ -50,6 +50,10 @@ Optional properties:
Default value is 2. Default value is 2.
- qcom,lmh-level : Optional property to configure flash current preemptive mitigation. - qcom,lmh-level : Optional property to configure flash current preemptive mitigation.
Accepted values are 0, 1, and 3. Default value is 0. Accepted values are 0, 1, and 3. Default value is 0.
- qcom,thermal-derate-en : Boolean property to enable flash current thermal mitigation.
- qcom,thermal-derate-current : Array of currrent limits for thermal mitigation. Required if
qcom,thermal-derate-en is specified. Unit is mA. Format is
qcom,thermal-derate-current = <OTST1_LIMIT, OTST2_LIMIT, OTST3_LIMIT>.
- qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified - qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified
value, additional GPIO configuration may be required to provide strobing value, additional GPIO configuration may be required to provide strobing
support. Supported values are: support. Supported values are:

View file

@ -43,6 +43,9 @@
#define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50) #define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50)
#define FLASH_LED_REG_WARMUP_DELAY(base) (base + 0x51) #define FLASH_LED_REG_WARMUP_DELAY(base) (base + 0x51)
#define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52) #define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52)
#define FLASH_LED_REG_THERMAL_THRSH1(base) (base + 0x56)
#define FLASH_LED_REG_THERMAL_THRSH2(base) (base + 0x57)
#define FLASH_LED_REG_THERMAL_THRSH3(base) (base + 0x58)
#define FLASH_LED_REG_VPH_DROOP_THRESHOLD(base) (base + 0x61) #define FLASH_LED_REG_VPH_DROOP_THRESHOLD(base) (base + 0x61)
#define FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base) (base + 0x62) #define FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base) (base + 0x62)
#define FLASH_LED_REG_MITIGATION_SEL(base) (base + 0x6E) #define FLASH_LED_REG_MITIGATION_SEL(base) (base + 0x6E)
@ -63,6 +66,8 @@
#define FLASH_LED_LMH_LEVEL_MASK GENMASK(1, 0) #define FLASH_LED_LMH_LEVEL_MASK GENMASK(1, 0)
#define FLASH_LED_VPH_DROOP_HYSTERESIS_MASK GENMASK(5, 4) #define FLASH_LED_VPH_DROOP_HYSTERESIS_MASK GENMASK(5, 4)
#define FLASH_LED_VPH_DROOP_THRESHOLD_MASK GENMASK(2, 0) #define FLASH_LED_VPH_DROOP_THRESHOLD_MASK GENMASK(2, 0)
#define FLASH_LED_THERMAL_THRSH_MASK GENMASK(2, 0)
#define FLASH_LED_THERMAL_OTST_MASK GENMASK(2, 0)
#define FLASH_LED_MOD_CTRL_MASK BIT(7) #define FLASH_LED_MOD_CTRL_MASK BIT(7)
#define FLASH_LED_HW_SW_STROBE_SEL_MASK BIT(2) #define FLASH_LED_HW_SW_STROBE_SEL_MASK BIT(2)
#define FLASH_LED_VPH_DROOP_FAULT_MASK BIT(4) #define FLASH_LED_VPH_DROOP_FAULT_MASK BIT(4)
@ -82,6 +87,8 @@
#define FLASH_LED_VPH_DROOP_DEBOUNCE_MAX 3 #define FLASH_LED_VPH_DROOP_DEBOUNCE_MAX 3
#define FLASH_LED_VPH_DROOP_HYST_MAX 3 #define FLASH_LED_VPH_DROOP_HYST_MAX 3
#define FLASH_LED_VPH_DROOP_THRESH_MAX 7 #define FLASH_LED_VPH_DROOP_THRESH_MAX 7
#define FLASH_LED_THERMAL_THRSH_MIN 3
#define FLASH_LED_THERMAL_OTST_LEVELS 3
#define FLASH_LED_VLED_MAX_DEFAULT_UV 3500000 #define FLASH_LED_VLED_MAX_DEFAULT_UV 3500000
#define FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA 4500000 #define FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA 4500000
#define FLASH_LED_RPARA_DEFAULT_UOHM 0 #define FLASH_LED_RPARA_DEFAULT_UOHM 0
@ -175,6 +182,7 @@ struct flash_switch_data {
* Flash LED configuration read from device tree * Flash LED configuration read from device tree
*/ */
struct flash_led_platform_data { struct flash_led_platform_data {
int *thermal_derate_current;
int all_ramp_up_done_irq; int all_ramp_up_done_irq;
int all_ramp_down_done_irq; int all_ramp_down_done_irq;
int led_fault_irq; int led_fault_irq;
@ -193,6 +201,7 @@ struct flash_led_platform_data {
u8 lmh_level; u8 lmh_level;
u8 hw_strobe_option; u8 hw_strobe_option;
bool hdrm_auto_mode_en; bool hdrm_auto_mode_en;
bool thermal_derate_en;
}; };
/* /*
@ -232,6 +241,20 @@ qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data)
return rc; return rc;
} }
static int
qpnp_flash_led_masked_read(struct qpnp_flash_led *led, u16 addr, u8 mask,
u8 *val)
{
int rc;
rc = qpnp_flash_led_read(led, addr, val);
if (rc < 0)
return rc;
*val &= mask;
return rc;
}
static int static int
qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask, qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask,
u8 val) u8 val)
@ -535,10 +558,107 @@ static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led)
(int)(avail_flash_ua / MCONV)); (int)(avail_flash_ua / MCONV));
} }
static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led)
{
int thermal_current_lim = 0;
int rc;
u8 thermal_thrsh1, thermal_thrsh2, thermal_thrsh3, otst_status;
/* Store THERMAL_THRSHx register values */
rc = qpnp_flash_led_masked_read(led,
FLASH_LED_REG_THERMAL_THRSH1(led->base),
FLASH_LED_THERMAL_THRSH_MASK,
&thermal_thrsh1);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_read(led,
FLASH_LED_REG_THERMAL_THRSH2(led->base),
FLASH_LED_THERMAL_THRSH_MASK,
&thermal_thrsh2);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_read(led,
FLASH_LED_REG_THERMAL_THRSH3(led->base),
FLASH_LED_THERMAL_THRSH_MASK,
&thermal_thrsh3);
if (rc < 0)
return rc;
/* Lower THERMAL_THRSHx thresholds to minimum */
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_THERMAL_THRSH1(led->base),
FLASH_LED_THERMAL_THRSH_MASK,
FLASH_LED_THERMAL_THRSH_MIN);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_THERMAL_THRSH2(led->base),
FLASH_LED_THERMAL_THRSH_MASK,
FLASH_LED_THERMAL_THRSH_MIN);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_THERMAL_THRSH3(led->base),
FLASH_LED_THERMAL_THRSH_MASK,
FLASH_LED_THERMAL_THRSH_MIN);
if (rc < 0)
return rc;
/* Check THERMAL_OTST status */
rc = qpnp_flash_led_read(led,
FLASH_LED_REG_LED_STATUS2(led->base),
&otst_status);
if (rc < 0)
return rc;
/* Look up current limit based on THERMAL_OTST status */
if (otst_status)
thermal_current_lim =
led->pdata->thermal_derate_current[otst_status >> 1];
/* Restore THERMAL_THRESHx registers to original values */
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_THERMAL_THRSH1(led->base),
FLASH_LED_THERMAL_THRSH_MASK,
thermal_thrsh1);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_THERMAL_THRSH2(led->base),
FLASH_LED_THERMAL_THRSH_MASK,
thermal_thrsh2);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_THERMAL_THRSH3(led->base),
FLASH_LED_THERMAL_THRSH_MASK,
thermal_thrsh3);
if (rc < 0)
return rc;
return thermal_current_lim;
}
static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led) static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led)
{ {
int max_avail_current, thermal_current_lim = 0;
led->trigger_lmh = false; led->trigger_lmh = false;
return qpnp_flash_led_calc_max_current(led); max_avail_current = qpnp_flash_led_calc_max_current(led);
if (led->pdata->thermal_derate_en)
thermal_current_lim =
qpnp_flash_led_calc_thermal_current_lim(led);
if (thermal_current_lim)
max_avail_current = min(max_avail_current, thermal_current_lim);
return max_avail_current;
} }
static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value) static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
@ -1338,6 +1458,28 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
led->pdata->current_derate_en_cfg = (vph_droop_det << 2) | led->pdata->current_derate_en_cfg = (vph_droop_det << 2) |
(open_circuit_det << 1) | short_circuit_det; (open_circuit_det << 1) | short_circuit_det;
led->pdata->thermal_derate_en =
of_property_read_bool(node, "qcom,thermal-derate-en");
if (led->pdata->thermal_derate_en) {
led->pdata->thermal_derate_current =
devm_kcalloc(&led->pdev->dev,
FLASH_LED_THERMAL_OTST_LEVELS,
sizeof(int), GFP_KERNEL);
if (!led->pdata->thermal_derate_current)
return -ENOMEM;
rc = of_property_read_u32_array(node,
"qcom,thermal-derate-current",
led->pdata->thermal_derate_current,
FLASH_LED_THERMAL_OTST_LEVELS);
if (rc < 0) {
dev_err(&led->pdev->dev, "Unable to read thermal current limits, rc=%d\n",
rc);
return rc;
}
}
led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT; led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT;
rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val); rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val);
if (!rc) { if (!rc) {